1// Package keyring keeps the JEV API key in the operating system's2// credential store: the macOS Keychain, the Windows Credential Manager,3// or the freedesktop Secret Service on Linux and the BSDs (GNOME4// Keyring, KWallet, KeePassXC). It needs nothing beyond the standard5// library and golang.org/x/sys: on macOS and Linux it runs the system's6// own command line tools (security, secret-tool), handing them the7// secret on stdin so it never appears in a process list; on Windows it8// calls the Credential Manager API directly. See docs/contributing/architecture.md.9package keyring1011import (12 "context"13 "errors"14 "sync"15)1617// Service and Account name the stored item.18const (19 Service = "012"20 Account = "jev-api-key"21 Label = "012 JEV API key"22)2324// ErrNotFound means no key is stored.25var ErrNotFound = errors.New("no key in the credential store")2627// Store keeps one secret.28type Store interface {29 Get(ctx context.Context) (string, error)30 Set(ctx context.Context, secret string) error31 Delete(ctx context.Context) error32 // Name is what the store is called, e.g. "macOS Keychain".33 Name() string34}3536// Memory is a Store in memory, for tests.37type Memory struct {38 mu sync.Mutex39 secret string40 Err error // returned by every call when set41}4243func (m *Memory) Get(context.Context) (string, error) {44 m.mu.Lock()45 defer m.mu.Unlock()46 if m.Err != nil {47 return "", m.Err48 }49 if m.secret == "" {50 return "", ErrNotFound51 }52 return m.secret, nil53}5455func (m *Memory) Set(_ context.Context, s string) error {56 m.mu.Lock()57 defer m.mu.Unlock()58 if m.Err != nil {59 return m.Err60 }61 m.secret = s62 return nil63}6465func (m *Memory) Delete(context.Context) error {66 m.mu.Lock()67 defer m.mu.Unlock()68 if m.Err != nil {69 return m.Err70 }71 if m.secret == "" {72 return ErrNotFound73 }74 m.secret = ""75 return nil76}7778func (m *Memory) Name() string { return "test store" }