network/pkg/auth/credentials.go
2025-09-20 08:15:31 +03:00

214 lines
5.5 KiB
Go

package auth
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"
)
// Credentials represents authentication credentials for a specific gateway
type Credentials struct {
APIKey string `json:"api_key"`
RefreshToken string `json:"refresh_token,omitempty"`
Namespace string `json:"namespace"`
UserID string `json:"user_id,omitempty"`
Wallet string `json:"wallet,omitempty"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
IssuedAt time.Time `json:"issued_at"`
LastUsedAt time.Time `json:"last_used_at,omitempty"`
Plan string `json:"plan,omitempty"`
}
// CredentialStore manages credentials for multiple gateways
type CredentialStore struct {
Gateways map[string]*Credentials `json:"gateways"`
Version string `json:"version"`
}
// GetCredentialsPath returns the path to the credentials file
func GetCredentialsPath() (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("failed to get home directory: %w", err)
}
debrosDir := filepath.Join(homeDir, ".debros")
if err := os.MkdirAll(debrosDir, 0700); err != nil {
return "", fmt.Errorf("failed to create .debros directory: %w", err)
}
return filepath.Join(debrosDir, "credentials.json"), nil
}
// LoadCredentials loads credentials from ~/.debros/credentials.json
func LoadCredentials() (*CredentialStore, error) {
credPath, err := GetCredentialsPath()
if err != nil {
return nil, err
}
// If file doesn't exist, return empty store
if _, err := os.Stat(credPath); os.IsNotExist(err) {
return &CredentialStore{
Gateways: make(map[string]*Credentials),
Version: "1.0",
}, nil
}
data, err := os.ReadFile(credPath)
if err != nil {
return nil, fmt.Errorf("failed to read credentials file: %w", err)
}
var store CredentialStore
if err := json.Unmarshal(data, &store); err != nil {
return nil, fmt.Errorf("failed to parse credentials file: %w", err)
}
// Initialize gateways map if nil
if store.Gateways == nil {
store.Gateways = make(map[string]*Credentials)
}
// Set version if empty
if store.Version == "" {
store.Version = "1.0"
}
return &store, nil
}
// SaveCredentials saves credentials to ~/.debros/credentials.json
func (store *CredentialStore) SaveCredentials() error {
credPath, err := GetCredentialsPath()
if err != nil {
return err
}
// Ensure version is set
if store.Version == "" {
store.Version = "1.0"
}
data, err := json.MarshalIndent(store, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal credentials: %w", err)
}
// Write with restricted permissions (readable only by owner)
if err := os.WriteFile(credPath, data, 0600); err != nil {
return fmt.Errorf("failed to write credentials file: %w", err)
}
return nil
}
// GetCredentialsForGateway returns credentials for a specific gateway URL
func (store *CredentialStore) GetCredentialsForGateway(gatewayURL string) (*Credentials, bool) {
creds, exists := store.Gateways[gatewayURL]
if !exists || creds == nil {
return nil, false
}
// Check if credentials are expired (if expiration is set)
if !creds.ExpiresAt.IsZero() && time.Now().After(creds.ExpiresAt) {
return nil, false
}
return creds, true
}
// SetCredentialsForGateway stores credentials for a specific gateway URL
func (store *CredentialStore) SetCredentialsForGateway(gatewayURL string, creds *Credentials) {
if store.Gateways == nil {
store.Gateways = make(map[string]*Credentials)
}
// Update last used time
creds.LastUsedAt = time.Now()
store.Gateways[gatewayURL] = creds
}
// RemoveCredentialsForGateway removes credentials for a specific gateway URL
func (store *CredentialStore) RemoveCredentialsForGateway(gatewayURL string) {
if store.Gateways != nil {
delete(store.Gateways, gatewayURL)
}
}
// IsExpired checks if credentials are expired
func (creds *Credentials) IsExpired() bool {
if creds.ExpiresAt.IsZero() {
return false // No expiration set
}
return time.Now().After(creds.ExpiresAt)
}
// IsValid checks if credentials are valid (not empty and not expired)
func (creds *Credentials) IsValid() bool {
if creds == nil {
return false
}
if creds.APIKey == "" {
return false
}
return !creds.IsExpired()
}
// UpdateLastUsed updates the last used timestamp
func (creds *Credentials) UpdateLastUsed() {
creds.LastUsedAt = time.Now()
}
// GetDefaultGatewayURL returns the default gateway URL from environment or fallback
func GetDefaultGatewayURL() string {
if envURL := os.Getenv("DEBROS_GATEWAY_URL"); envURL != "" {
return envURL
}
if envURL := os.Getenv("DEBROS_GATEWAY"); envURL != "" {
return envURL
}
return "http://localhost:6001"
}
// HasValidCredentials checks if there are valid credentials for the default gateway
func HasValidCredentials() (bool, error) {
store, err := LoadCredentials()
if err != nil {
return false, err
}
gatewayURL := GetDefaultGatewayURL()
creds, exists := store.GetCredentialsForGateway(gatewayURL)
return exists && creds.IsValid(), nil
}
// SaveCredentialsForDefaultGateway saves credentials for the default gateway
func SaveCredentialsForDefaultGateway(creds *Credentials) error {
store, err := LoadCredentials()
if err != nil {
return err
}
gatewayURL := GetDefaultGatewayURL()
store.SetCredentialsForGateway(gatewayURL, creds)
return store.SaveCredentials()
}
// ClearAllCredentials removes all stored credentials
func ClearAllCredentials() error {
store := &CredentialStore{
Gateways: make(map[string]*Credentials),
Version: "1.0",
}
return store.SaveCredentials()
}