ageplugin

package
v0.0.0-...-e24c95d Latest Latest
Warning

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

Go to latest
Published: Sep 6, 2026 License: AGPL-3.0, MIT, BSD-3-Clause Imports: 15 Imported by: 0

README

Maintained age plugin client

This package derives from the official filippo.io/age v1.3.2 plugin client. It exists to own bounded shutdown after a plugin operation has completed or failed. File encryption/decryption and identity/recipient encoding still use the upstream module. This is a maintained adaptation, not an unmodified upstream package. The BSD license is preserved here and in packaged THIRD_PARTY_NOTICES.

Auditable changes

  • client.go: package/import relocation; identity/recipient encoding delegates to upstream plugin functions; clientConnection.Close allows one second after SIGINT, then kills and waits for the owned child if it has not exited.
  • format/format.go: byte-identical upstream source, needed because age's internal package cannot be imported from another module.
  • format/format_test.go: upstream deterministic tests with the import relocated. The CCTV-dependent fuzz function is omitted to avoid adding a test-only module; all other test functions and synthetic redaction constants are retained.
  • lifecycle_test.go: Fulla regression tests prove graceful cleanup and bounded SIGKILL/reaping of a child that ignores SIGINT, with a watchdog that makes the original unbounded behavior fail deterministically.

This is a shutdown deadline, not a timeout on protocol exchanges, PIN input, or hardware touch. It controls the direct plugin child; it does not sandbox trusted plugins or guarantee cleanup of arbitrary independently spawned descendants. The existing protocol behavior is deliberately preserved. Fulla's native malformed-response acceptance exercises the integration in Linux/macOS CI.

Source provenance

Source: https://github.com/FiloSottile/age/tree/v1.3.2. Hashes below identify the original files before adaptations:

Upstream file SHA-256
plugin/client.go 6e8d44a4e3095c9803556520773068f44225f5951ea541d2b3d0b69abcc12cff
internal/format/format.go 74478c5facf49bbca09098815c637afae566f5495fb2049bf342d9ef3c93efab
internal/format/format_test.go 5210efe186366b44d461f1118eeb9e34155c336ddd3482393f9aee929eb6bff0
LICENSE c5d65279d02955c0fc2294ae417c3add650d228f4f5c82bd6d531fc26c89cd96

On an age dependency update, compare these files against the new upstream source, review each upstream protocol/parser change, refresh this adaptation and its provenance, and rerun plugin roundtrip/interaction, lifecycle, parser, and native acceptance. Remove the adaptation when an upstream supported lifecycle API can supply equivalent termination/reaping behavior. Do not silently update the module while leaving this client behind.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

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.

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

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

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

func (e *NotFoundError) Error() string

func (*NotFoundError) Unwrap

func (e *NotFoundError) Unwrap() error

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

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)

Directories

Path Synopsis
Package format implements the age file format.
Package format implements the age file format.

Jump to

Keyboard shortcuts

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