Files
andy 35bc9c75b1 Add Go project scaffold for Wails v2 SSH/Telnet/RAW TCP client
- go.mod with Wails v2.9.2, x/crypto, go-sqlite3, go-keyring, uuid
- cmd/app/main.go: Wails entry point (Nexus Terminal, 1400x900, #1a1a2e)
- internal/app/app.go: lifecycle (Startup/Shutdown/DomReady)
- internal/models/models.go: full model definitions (Profile, SSHConfig,
  TelnetConfig, RAWConfig, SessionInfo, KnownHost, AppPreferences, etc.)
- internal/models/defaults.go: default values and NewProfile factory
- internal/validation/validation.go: thorough field-level validation
- frontend/embed.go: embedded frontend assets
- Updated existing storage, secrets, config to match new model structure
2026-04-15 00:00:00 +01:00

67 lines
2.2 KiB
Go

package secrets
import (
"fmt"
"github.com/zalando/go-keyring"
)
// KeychainStore attempts to use the OS keychain for secret storage.
// On macOS this uses the Keychain, on Linux it uses the Secret Service API,
// and on Windows it uses the Credential Manager.
//
// This is the preferred storage method when available. Falls back to
// the encrypted file-based SecretStore when the keychain is not accessible.
type KeychainStore struct {
serviceName string
}
// NewKeychainStore creates a KeychainStore that stores credentials under the
// given service name in the operating system's native keychain.
func NewKeychainStore(serviceName string) *KeychainStore {
return &KeychainStore{serviceName: serviceName}
}
// Available checks whether the OS keychain is accessible by performing a
// harmless write-then-delete probe. Returns true if the keychain responded
// without error.
func (k *KeychainStore) Available() bool {
// Attempt a round-trip to verify the keychain is usable.
probeKey := "__nexus_keychain_probe__"
probeVal := "probe"
if err := keyring.Set(k.serviceName, probeKey, probeVal); err != nil {
return false
}
_ = keyring.Delete(k.serviceName, probeKey)
return true
}
// SetSecret stores a secret in the OS keychain under the configured service
// name with the given key.
func (k *KeychainStore) SetSecret(key, value string) error {
if err := keyring.Set(k.serviceName, key, value); err != nil {
return fmt.Errorf("keychain: failed to store secret %q: %w", key, err)
}
return nil
}
// GetSecret retrieves a secret from the OS keychain. Returns an error if the
// key does not exist or the keychain is inaccessible.
func (k *KeychainStore) GetSecret(key string) (string, error) {
val, err := keyring.Get(k.serviceName, key)
if err != nil {
return "", fmt.Errorf("keychain: failed to retrieve secret %q: %w", key, err)
}
return val, nil
}
// DeleteSecret removes a secret from the OS keychain. Returns an error if the
// key does not exist or the keychain is inaccessible.
func (k *KeychainStore) DeleteSecret(key string) error {
if err := keyring.Delete(k.serviceName, key); err != nil {
return fmt.Errorf("keychain: failed to delete secret %q: %w", key, err)
}
return nil
}