refactor: remove confusing dual ID method pattern from Unlocker interface - Removed redundant ID() method from Unlocker interface - Removed ID field from UnlockerMetadata struct - Modified GetID() to generate IDs dynamically based on unlocker type and data - Updated vault package to create unlocker instances when searching by ID - Fixed all tests and CLI code to remove ID field references - IDs are now consistently generated from unlocker data, preventing redundancy
This commit is contained in:
parent
9adf0c0803
commit
03e0ee2f95
@ -149,12 +149,12 @@ func (cli *CLIInstance) UnlockersList(jsonOutput bool) error {
|
|||||||
// Check if this is the right unlocker by comparing metadata
|
// Check if this is the right unlocker by comparing metadata
|
||||||
metadataBytes, err := afero.ReadFile(cli.fs, metadataPath)
|
metadataBytes, err := afero.ReadFile(cli.fs, metadataPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue //FIXME this error needs to be handled
|
||||||
}
|
}
|
||||||
|
|
||||||
var diskMetadata secret.UnlockerMetadata
|
var diskMetadata secret.UnlockerMetadata
|
||||||
if err := json.Unmarshal(metadataBytes, &diskMetadata); err != nil {
|
if err := json.Unmarshal(metadataBytes, &diskMetadata); err != nil {
|
||||||
continue
|
continue //FIXME this error needs to be handled
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match by type and creation time
|
// Match by type and creation time
|
||||||
@ -177,7 +177,8 @@ func (cli *CLIInstance) UnlockersList(jsonOutput bool) error {
|
|||||||
if unlocker != nil {
|
if unlocker != nil {
|
||||||
properID = unlocker.GetID()
|
properID = unlocker.GetID()
|
||||||
} else {
|
} else {
|
||||||
properID = metadata.ID // fallback to metadata ID
|
// Generate ID as fallback
|
||||||
|
properID = fmt.Sprintf("%s-%s", metadata.CreatedAt.Format("2006-01-02.15.04"), metadata.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
unlockerInfo := UnlockerInfo{
|
unlockerInfo := UnlockerInfo{
|
||||||
|
@ -131,18 +131,14 @@ func (k *KeychainUnlocker) GetDirectory() string {
|
|||||||
return k.Directory
|
return k.Directory
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetID implements Unlocker interface
|
// GetID implements Unlocker interface - generates ID from keychain item name
|
||||||
func (k *KeychainUnlocker) GetID() string {
|
func (k *KeychainUnlocker) GetID() string {
|
||||||
return k.Metadata.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID implements Unlocker interface - generates ID from keychain item name
|
|
||||||
func (k *KeychainUnlocker) ID() string {
|
|
||||||
// Generate ID using keychain item name
|
// Generate ID using keychain item name
|
||||||
keychainItemName, err := k.GetKeychainItemName()
|
keychainItemName, err := k.GetKeychainItemName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Fallback to metadata ID if we can't read the keychain item name
|
// Fallback to creation time-based ID if we can't read the keychain item name
|
||||||
return k.Metadata.ID
|
createdAt := k.Metadata.CreatedAt
|
||||||
|
return fmt.Sprintf("%s-keychain", createdAt.Format("2006-01-02.15.04"))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s-keychain", keychainItemName)
|
return fmt.Sprintf("%s-keychain", keychainItemName)
|
||||||
}
|
}
|
||||||
@ -362,12 +358,8 @@ func CreateKeychainUnlocker(fs afero.Fs, stateDir string) (*KeychainUnlocker, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 9: Create and write enhanced metadata
|
// Step 9: Create and write enhanced metadata
|
||||||
// Generate the key ID directly using the keychain item name
|
|
||||||
keyID := fmt.Sprintf("%s-keychain", keychainItemName)
|
|
||||||
|
|
||||||
keychainMetadata := KeychainUnlockerMetadata{
|
keychainMetadata := KeychainUnlockerMetadata{
|
||||||
UnlockerMetadata: UnlockerMetadata{
|
UnlockerMetadata: UnlockerMetadata{
|
||||||
ID: keyID,
|
|
||||||
Type: "keychain",
|
Type: "keychain",
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
Flags: []string{"keychain", "macos"},
|
Flags: []string{"keychain", "macos"},
|
||||||
|
@ -14,7 +14,6 @@ type VaultMetadata struct {
|
|||||||
|
|
||||||
// UnlockerMetadata contains information about an unlocker
|
// UnlockerMetadata contains information about an unlocker
|
||||||
type UnlockerMetadata struct {
|
type UnlockerMetadata struct {
|
||||||
ID string `json:"id"`
|
|
||||||
Type string `json:"type"` // passphrase, pgp, keychain
|
Type string `json:"type"` // passphrase, pgp, keychain
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
Flags []string `json:"flags,omitempty"`
|
Flags []string `json:"flags,omitempty"`
|
||||||
|
@ -40,7 +40,6 @@ func TestPassphraseUnlockerWithRealFS(t *testing.T) {
|
|||||||
|
|
||||||
// Set up test metadata
|
// Set up test metadata
|
||||||
metadata := secret.UnlockerMetadata{
|
metadata := secret.UnlockerMetadata{
|
||||||
ID: "test-passphrase",
|
|
||||||
Type: "passphrase",
|
Type: "passphrase",
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
Flags: []string{},
|
Flags: []string{},
|
||||||
|
@ -107,13 +107,8 @@ func (p *PassphraseUnlocker) GetDirectory() string {
|
|||||||
return p.Directory
|
return p.Directory
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetID implements Unlocker interface
|
// GetID implements Unlocker interface - generates ID from creation timestamp
|
||||||
func (p *PassphraseUnlocker) GetID() string {
|
func (p *PassphraseUnlocker) GetID() string {
|
||||||
return p.Metadata.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID implements Unlocker interface - generates ID from creation timestamp
|
|
||||||
func (p *PassphraseUnlocker) ID() string {
|
|
||||||
// Generate ID using creation timestamp: YYYY-MM-DD.HH.mm-passphrase
|
// Generate ID using creation timestamp: YYYY-MM-DD.HH.mm-passphrase
|
||||||
createdAt := p.Metadata.CreatedAt
|
createdAt := p.Metadata.CreatedAt
|
||||||
return fmt.Sprintf("%s-passphrase", createdAt.Format("2006-01-02.15.04"))
|
return fmt.Sprintf("%s-passphrase", createdAt.Format("2006-01-02.15.04"))
|
||||||
|
@ -413,7 +413,6 @@ Passphrase: ` + testPassphrase + `
|
|||||||
|
|
||||||
// Set up test metadata
|
// Set up test metadata
|
||||||
metadata := secret.UnlockerMetadata{
|
metadata := secret.UnlockerMetadata{
|
||||||
ID: fmt.Sprintf("%s-pgp", keyID),
|
|
||||||
Type: "pgp",
|
Type: "pgp",
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
Flags: []string{"gpg", "encrypted"},
|
Flags: []string{"gpg", "encrypted"},
|
||||||
|
@ -106,18 +106,14 @@ func (p *PGPUnlocker) GetDirectory() string {
|
|||||||
return p.Directory
|
return p.Directory
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetID implements Unlocker interface
|
// GetID implements Unlocker interface - generates ID from GPG key ID
|
||||||
func (p *PGPUnlocker) GetID() string {
|
func (p *PGPUnlocker) GetID() string {
|
||||||
return p.Metadata.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID implements Unlocker interface - generates ID from GPG key ID
|
|
||||||
func (p *PGPUnlocker) ID() string {
|
|
||||||
// Generate ID using GPG key ID: <keyid>-pgp
|
// Generate ID using GPG key ID: <keyid>-pgp
|
||||||
gpgKeyID, err := p.GetGPGKeyID()
|
gpgKeyID, err := p.GetGPGKeyID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Fallback to metadata ID if we can't read the GPG key ID
|
// Fallback to creation time-based ID if we can't read the GPG key ID
|
||||||
return p.Metadata.ID
|
createdAt := p.Metadata.CreatedAt
|
||||||
|
return fmt.Sprintf("%s-pgp", createdAt.Format("2006-01-02.15.04"))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s-pgp", gpgKeyID)
|
return fmt.Sprintf("%s-pgp", gpgKeyID)
|
||||||
}
|
}
|
||||||
@ -290,12 +286,8 @@ func CreatePGPUnlocker(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 9: Create and write enhanced metadata
|
// Step 9: Create and write enhanced metadata
|
||||||
// Generate the key ID directly using the GPG key ID
|
|
||||||
keyID := fmt.Sprintf("%s-pgp", gpgKeyID)
|
|
||||||
|
|
||||||
pgpMetadata := PGPUnlockerMetadata{
|
pgpMetadata := PGPUnlockerMetadata{
|
||||||
UnlockerMetadata: UnlockerMetadata{
|
UnlockerMetadata: UnlockerMetadata{
|
||||||
ID: keyID,
|
|
||||||
Type: "pgp",
|
Type: "pgp",
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
Flags: []string{"gpg", "encrypted"},
|
Flags: []string{"gpg", "encrypted"},
|
||||||
|
@ -10,7 +10,6 @@ type Unlocker interface {
|
|||||||
GetType() string
|
GetType() string
|
||||||
GetMetadata() UnlockerMetadata
|
GetMetadata() UnlockerMetadata
|
||||||
GetDirectory() string
|
GetDirectory() string
|
||||||
GetID() string
|
GetID() string // Generate ID based on unlocker type and data
|
||||||
ID() string // Generate ID from the unlocker's public key
|
|
||||||
Remove() error // Remove the unlocker and any associated resources
|
Remove() error // Remove the unlocker and any associated resources
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,6 @@ func (v *Vault) GetCurrentUnlocker() (secret.Unlocker, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
secret.DebugWith("Parsed unlocker metadata",
|
secret.DebugWith("Parsed unlocker metadata",
|
||||||
slog.String("unlocker_id", metadata.ID),
|
|
||||||
slog.String("unlocker_type", metadata.Type),
|
slog.String("unlocker_type", metadata.Type),
|
||||||
slog.Time("created_at", metadata.CreatedAt),
|
slog.Time("created_at", metadata.CreatedAt),
|
||||||
slog.Any("flags", metadata.Flags),
|
slog.Any("flags", metadata.Flags),
|
||||||
@ -87,16 +86,16 @@ func (v *Vault) GetCurrentUnlocker() (secret.Unlocker, error) {
|
|||||||
secretMetadata := secret.UnlockerMetadata(metadata)
|
secretMetadata := secret.UnlockerMetadata(metadata)
|
||||||
switch metadata.Type {
|
switch metadata.Type {
|
||||||
case "passphrase":
|
case "passphrase":
|
||||||
secret.Debug("Creating passphrase unlocker instance", "unlocker_id", metadata.ID)
|
secret.Debug("Creating passphrase unlocker instance", "unlocker_type", metadata.Type)
|
||||||
unlocker = secret.NewPassphraseUnlocker(v.fs, unlockerDir, secretMetadata)
|
unlocker = secret.NewPassphraseUnlocker(v.fs, unlockerDir, secretMetadata)
|
||||||
case "pgp":
|
case "pgp":
|
||||||
secret.Debug("Creating PGP unlocker instance", "unlocker_id", metadata.ID)
|
secret.Debug("Creating PGP unlocker instance", "unlocker_type", metadata.Type)
|
||||||
unlocker = secret.NewPGPUnlocker(v.fs, unlockerDir, secretMetadata)
|
unlocker = secret.NewPGPUnlocker(v.fs, unlockerDir, secretMetadata)
|
||||||
case "keychain":
|
case "keychain":
|
||||||
secret.Debug("Creating keychain unlocker instance", "unlocker_id", metadata.ID)
|
secret.Debug("Creating keychain unlocker instance", "unlocker_type", metadata.Type)
|
||||||
unlocker = secret.NewKeychainUnlocker(v.fs, unlockerDir, secretMetadata)
|
unlocker = secret.NewKeychainUnlocker(v.fs, unlockerDir, secretMetadata)
|
||||||
default:
|
default:
|
||||||
secret.Debug("Unsupported unlocker type", "type", metadata.Type, "unlocker_id", metadata.ID)
|
secret.Debug("Unsupported unlocker type", "type", metadata.Type)
|
||||||
return nil, fmt.Errorf("unsupported unlocker type: %s", metadata.Type)
|
return nil, fmt.Errorf("unsupported unlocker type: %s", metadata.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,23 +199,27 @@ func (v *Vault) RemoveUnlocker(unlockerID string) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata.ID == unlockerID {
|
unlockerDirPath = filepath.Join(unlockersDir, file.Name())
|
||||||
unlockerDirPath = filepath.Join(unlockersDir, file.Name())
|
|
||||||
|
|
||||||
// Convert our metadata to secret.UnlockerMetadata
|
// Convert our metadata to secret.UnlockerMetadata
|
||||||
secretMetadata := secret.UnlockerMetadata(metadata)
|
secretMetadata := secret.UnlockerMetadata(metadata)
|
||||||
|
|
||||||
// Create the appropriate unlocker instance
|
// Create the appropriate unlocker instance
|
||||||
switch metadata.Type {
|
var tempUnlocker secret.Unlocker
|
||||||
case "passphrase":
|
switch metadata.Type {
|
||||||
unlocker = secret.NewPassphraseUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
case "passphrase":
|
||||||
case "pgp":
|
tempUnlocker = secret.NewPassphraseUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
||||||
unlocker = secret.NewPGPUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
case "pgp":
|
||||||
case "keychain":
|
tempUnlocker = secret.NewPGPUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
||||||
unlocker = secret.NewKeychainUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
case "keychain":
|
||||||
default:
|
tempUnlocker = secret.NewKeychainUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
||||||
return fmt.Errorf("unsupported unlocker type: %s", metadata.Type)
|
default:
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this unlocker's ID matches
|
||||||
|
if tempUnlocker.GetID() == unlockerID {
|
||||||
|
unlocker = tempUnlocker
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,8 +269,27 @@ func (v *Vault) SelectUnlocker(unlockerID string) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata.ID == unlockerID {
|
unlockerDirPath := filepath.Join(unlockersDir, file.Name())
|
||||||
targetUnlockerDir = filepath.Join(unlockersDir, file.Name())
|
|
||||||
|
// Convert our metadata to secret.UnlockerMetadata
|
||||||
|
secretMetadata := secret.UnlockerMetadata(metadata)
|
||||||
|
|
||||||
|
// Create the appropriate unlocker instance
|
||||||
|
var tempUnlocker secret.Unlocker
|
||||||
|
switch metadata.Type {
|
||||||
|
case "passphrase":
|
||||||
|
tempUnlocker = secret.NewPassphraseUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
||||||
|
case "pgp":
|
||||||
|
tempUnlocker = secret.NewPGPUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
||||||
|
case "keychain":
|
||||||
|
tempUnlocker = secret.NewKeychainUnlocker(v.fs, unlockerDirPath, secretMetadata)
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this unlocker's ID matches
|
||||||
|
if tempUnlocker.GetID() == unlockerID {
|
||||||
|
targetUnlockerDir = unlockerDirPath
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,8 +320,7 @@ func (v *Vault) CreatePassphraseUnlocker(passphrase string) (*secret.PassphraseU
|
|||||||
return nil, fmt.Errorf("failed to get vault directory: %w", err)
|
return nil, fmt.Errorf("failed to get vault directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create unlocker directory with timestamp
|
// Create unlocker directory
|
||||||
timestamp := time.Now().Format("2006-01-02.15.04")
|
|
||||||
unlockerDir := filepath.Join(vaultDir, "unlockers.d", "passphrase")
|
unlockerDir := filepath.Join(vaultDir, "unlockers.d", "passphrase")
|
||||||
if err := v.fs.MkdirAll(unlockerDir, secret.DirPerms); err != nil {
|
if err := v.fs.MkdirAll(unlockerDir, secret.DirPerms); err != nil {
|
||||||
return nil, fmt.Errorf("failed to create unlocker directory: %w", err)
|
return nil, fmt.Errorf("failed to create unlocker directory: %w", err)
|
||||||
@ -331,9 +352,7 @@ func (v *Vault) CreatePassphraseUnlocker(passphrase string) (*secret.PassphraseU
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create metadata
|
// Create metadata
|
||||||
unlockerID := fmt.Sprintf("%s-passphrase", timestamp)
|
|
||||||
metadata := UnlockerMetadata{
|
metadata := UnlockerMetadata{
|
||||||
ID: unlockerID,
|
|
||||||
Type: "passphrase",
|
Type: "passphrase",
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
Flags: []string{},
|
Flags: []string{},
|
||||||
@ -368,13 +387,16 @@ func (v *Vault) CreatePassphraseUnlocker(passphrase string) (*secret.PassphraseU
|
|||||||
return nil, fmt.Errorf("failed to write encrypted long-term private key: %w", err)
|
return nil, fmt.Errorf("failed to write encrypted long-term private key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select this unlocker as current
|
|
||||||
if err := v.SelectUnlocker(unlockerID); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to select new unlocker: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert our metadata to secret.UnlockerMetadata for the constructor
|
// Convert our metadata to secret.UnlockerMetadata for the constructor
|
||||||
secretMetadata := secret.UnlockerMetadata(metadata)
|
secretMetadata := secret.UnlockerMetadata(metadata)
|
||||||
|
|
||||||
return secret.NewPassphraseUnlocker(v.fs, unlockerDir, secretMetadata), nil
|
// Create the unlocker instance
|
||||||
|
unlocker := secret.NewPassphraseUnlocker(v.fs, unlockerDir, secretMetadata)
|
||||||
|
|
||||||
|
// Select this unlocker as current
|
||||||
|
if err := v.SelectUnlocker(unlocker.GetID()); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to select new unlocker: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return unlocker, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user