plugin

package
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 28, 2025 License: BSD-3-Clause Imports: 20 Imported by: 26

Documentation

Overview

Package plugin implements the age plugin protocol.

Recipient and [Indentity] are plugin clients, that execute plugin binaries to perform encryption and decryption operations.

Plugin is a framework for writing age plugins, that exposes an age.Recipient and/or age.Identity implementation as a plugin binary.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func EncodeHybridRecipient added in v1.3.0

func EncodeHybridRecipient(pq *mlkem.EncapsulationKey768, t *ecdh.PublicKey) (string, error)

EncodeHybridRecipient encodes a native MLKEM768-X25519 recipient from a crypto/mlkem.EncapsulationKey768 and a crypto/ecdh.X25519 public key. It's meant for plugins that implement identities that are compatible with native recipients.

func EncodeIdentity

func EncodeIdentity(name string, data []byte) string

EncodeIdentity encodes a plugin identity string for a plugin with the given name. If the name is invalid, it returns an empty string.

func EncodeRecipient

func EncodeRecipient(name string, data []byte) string

EncodeRecipient encodes a plugin recipient string for a plugin with the given name. If the name is invalid, it returns an empty string.

func EncodeX25519Recipient

func EncodeX25519Recipient(pk *ecdh.PublicKey) (string, error)

EncodeX25519Recipient encodes a native X25519 recipient from a crypto/ecdh.X25519 public key. It's meant for plugins that implement identities that are compatible with native recipients.

func ParseIdentity

func ParseIdentity(s string) (name string, data []byte, err error)

ParseIdentity decodes a plugin identity string. It returns the plugin name in lowercase and the encoded data.

func ParseRecipient

func ParseRecipient(s string) (name string, data []byte, err error)

ParseRecipient decodes a plugin recipient string. It returns the plugin name in lowercase and the encoded data.

Types

type ClientUI

type ClientUI struct {
	// DisplayMessage displays the message, which is expected to have lowercase
	// initials and no final period.
	DisplayMessage func(name, message string) error

	// RequestValue requests a secret or public input, with the provided prompt.
	RequestValue func(name, prompt string, secret bool) (string, error)

	// Confirm requests a confirmation with the provided prompt. The yes and no
	// value are the choices provided to the user. no may be empty. The return
	// value indicates whether the user selected the yes or no option.
	Confirm func(name, prompt, yes, no string) (choseYes bool, err error)

	// WaitTimer is invoked once (Un)Wrap has been waiting for 5 seconds on the
	// plugin, for example because the plugin is waiting for an external event
	// (e.g. a hardware token touch). Unlike the other callbacks, WaitTimer runs
	// in a separate goroutine, and if missing it's simply ignored.
	WaitTimer func(name string)
}

ClientUI holds callbacks that will be invoked by (Un)Wrap if the plugin wishes to interact with the user. If any of them is nil or returns an error, failure will be reported to the plugin, but note that the error is otherwise discarded. Implementations are encouraged to display errors to the user before returning them.

func NewTerminalUI added in v1.3.0

func NewTerminalUI(printf, warningf func(format string, v ...any)) *ClientUI

NewTerminalUI returns a ClientUI that uses the terminal to request inputs, and the provided functions to display messages and errors.

The terminal is reached directly through /dev/tty or CONIN$/CONOUT$, bypassing standard input and output, so this UI can be used even when standard input or output are redirected.

type Identity

type Identity struct {
	// contains filtered or unexported fields
}

func NewIdentity

func NewIdentity(s string, ui *ClientUI) (*Identity, error)

func NewIdentityWithoutData

func NewIdentityWithoutData(name string, ui *ClientUI) (*Identity, error)

func (*Identity) Name

func (i *Identity) Name() string

Name returns the plugin name, which is used in the recipient ("age1name1...") and identity ("AGE-PLUGIN-NAME-1...") encodings, as well as in the plugin binary name ("age-plugin-name").

func (*Identity) Recipient

func (i *Identity) Recipient() *Recipient

Recipient returns a Recipient wrapping this identity. When that Recipient is used to encrypt a file key, the identity encoding is provided as-is to the plugin, which is expected to support encrypting to identities.

func (*Identity) String added in v1.3.0

func (i *Identity) String() string

String returns the identity encoding string ("AGE-PLUGIN-NAME-1...").

func (*Identity) Unwrap

func (i *Identity) Unwrap(stanzas []*age.Stanza) (fileKey []byte, err error)

type NotFoundError added in v1.3.0

type NotFoundError struct {
	// Name is the plugin (not binary) name.
	Name string
	// Err is the underlying error, usually an [exec.Error] wrapping
	// [exec.ErrNotFound].
	Err error
}

NotFoundError is returned by Recipient.Wrap and Identity.Unwrap when the plugin binary cannot be found.

func (*NotFoundError) Error added in v1.3.0

func (e *NotFoundError) Error() string

func (*NotFoundError) Unwrap added in v1.3.0

func (e *NotFoundError) Unwrap() error

type Plugin added in v1.3.0

type Plugin struct {
	// contains filtered or unexported fields
}

Plugin is a framework for writing age plugins. It allows exposing regular age.Recipient and age.Identity implementations as plugins, and handles all the protocol details.

Example (Main)
package main

import (
	"log"
	"os"

	"filippo.io/age"
	"filippo.io/age/plugin"
)

type Recipient struct{}

func (r *Recipient) Wrap(fileKey []byte) ([]*age.Stanza, error) {
	panic("unimplemented")
}

func NewRecipient(data []byte) (*Recipient, error) {
	return &Recipient{}, nil
}

type Identity struct{}

func (i *Identity) Unwrap(s []*age.Stanza) ([]byte, error) {
	panic("unimplemented")
}

func NewIdentity(data []byte) (*Identity, error) {
	return &Identity{}, nil
}

func main() {
	p, err := plugin.New("example")
	if err != nil {
		log.Fatal(err)
	}
	p.HandleRecipient(func(data []byte) (age.Recipient, error) {
		return NewRecipient(data)
	})
	p.HandleIdentity(func(data []byte) (age.Identity, error) {
		return NewIdentity(data)
	})
	os.Exit(p.Main())
}

func New added in v1.3.0

func New(name string) (*Plugin, error)

New creates a new Plugin with the given name.

For example, a plugin named "frood" would be invoked as "age-plugin-frood".

func (*Plugin) Confirm added in v1.3.0

func (p *Plugin) Confirm(prompt, yes, no string) (choseYes bool, err error)

Confirm requests a confirmation from the user through the client, with the provided prompt. The yes and no value are the choices provided to the user. no may be empty. The return value choseYes indicates whether the user selected the yes or no option. Confirm returns an error if the client can't request the confirmation.

It must only be called by a Wrap or Unwrap method invoked by Plugin.Main.

func (*Plugin) DisplayMessage added in v1.3.0

func (p *Plugin) DisplayMessage(message string) error

DisplayMessage requests that the client display a message to the user. The message should start with a lowercase letter and have no final period. DisplayMessage returns an error if the client can't display the message, and may return before the message has been displayed to the user.

It must only be called by a Wrap or Unwrap method invoked by Plugin.Main.

func (*Plugin) HandleIdentity added in v1.3.0

func (p *Plugin) HandleIdentity(f func(data []byte) (age.Identity, error))

HandleIdentity registers a function to parse identities of the form AGE-PLUGIN-NAME-1... into age.Identity values. data is the decoded Bech32 payload.

It must be called before Plugin.Main, and can be called at most once. Otherwise, it panics.

func (*Plugin) HandleIdentityAsRecipient added in v1.3.0

func (p *Plugin) HandleIdentityAsRecipient(f func(data []byte) (age.Recipient, error))

HandleIdentityAsRecipient registers a function to parse identities of the form AGE-PLUGIN-NAME-1... into age.Recipient values, for when identities are used as recipients. data is the decoded Bech32 payload.

If the returned Recipient implements age.RecipientWithLabels, Plugin will use it and enforce consistency across every returned stanza in an execution. If the client supports labels, they will be passed through the protocol.

It must be called before Plugin.Main, and can be called at most once. Otherwise, it panics.

func (*Plugin) HandleIdentityEncoding added in v1.3.0

func (p *Plugin) HandleIdentityEncoding(f func(identity string) (age.Identity, error))

HandleIdentityEncoding is like Plugin.HandleIdentity but provides the full identity encoding string to the callback.

It allows using functions like ParseIdentity directly.

func (*Plugin) HandleIdentityEncodingAsRecipient added in v1.3.0

func (p *Plugin) HandleIdentityEncodingAsRecipient(f func(identity string) (age.Recipient, error))

HandleIdentityEncodingAsRecipient is like Plugin.HandleIdentityAsRecipient but provides the full identity encoding string to the callback.

func (*Plugin) HandleRecipient added in v1.3.0

func (p *Plugin) HandleRecipient(f func(data []byte) (age.Recipient, error))

HandleRecipient registers a function to parse recipients of the form age1name1... into age.Recipient values. data is the decoded Bech32 payload.

If the returned Recipient implements age.RecipientWithLabels, Plugin will use it and enforce consistency across every returned stanza in an execution. If the client supports labels, they will be passed through the protocol.

It must be called before Plugin.Main, and can be called at most once. Otherwise, it panics.

func (*Plugin) HandleRecipientEncoding added in v1.3.0

func (p *Plugin) HandleRecipientEncoding(f func(recipient string) (age.Recipient, error))

HandleRecipientEncoding is like Plugin.HandleRecipient but provides the full recipient encoding string to the callback.

It allows using functions like ParseRecipient directly.

func (*Plugin) IdentityV1 added in v1.3.0

func (p *Plugin) IdentityV1() int

IdentityV1 implements the identity-v1 state machine. It returns an exit code to pass to os.Exit.

Most plugins should call Plugin.Main instead of this method.

func (*Plugin) Main added in v1.3.0

func (p *Plugin) Main() int

Main runs the plugin protocol. It returns an exit code to pass to os.Exit.

It automatically calls Plugin.RegisterFlags and flag.Parse if they were not called before.

func (*Plugin) Name added in v1.3.0

func (p *Plugin) Name() string

Name returns the name of the plugin.

func (*Plugin) RecipientV1 added in v1.3.0

func (p *Plugin) RecipientV1() int

RecipientV1 implements the recipient-v1 state machine. It returns an exit code to pass to os.Exit.

Most plugins should call Plugin.Main instead of this method.

func (*Plugin) RegisterFlags added in v1.3.0

func (p *Plugin) RegisterFlags(fs *flag.FlagSet)

RegisterFlags registers the plugin's flags with the given flag.FlagSet, or with the default flag.CommandLine if fs is nil. It must be called before flag.Parse and Plugin.Main.

This allows the plugin to expose additional flags when invoked manually, for example to implement a keygen mode.

func (*Plugin) RequestValue added in v1.3.0

func (p *Plugin) RequestValue(prompt string, secret bool) (string, error)

RequestValue requests a secret or public input from the user through the client, with the provided prompt. It returns an error if the client can't request the input or if the user dismisses the prompt.

It must only be called by a Wrap or Unwrap method invoked by Plugin.Main.

func (*Plugin) SetIO added in v1.3.0

func (p *Plugin) SetIO(stdin io.Reader, stdout, stderr io.Writer)

SetIO sets the plugin's input and output streams, which default to stdin/stdout/stderr.

It must be called before Plugin.Main.

type Recipient

type Recipient struct {
	// contains filtered or unexported fields
}

func NewRecipient

func NewRecipient(s string, ui *ClientUI) (*Recipient, error)

func (*Recipient) Name

func (r *Recipient) Name() string

Name returns the plugin name, which is used in the recipient ("age1name1...") and identity ("AGE-PLUGIN-NAME-1...") encodings, as well as in the plugin binary name ("age-plugin-name").

func (*Recipient) String added in v1.3.0

func (r *Recipient) String() string

String returns the recipient encoding string ("age1name1...") or "<identity-based recipient>" if r was created by Identity.Recipient.

func (*Recipient) Wrap

func (r *Recipient) Wrap(fileKey []byte) (stanzas []*age.Stanza, err error)

func (*Recipient) WrapWithLabels

func (r *Recipient) WrapWithLabels(fileKey []byte) (stanzas []*age.Stanza, labels []string, err error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL