mirror of
https://github.com/FiloSottile/age.git
synced 2026-05-01 07:35:46 +00:00
internal/plugin,cmd/age: implement preliminary plugin client support
This commit is contained in:
@@ -249,7 +249,7 @@ func main() {
|
||||
}
|
||||
encryptPass(pass, in, out, armorFlag)
|
||||
default:
|
||||
encryptKeys(recipientFlags, recipientsFileFlags, identityFlags, in, out, armorFlag)
|
||||
encryptNotPass(recipientFlags, recipientsFileFlags, identityFlags, in, out, armorFlag)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ func passphrasePromptForEncryption() (string, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func encryptKeys(keys, files, identities []string, in io.Reader, out io.Writer, armor bool) {
|
||||
func encryptNotPass(keys, files, identities []string, in io.Reader, out io.Writer, armor bool) {
|
||||
var recipients []age.Recipient
|
||||
for _, arg := range keys {
|
||||
r, err := parseRecipient(arg)
|
||||
|
||||
@@ -99,7 +99,7 @@ func (i *EncryptedIdentity) decrypt() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt identity file: %v", err)
|
||||
}
|
||||
i.identities, err = age.ParseIdentities(d)
|
||||
i.identities, err = parseIdentities(d)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"filippo.io/age"
|
||||
"filippo.io/age/agessh"
|
||||
"filippo.io/age/armor"
|
||||
"filippo.io/age/internal/plugin"
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
@@ -32,6 +33,8 @@ func (gitHubRecipientError) Error() string {
|
||||
|
||||
func parseRecipient(arg string) (age.Recipient, error) {
|
||||
switch {
|
||||
case strings.HasPrefix(arg, "age1") && strings.Count(arg, "1") > 1:
|
||||
return plugin.NewRecipient(arg)
|
||||
case strings.HasPrefix(arg, "age1"):
|
||||
return age.ParseX25519Recipient(arg)
|
||||
case strings.HasPrefix(arg, "ssh-"):
|
||||
@@ -187,7 +190,7 @@ func parseIdentitiesFile(name string) ([]age.Identity, error) {
|
||||
|
||||
// An unencrypted age identity file.
|
||||
default:
|
||||
ids, err := age.ParseIdentities(b)
|
||||
ids, err := parseIdentities(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read %q: %v", name, err)
|
||||
}
|
||||
@@ -195,6 +198,45 @@ func parseIdentitiesFile(name string) ([]age.Identity, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func parseIdentity(s string) (age.Identity, error) {
|
||||
switch {
|
||||
case strings.HasPrefix(s, "AGE-PLUGIN-"):
|
||||
return plugin.NewIdentity(s)
|
||||
case strings.HasPrefix(s, "AGE-SECRET-KEY-1"):
|
||||
return age.ParseX25519Identity(s)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown identity type")
|
||||
}
|
||||
|
||||
// parseIdentities is like age.ParseIdentities, but supports plugin identities.
|
||||
func parseIdentities(f io.Reader) ([]age.Identity, error) {
|
||||
const privateKeySizeLimit = 1 << 24 // 16 MiB
|
||||
var ids []age.Identity
|
||||
scanner := bufio.NewScanner(io.LimitReader(f, privateKeySizeLimit))
|
||||
var n int
|
||||
for scanner.Scan() {
|
||||
n++
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "#") || line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
i, err := parseIdentity(line)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error at line %d: %v", n, err)
|
||||
}
|
||||
ids = append(ids, i)
|
||||
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("failed to read secret keys file: %v", err)
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return nil, fmt.Errorf("no secret keys found")
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func parseSSHIdentity(name string, pemBytes []byte) ([]age.Identity, error) {
|
||||
id, err := agessh.ParseIdentity(pemBytes)
|
||||
if sshErr, ok := err.(*ssh.PassphraseMissingError); ok {
|
||||
|
||||
Reference in New Issue
Block a user