mirror of
https://github.com/sstent/go-garth.git
synced 2026-01-26 17:11:42 +00:00
Refactor: Complete authentication flow changes
This commit includes the remaining files from the authentication flow refactoring.\nThese changes were part of the initial diff between c00ea67f31 and HEAD,\nand complete the transition to the new SSO and OAuth-based authentication mechanism.
This commit is contained in:
BIN
garmin-connect
BIN
garmin-connect
Binary file not shown.
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"domain": "garmin.com",
|
|
||||||
"username": "fbleagh",
|
|
||||||
"auth_token": "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRpLW9hdXRoLXNpZ25lci1wcm9kLTIwMjQtcTEifQ.eyJzY29wZSI6WyJBVFBfUkVBRCIsIkFUUF9XUklURSIsIkNPTU1VTklUWV9DT1VSU0VfUkVBRCIsIkNPTU1VTklUWV9DT1VSU0VfV1JJVEUiLCJDT05ORUNUX01DVF9EQUlMWV9MT0dfUkVBRCIsIkNPTk5FQ1RfUkVBRCIsIkNPTk5FQ1RfV1JJVEUiLCJESVZFX0FQSV9SRUFEIiwiRElfT0FVVEhfMl9BVVRIT1JJWkFUSU9OX0NPREVfQ1JFQVRFIiwiRFRfQ0xJRU5UX0FOQUxZVElDU19XUklURSIsIkdBUk1JTlBBWV9SRUFEIiwiR0FSTUlOUEFZX1dSSVRFIiwiR0NPRkZFUl9SRUFEIiwiR0NPRkZFUl9XUklURSIsIkdIU19TQU1EIiwiR0hTX1VQTE9BRCIsIkdPTEZfQVBJX1JFQUQiLCJHT0xGX0FQSV9XUklURSIsIklOU0lHSFRTX1JFQUQiLCJJTlNJR0hUU19XUklURSIsIk9NVF9DQU1QQUlHTl9SRUFEIiwiT01UX1NVQlNDUklQVElPTl9SRUFEIiwiUFJPRFVDVF9TRUFSQ0hfUkVBRCJdLCJpc3MiOiJodHRwczovL2RpYXV0aC5nYXJtaW4uY29tIiwicmV2b2NhdGlvbl9lbGlnaWJpbGl0eSI6WyJHTE9CQUxfU0lHTk9VVCIsIk1BTkFHRURfU1RBVFVTIl0sImNsaWVudF90eXBlIjoiVU5ERUZJTkVEIiwiZXhwIjoxNzU4MjYzODU0LCJpYXQiOjE3NTgxOTkwMzUsImdhcm1pbl9ndWlkIjoiNTZlZTk1ZmMtMzY0MC00NGU2LTg1ODAtNDc4NDEwZDQwZGFhIiwianRpIjoiMjA5MTA2M2ItNTk0OC00MGM0LWE0YTEtMzI5ODY3ZWVmYjhlIiwiY2xpZW50X2lkIjoiR0FSTUlOX0NPTk5FQ1RfTU9CSUxFX0FORFJPSURfREkifQ.EdTSIGfBMnQJNX3HNGYRi_BM-JL5UlmrCriaxS5LSW4gdqq5j2oOzcHGwXIFxk2sNxjlBWZDQz5p8EdhDD9VG3wkGhtn51BwPlt4Nc0TwdVPtyvlfbYFZLSf6JPRqZT9bscAJRq38ObxjCFweRRIypUIWx78M9sF9Ubz1eJN8Z84qRrUjlToCvYoaink3_TJwHAEuHmaqJMfxwoKFk0LnQUF2wiDqvDoaYwkTbC0UoPqBtku_bYYou-2kolL9-l7VA696C8Mt9rEt9ydBb5DoC-8HKTrUKKBia4oIhRb9XumB7Hb9oE3NqGVVaxbXpZPibydRacMNAPI1O9N2PLQ3A"
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package client_test
|
package client_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -28,7 +29,12 @@ func TestClient_GetUserProfile(t *testing.T) {
|
|||||||
u, _ := url.Parse(server.URL)
|
u, _ := url.Parse(server.URL)
|
||||||
c, err := client.NewClient(u.Host)
|
c, err := client.NewClient(u.Host)
|
||||||
require.NoError(t, err)
|
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"
|
c.AuthToken = "Bearer testtoken"
|
||||||
|
|
||||||
// Get user profile
|
// Get user profile
|
||||||
|
|||||||
@@ -3,15 +3,20 @@ package credentials
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoadEnvCredentials loads credentials from .env file
|
// LoadEnvCredentials loads credentials from .env file
|
||||||
func LoadEnvCredentials() (email, password, domain string, err error) {
|
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
|
// Load .env file
|
||||||
if err := godotenv.Load(); err != nil {
|
if err := godotenv.Load(envPath); err != nil {
|
||||||
return "", "", "", fmt.Errorf("error loading .env file: %w", err)
|
return "", "", "", fmt.Errorf("error loading .env file from %s: %w", envPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
email = os.Getenv("GARMIN_EMAIL")
|
email = os.Getenv("GARMIN_EMAIL")
|
||||||
|
|||||||
@@ -15,13 +15,17 @@ import (
|
|||||||
|
|
||||||
// GetOAuth1Token retrieves an OAuth1 token using the provided ticket
|
// GetOAuth1Token retrieves an OAuth1 token using the provided ticket
|
||||||
func GetOAuth1Token(domain, ticket string) (*types.OAuth1Token, error) {
|
func GetOAuth1Token(domain, ticket string) (*types.OAuth1Token, error) {
|
||||||
|
scheme := "https"
|
||||||
|
if strings.HasPrefix(domain, "127.0.0.1") {
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
consumer, err := utils.LoadOAuthConsumer()
|
consumer, err := utils.LoadOAuthConsumer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to load OAuth consumer: %w", err)
|
return nil, fmt.Errorf("failed to load OAuth consumer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseURL := fmt.Sprintf("https://connectapi.%s/oauth-service/oauth/", domain)
|
baseURL := fmt.Sprintf("%s://connectapi.%s/oauth-service/oauth/", scheme, domain)
|
||||||
loginURL := fmt.Sprintf("https://sso.%s/sso/embed", domain)
|
loginURL := fmt.Sprintf("%s://sso.%s/sso/embed", scheme, domain)
|
||||||
tokenURL := fmt.Sprintf("%spreauthorized?ticket=%s&login-url=%s&accepts-mfa-tokens=true",
|
tokenURL := fmt.Sprintf("%spreauthorized?ticket=%s&login-url=%s&accepts-mfa-tokens=true",
|
||||||
baseURL, ticket, url.QueryEscape(loginURL))
|
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
|
// ExchangeToken exchanges an OAuth1 token for an OAuth2 token
|
||||||
func ExchangeToken(oauth1Token *types.OAuth1Token) (*types.OAuth2Token, error) {
|
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()
|
consumer, err := utils.LoadOAuthConsumer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to load OAuth consumer: %w", err)
|
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
|
// Prepare form data
|
||||||
formData := url.Values{}
|
formData := url.Values{}
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ func NewClient(domain string) *Client {
|
|||||||
func (c *Client) Login(email, password string) (*types.OAuth2Token, *MFAContext, error) {
|
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)
|
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
|
// Step 1: Set up SSO parameters
|
||||||
ssoURL := fmt.Sprintf("https://sso.%s/sso", c.Domain)
|
ssoURL := fmt.Sprintf("https://sso.%s/sso", c.Domain)
|
||||||
ssoEmbedURL := fmt.Sprintf("%s/embed", ssoURL)
|
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
|
// Step 3: Get signin page and CSRF token
|
||||||
fmt.Println("Getting signin page...")
|
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)
|
req, err = http.NewRequest("GET", signinURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to create signin request: %w", err)
|
return nil, nil, fmt.Errorf("failed to create signin request: %w", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user