diff --git a/garmin-connect b/garmin-connect index 8edbdee..5c0beef 100755 Binary files a/garmin-connect and b/garmin-connect differ diff --git a/garmin_session.json b/garmin_session.json deleted file mode 100644 index f67e469..0000000 --- a/garmin_session.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "domain": "garmin.com", - "username": "fbleagh", - "auth_token": "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRpLW9hdXRoLXNpZ25lci1wcm9kLTIwMjQtcTEifQ.eyJzY29wZSI6WyJBVFBfUkVBRCIsIkFUUF9XUklURSIsIkNPTU1VTklUWV9DT1VSU0VfUkVBRCIsIkNPTU1VTklUWV9DT1VSU0VfV1JJVEUiLCJDT05ORUNUX01DVF9EQUlMWV9MT0dfUkVBRCIsIkNPTk5FQ1RfUkVBRCIsIkNPTk5FQ1RfV1JJVEUiLCJESVZFX0FQSV9SRUFEIiwiRElfT0FVVEhfMl9BVVRIT1JJWkFUSU9OX0NPREVfQ1JFQVRFIiwiRFRfQ0xJRU5UX0FOQUxZVElDU19XUklURSIsIkdBUk1JTlBBWV9SRUFEIiwiR0FSTUlOUEFZX1dSSVRFIiwiR0NPRkZFUl9SRUFEIiwiR0NPRkZFUl9XUklURSIsIkdIU19TQU1EIiwiR0hTX1VQTE9BRCIsIkdPTEZfQVBJX1JFQUQiLCJHT0xGX0FQSV9XUklURSIsIklOU0lHSFRTX1JFQUQiLCJJTlNJR0hUU19XUklURSIsIk9NVF9DQU1QQUlHTl9SRUFEIiwiT01UX1NVQlNDUklQVElPTl9SRUFEIiwiUFJPRFVDVF9TRUFSQ0hfUkVBRCJdLCJpc3MiOiJodHRwczovL2RpYXV0aC5nYXJtaW4uY29tIiwicmV2b2NhdGlvbl9lbGlnaWJpbGl0eSI6WyJHTE9CQUxfU0lHTk9VVCIsIk1BTkFHRURfU1RBVFVTIl0sImNsaWVudF90eXBlIjoiVU5ERUZJTkVEIiwiZXhwIjoxNzU4MjYzODU0LCJpYXQiOjE3NTgxOTkwMzUsImdhcm1pbl9ndWlkIjoiNTZlZTk1ZmMtMzY0MC00NGU2LTg1ODAtNDc4NDEwZDQwZGFhIiwianRpIjoiMjA5MTA2M2ItNTk0OC00MGM0LWE0YTEtMzI5ODY3ZWVmYjhlIiwiY2xpZW50X2lkIjoiR0FSTUlOX0NPTk5FQ1RfTU9CSUxFX0FORFJPSURfREkifQ.EdTSIGfBMnQJNX3HNGYRi_BM-JL5UlmrCriaxS5LSW4gdqq5j2oOzcHGwXIFxk2sNxjlBWZDQz5p8EdhDD9VG3wkGhtn51BwPlt4Nc0TwdVPtyvlfbYFZLSf6JPRqZT9bscAJRq38ObxjCFweRRIypUIWx78M9sF9Ubz1eJN8Z84qRrUjlToCvYoaink3_TJwHAEuHmaqJMfxwoKFk0LnQUF2wiDqvDoaYwkTbC0UoPqBtku_bYYou-2kolL9-l7VA696C8Mt9rEt9ydBb5DoC-8HKTrUKKBia4oIhRb9XumB7Hb9oE3NqGVVaxbXpZPibydRacMNAPI1O9N2PLQ3A" -} \ No newline at end of file diff --git a/internal/api/client/client_test.go b/internal/api/client/client_test.go index db60dd6..8e4c3c0 100644 --- a/internal/api/client/client_test.go +++ b/internal/api/client/client_test.go @@ -1,6 +1,7 @@ package client_test import ( + "crypto/tls" "net/http" "net/url" "testing" @@ -16,7 +17,7 @@ import ( func TestClient_GetUserProfile(t *testing.T) { // Create mock server returning user profile - server := testutils.MockJSONResponse(http.StatusOK, `{ + server := testutils.MockJSONResponse(http.StatusOK, `{ "userName": "testuser", "displayName": "Test User", "fullName": "Test User", @@ -28,7 +29,12 @@ func TestClient_GetUserProfile(t *testing.T) { u, _ := url.Parse(server.URL) c, err := client.NewClient(u.Host) require.NoError(t, err) - c.HTTPClient = &http.Client{Timeout: 5 * time.Second} + c.HTTPClient = &http.Client{ + Timeout: 5 * time.Second, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } c.AuthToken = "Bearer testtoken" // Get user profile @@ -38,4 +44,4 @@ func TestClient_GetUserProfile(t *testing.T) { require.NoError(t, err) assert.Equal(t, "testuser", profile.UserName) assert.Equal(t, "Test User", profile.DisplayName) -} +} \ No newline at end of file diff --git a/internal/auth/credentials/credentials.go b/internal/auth/credentials/credentials.go index 34530c3..d856078 100644 --- a/internal/auth/credentials/credentials.go +++ b/internal/auth/credentials/credentials.go @@ -3,15 +3,20 @@ package credentials import ( "fmt" "os" + "path/filepath" "github.com/joho/godotenv" ) // LoadEnvCredentials loads credentials from .env file func LoadEnvCredentials() (email, password, domain string, err error) { + // Determine project root (assuming .env is in the project root) + projectRoot := "/home/sstent/Projects/go-garth" + envPath := filepath.Join(projectRoot, ".env") + // Load .env file - if err := godotenv.Load(); err != nil { - return "", "", "", fmt.Errorf("error loading .env file: %w", err) + if err := godotenv.Load(envPath); err != nil { + return "", "", "", fmt.Errorf("error loading .env file from %s: %w", envPath, err) } email = os.Getenv("GARMIN_EMAIL") @@ -29,4 +34,4 @@ func LoadEnvCredentials() (email, password, domain string, err error) { } return email, password, domain, nil -} +} \ No newline at end of file diff --git a/internal/auth/oauth/oauth.go b/internal/auth/oauth/oauth.go index bbb4290..e9bf1f5 100644 --- a/internal/auth/oauth/oauth.go +++ b/internal/auth/oauth/oauth.go @@ -15,13 +15,17 @@ import ( // GetOAuth1Token retrieves an OAuth1 token using the provided ticket func GetOAuth1Token(domain, ticket string) (*types.OAuth1Token, error) { + scheme := "https" + if strings.HasPrefix(domain, "127.0.0.1") { + scheme = "http" + } consumer, err := utils.LoadOAuthConsumer() if err != nil { return nil, fmt.Errorf("failed to load OAuth consumer: %w", err) } - baseURL := fmt.Sprintf("https://connectapi.%s/oauth-service/oauth/", domain) - loginURL := fmt.Sprintf("https://sso.%s/sso/embed", domain) + baseURL := fmt.Sprintf("%s://connectapi.%s/oauth-service/oauth/", scheme, domain) + loginURL := fmt.Sprintf("%s://sso.%s/sso/embed", scheme, domain) tokenURL := fmt.Sprintf("%spreauthorized?ticket=%s&login-url=%s&accepts-mfa-tokens=true", baseURL, ticket, url.QueryEscape(loginURL)) @@ -91,12 +95,16 @@ func GetOAuth1Token(domain, ticket string) (*types.OAuth1Token, error) { // ExchangeToken exchanges an OAuth1 token for an OAuth2 token func ExchangeToken(oauth1Token *types.OAuth1Token) (*types.OAuth2Token, error) { + scheme := "https" + if strings.HasPrefix(oauth1Token.Domain, "127.0.0.1") { + scheme = "http" + } consumer, err := utils.LoadOAuthConsumer() if err != nil { return nil, fmt.Errorf("failed to load OAuth consumer: %w", err) } - exchangeURL := fmt.Sprintf("https://connectapi.%s/oauth-service/oauth/exchange/user/2.0", oauth1Token.Domain) + exchangeURL := fmt.Sprintf("%s://connectapi.%s/oauth-service/oauth/exchange/user/2.0", scheme, oauth1Token.Domain) // Prepare form data formData := url.Values{} @@ -151,4 +159,4 @@ func ExchangeToken(oauth1Token *types.OAuth1Token) (*types.OAuth2Token, error) { } return &oauth2Token, nil -} +} \ No newline at end of file diff --git a/internal/auth/sso/sso.go b/internal/auth/sso/sso.go index 97a2d75..b120c5b 100644 --- a/internal/auth/sso/sso.go +++ b/internal/auth/sso/sso.go @@ -44,6 +44,11 @@ func NewClient(domain string) *Client { func (c *Client) Login(email, password string) (*types.OAuth2Token, *MFAContext, error) { fmt.Printf("Logging in to Garmin Connect (%s) using SSO flow...\n", c.Domain) + scheme := "https" + if strings.HasPrefix(c.Domain, "127.0.0.1") { + scheme = "http" + } + // Step 1: Set up SSO parameters ssoURL := fmt.Sprintf("https://sso.%s/sso", c.Domain) ssoEmbedURL := fmt.Sprintf("%s/embed", ssoURL) @@ -81,7 +86,7 @@ func (c *Client) Login(email, password string) (*types.OAuth2Token, *MFAContext, // Step 3: Get signin page and CSRF token fmt.Println("Getting signin page...") - signinURL := fmt.Sprintf("https://sso.%s/sso/signin?%s", c.Domain, signinParams.Encode()) + signinURL := fmt.Sprintf("%s://sso.%s/sso/signin?%s", scheme, c.Domain, signinParams.Encode()) req, err = http.NewRequest("GET", signinURL, nil) if err != nil { return nil, nil, fmt.Errorf("failed to create signin request: %w", err)