- Added internal/vault/client.go for creating a Vault client with configuration settings. - Introduced internal/vault/errors.go to classify Vault API errors for better UI handling. - Created internal/vault/kv.go to manage KV secrets, including listing, reading, writing, and deleting operations. - Implemented internal/vault/mounts.go to list and describe secret engine mounts. - Developed internal/vault/service.go to provide a unified entry point for Vault operations. - Added internal/vault/kv_test.go for comprehensive testing of KV operations. - Introduced internal/ui/toast.go for transient notifications in the UI. - Added renovate.json for dependency management and updates.
69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
package token
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/natefinch/atomic"
|
|
)
|
|
|
|
// profileStore keeps one token per profile under the XDG state directory.
|
|
// It exists because vault-cli storage is single-valued (~/.vault-token):
|
|
// logging into "prod" would silently clobber "dev". Uses the same
|
|
// write-then-atomic-rename pattern as Vault's own InternalTokenHelper.
|
|
type profileStore struct {
|
|
path string
|
|
}
|
|
|
|
// NewProfileStore returns a Store scoped to one profile name, rooted at
|
|
// stateDir (see config.StateDir), e.g. stateDir/tokens/<profile>.token.
|
|
func NewProfileStore(stateDir, profile string) Store {
|
|
return profileStore{path: filepath.Join(stateDir, "tokens", sanitize(profile)+".token")}
|
|
}
|
|
|
|
// NewFileStore is a profileStore pinned to an explicit path, used for
|
|
// token.file in the config.
|
|
func NewFileStore(path string) Store {
|
|
return profileStore{path: path}
|
|
}
|
|
|
|
func sanitize(name string) string {
|
|
return strings.NewReplacer("/", "_", "\\", "_", "..", "_").Replace(name)
|
|
}
|
|
|
|
func (s profileStore) Kind() string { return "profile" }
|
|
func (s profileStore) Location() string { return s.path }
|
|
|
|
func (s profileStore) Get(context.Context) (string, error) {
|
|
b, err := os.ReadFile(s.path)
|
|
if os.IsNotExist(err) {
|
|
return "", nil
|
|
}
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return strings.TrimSpace(string(b)), nil
|
|
}
|
|
|
|
func (s profileStore) Store(_ context.Context, tok string) error {
|
|
dir := filepath.Dir(s.path)
|
|
if err := os.MkdirAll(dir, 0o700); err != nil {
|
|
return fmt.Errorf("creating token directory %q: %w", dir, err)
|
|
}
|
|
tmp := s.path + ".tmp"
|
|
if err := os.WriteFile(tmp, []byte(tok), 0o600); err != nil {
|
|
return err
|
|
}
|
|
return atomic.ReplaceFile(tmp, s.path)
|
|
}
|
|
|
|
func (s profileStore) Erase(context.Context) error {
|
|
if err := os.Remove(s.path); err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|