mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-08 22:08:03 -05:00
## CHANGES - Move domain types from common to domain package - Move utility functions from common to util package - Update all import statements across codebase - Reorganize OAuth storage functionality into util package - Move file management functions to domain package - Update test files to use new package structure - Maintain backward compatibility for existing functionality
125 lines
3.3 KiB
Go
125 lines
3.3 KiB
Go
package util
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
// OAuthToken represents stored OAuth token information
|
|
type OAuthToken struct {
|
|
AccessToken string `json:"access_token"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
ExpiresAt int64 `json:"expires_at"`
|
|
TokenType string `json:"token_type"`
|
|
Scope string `json:"scope"`
|
|
}
|
|
|
|
// IsExpired checks if the token is expired or will expire within the buffer time
|
|
func (t *OAuthToken) IsExpired(bufferMinutes int) bool {
|
|
if t.ExpiresAt == 0 {
|
|
return true
|
|
}
|
|
bufferTime := time.Duration(bufferMinutes) * time.Minute
|
|
return time.Now().Add(bufferTime).Unix() >= t.ExpiresAt
|
|
}
|
|
|
|
// OAuthStorage handles persistent storage of OAuth tokens
|
|
type OAuthStorage struct {
|
|
configDir string
|
|
}
|
|
|
|
// NewOAuthStorage creates a new OAuth storage instance
|
|
func NewOAuthStorage() (*OAuthStorage, error) {
|
|
homeDir, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get user home directory: %w", err)
|
|
}
|
|
|
|
configDir := filepath.Join(homeDir, ".config", "fabric")
|
|
|
|
// Ensure config directory exists
|
|
if err := os.MkdirAll(configDir, 0755); err != nil {
|
|
return nil, fmt.Errorf("failed to create config directory: %w", err)
|
|
}
|
|
|
|
return &OAuthStorage{configDir: configDir}, nil
|
|
}
|
|
|
|
// GetTokenPath returns the file path for a provider's OAuth token
|
|
func (s *OAuthStorage) GetTokenPath(provider string) string {
|
|
return filepath.Join(s.configDir, fmt.Sprintf(".%s_oauth", provider))
|
|
}
|
|
|
|
// SaveToken saves an OAuth token to disk with proper permissions
|
|
func (s *OAuthStorage) SaveToken(provider string, token *OAuthToken) error {
|
|
tokenPath := s.GetTokenPath(provider)
|
|
|
|
// Marshal token to JSON
|
|
data, err := json.MarshalIndent(token, "", " ")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal token: %w", err)
|
|
}
|
|
|
|
// Write to temporary file first for atomic operation
|
|
tempPath := tokenPath + ".tmp"
|
|
if err := os.WriteFile(tempPath, data, 0600); err != nil {
|
|
return fmt.Errorf("failed to write token file: %w", err)
|
|
}
|
|
|
|
// Atomic rename
|
|
if err := os.Rename(tempPath, tokenPath); err != nil {
|
|
os.Remove(tempPath) // Clean up temp file
|
|
return fmt.Errorf("failed to save token file: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// LoadToken loads an OAuth token from disk
|
|
func (s *OAuthStorage) LoadToken(provider string) (*OAuthToken, error) {
|
|
tokenPath := s.GetTokenPath(provider)
|
|
|
|
// Check if file exists
|
|
if _, err := os.Stat(tokenPath); os.IsNotExist(err) {
|
|
return nil, nil // No token stored
|
|
}
|
|
|
|
// Read token file
|
|
data, err := os.ReadFile(tokenPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read token file: %w", err)
|
|
}
|
|
|
|
// Unmarshal token
|
|
var token OAuthToken
|
|
if err := json.Unmarshal(data, &token); err != nil {
|
|
return nil, fmt.Errorf("failed to parse token file: %w", err)
|
|
}
|
|
|
|
return &token, nil
|
|
}
|
|
|
|
// DeleteToken removes a stored OAuth token
|
|
func (s *OAuthStorage) DeleteToken(provider string) error {
|
|
tokenPath := s.GetTokenPath(provider)
|
|
|
|
if err := os.Remove(tokenPath); err != nil && !os.IsNotExist(err) {
|
|
return fmt.Errorf("failed to delete token file: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// HasValidToken checks if a valid (non-expired) token exists for a provider
|
|
func (s *OAuthStorage) HasValidToken(provider string, bufferMinutes int) bool {
|
|
token, err := s.LoadToken(provider)
|
|
if err != nil || token == nil {
|
|
return false
|
|
}
|
|
|
|
return !token.IsExpired(bufferMinutes)
|
|
}
|