fix: resolve exported type stuttering issues (revive)

- Rename VaultMetadata to Metadata in internal/vault package to avoid stuttering
- Rename BIP85DRNG to DRNG in pkg/bip85 package to avoid stuttering
- Update all references in code and tests
This commit is contained in:
Jeffrey Paul 2025-06-20 12:47:06 -07:00
parent 4062242063
commit bdcddadf90
21 changed files with 89 additions and 34 deletions

View File

@ -15,7 +15,8 @@
"Bash(golangci-lint run:*)", "Bash(golangci-lint run:*)",
"Bash(git add:*)", "Bash(git add:*)",
"Bash(gofumpt:*)", "Bash(gofumpt:*)",
"Bash(git stash:*)" "Bash(git stash:*)",
"Bash(git commit:*)"
], ],
"deny": [] "deny": []
} }

View File

@ -1283,6 +1283,7 @@ func test18AgeKeyOperations(t *testing.T, tempDir, secretPath, testMnemonic stri
fmt.Sprintf("HOME=%s", os.Getenv("HOME")), fmt.Sprintf("HOME=%s", os.Getenv("HOME")),
} }
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
return string(output), err return string(output), err
} }
@ -1349,6 +1350,7 @@ func test19DisasterRecovery(t *testing.T, tempDir, secretPath, testMnemonic stri
fmt.Sprintf("HOME=%s", os.Getenv("HOME")), fmt.Sprintf("HOME=%s", os.Getenv("HOME")),
} }
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
return string(output), err return string(output), err
} }
@ -1443,6 +1445,7 @@ func test20VersionTimestamps(t *testing.T, tempDir, secretPath, testMnemonic str
fmt.Sprintf("HOME=%s", os.Getenv("HOME")), fmt.Sprintf("HOME=%s", os.Getenv("HOME")),
} }
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
return string(output), err return string(output), err
} }
@ -2076,6 +2079,7 @@ func readFile(t *testing.T, path string) []byte {
t.Helper() t.Helper()
data, err := os.ReadFile(path) data, err := os.ReadFile(path)
require.NoError(t, err, "Should be able to read file: %s", path) require.NoError(t, err, "Should be able to read file: %s", path)
return data return data
} }
@ -2125,6 +2129,7 @@ func copyDir(src, dst string) error {
} }
} }
} }
return nil return nil
} }

View File

@ -244,7 +244,7 @@ func (cli *Instance) VaultImport(cmd *cobra.Command, vaultName string) error {
existingMetadata, err := vault.LoadVaultMetadata(cli.fs, vaultDir) existingMetadata, err := vault.LoadVaultMetadata(cli.fs, vaultDir)
if err != nil { if err != nil {
// If metadata doesn't exist, create new // If metadata doesn't exist, create new
existingMetadata = &vault.VaultMetadata{ existingMetadata = &vault.Metadata{
CreatedAt: time.Now(), CreatedAt: time.Now(),
} }
} }

View File

@ -126,6 +126,7 @@ func (cli *Instance) ListVersions(cmd *cobra.Command, secretName string) error {
status = "current (error)" status = "current (error)"
} }
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", version, "-", status, "-", "-") fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", version, "-", status, "-", "-")
continue continue
} }
@ -192,5 +193,6 @@ func (cli *Instance) PromoteVersion(cmd *cobra.Command, secretName string, versi
} }
cmd.Printf("Promoted version %s to current for secret '%s'\n", version, secretName) cmd.Printf("Promoted version %s to current for secret '%s'\n", version, secretName)
return nil return nil
} }

View File

@ -145,6 +145,7 @@ func (k *KeychainUnlocker) GetID() string {
// We cannot continue with a fallback ID as that would mask data corruption // We cannot continue with a fallback ID as that would mask data corruption
panic(fmt.Sprintf("Keychain unlocker metadata is corrupt or missing keychain item name: %v", err)) panic(fmt.Sprintf("Keychain unlocker metadata is corrupt or missing keychain item name: %v", err))
} }
return fmt.Sprintf("%s-keychain", keychainItemName) return fmt.Sprintf("%s-keychain", keychainItemName)
} }
@ -172,6 +173,7 @@ func (k *KeychainUnlocker) Remove() error {
} }
Debug("Successfully removed keychain unlocker", "unlocker_id", k.GetID(), "keychain_item", keychainItemName) Debug("Successfully removed keychain unlocker", "unlocker_id", k.GetID(), "keychain_item", keychainItemName)
return nil return nil
} }
@ -210,6 +212,7 @@ func generateKeychainUnlockerName(vaultName string) (string, error) {
// Format: secret-<vault>-<hostname>-<date> // Format: secret-<vault>-<hostname>-<date>
enrollmentDate := time.Now().Format("2006-01-02") enrollmentDate := time.Now().Format("2006-01-02")
return fmt.Sprintf("secret-%s-%s-%s", vaultName, hostname, enrollmentDate), nil return fmt.Sprintf("secret-%s-%s-%s", vaultName, hostname, enrollmentDate), nil
} }
@ -377,7 +380,9 @@ func CreateKeychainUnlocker(fs afero.Fs, stateDir string) (*KeychainUnlocker, er
return nil, fmt.Errorf("failed to marshal unlocker metadata: %w", err) return nil, fmt.Errorf("failed to marshal unlocker metadata: %w", err)
} }
if err := afero.WriteFile(fs, filepath.Join(unlockerDir, "unlocker-metadata.json"), metadataBytes, FilePerms); err != nil { if err := afero.WriteFile(fs,
filepath.Join(unlockerDir, "unlocker-metadata.json"),
metadataBytes, FilePerms); err != nil {
return nil, fmt.Errorf("failed to write unlocker metadata: %w", err) return nil, fmt.Errorf("failed to write unlocker metadata: %w", err)
} }
@ -394,6 +399,7 @@ func checkMacOSAvailable() error {
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return fmt.Errorf("macOS security command not available: %w (keychain unlockers are only supported on macOS)", err) return fmt.Errorf("macOS security command not available: %w (keychain unlockers are only supported on macOS)", err)
} }
return nil return nil
} }
@ -415,7 +421,7 @@ func storeInKeychain(itemName string, data []byte) error {
if err := validateKeychainItemName(itemName); err != nil { if err := validateKeychainItemName(itemName); err != nil {
return fmt.Errorf("invalid keychain item name: %w", err) return fmt.Errorf("invalid keychain item name: %w", err)
} }
cmd := exec.Command("/usr/bin/security", "add-generic-password", //nolint:gosec // Input validated by validateKeychainItemName cmd := exec.Command("/usr/bin/security", "add-generic-password", //nolint:gosec
"-a", itemName, "-a", itemName,
"-s", itemName, "-s", itemName,
"-w", string(data), "-w", string(data),
@ -434,7 +440,7 @@ func retrieveFromKeychain(itemName string) ([]byte, error) {
return nil, fmt.Errorf("invalid keychain item name: %w", err) return nil, fmt.Errorf("invalid keychain item name: %w", err)
} }
cmd := exec.Command("/usr/bin/security", "find-generic-password", //nolint:gosec // Input validated by validateKeychainItemName cmd := exec.Command("/usr/bin/security", "find-generic-password", //nolint:gosec
"-a", itemName, "-a", itemName,
"-s", itemName, "-s", itemName,
"-w") // Return password only "-w") // Return password only
@ -458,7 +464,7 @@ func deleteFromKeychain(itemName string) error {
return fmt.Errorf("invalid keychain item name: %w", err) return fmt.Errorf("invalid keychain item name: %w", err)
} }
cmd := exec.Command("/usr/bin/security", "delete-generic-password", //nolint:gosec // Input validated by validateKeychainItemName cmd := exec.Command("/usr/bin/security", "delete-generic-password", //nolint:gosec
"-a", itemName, "-a", itemName,
"-s", itemName) "-s", itemName)

View File

@ -6,11 +6,13 @@ import (
// VaultMetadata contains information about a vault // VaultMetadata contains information about a vault
type VaultMetadata struct { type VaultMetadata struct {
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
DerivationIndex uint32 `json:"derivation_index"` DerivationIndex uint32 `json:"derivation_index"`
PublicKeyHash string `json:"public_key_hash,omitempty"` // Double SHA256 hash of the actual long-term public key // Double SHA256 hash of the actual long-term public key
MnemonicFamilyHash string `json:"mnemonic_family_hash,omitempty"` // Double SHA256 hash of index-0 key (for grouping vaults from same mnemonic) PublicKeyHash string `json:"public_key_hash,omitempty"`
// Double SHA256 hash of index-0 key (for grouping vaults from same mnemonic)
MnemonicFamilyHash string `json:"mnemonic_family_hash,omitempty"`
} }
// UnlockerMetadata contains information about an unlocker // UnlockerMetadata contains information about an unlocker

View File

@ -121,6 +121,7 @@ func (p *PassphraseUnlocker) Remove() error {
if err := p.fs.RemoveAll(p.Directory); err != nil { if err := p.fs.RemoveAll(p.Directory); err != nil {
return fmt.Errorf("failed to remove passphrase unlocker directory: %w", err) return fmt.Errorf("failed to remove passphrase unlocker directory: %w", err)
} }
return nil return nil
} }

View File

@ -129,6 +129,7 @@ func (p *PGPUnlocker) GetID() string {
// We cannot continue with a fallback ID as that would mask data corruption // We cannot continue with a fallback ID as that would mask data corruption
panic(fmt.Sprintf("PGP unlocker metadata is corrupt or missing GPG key ID: %v", err)) panic(fmt.Sprintf("PGP unlocker metadata is corrupt or missing GPG key ID: %v", err))
} }
return fmt.Sprintf("%s-pgp", gpgKeyID) return fmt.Sprintf("%s-pgp", gpgKeyID)
} }
@ -139,6 +140,7 @@ func (p *PGPUnlocker) Remove() error {
if err := p.fs.RemoveAll(p.Directory); err != nil { if err := p.fs.RemoveAll(p.Directory); err != nil {
return fmt.Errorf("failed to remove PGP unlocker directory: %w", err) return fmt.Errorf("failed to remove PGP unlocker directory: %w", err)
} }
return nil return nil
} }
@ -177,6 +179,7 @@ func generatePGPUnlockerName() (string, error) {
// Format: hostname-pgp-YYYY-MM-DD // Format: hostname-pgp-YYYY-MM-DD
enrollmentDate := time.Now().Format("2006-01-02") enrollmentDate := time.Now().Format("2006-01-02")
return fmt.Sprintf("%s-pgp-%s", hostname, enrollmentDate), nil return fmt.Sprintf("%s-pgp-%s", hostname, enrollmentDate), nil
} }
@ -320,7 +323,9 @@ func CreatePGPUnlocker(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnloc
return nil, fmt.Errorf("failed to marshal unlocker metadata: %w", err) return nil, fmt.Errorf("failed to marshal unlocker metadata: %w", err)
} }
if err := afero.WriteFile(fs, filepath.Join(unlockerDir, "unlocker-metadata.json"), metadataBytes, FilePerms); err != nil { if err := afero.WriteFile(fs,
filepath.Join(unlockerDir, "unlocker-metadata.json"),
metadataBytes, FilePerms); err != nil {
return nil, fmt.Errorf("failed to write unlocker metadata: %w", err) return nil, fmt.Errorf("failed to write unlocker metadata: %w", err)
} }
@ -377,6 +382,7 @@ func checkGPGAvailable() error {
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return fmt.Errorf("GPG not available: %w (make sure 'gpg' command is installed and in PATH)", err) return fmt.Errorf("GPG not available: %w (make sure 'gpg' command is installed and in PATH)", err)
} }
return nil return nil
} }

View File

@ -78,6 +78,7 @@ func (s *Secret) Save(value []byte, force bool) error {
} }
Debug("Successfully saved secret", "secret_name", s.Name) Debug("Successfully saved secret", "secret_name", s.Name)
return nil return nil
} }
@ -220,6 +221,7 @@ func (s *Secret) LoadMetadata() error {
CreatedAt: now, CreatedAt: now,
UpdatedAt: now, UpdatedAt: now,
} }
return nil return nil
} }
@ -278,6 +280,7 @@ func GetCurrentVault(fs afero.Fs, stateDir string) (VaultInterface, error) {
if getCurrentVaultFunc == nil { if getCurrentVaultFunc == nil {
return nil, fmt.Errorf("GetCurrentVault function not registered") return nil, fmt.Errorf("GetCurrentVault function not registered")
} }
return getCurrentVaultFunc(fs, stateDir) return getCurrentVaultFunc(fs, stateDir)
} }

View File

@ -262,6 +262,7 @@ func isValidSecretName(name string) bool {
return false return false
} }
} }
return true return true
} }

View File

@ -51,6 +51,7 @@ func NewVersion(vault VaultInterface, secretName string, version string) *Versio
) )
now := time.Now() now := time.Now()
return &Version{ return &Version{
SecretName: secretName, SecretName: secretName,
Version: version, Version: version,
@ -219,6 +220,7 @@ func (sv *Version) Save(value []byte) error {
} }
Debug("Successfully saved secret version", "version", sv.Version, "secret_name", sv.SecretName) Debug("Successfully saved secret version", "version", sv.Version, "secret_name", sv.SecretName)
return nil return nil
} }
@ -277,6 +279,7 @@ func (sv *Version) LoadMetadata(ltIdentity *age.X25519Identity) error {
sv.Metadata = metadata sv.Metadata = metadata
Debug("Successfully loaded version metadata", "version", sv.Version) Debug("Successfully loaded version metadata", "version", sv.Version)
return nil return nil
} }
@ -344,6 +347,7 @@ func (sv *Version) GetValue(ltIdentity *age.X25519Identity) ([]byte, error) {
"version", sv.Version, "version", sv.Version,
"value_length", len(value), "value_length", len(value),
"is_empty", len(value) == 0) "is_empty", len(value) == 0)
return value, nil return value, nil
} }
@ -392,6 +396,7 @@ func GetCurrentVersion(fs afero.Fs, secretDir string) (string, error) {
if len(parts) >= 2 && parts[0] == "versions" { if len(parts) >= 2 && parts[0] == "versions" {
return parts[1], nil return parts[1], nil
} }
return "", fmt.Errorf("invalid current version symlink format: %s", target) return "", fmt.Errorf("invalid current version symlink format: %s", target)
} }
} }

View File

@ -40,7 +40,9 @@ func TestVersionIntegrationWorkflow(t *testing.T) {
stateDir := "/test/state" stateDir := "/test/state"
// Set mnemonic for testing // Set mnemonic for testing
t.Setenv(secret.EnvMnemonic, "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about") t.Setenv(secret.EnvMnemonic,
"abandon abandon abandon abandon abandon abandon "+
"abandon abandon abandon abandon abandon about")
// Create vault // Create vault
vault, err := CreateVault(fs, stateDir, "test") vault, err := CreateVault(fs, stateDir, "test")
@ -278,7 +280,7 @@ func TestVersionConcurrency(t *testing.T) {
done := make(chan bool, 10) done := make(chan bool, 10)
errors := make(chan error, 10) errors := make(chan error, 10)
for i := 0; i < 10; i++ { for range 10 {
go func() { go func() {
value, err := vault.GetSecret(secretName) value, err := vault.GetSecret(secretName)
if err != nil { if err != nil {
@ -291,7 +293,7 @@ func TestVersionConcurrency(t *testing.T) {
} }
// Wait for all goroutines // Wait for all goroutines
for i := 0; i < 10; i++ { for range 10 {
<-done <-done
} }

View File

@ -26,6 +26,7 @@ func isValidVaultName(name string) bool {
return false return false
} }
matched, _ := regexp.MatchString(`^[a-z0-9\.\-\_]+$`, name) matched, _ := regexp.MatchString(`^[a-z0-9\.\-\_]+$`, name)
return matched return matched
} }
@ -85,6 +86,7 @@ func ResolveVaultSymlink(fs afero.Fs, symlinkPath string) (string, error) {
} }
secret.Debug("resolveVaultSymlink completed successfully", "result", target) secret.Debug("resolveVaultSymlink completed successfully", "result", target)
return target, nil return target, nil
} }
} }
@ -102,6 +104,7 @@ func ResolveVaultSymlink(fs afero.Fs, symlinkPath string) (string, error) {
secret.Debug("Read target path from file", "target", target) secret.Debug("Read target path from file", "target", target)
secret.Debug("resolveVaultSymlink completed via fallback", "result", target) secret.Debug("resolveVaultSymlink completed via fallback", "result", target)
return target, nil return target, nil
} }
@ -250,7 +253,7 @@ func CreateVault(fs afero.Fs, stateDir string, name string) (*Vault, error) {
} }
// Save vault metadata // Save vault metadata
metadata := &VaultMetadata{ metadata := &Metadata{
CreatedAt: time.Now(), CreatedAt: time.Now(),
DerivationIndex: derivationIndex, DerivationIndex: derivationIndex,
PublicKeyHash: publicKeyHash, PublicKeyHash: publicKeyHash,
@ -268,6 +271,7 @@ func CreateVault(fs afero.Fs, stateDir string, name string) (*Vault, error) {
// Create and return the vault // Create and return the vault
secret.Debug("Successfully created vault", "name", name) secret.Debug("Successfully created vault", "name", name)
return NewVault(fs, stateDir, name), nil return NewVault(fs, stateDir, name), nil
} }
@ -321,5 +325,6 @@ func SelectVault(fs afero.Fs, stateDir string, name string) error {
} }
secret.Debug("Successfully selected vault", "vault_name", name) secret.Debug("Successfully selected vault", "vault_name", name)
return nil return nil
} }

View File

@ -14,7 +14,7 @@ import (
// Alias the metadata types from secret package for convenience // Alias the metadata types from secret package for convenience
type ( type (
VaultMetadata = secret.VaultMetadata Metadata = secret.VaultMetadata
UnlockerMetadata = secret.UnlockerMetadata UnlockerMetadata = secret.UnlockerMetadata
SecretMetadata = secret.Metadata SecretMetadata = secret.Metadata
Configuration = secret.Configuration Configuration = secret.Configuration
@ -24,6 +24,7 @@ type (
func ComputeDoubleSHA256(data []byte) string { func ComputeDoubleSHA256(data []byte) string {
firstHash := sha256.Sum256(data) firstHash := sha256.Sum256(data)
secondHash := sha256.Sum256(firstHash[:]) secondHash := sha256.Sum256(firstHash[:])
return hex.EncodeToString(secondHash[:]) return hex.EncodeToString(secondHash[:])
} }
@ -71,7 +72,7 @@ func GetNextDerivationIndex(fs afero.Fs, stateDir string, mnemonic string) (uint
continue continue
} }
var metadata VaultMetadata var metadata Metadata
if err := json.Unmarshal(metadataBytes, &metadata); err != nil { if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
// Skip vaults with invalid metadata // Skip vaults with invalid metadata
continue continue
@ -93,7 +94,7 @@ func GetNextDerivationIndex(fs afero.Fs, stateDir string, mnemonic string) (uint
} }
// SaveVaultMetadata saves vault metadata to the vault directory // SaveVaultMetadata saves vault metadata to the vault directory
func SaveVaultMetadata(fs afero.Fs, vaultDir string, metadata *VaultMetadata) error { func SaveVaultMetadata(fs afero.Fs, vaultDir string, metadata *Metadata) error {
metadataPath := filepath.Join(vaultDir, "vault-metadata.json") metadataPath := filepath.Join(vaultDir, "vault-metadata.json")
metadataBytes, err := json.MarshalIndent(metadata, "", " ") metadataBytes, err := json.MarshalIndent(metadata, "", " ")
@ -109,7 +110,7 @@ func SaveVaultMetadata(fs afero.Fs, vaultDir string, metadata *VaultMetadata) er
} }
// LoadVaultMetadata loads vault metadata from the vault directory // LoadVaultMetadata loads vault metadata from the vault directory
func LoadVaultMetadata(fs afero.Fs, vaultDir string) (*VaultMetadata, error) { func LoadVaultMetadata(fs afero.Fs, vaultDir string) (*Metadata, error) {
metadataPath := filepath.Join(vaultDir, "vault-metadata.json") metadataPath := filepath.Join(vaultDir, "vault-metadata.json")
metadataBytes, err := afero.ReadFile(fs, metadataPath) metadataBytes, err := afero.ReadFile(fs, metadataPath)
@ -117,7 +118,7 @@ func LoadVaultMetadata(fs afero.Fs, vaultDir string) (*VaultMetadata, error) {
return nil, fmt.Errorf("failed to read vault metadata: %w", err) return nil, fmt.Errorf("failed to read vault metadata: %w", err)
} }
var metadata VaultMetadata var metadata Metadata
if err := json.Unmarshal(metadataBytes, &metadata); err != nil { if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
return nil, fmt.Errorf("failed to unmarshal vault metadata: %w", err) return nil, fmt.Errorf("failed to unmarshal vault metadata: %w", err)
} }

View File

@ -68,7 +68,7 @@ func TestVaultMetadata(t *testing.T) {
t.Fatalf("Failed to write public key: %v", err) t.Fatalf("Failed to write public key: %v", err)
} }
metadata1 := &VaultMetadata{ metadata1 := &Metadata{
DerivationIndex: 0, DerivationIndex: 0,
PublicKeyHash: pubKeyHash0, // Hash of the actual key (index 0) PublicKeyHash: pubKeyHash0, // Hash of the actual key (index 0)
MnemonicFamilyHash: pubKeyHash0, // Hash of index 0 key (for family identification) MnemonicFamilyHash: pubKeyHash0, // Hash of index 0 key (for family identification)
@ -117,7 +117,7 @@ func TestVaultMetadata(t *testing.T) {
// Compute the hash for index 5 key // Compute the hash for index 5 key
pubKeyHash5 := ComputeDoubleSHA256([]byte(pubKey5)) pubKeyHash5 := ComputeDoubleSHA256([]byte(pubKey5))
metadata2 := &VaultMetadata{ metadata2 := &Metadata{
DerivationIndex: 5, DerivationIndex: 5,
PublicKeyHash: pubKeyHash5, // Hash of the actual key (index 5) PublicKeyHash: pubKeyHash5, // Hash of the actual key (index 5)
MnemonicFamilyHash: pubKeyHash0, // Same family hash since it's from the same mnemonic MnemonicFamilyHash: pubKeyHash0, // Same family hash since it's from the same mnemonic
@ -143,7 +143,7 @@ func TestVaultMetadata(t *testing.T) {
} }
// Create and save metadata // Create and save metadata
metadata := &VaultMetadata{ metadata := &Metadata{
DerivationIndex: 3, DerivationIndex: 3,
PublicKeyHash: "test-public-key-hash", PublicKeyHash: "test-public-key-hash",
} }

View File

@ -89,6 +89,7 @@ func isValidSecretName(name string) bool {
// Check the basic pattern // Check the basic pattern
matched, _ := regexp.MatchString(`^[a-z0-9\.\-\_\/]+$`, name) matched, _ := regexp.MatchString(`^[a-z0-9\.\-\_\/]+$`, name)
return matched return matched
} }
@ -221,7 +222,10 @@ func (v *Vault) AddSecret(name string, value []byte, force bool) error {
return fmt.Errorf("failed to set current version: %w", err) return fmt.Errorf("failed to set current version: %w", err)
} }
secret.Debug("Successfully added secret version to vault", "secret_name", name, "version", versionName, "vault_name", v.Name) secret.Debug("Successfully added secret version to vault",
"secret_name", name, "version", versionName,
"vault_name", v.Name)
return nil return nil
} }

View File

@ -39,7 +39,8 @@ func (v *Vault) GetCurrentUnlocker() (secret.Unlocker, error) {
// Try to read as symlink first // Try to read as symlink first
unlockerDir, err = linkReader.ReadlinkIfPossible(currentUnlockerPath) unlockerDir, err = linkReader.ReadlinkIfPossible(currentUnlockerPath)
if err != nil { if err != nil {
secret.Debug("Failed to read symlink, falling back to file contents", "error", err, "symlink_path", currentUnlockerPath) secret.Debug("Failed to read symlink, falling back to file contents",
"error", err, "symlink_path", currentUnlockerPath)
// Fallback: read the path from file contents // Fallback: read the path from file contents
unlockerDirBytes, err := afero.ReadFile(v.fs, currentUnlockerPath) unlockerDirBytes, err := afero.ReadFile(v.fs, currentUnlockerPath)
if err != nil { if err != nil {
@ -363,7 +364,9 @@ func (v *Vault) CreatePassphraseUnlocker(passphrase string) (*secret.PassphraseU
// Write public key // Write public key
pubKeyPath := filepath.Join(unlockerDir, "pub.age") pubKeyPath := filepath.Join(unlockerDir, "pub.age")
if err := afero.WriteFile(v.fs, pubKeyPath, []byte(unlockerIdentity.Recipient().String()), secret.FilePerms); err != nil { if err := afero.WriteFile(v.fs, pubKeyPath,
[]byte(unlockerIdentity.Recipient().String()),
secret.FilePerms); err != nil {
return nil, fmt.Errorf("failed to write unlocker public key: %w", err) return nil, fmt.Errorf("failed to write unlocker public key: %w", err)
} }

View File

@ -30,6 +30,7 @@ func NewVault(fs afero.Fs, stateDir string, name string) *Vault {
longTermKey: nil, longTermKey: nil,
} }
secret.Debug("Created NewVault instance successfully") secret.Debug("Created NewVault instance successfully")
return v return v
} }
@ -92,6 +93,7 @@ func (v *Vault) GetOrDeriveLongTermKey() (*age.X25519Identity, error) {
"derived_hash", derivedPubKeyHash, "derived_hash", derivedPubKeyHash,
"stored_hash", metadata.PublicKeyHash, "stored_hash", metadata.PublicKeyHash,
"derivation_index", metadata.DerivationIndex) "derivation_index", metadata.DerivationIndex)
return nil, fmt.Errorf("derived public key does not match vault: mnemonic may be incorrect") return nil, fmt.Errorf("derived public key does not match vault: mnemonic may be incorrect")
} }
@ -178,7 +180,8 @@ func (v *Vault) GetOrDeriveLongTermKey() (*age.X25519Identity, error) {
// Cache the derived key by unlocking the vault // Cache the derived key by unlocking the vault
v.Unlock(ltIdentity) v.Unlock(ltIdentity)
secret.Debug("Vault is unlocked (lt key in memory) via unlocker", "vault_name", v.Name, "unlocker_type", unlocker.GetType()) secret.Debug("Vault is unlocked (lt key in memory) via unlocker",
"vault_name", v.Name, "unlocker_type", unlocker.GetType())
return ltIdentity, nil return ltIdentity, nil
} }

View File

@ -54,6 +54,7 @@ func IdentityFromEntropy(ent []byte) (*age.X25519Identity, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("bech32 encode: %w", err) return nil, fmt.Errorf("bech32 encode: %w", err)
} }
return age.ParseX25519Identity(strings.ToUpper(s)) return age.ParseX25519Identity(strings.ToUpper(s))
} }
@ -125,6 +126,7 @@ func DeriveIdentity(mnemonic string, n uint32) (*age.X25519Identity, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return IdentityFromEntropy(ent) return IdentityFromEntropy(ent)
} }
@ -135,5 +137,6 @@ func DeriveIdentityFromXPRV(xprv string, n uint32) (*age.X25519Identity, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return IdentityFromEntropy(ent) return IdentityFromEntropy(ent)
} }

View File

@ -393,6 +393,7 @@ func TestIdentityFromEntropyEdgeCases(t *testing.T) {
err, err,
) // In test context, panic is acceptable for setup failures ) // In test context, panic is acceptable for setup failures
} }
return b return b
}(), }(),
expectError: false, expectError: false,

View File

@ -45,29 +45,29 @@ var (
TestNetPrivateKey = []byte{0x04, 0x35, 0x83, 0x94} TestNetPrivateKey = []byte{0x04, 0x35, 0x83, 0x94}
) )
// BIP85DRNG is a deterministic random number generator seeded by BIP85 entropy // DRNG is a deterministic random number generator seeded by BIP85 entropy
type BIP85DRNG struct { type DRNG struct {
shake io.Reader shake io.Reader
} }
// NewBIP85DRNG creates a new DRNG seeded with BIP85 entropy // NewBIP85DRNG creates a new DRNG seeded with BIP85 entropy
func NewBIP85DRNG(entropy []byte) *BIP85DRNG { func NewBIP85DRNG(entropy []byte) *DRNG {
// The entropy must be exactly 64 bytes (512 bits) // The entropy must be exactly 64 bytes (512 bits)
if len(entropy) != 64 { if len(entropy) != 64 {
panic("BIP85DRNG entropy must be 64 bytes") panic("DRNG entropy must be 64 bytes")
} }
// Initialize SHAKE256 with the entropy // Initialize SHAKE256 with the entropy
shake := sha3.NewShake256() shake := sha3.NewShake256()
shake.Write(entropy) shake.Write(entropy)
return &BIP85DRNG{ return &DRNG{
shake: shake, shake: shake,
} }
} }
// Read implements the io.Reader interface // Read implements the io.Reader interface
func (d *BIP85DRNG) Read(p []byte) (n int, err error) { func (d *DRNG) Read(p []byte) (n int, err error) {
return d.shake.Read(p) return d.shake.Read(p)
} }
@ -266,6 +266,7 @@ func DeriveXPRV(masterKey *hdkeychain.ExtendedKey, index uint32) (*hdkeychain.Ex
func doubleSHA256(data []byte) []byte { func doubleSHA256(data []byte) []byte {
hash1 := sha256.Sum256(data) hash1 := sha256.Sum256(data)
hash2 := sha256.Sum256(hash1[:]) hash2 := sha256.Sum256(hash1[:])
return hash2[:] return hash2[:]
} }