Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions action.list.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
runtime: plugin
action:
title: "Keyring: List"
description: >-
Returns list of all stored key-value pairs and URLs.
24 changes: 24 additions & 0 deletions keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func (i KeyValueItem) isEmpty() bool {

// DataStore provides password storage functionality.
type DataStore interface {
// GetUrls retrieves a list of stored URLs.
GetUrls() ([]string, error)
// GetKeys retrieves a list of stored keys.
GetKeys() ([]string, error)
// GetForURL returns a credentials item by a URL.
// Error is returned if either the keyring could not be unlocked
// Error ErrNotFound if the credentials were not found.
Expand Down Expand Up @@ -124,6 +128,26 @@ func (k *keyringService) defaultStore() (DataStore, error) {
return k.store, nil
}

// GetUrls implements DataStore interface. Uses service default store.
func (k *keyringService) GetUrls() ([]string, error) {
s, err := k.defaultStore()
if err != nil {
return []string{}, err
}

return s.GetUrls()
}

// GetKeys implements DataStore interface. Uses service default store.
func (k *keyringService) GetKeys() ([]string, error) {
s, err := k.defaultStore()
if err != nil {
return []string{}, err
}

return s.GetKeys()
}

// GetForURL implements DataStore interface. Uses service default store.
func (k *keyringService) GetForURL(url string) (CredentialsItem, error) {
s, err := k.defaultStore()
Expand Down
47 changes: 47 additions & 0 deletions plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ var (
)

var (
//go:embed action.list.yaml
actionListYaml []byte
//go:embed action.login.yaml
actionLoginYaml []byte
//go:embed action.logout.yaml
Expand Down Expand Up @@ -107,6 +109,17 @@ func processGetByKey(value any, opts GetKeyValueProcessorOptions, ctx action.Val

// DiscoverActions implements [launchr.ActionDiscoveryPlugin] interface.
func (p *Plugin) DiscoverActions(_ context.Context) ([]*action.Action, error) {
// Action list.
listCmd := action.NewFromYAML("keyring:list", actionListYaml)
listCmd.SetRuntime(action.NewFnRuntime(func(_ context.Context, a *action.Action) error {
printer := launchr.Term()
if rt, ok := a.Runtime().(action.RuntimeTermAware); ok {
printer = rt.Term()
}

return list(p.k, printer)
}))

// Action login.
loginCmd := action.NewFromYAML("keyring:login", actionLoginYaml)
loginCmd.SetRuntime(action.NewFnRuntime(func(_ context.Context, a *action.Action) error {
Expand Down Expand Up @@ -161,6 +174,7 @@ func (p *Plugin) DiscoverActions(_ context.Context) ([]*action.Action, error) {
}))

return []*action.Action{
listCmd,
loginCmd,
logoutCmd,
setKeyCmd,
Expand Down Expand Up @@ -198,6 +212,39 @@ func buildNotFoundError(item, template string, err error) error {
return fmt.Errorf(template, item, version.Name)
}

func list(k Keyring, printer *launchr.Terminal) error {
urls, err := k.GetUrls()
if err != nil {
return err
}

keys, err := k.GetKeys()
if err != nil {
return err
}

// Show both key-value pairs and URLs
if len(keys) > 0 {
printer.Info().Printfln("Key-value pairs:")
for _, key := range keys {
printer.Printfln("- %s", key)
}
}

if len(urls) > 0 {
printer.Info().Printfln("URLs:")
for _, url := range urls {
printer.Printfln("- %s", url)
}
}

if len(urls) == 0 && len(keys) == 0 {
printer.Info().Printfln("No items found in keyring")
}

return nil
}

func login(k Keyring, creds CredentialsItem) error {
// Ask for login elements if some elements are empty.
if creds.isEmpty() {
Expand Down
28 changes: 28 additions & 0 deletions yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,34 @@ func (s *dataStoreYaml) load() error {
return nil
}

// GetUrls implements DataStore interface.
func (s *dataStoreYaml) GetUrls() ([]string, error) {
var result []string
if err := s.load(); err != nil {
return result, err
}

for i := 0; i < len(s.data.CredentialStorage); i++ {
result = append(result, s.data.CredentialStorage[i].URL)
}

return result, nil
}

// GetKeys implements DataStore interface.
func (s *dataStoreYaml) GetKeys() ([]string, error) {
var result []string
if err := s.load(); err != nil {
return result, err
}

for i := 0; i < len(s.data.KeyValueStorage); i++ {
result = append(result, s.data.KeyValueStorage[i].Key)
}

return result, nil
}

// GetForURL implements DataStore interface.
func (s *dataStoreYaml) GetForURL(url string) (CredentialsItem, error) {
if err := s.load(); err != nil {
Expand Down
Loading