11package age
22
33import (
4+ "bufio"
45 "bytes"
56 "errors"
7+ "filippo.io/age/plugin"
8+ "filippo.io/age/tui"
69 "fmt"
710 "io"
811 "os"
@@ -60,7 +63,7 @@ type MasterKey struct {
6063 parsedIdentities []age.Identity
6164 // parsedRecipient contains a parsed age public key.
6265 // It is used to lazy-load the Recipient at-most once.
63- parsedRecipient * age.X25519Recipient
66+ parsedRecipient age.Recipient
6467}
6568
6669// MasterKeysFromRecipients takes a comma-separated list of Bech32-encoded
@@ -126,6 +129,7 @@ func (i ParsedIdentities) ApplyToMasterKey(key *MasterKey) {
126129
127130// Encrypt takes a SOPS data key, encrypts it with the Recipient, and stores
128131// the result in the EncryptedKey field.
132+
129133func (key * MasterKey ) Encrypt (dataKey []byte ) error {
130134 if key .parsedRecipient == nil {
131135 parsedRecipient , err := parseRecipient (key .Recipient )
@@ -284,7 +288,12 @@ func (key *MasterKey) loadIdentities() (ParsedIdentities, error) {
284288
285289 var identities ParsedIdentities
286290 for n , r := range readers {
287- ids , err := age .ParseIdentities (r )
291+ buf := new (strings.Builder )
292+ _ , err := io .Copy (buf , r )
293+ if err != nil {
294+ return nil , fmt .Errorf ("failed to read '%s' age identities: %w" , n , err )
295+ }
296+ ids , err := parseIdentities (buf .String ())
288297 if err != nil {
289298 return nil , fmt .Errorf ("failed to parse '%s' age identities: %w" , n , err )
290299 }
@@ -295,12 +304,21 @@ func (key *MasterKey) loadIdentities() (ParsedIdentities, error) {
295304
296305// parseRecipient attempts to parse a string containing an encoded age public
297306// key.
298- func parseRecipient (recipient string ) (* age.X25519Recipient , error ) {
299- parsedRecipient , err := age .ParseX25519Recipient (recipient )
300- if err != nil {
301- return nil , fmt .Errorf ("failed to parse input as Bech32-encoded age public key: %w" , err )
307+ func parseRecipient (recipient string ) (age.Recipient , error ) {
308+ switch {
309+ case strings .HasPrefix (recipient , "age1" ) && strings .Count (recipient , "1" ) > 1 :
310+ parsedRecipient , err := plugin .NewRecipient (recipient , tui .PluginTerminalUI )
311+ if err != nil {
312+ return nil , fmt .Errorf ("failed to parse input as age key from age plugin: %w" , err )
313+ }
314+ return parsedRecipient , nil
315+ default :
316+ parsedRecipient , err := age .ParseX25519Recipient (recipient )
317+ if err != nil {
318+ return nil , fmt .Errorf ("failed to parse input as Bech32-encoded age public key: %w" , err )
319+ }
320+ return parsedRecipient , nil
302321 }
303- return parsedRecipient , nil
304322}
305323
306324// parseIdentities attempts to parse the string set of encoded age identities.
@@ -309,11 +327,51 @@ func parseRecipient(recipient string) (*age.X25519Recipient, error) {
309327func parseIdentities (identity ... string ) (ParsedIdentities , error ) {
310328 var identities []age.Identity
311329 for _ , i := range identity {
312- parsed , err := age . ParseIdentities (strings .NewReader (i ))
330+ parsed , err := _parseIdentities (strings .NewReader (i ))
313331 if err != nil {
314332 return nil , err
315333 }
316334 identities = append (identities , parsed ... )
317335 }
318336 return identities , nil
319337}
338+
339+ func parseIdentity (s string ) (age.Identity , error ) {
340+ switch {
341+ case strings .HasPrefix (s , "AGE-PLUGIN-" ):
342+ return plugin .NewIdentity (s , tui .PluginTerminalUI )
343+ case strings .HasPrefix (s , "AGE-SECRET-KEY-1" ):
344+ return age .ParseX25519Identity (s )
345+ default :
346+ return nil , fmt .Errorf ("unknown identity type" )
347+ }
348+ }
349+
350+ // parseIdentities is like age.ParseIdentities, but supports plugin identities.
351+ func _parseIdentities (f io.Reader ) (ParsedIdentities , error ) {
352+ const privateKeySizeLimit = 1 << 24 // 16 MiB
353+ var ids []age.Identity
354+ scanner := bufio .NewScanner (io .LimitReader (f , privateKeySizeLimit ))
355+ var n int
356+ for scanner .Scan () {
357+ n ++
358+ line := scanner .Text ()
359+ if strings .HasPrefix (line , "#" ) || line == "" {
360+ continue
361+ }
362+
363+ i , err := parseIdentity (line )
364+ if err != nil {
365+ return nil , fmt .Errorf ("error at line %d: %v" , n , err )
366+ }
367+ ids = append (ids , i )
368+
369+ }
370+ if err := scanner .Err (); err != nil {
371+ return nil , fmt .Errorf ("failed to read secret keys file: %v" , err )
372+ }
373+ if len (ids ) == 0 {
374+ return nil , fmt .Errorf ("no secret keys found" )
375+ }
376+ return ids , nil
377+ }
0 commit comments