getOrCreateAgeIdentity returns an age identity for encryption/decryption. Creates a new identity if one doesn't exist, storing it in the config directory.
()
| 53 | // getOrCreateAgeIdentity returns an age identity for encryption/decryption. |
| 54 | // Creates a new identity if one doesn't exist, storing it in the config directory. |
| 55 | func getOrCreateAgeIdentity() (age.Identity, age.Recipient, error) { |
| 56 | configDir := getAgeDir() |
| 57 | identityPath := filepath.Join(configDir, identityFileName) |
| 58 | recipientPath := filepath.Join(configDir, recipientFileName) |
| 59 | |
| 60 | // Try to load existing identity |
| 61 | if data, err := os.ReadFile(identityPath); err == nil { |
| 62 | identities, err := age.ParseIdentities(strings.NewReader(string(data))) |
| 63 | if err != nil { |
| 64 | return nil, nil, fmt.Errorf("parse existing identity: %w", err) |
| 65 | } |
| 66 | if len(identities) == 0 { |
| 67 | return nil, nil, fmt.Errorf("no identity found in file") |
| 68 | } |
| 69 | identity := identities[0] |
| 70 | // Try to load recipient from file, or derive from identity |
| 71 | var recipient age.Recipient |
| 72 | if recipientData, err := os.ReadFile(recipientPath); err == nil { |
| 73 | recipients, err := age.ParseRecipients(strings.NewReader(string(recipientData))) |
| 74 | if err == nil && len(recipients) > 0 { |
| 75 | recipient = recipients[0] |
| 76 | } |
| 77 | } |
| 78 | // If recipient file doesn't exist or parsing failed, try to get from identity |
| 79 | if recipient == nil { |
| 80 | // For X25519Identity, we can extract the recipient |
| 81 | if x25519Identity, ok := identity.(*age.X25519Identity); ok { |
| 82 | recipient = x25519Identity.Recipient() |
| 83 | } else { |
| 84 | return nil, nil, fmt.Errorf("unsupported identity type, cannot get recipient") |
| 85 | } |
| 86 | } |
| 87 | return identity, recipient, nil |
| 88 | } |
| 89 | |
| 90 | // Create new identity |
| 91 | identity, err := age.GenerateX25519Identity() |
| 92 | if err != nil { |
| 93 | return nil, nil, fmt.Errorf("generate identity: %w", err) |
| 94 | } |
| 95 | |
| 96 | recipient := identity.Recipient() |
| 97 | |
| 98 | // Ensure config directory exists |
| 99 | if err := os.MkdirAll(configDir, 0o700); err != nil { |
| 100 | return nil, nil, fmt.Errorf("create config directory: %w", err) |
| 101 | } |
| 102 | |
| 103 | // Save identity (private key) |
| 104 | identityStr := identity.String() |
| 105 | if err := os.WriteFile(identityPath, []byte(identityStr), 0o600); err != nil { |
| 106 | return nil, nil, fmt.Errorf("save identity: %w", err) |
| 107 | } |
| 108 | |
| 109 | // Save recipient (public key) for reference |
| 110 | recipientStr := recipient.String() |
| 111 | if err := os.WriteFile(recipientPath, []byte(recipientStr), 0o600); err != nil { |
| 112 | return nil, nil, fmt.Errorf("save recipient: %w", err) |
no test coverage detected