package app import ( "crypto/rand" "encoding/base64" "fmt" "os" "path/filepath" "strings" ) func ClientTokenPath() (string, error) { base := os.Getenv("XDG_DATA_HOME") if base == "" { home, err := os.UserHomeDir() if err != nil { return "", err } base = filepath.Join(home, ".local", "share") } return filepath.Join(base, "patterm", "clients", "token"), nil } func LoadClientToken() (string, error) { path, err := ClientTokenPath() if err != nil { return "", err } b, err := os.ReadFile(path) if err != nil { return "", err } return strings.TrimSpace(string(b)), nil } func LoadOrCreateClientToken() (string, error) { if token, err := LoadClientToken(); err == nil && token != "" { return token, nil } token, err := generateClientToken() if err != nil { return "", err } path, err := ClientTokenPath() if err != nil { return "", err } if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil { return "", err } if err := os.WriteFile(path, []byte(token+"\n"), 0o600); err != nil { return "", err } return token, nil } func generateClientToken() (string, error) { var b [32]byte if _, err := rand.Read(b[:]); err != nil { return "", fmt.Errorf("token: random: %w", err) } return base64.RawURLEncoding.EncodeToString(b[:]), nil }