package cli import ( "path/filepath" "strings" "git.eeqj.de/sneak/secret/internal/vault" "github.com/spf13/afero" "github.com/spf13/cobra" ) // getSecretNamesCompletionFunc returns a completion function that provides // secret names func getSecretNamesCompletionFunc(fs afero.Fs, stateDir string) func( cmd *cobra.Command, args []string, toComplete string, ) ([]string, cobra.ShellCompDirective) { return func( _ *cobra.Command, _ []string, toComplete string, ) ([]string, cobra.ShellCompDirective) { // Get current vault vlt, err := vault.GetCurrentVault(fs, stateDir) if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } // Get list of secrets secrets, err := vlt.ListSecrets() if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } // Filter secrets based on what user has typed var completions []string for _, secret := range secrets { if strings.HasPrefix(secret, toComplete) { completions = append(completions, secret) } } return completions, cobra.ShellCompDirectiveNoFileComp } } // getUnlockerIDsCompletionFunc returns a completion function that provides // unlocker IDs func getUnlockerIDsCompletionFunc(fs afero.Fs, stateDir string) func( cmd *cobra.Command, args []string, toComplete string, ) ([]string, cobra.ShellCompDirective) { return func( _ *cobra.Command, _ []string, toComplete string, ) ([]string, cobra.ShellCompDirective) { // Get current vault vlt, err := vault.GetCurrentVault(fs, stateDir) if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } // Get unlocker metadata list unlockerMetadataList, err := vlt.ListUnlockers() if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } // Get vault directory vaultDir, err := vlt.GetDirectory() if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } // Collect unlocker IDs var completions []string unlockersDir := filepath.Join(vaultDir, "unlockers.d") for _, metadata := range unlockerMetadataList { // Get the actual unlocker ID by creating the unlocker instance id := findUnlockerIDByMetadata(fs, unlockersDir, metadata, false) if id != "" && strings.HasPrefix(id, toComplete) { completions = append(completions, id) } } return completions, cobra.ShellCompDirectiveNoFileComp } } // getVaultNamesCompletionFunc returns a completion function that provides // vault names func getVaultNamesCompletionFunc(fs afero.Fs, stateDir string) func( cmd *cobra.Command, args []string, toComplete string, ) ([]string, cobra.ShellCompDirective) { return func( _ *cobra.Command, _ []string, toComplete string, ) ([]string, cobra.ShellCompDirective) { vaults, err := vault.ListVaults(fs, stateDir) if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } var completions []string for _, v := range vaults { if strings.HasPrefix(v, toComplete) { completions = append(completions, v) } } return completions, cobra.ShellCompDirectiveNoFileComp } } // completeVaultQualifiedSecrets completes "vault:secret" references once a // colon is present in the input func completeVaultQualifiedSecrets( fs afero.Fs, stateDir, toComplete string, ) []string { var completions []string // Complete secret names for the specified vault parts := strings.SplitN(toComplete, ":", vaultSecretParts) vaultName := parts[0] secretPrefix := parts[1] vlt := vault.NewVault(fs, stateDir, vaultName) secrets, err := vlt.ListSecrets() if err == nil { for _, secretName := range secrets { if strings.HasPrefix(secretName, secretPrefix) { completions = append(completions, vaultName+":"+secretName) } } } return completions } // completeUnqualifiedVaultSecrets completes vault names (with a ":" // suffix) and secrets from the current vault func completeUnqualifiedVaultSecrets( fs afero.Fs, stateDir, toComplete string, ) []string { var completions []string // Complete vault names with ":" suffix vaults, err := vault.ListVaults(fs, stateDir) if err == nil { for _, v := range vaults { if strings.HasPrefix(v, toComplete) { completions = append(completions, v+":") } } } // Also complete secrets from current vault (for within-vault moves) currentVlt, err := vault.GetCurrentVault(fs, stateDir) if err == nil { secrets, err := currentVlt.ListSecrets() if err == nil { for _, secretName := range secrets { if strings.HasPrefix(secretName, toComplete) { completions = append(completions, secretName) } } } } return completions } // getVaultSecretCompletionFunc returns a completion function for the // vault:secret format. It completes vault names with ":" suffix, and // after ":" it completes secrets from that vault. func getVaultSecretCompletionFunc(fs afero.Fs, stateDir string) func( cmd *cobra.Command, args []string, toComplete string, ) ([]string, cobra.ShellCompDirective) { return func( _ *cobra.Command, _ []string, toComplete string, ) ([]string, cobra.ShellCompDirective) { // Check if we're completing after a vault: prefix if strings.Contains(toComplete, ":") { return completeVaultQualifiedSecrets(fs, stateDir, toComplete), cobra.ShellCompDirectiveNoFileComp } return completeUnqualifiedVaultSecrets(fs, stateDir, toComplete), cobra.ShellCompDirectiveNoSpace } }