11package auth
22
33import (
4+ "crypto/sha256"
5+ "encoding/hex"
46 "encoding/json"
7+ "os"
8+ "path/filepath"
59
610 "github.com/99designs/keyring"
711)
@@ -11,15 +15,63 @@ const (
1115 keyringKey = "auth_token"
1216)
1317
18+ // getKeyringConfig returns a keyring configuration that works with CGO_ENABLED=0
19+ func getKeyringConfig () keyring.Config {
20+ // Get config directory
21+ configDir := filepath .Join (os .Getenv ("HOME" ), ".config" , "momorph" )
22+ if xdgConfig := os .Getenv ("XDG_CONFIG_HOME" ); xdgConfig != "" {
23+ configDir = filepath .Join (xdgConfig , "momorph" )
24+ }
25+
26+ // Create a deterministic password based on machine ID and home directory
27+ // This allows the file backend to work without prompting for a password
28+ machineID := getMachineID ()
29+ password := sha256 .Sum256 ([]byte (machineID + os .Getenv ("HOME" )))
30+
31+ return keyring.Config {
32+ ServiceName : keyringService ,
33+ // When CGO_ENABLED=0, prefer FileBackend as it doesn't require C libraries
34+ AllowedBackends : []keyring.BackendType {
35+ keyring .KeychainBackend , // macOS (requires CGO)
36+ keyring .SecretServiceBackend , // Linux (requires CGO)
37+ keyring .WinCredBackend , // Windows
38+ keyring .FileBackend , // Fallback for all platforms
39+ },
40+ KeychainTrustApplication : true ,
41+ FileDir : configDir ,
42+ // Provide a password function to avoid prompting
43+ FilePasswordFunc : func (prompt string ) (string , error ) {
44+ return hex .EncodeToString (password [:]), nil
45+ },
46+ }
47+ }
48+
49+ // getMachineID returns a unique identifier for the current machine
50+ func getMachineID () string {
51+ // Try to read machine-id from various locations
52+ paths := []string {
53+ "/etc/machine-id" ,
54+ "/var/lib/dbus/machine-id" ,
55+ }
56+
57+ for _ , path := range paths {
58+ if data , err := os .ReadFile (path ); err == nil {
59+ return string (data )
60+ }
61+ }
62+
63+ // Fallback to hostname
64+ if hostname , err := os .Hostname (); err == nil {
65+ return hostname
66+ }
67+
68+ return "default-machine-id"
69+ }
70+
1471// SaveToken saves the authentication token to the OS credential manager
1572func SaveToken (token * AuthToken ) error {
1673 // Open keyring
17- ring , err := keyring .Open (keyring.Config {
18- ServiceName : keyringService ,
19- AllowedBackends : []keyring.BackendType {keyring .KeychainBackend , keyring .SecretServiceBackend , keyring .WinCredBackend , keyring .FileBackend },
20- KeychainTrustApplication : true ,
21- FileDir : "~/.config/momorph" ,
22- })
74+ ring , err := keyring .Open (getKeyringConfig ())
2375 if err != nil {
2476 return err
2577 }
@@ -40,12 +92,7 @@ func SaveToken(token *AuthToken) error {
4092// LoadToken loads the authentication token from the OS credential manager
4193func LoadToken () (* AuthToken , error ) {
4294 // Open keyring
43- ring , err := keyring .Open (keyring.Config {
44- ServiceName : keyringService ,
45- AllowedBackends : []keyring.BackendType {keyring .KeychainBackend , keyring .SecretServiceBackend , keyring .WinCredBackend , keyring .FileBackend },
46- KeychainTrustApplication : true ,
47- FileDir : "~/.config/momorph" ,
48- })
95+ ring , err := keyring .Open (getKeyringConfig ())
4996 if err != nil {
5097 return nil , err
5198 }
@@ -68,12 +115,7 @@ func LoadToken() (*AuthToken, error) {
68115// ClearToken removes the authentication token from the OS credential manager
69116func ClearToken () error {
70117 // Open keyring
71- ring , err := keyring .Open (keyring.Config {
72- ServiceName : keyringService ,
73- AllowedBackends : []keyring.BackendType {keyring .KeychainBackend , keyring .SecretServiceBackend , keyring .WinCredBackend , keyring .FileBackend },
74- KeychainTrustApplication : true ,
75- FileDir : "~/.config/momorph" ,
76- })
118+ ring , err := keyring .Open (getKeyringConfig ())
77119 if err != nil {
78120 return err
79121 }
0 commit comments