fix: resolve all nestif linter errors
- Extract getLongTermPrivateKey helper function to reduce nesting in keychainunlocker.go and pgpunlocker.go - Add getPassphrase helper method to reduce nesting in passphraseunlocker.go - Refactor version serial extraction to use early returns in version.go - Extract resolveRelativeSymlink and tryResolveOsSymlink helpers in management.go - Add processMnemonicForVault helper to reduce nesting in vault creation - Extract resolveUnlockerDirectory and readUnlockerPathFromFile helpers in unlockers.go - Add findUnlockerByID helper to reduce duplicate code in RemoveUnlocker and SelectUnlocker All tests pass after refactoring.
This commit is contained in:
@@ -33,31 +33,9 @@ func (v *Vault) GetCurrentUnlocker() (secret.Unlocker, error) {
|
||||
}
|
||||
|
||||
// Resolve the symlink to get the target directory
|
||||
var unlockerDir string
|
||||
if linkReader, ok := v.fs.(afero.LinkReader); ok {
|
||||
secret.Debug("Resolving unlocker symlink using afero")
|
||||
// Try to read as symlink first
|
||||
unlockerDir, err = linkReader.ReadlinkIfPossible(currentUnlockerPath)
|
||||
if err != nil {
|
||||
secret.Debug("Failed to read symlink, falling back to file contents",
|
||||
"error", err, "symlink_path", currentUnlockerPath)
|
||||
// Fallback: read the path from file contents
|
||||
unlockerDirBytes, err := afero.ReadFile(v.fs, currentUnlockerPath)
|
||||
if err != nil {
|
||||
secret.Debug("Failed to read unlocker path file", "error", err, "path", currentUnlockerPath)
|
||||
return nil, fmt.Errorf("failed to read current unlocker: %w", err)
|
||||
}
|
||||
unlockerDir = strings.TrimSpace(string(unlockerDirBytes))
|
||||
}
|
||||
} else {
|
||||
secret.Debug("Reading unlocker path (filesystem doesn't support symlinks)")
|
||||
// Fallback for filesystems that don't support symlinks: read the path from file contents
|
||||
unlockerDirBytes, err := afero.ReadFile(v.fs, currentUnlockerPath)
|
||||
if err != nil {
|
||||
secret.Debug("Failed to read unlocker path file", "error", err, "path", currentUnlockerPath)
|
||||
return nil, fmt.Errorf("failed to read current unlocker: %w", err)
|
||||
}
|
||||
unlockerDir = strings.TrimSpace(string(unlockerDirBytes))
|
||||
unlockerDir, err := v.resolveUnlockerDirectory(currentUnlockerPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secret.DebugWith("Resolved unlocker directory",
|
||||
@@ -114,6 +92,95 @@ func (v *Vault) GetCurrentUnlocker() (secret.Unlocker, error) {
|
||||
return unlocker, nil
|
||||
}
|
||||
|
||||
// resolveUnlockerDirectory resolves the unlocker directory from a symlink or file
|
||||
func (v *Vault) resolveUnlockerDirectory(currentUnlockerPath string) (string, error) {
|
||||
linkReader, ok := v.fs.(afero.LinkReader)
|
||||
if !ok {
|
||||
// Fallback for filesystems that don't support symlinks
|
||||
return v.readUnlockerPathFromFile(currentUnlockerPath)
|
||||
}
|
||||
|
||||
secret.Debug("Resolving unlocker symlink using afero")
|
||||
// Try to read as symlink first
|
||||
unlockerDir, err := linkReader.ReadlinkIfPossible(currentUnlockerPath)
|
||||
if err == nil {
|
||||
return unlockerDir, nil
|
||||
}
|
||||
|
||||
secret.Debug("Failed to read symlink, falling back to file contents",
|
||||
"error", err, "symlink_path", currentUnlockerPath)
|
||||
// Fallback: read the path from file contents
|
||||
return v.readUnlockerPathFromFile(currentUnlockerPath)
|
||||
}
|
||||
|
||||
// readUnlockerPathFromFile reads the unlocker directory path from a file
|
||||
func (v *Vault) readUnlockerPathFromFile(path string) (string, error) {
|
||||
secret.Debug("Reading unlocker path from file", "path", path)
|
||||
unlockerDirBytes, err := afero.ReadFile(v.fs, path)
|
||||
if err != nil {
|
||||
secret.Debug("Failed to read unlocker path file", "error", err, "path", path)
|
||||
return "", fmt.Errorf("failed to read current unlocker: %w", err)
|
||||
}
|
||||
return strings.TrimSpace(string(unlockerDirBytes)), nil
|
||||
}
|
||||
|
||||
// findUnlockerByID finds an unlocker by its ID and returns the unlocker instance and its directory path
|
||||
func (v *Vault) findUnlockerByID(unlockersDir, unlockerID string) (secret.Unlocker, string, error) {
|
||||
files, err := afero.ReadDir(v.fs, unlockersDir)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to read unlockers directory: %w", err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Read metadata file
|
||||
metadataPath := filepath.Join(unlockersDir, file.Name(), "unlocker-metadata.json")
|
||||
exists, err := afero.Exists(v.fs, metadataPath)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to check if metadata exists for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
if !exists {
|
||||
// Skip directories without metadata - they might not be unlockers
|
||||
continue
|
||||
}
|
||||
|
||||
metadataBytes, err := afero.ReadFile(v.fs, metadataPath)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to read metadata for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
|
||||
var metadata UnlockerMetadata
|
||||
if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
|
||||
return nil, "", fmt.Errorf("failed to parse metadata for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
|
||||
unlockerDirPath := filepath.Join(unlockersDir, file.Name())
|
||||
|
||||
// Create the appropriate unlocker instance
|
||||
var tempUnlocker secret.Unlocker
|
||||
switch metadata.Type {
|
||||
case "passphrase":
|
||||
tempUnlocker = secret.NewPassphraseUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
case "pgp":
|
||||
tempUnlocker = secret.NewPGPUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
case "keychain":
|
||||
tempUnlocker = secret.NewKeychainUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if this unlocker's ID matches
|
||||
if tempUnlocker.GetID() == unlockerID {
|
||||
return tempUnlocker, unlockerDirPath, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
// ListUnlockers returns a list of available unlockers for this vault
|
||||
func (v *Vault) ListUnlockers() ([]UnlockerMetadata, error) {
|
||||
vaultDir, err := v.GetDirectory()
|
||||
@@ -178,58 +245,10 @@ func (v *Vault) RemoveUnlocker(unlockerID string) error {
|
||||
// Find the unlocker directory and create the unlocker instance
|
||||
unlockersDir := filepath.Join(vaultDir, "unlockers.d")
|
||||
|
||||
// List directories in unlockers.d
|
||||
files, err := afero.ReadDir(v.fs, unlockersDir)
|
||||
// Find the unlocker by ID
|
||||
unlocker, _, err := v.findUnlockerByID(unlockersDir, unlockerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read unlockers directory: %w", err)
|
||||
}
|
||||
|
||||
var unlocker secret.Unlocker
|
||||
var unlockerDirPath string
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
// Read metadata file
|
||||
metadataPath := filepath.Join(unlockersDir, file.Name(), "unlocker-metadata.json")
|
||||
exists, err := afero.Exists(v.fs, metadataPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check if metadata exists for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
if !exists {
|
||||
// Skip directories without metadata - they might not be unlockers
|
||||
continue
|
||||
}
|
||||
|
||||
metadataBytes, err := afero.ReadFile(v.fs, metadataPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read metadata for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
|
||||
var metadata UnlockerMetadata
|
||||
if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
|
||||
return fmt.Errorf("failed to parse metadata for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
|
||||
unlockerDirPath = filepath.Join(unlockersDir, file.Name())
|
||||
|
||||
// Create the appropriate unlocker instance
|
||||
var tempUnlocker secret.Unlocker
|
||||
switch metadata.Type {
|
||||
case "passphrase":
|
||||
tempUnlocker = secret.NewPassphraseUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
case "pgp":
|
||||
tempUnlocker = secret.NewPGPUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
case "keychain":
|
||||
tempUnlocker = secret.NewKeychainUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if this unlocker's ID matches
|
||||
if tempUnlocker.GetID() == unlockerID {
|
||||
unlocker = tempUnlocker
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if unlocker == nil {
|
||||
@@ -250,57 +269,10 @@ func (v *Vault) SelectUnlocker(unlockerID string) error {
|
||||
// Find the unlocker directory by ID
|
||||
unlockersDir := filepath.Join(vaultDir, "unlockers.d")
|
||||
|
||||
// List directories in unlockers.d to find the unlocker
|
||||
files, err := afero.ReadDir(v.fs, unlockersDir)
|
||||
// Find the unlocker by ID
|
||||
_, targetUnlockerDir, err := v.findUnlockerByID(unlockersDir, unlockerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read unlockers directory: %w", err)
|
||||
}
|
||||
|
||||
var targetUnlockerDir string
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
// Read metadata file
|
||||
metadataPath := filepath.Join(unlockersDir, file.Name(), "unlocker-metadata.json")
|
||||
exists, err := afero.Exists(v.fs, metadataPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check if metadata exists for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
if !exists {
|
||||
// Skip directories without metadata - they might not be unlockers
|
||||
continue
|
||||
}
|
||||
|
||||
metadataBytes, err := afero.ReadFile(v.fs, metadataPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read metadata for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
|
||||
var metadata UnlockerMetadata
|
||||
if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
|
||||
return fmt.Errorf("failed to parse metadata for unlocker %s: %w", file.Name(), err)
|
||||
}
|
||||
|
||||
unlockerDirPath := filepath.Join(unlockersDir, file.Name())
|
||||
|
||||
// Create the appropriate unlocker instance
|
||||
var tempUnlocker secret.Unlocker
|
||||
switch metadata.Type {
|
||||
case "passphrase":
|
||||
tempUnlocker = secret.NewPassphraseUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
case "pgp":
|
||||
tempUnlocker = secret.NewPGPUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
case "keychain":
|
||||
tempUnlocker = secret.NewKeychainUnlocker(v.fs, unlockerDirPath, metadata)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if this unlocker's ID matches
|
||||
if tempUnlocker.GetID() == unlockerID {
|
||||
targetUnlockerDir = unlockerDirPath
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if targetUnlockerDir == "" {
|
||||
|
||||
Reference in New Issue
Block a user