Files
go-garth-cli/cmd/garth/auth.go
2025-09-21 11:03:52 -07:00

184 lines
4.9 KiB
Go

package main
import (
"fmt"
"os"
"golang.org/x/term"
"go-garth/pkg/garmin"
"github.com/spf13/cobra"
)
var (
authCmd = &cobra.Command{
Use: "auth",
Short: "Authentication management",
Long: `Manage authentication with Garmin Connect, including login, logout, and status.`,
}
loginCmd = &cobra.Command{
Use: "login",
Short: "Login to Garmin Connect",
Long: `Login to Garmin Connect interactively or using provided credentials.`,
RunE: runLogin,
}
logoutCmd = &cobra.Command{
Use: "logout",
Short: "Logout from Garmin Connect",
Long: `Clear the current Garmin Connect session.`,
RunE: runLogout,
}
statusCmd = &cobra.Command{
Use: "status",
Short: "Show Garmin Connect authentication status",
Long: `Display the current authentication status and session information.`,
RunE: runStatus,
}
refreshCmd = &cobra.Command{
Use: "refresh",
Short: "Refresh Garmin Connect session tokens",
Long: `Refresh the authentication tokens for the current Garmin Connect session.`,
RunE: runRefresh,
}
loginEmail string
loginPassword string
passwordStdinFlag bool
)
func init() {
rootCmd.AddCommand(authCmd)
authCmd.AddCommand(loginCmd)
loginCmd.Flags().StringVarP(&loginEmail, "email", "e", "", "Email for Garmin Connect login")
loginCmd.Flags().BoolVarP(&passwordStdinFlag, "password-stdin", "p", false, "Read password from stdin")
authCmd.AddCommand(logoutCmd)
authCmd.AddCommand(statusCmd)
authCmd.AddCommand(refreshCmd)
}
func runLogin(cmd *cobra.Command, args []string) error {
var email, password string
var err error
if loginEmail != "" {
email = loginEmail
} else {
fmt.Print("Enter Garmin Connect email: ")
_, err = fmt.Scanln(&email)
if err != nil {
return fmt.Errorf("failed to read email: %w", err)
}
}
if passwordStdinFlag {
fmt.Print("Enter password: ")
passwordBytes, err := term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return fmt.Errorf("failed to read password from stdin: %w", err)
}
password = string(passwordBytes)
fmt.Println() // Newline after password input
} else {
fmt.Print("Enter password: ")
passwordBytes, err := term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return fmt.Errorf("failed to read password: %w", err)
}
password = string(passwordBytes)
fmt.Println() // Newline after password input
}
// Create client
// TODO: Domain should be configurable
garminClient, err := garmin.NewClient("www.garmin.com")
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
// Try to load existing session first
sessionFile := "garmin_session.json" // TODO: Make session file configurable
if err := garminClient.LoadSession(sessionFile); err != nil {
fmt.Println("No existing session found or session invalid, logging in with credentials...")
if err := garminClient.Login(email, password); err != nil {
return fmt.Errorf("login failed: %w", err)
}
// Save session for future use
if err := garminClient.SaveSession(sessionFile); err != nil {
fmt.Printf("Failed to save session: %v\n", err)
}
} else {
fmt.Println("Loaded existing session")
}
fmt.Println("Login successful!")
return nil
}
func runLogout(cmd *cobra.Command, args []string) error {
sessionFile := "garmin_session.json" // TODO: Make session file configurable
if _, err := os.Stat(sessionFile); os.IsNotExist(err) {
fmt.Println("No active session to log out from.")
return nil
}
if err := os.Remove(sessionFile); err != nil {
return fmt.Errorf("failed to remove session file: %w", err)
}
fmt.Println("Logged out successfully. Session cleared.")
return nil
}
func runStatus(cmd *cobra.Command, args []string) error {
sessionFile := "garmin_session.json" // TODO: Make session file configurable
garminClient, err := garmin.NewClient("www.garmin.com") // TODO: Domain should be configurable
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
if err := garminClient.LoadSession(sessionFile); err != nil {
fmt.Println("Not logged in or session expired.")
return nil
}
fmt.Println("Logged in. Session is active.")
// TODO: Add more detailed status information, e.g., session expiry
return nil
}
func runRefresh(cmd *cobra.Command, args []string) error {
sessionFile := "garmin_session.json" // TODO: Make session file configurable
garminClient, err := garmin.NewClient("www.garmin.com") // TODO: Domain should be configurable
if err != nil {
return fmt.Errorf("failed to create client: %w", err)
}
if err := garminClient.LoadSession(sessionFile); err != nil {
return fmt.Errorf("cannot refresh: no active session found: %w", err)
}
fmt.Println("Attempting to refresh session...")
if err := garminClient.RefreshSession(); err != nil {
return fmt.Errorf("failed to refresh session: %w", err)
}
if err := garminClient.SaveSession(sessionFile); err != nil {
fmt.Printf("Failed to save refreshed session: %v\n", err)
}
fmt.Println("Session refreshed successfully.")
return nil
}