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
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user