sync authfix

This commit is contained in:
2025-09-06 07:27:59 -07:00
parent 01ba9a0042
commit a1cc209e46
22 changed files with 1041 additions and 292 deletions

294
auth.go
View File

@@ -2,10 +2,7 @@ package garth
import (
"context"
"crypto/hmac"
"crypto/sha1"
"crypto/tls"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@@ -16,7 +13,7 @@ import (
"net/url"
"os"
"regexp"
"sort"
"strconv"
"strings"
"time"
@@ -164,28 +161,10 @@ func (a *GarthAuthenticator) Login(ctx context.Context, username, password, mfaT
}
}
// Step 3: Get OAuth1 request token
oauth1RequestToken, err := a.fetchOAuth1RequestToken(ctx)
// Step 3: Exchange service ticket for access token
token, err := a.exchangeServiceTicketForToken(ctx, serviceTicket)
if err != nil {
return nil, fmt.Errorf("failed to get OAuth1 request token: %w", err)
}
// Step 4: Authorize OAuth1 request token (using the session from authentication)
err = a.authorizeOAuth1Token(ctx, oauth1RequestToken)
if err != nil {
return nil, fmt.Errorf("failed to authorize OAuth1 token: %w", err)
}
// Step 5: Exchange service ticket for OAuth1 access token
oauth1AccessToken, err := a.exchangeTicketForOAuth1Token(ctx, serviceTicket)
if err != nil {
return nil, fmt.Errorf("failed to exchange ticket for OAuth1 access token: %w", err)
}
// Step 6: Exchange OAuth1 access token for OAuth2 token
token, err := a.exchangeOAuth1ForOAuth2Token(ctx, oauth1AccessToken)
if err != nil {
return nil, fmt.Errorf("failed to exchange OAuth1 for OAuth2 token: %w", err)
return nil, fmt.Errorf("failed to exchange service ticket for token: %w", err)
}
if err := a.storage.StoreToken(token); err != nil {
@@ -195,203 +174,61 @@ func (a *GarthAuthenticator) Login(ctx context.Context, username, password, mfaT
return token, nil
}
func (a *GarthAuthenticator) fetchOAuth1RequestToken(ctx context.Context) (*OAuth1Token, error) {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://connectapi.%s/oauth-service/oauth/request_token", a.domain), nil)
// exchangeServiceTicketForToken exchanges service ticket for access token
func (a *GarthAuthenticator) exchangeServiceTicketForToken(ctx context.Context, ticket string) (*Token, error) {
callbackURL := fmt.Sprintf("https://connect.%s/oauthConfirm?ticket=%s", a.domain, ticket)
req, err := http.NewRequestWithContext(ctx, "GET", callbackURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
// Sign request with OAuth1 consumer credentials
req.Header.Set("Authorization", a.buildOAuth1Header(req, nil, ""))
resp, err := a.client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("request failed with status: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
values, err := url.ParseQuery(string(body))
if err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
return &OAuth1Token{
Token: values.Get("oauth_token"),
Secret: values.Get("oauth_token_secret"),
}, nil
}
func (a *GarthAuthenticator) authorizeOAuth1Token(ctx context.Context, token *OAuth1Token) error {
params := url.Values{}
params.Set("oauth_token", token.Token)
authURL := fmt.Sprintf("https://connect.%s/oauthConfirm?%s", a.domain, params.Encode())
req, err := http.NewRequestWithContext(ctx, "GET", authURL, nil)
if err != nil {
return fmt.Errorf("failed to create authorization request: %w", err)
return nil, fmt.Errorf("failed to create callback request: %w", err)
}
// Use realistic browser headers
req.Header = a.getRealisticBrowserHeaders("https://connect.garmin.com")
req.Header = a.getRealisticBrowserHeaders("https://sso.garmin.com")
resp, err := a.client.Do(req)
if err != nil {
return fmt.Errorf("authorization request failed: %w", err)
}
defer resp.Body.Close()
// We don't need the CSRF token anymore, so just check for success
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("authorization failed with status: %d, response: %s", resp.StatusCode, body)
}
return nil
}
func (a *GarthAuthenticator) exchangeTicketForOAuth1Token(ctx context.Context, ticket string) (*OAuth1Token, error) {
data := url.Values{}
data.Set("oauth_verifier", ticket)
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("https://connectapi.%s/oauth-service/oauth/access_token", a.domain), strings.NewReader(data.Encode()))
if err != nil {
return nil, fmt.Errorf("failed to create access token request: %w", err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", a.buildOAuth1Header(req, nil, ""))
resp, err := a.client.Do(req)
if err != nil {
return nil, fmt.Errorf("access token request failed: %w", err)
return nil, fmt.Errorf("callback request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("access token request failed with status: %d", resp.StatusCode)
return nil, fmt.Errorf("callback failed with status: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read access token response: %w", err)
return nil, fmt.Errorf("failed to read callback response: %w", err)
}
values, err := url.ParseQuery(string(body))
// Extract tokens from embedded JavaScript
accessToken, err := extractParam(`"accessToken":"([^"]+)"`, string(body))
if err != nil {
return nil, fmt.Errorf("failed to parse access token response: %w", err)
return nil, fmt.Errorf("failed to extract access token: %w", err)
}
return &OAuth1Token{
Token: values.Get("oauth_token"),
Secret: values.Get("oauth_token_secret"),
refreshToken, err := extractParam(`"refreshToken":"([^"]+)"`, string(body))
if err != nil {
return nil, fmt.Errorf("failed to extract refresh token: %w", err)
}
expiresAt, err := extractParam(`"expiresAt":(\d+)`, string(body))
if err != nil {
return nil, fmt.Errorf("failed to extract expiresAt: %w", err)
}
expiresAtInt, err := strconv.ParseInt(expiresAt, 10, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse expiresAt: %w", err)
}
return &Token{
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresAt: expiresAtInt,
Domain: a.domain,
}, nil
}
func (a *GarthAuthenticator) exchangeOAuth1ForOAuth2Token(ctx context.Context, oauth1Token *OAuth1Token) (*Token, error) {
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("https://connectapi.%s/oauth-service/oauth/exchange_token", a.domain), nil)
if err != nil {
return nil, fmt.Errorf("failed to create token exchange request: %w", err)
}
req.Header.Set("Authorization", a.buildOAuth1Header(req, oauth1Token, ""))
resp, err := a.client.Do(req)
if err != nil {
return nil, fmt.Errorf("token exchange request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("token exchange failed with status: %d", resp.StatusCode)
}
var token Token
if err := json.NewDecoder(resp.Body).Decode(&token); err != nil {
return nil, fmt.Errorf("failed to parse token response: %w", err)
}
if token.OAuth2Token != nil {
token.OAuth2Token.ExpiresAt = time.Now().Add(time.Duration(token.OAuth2Token.ExpiresIn) * time.Second).Unix()
}
token.OAuth1Token = oauth1Token
return &token, nil
}
func (a *GarthAuthenticator) buildOAuth1Header(req *http.Request, token *OAuth1Token, callback string) string {
oauthParams := url.Values{}
oauthParams.Set("oauth_consumer_key", "fc020df2-e33d-4ec5-987a-7fb6de2e3850")
oauthParams.Set("oauth_signature_method", "HMAC-SHA1")
oauthParams.Set("oauth_timestamp", fmt.Sprintf("%d", time.Now().Unix()))
oauthParams.Set("oauth_nonce", fmt.Sprintf("%d", rand.Int63()))
oauthParams.Set("oauth_version", "1.0")
if token != nil {
oauthParams.Set("oauth_token", token.Token)
}
if callback != "" {
oauthParams.Set("oauth_callback", callback)
}
// Generate signature
baseString := a.buildSignatureBaseString(req, oauthParams)
signingKey := url.QueryEscape("secret_key_from_mobile_app") + "&"
if token != nil {
signingKey += url.QueryEscape(token.Secret)
}
mac := hmac.New(sha1.New, []byte(signingKey))
mac.Write([]byte(baseString))
signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
oauthParams.Set("oauth_signature", signature)
// Build header
params := make([]string, 0, len(oauthParams))
for k, v := range oauthParams {
params = append(params, fmt.Sprintf(`%s="%s"`, k, url.QueryEscape(v[0])))
}
sort.Strings(params)
return "OAuth " + strings.Join(params, ", ")
}
func (a *GarthAuthenticator) buildSignatureBaseString(req *http.Request, oauthParams url.Values) string {
method := strings.ToUpper(req.Method)
baseURL := req.URL.Scheme + "://" + req.URL.Host + req.URL.Path
// Collect all parameters
params := url.Values{}
for k, v := range req.URL.Query() {
params[k] = v
}
for k, v := range oauthParams {
params[k] = v
}
// Sort parameters
paramKeys := make([]string, 0, len(params))
for k := range params {
paramKeys = append(paramKeys, k)
}
sort.Strings(paramKeys)
paramPairs := make([]string, 0, len(paramKeys))
for _, k := range paramKeys {
paramPairs = append(paramPairs, fmt.Sprintf("%s=%s", k, url.QueryEscape(params[k][0])))
}
queryString := strings.Join(paramPairs, "&")
return fmt.Sprintf("%s&%s&%s", method, url.QueryEscape(baseURL), url.QueryEscape(queryString))
}
func (a *GarthAuthenticator) getLoginTicket(ctx context.Context) (string, string, error) {
params := url.Values{}
params.Set("id", "gauth-widget")
@@ -527,10 +364,6 @@ func (a *GarthAuthenticator) authenticate(ctx context.Context, username, passwor
return authResponse.Ticket, nil
}
func (a *GarthAuthenticator) ExchangeToken(ctx context.Context, token *OAuth1Token) (*Token, error) {
return a.exchangeOAuth1ForOAuth2Token(ctx, token)
}
func (a *GarthAuthenticator) getEnhancedBrowserHeaders(referrer string) http.Header {
u, _ := url.Parse(referrer)
origin := fmt.Sprintf("%s://%s", u.Scheme, u.Host)
@@ -553,25 +386,27 @@ func (a *GarthAuthenticator) getEnhancedBrowserHeaders(referrer string) http.Hea
}
func getCSRFToken(html string) (string, string, error) {
// Extract login ticket (lt) from hidden input field
re := regexp.MustCompile(`<input\s+type="hidden"\s+name="lt"\s+value="([^"]+)"\s*/>`)
matches := re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1], "lt", nil
// More robust regex patterns to handle variations in HTML structure
patterns := []struct {
regex string
tokenType string
}{
// Pattern for login ticket (lt)
{`<input[^>]*name="lt"[^>]*value="([^"]+)"`, "lt"},
// Pattern for CSRF token in hidden input
{`<input[^>]*name="_csrf"[^>]*value="([^"]+)"`, "_csrf"},
// Pattern for CSRF token in meta tag
{`<meta[^>]*name="_csrf"[^>]*content="([^"]+)"`, "_csrf"},
// Pattern for CSRF token in JSON payload
{`"csrfToken"\s*:\s*"([^"]+)"`, "_csrf"},
}
// Extract CSRF token as fallback
re = regexp.MustCompile(`<input\s+type="hidden"\s+name="_csrf"\s+value="([^"]+)"\s*/>`)
matches = re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1], "_csrf", nil
}
// Try alternative CSRF token pattern
re = regexp.MustCompile(`"csrfToken":"([^"]+)"`)
matches = re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1], "_csrf", nil
for _, p := range patterns {
re := regexp.MustCompile(p.regex)
matches := re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1], p.tokenType, nil
}
}
// If we get here, we didn't find a token
@@ -609,15 +444,22 @@ func (a *GarthAuthenticator) RefreshToken(ctx context.Context, refreshToken stri
return nil, fmt.Errorf("refresh failed: %d %s", resp.StatusCode, body)
}
var token Token
if err := json.NewDecoder(resp.Body).Decode(&token); err != nil {
var response struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"`
}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed to parse refresh response: %w", err)
}
if token.OAuth2Token != nil {
token.OAuth2Token.ExpiresAt = time.Now().Add(time.Duration(token.OAuth2Token.ExpiresIn) * time.Second).Unix()
}
return &token, nil
expiresAt := time.Now().Add(time.Duration(response.ExpiresIn) * time.Second).Unix()
return &Token{
AccessToken: response.AccessToken,
RefreshToken: response.RefreshToken,
ExpiresAt: expiresAt,
Domain: a.domain,
}, nil
}
// GetClient returns the HTTP client used for authentication

View File

@@ -59,27 +59,27 @@ func TestRealAuthentication(t *testing.T) {
}
log.Printf("Authentication successful! Token details:")
log.Printf("Access Token: %s", token.OAuth2Token.AccessToken)
log.Printf("Expires At: %d", token.OAuth2Token.ExpiresAt)
log.Printf("Refresh Token: %s", token.OAuth2Token.RefreshToken)
log.Printf("Access Token: %s", token.AccessToken)
log.Printf("Expires At: %d", token.ExpiresAt)
log.Printf("Refresh Token: %s", token.RefreshToken)
// Verify token storage
storedToken, err := storage.GetToken()
if err != nil {
t.Fatalf("Token storage verification failed: %v", err)
}
if storedToken.OAuth2Token.AccessToken != token.OAuth2Token.AccessToken {
if storedToken.AccessToken != token.AccessToken {
t.Fatal("Stored token doesn't match authenticated token")
}
log.Println("Token storage verification successful")
// Test token refresh
newToken, err := auth.RefreshToken(ctx, token.OAuth2Token.RefreshToken)
newToken, err := auth.RefreshToken(ctx, token.RefreshToken)
if err != nil {
t.Fatalf("Token refresh failed: %v", err)
}
if newToken.OAuth2Token.AccessToken == token.OAuth2Token.AccessToken {
if newToken.AccessToken == token.AccessToken {
t.Fatal("Refreshed token should be different from original")
}
log.Println("Token refresh successful")

View File

@@ -59,7 +59,7 @@ func (t *AuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
}
// Add Authorization header
req.Header.Set("Authorization", "Bearer "+token.OAuth2Token.AccessToken)
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
req.Header.Set("User-Agent", t.userAgent)
req.Header.Set("Referer", "https://sso.garmin.com/sso/signin")
@@ -85,7 +85,7 @@ func (t *AuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+token.OAuth2Token.AccessToken)
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
continue
}
@@ -123,7 +123,7 @@ func (t *AuthTransport) refreshToken(ctx context.Context, token *Token) (*Token,
}
// Perform refresh
newToken, err := t.auth.RefreshToken(ctx, token.OAuth2Token.RefreshToken)
newToken, err := t.auth.RefreshToken(ctx, token.RefreshToken)
if err != nil {
return nil, err
}

View File

@@ -40,16 +40,16 @@ func main() {
}
fmt.Println("\nAuthentication successful! Token details:")
fmt.Printf("Access Token: %s\n", token.OAuth2Token.AccessToken)
fmt.Printf("Expires At: %d\n", token.OAuth2Token.ExpiresAt)
fmt.Printf("Refresh Token: %s\n", token.OAuth2Token.RefreshToken)
fmt.Printf("Access Token: %s\n", token.AccessToken)
fmt.Printf("Expires At: %d\n", token.ExpiresAt)
fmt.Printf("Refresh Token: %s\n", token.RefreshToken)
// Verify token storage
storedToken, err := storage.GetToken()
if err != nil {
log.Fatalf("Token storage verification failed: %v", err)
}
if storedToken.OAuth2Token.AccessToken != token.OAuth2Token.AccessToken {
if storedToken.AccessToken != token.AccessToken {
log.Fatal("Stored token doesn't match authenticated token")
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>
<!--[if gte IE 10]><!-->
<script>
if (!navigator.cookieEnabled) {
window.addEventListener('DOMContentLoaded', function () {
var cookieEl = document.getElementById('cookie-alert');
cookieEl.style.display = 'block';
})
}
</script>
<!--<![endif]-->
</head>
<body>
<div id="cf-wrapper">
<div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
<div id="cf-error-details" class="cf-error-details-wrapper">
<div class="cf-wrapper cf-header cf-error-overview">
<h1 data-translate="block_headline">Sorry, you have been blocked</h1>
<h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> sso.garmin.com</h2>
</div><!-- /.header -->
<div class="cf-section cf-highlight">
<div class="cf-wrapper">
<div class="cf-screenshot-container cf-screenshot-full">
<span class="cf-no-screenshot error"></span>
</div>
</div>
</div><!-- /.captcha-container -->
<div class="cf-section cf-wrapper">
<div class="cf-columns two">
<div class="cf-column">
<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>
<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>
<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>
<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
<p class="text-13">
<span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">97a86f0198f008fa</strong></span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
Your IP:
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
<span class="hidden" id="cf-footer-ip">47.150.230.21</span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
</span>
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
</p>
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
</div><!-- /.error-footer -->
</div><!-- /#cf-error-details -->
</div><!-- /#cf-wrapper -->
<script>
window._cf_translation = {};
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a86f0198f008fa',t:'MTc1NzEwMzY5My4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>
<!--[if gte IE 10]><!-->
<script>
if (!navigator.cookieEnabled) {
window.addEventListener('DOMContentLoaded', function () {
var cookieEl = document.getElementById('cookie-alert');
cookieEl.style.display = 'block';
})
}
</script>
<!--<![endif]-->
</head>
<body>
<div id="cf-wrapper">
<div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
<div id="cf-error-details" class="cf-error-details-wrapper">
<div class="cf-wrapper cf-header cf-error-overview">
<h1 data-translate="block_headline">Sorry, you have been blocked</h1>
<h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> sso.garmin.com</h2>
</div><!-- /.header -->
<div class="cf-section cf-highlight">
<div class="cf-wrapper">
<div class="cf-screenshot-container cf-screenshot-full">
<span class="cf-no-screenshot error"></span>
</div>
</div>
</div><!-- /.captcha-container -->
<div class="cf-section cf-wrapper">
<div class="cf-columns two">
<div class="cf-column">
<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>
<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>
<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>
<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
<p class="text-13">
<span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">97a87306fc145337</strong></span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
Your IP:
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
<span class="hidden" id="cf-footer-ip">47.150.230.21</span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
</span>
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
</p>
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
</div><!-- /.error-footer -->
</div><!-- /#cf-error-details -->
</div><!-- /#cf-wrapper -->
<script>
window._cf_translation = {};
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a87306fc145337',t:'MTc1NzEwMzg1Ny4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>
<!--[if gte IE 10]><!-->
<script>
if (!navigator.cookieEnabled) {
window.addEventListener('DOMContentLoaded', function () {
var cookieEl = document.getElementById('cookie-alert');
cookieEl.style.display = 'block';
})
}
</script>
<!--<![endif]-->
</head>
<body>
<div id="cf-wrapper">
<div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
<div id="cf-error-details" class="cf-error-details-wrapper">
<div class="cf-wrapper cf-header cf-error-overview">
<h1 data-translate="block_headline">Sorry, you have been blocked</h1>
<h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> sso.garmin.com</h2>
</div><!-- /.header -->
<div class="cf-section cf-highlight">
<div class="cf-wrapper">
<div class="cf-screenshot-container cf-screenshot-full">
<span class="cf-no-screenshot error"></span>
</div>
</div>
</div><!-- /.captcha-container -->
<div class="cf-section cf-wrapper">
<div class="cf-columns two">
<div class="cf-column">
<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>
<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>
<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>
<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
<p class="text-13">
<span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">97a8823fcfbc0904</strong></span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
Your IP:
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
<span class="hidden" id="cf-footer-ip">47.150.230.21</span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
</span>
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
</p>
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
</div><!-- /.error-footer -->
</div><!-- /#cf-error-details -->
</div><!-- /#cf-wrapper -->
<script>
window._cf_translation = {};
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a8823fcfbc0904',t:'MTc1NzEwNDQ4MS4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>
<!--[if gte IE 10]><!-->
<script>
if (!navigator.cookieEnabled) {
window.addEventListener('DOMContentLoaded', function () {
var cookieEl = document.getElementById('cookie-alert');
cookieEl.style.display = 'block';
})
}
</script>
<!--<![endif]-->
</head>
<body>
<div id="cf-wrapper">
<div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
<div id="cf-error-details" class="cf-error-details-wrapper">
<div class="cf-wrapper cf-header cf-error-overview">
<h1 data-translate="block_headline">Sorry, you have been blocked</h1>
<h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> sso.garmin.com</h2>
</div><!-- /.header -->
<div class="cf-section cf-highlight">
<div class="cf-wrapper">
<div class="cf-screenshot-container cf-screenshot-full">
<span class="cf-no-screenshot error"></span>
</div>
</div>
</div><!-- /.captcha-container -->
<div class="cf-section cf-wrapper">
<div class="cf-columns two">
<div class="cf-column">
<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>
<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>
<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>
<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
<p class="text-13">
<span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">97a9b3b9dbc89dea</strong></span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
Your IP:
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
<span class="hidden" id="cf-footer-ip">47.150.230.21</span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
</span>
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
</p>
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
</div><!-- /.error-footer -->
</div><!-- /#cf-error-details -->
</div><!-- /#cf-wrapper -->
<script>
window._cf_translation = {};
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a9b3b9dbc89dea',t:'MTc1NzExNjk5My4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>
<!--[if gte IE 10]><!-->
<script>
if (!navigator.cookieEnabled) {
window.addEventListener('DOMContentLoaded', function () {
var cookieEl = document.getElementById('cookie-alert');
cookieEl.style.display = 'block';
})
}
</script>
<!--<![endif]-->
</head>
<body>
<div id="cf-wrapper">
<div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
<div id="cf-error-details" class="cf-error-details-wrapper">
<div class="cf-wrapper cf-header cf-error-overview">
<h1 data-translate="block_headline">Sorry, you have been blocked</h1>
<h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> sso.garmin.com</h2>
</div><!-- /.header -->
<div class="cf-section cf-highlight">
<div class="cf-wrapper">
<div class="cf-screenshot-container cf-screenshot-full">
<span class="cf-no-screenshot error"></span>
</div>
</div>
</div><!-- /.captcha-container -->
<div class="cf-section cf-wrapper">
<div class="cf-columns two">
<div class="cf-column">
<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>
<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>
<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>
<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
<p class="text-13">
<span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">97a9b677e98ff8d5</strong></span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
Your IP:
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
<span class="hidden" id="cf-footer-ip">138.199.43.80</span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
</span>
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
</p>
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
</div><!-- /.error-footer -->
</div><!-- /#cf-error-details -->
</div><!-- /#cf-wrapper -->
<script>
window._cf_translation = {};
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a9b677e98ff8d5',t:'MTc1NzExNzEwNS4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>
<!--[if gte IE 10]><!-->
<script>
if (!navigator.cookieEnabled) {
window.addEventListener('DOMContentLoaded', function () {
var cookieEl = document.getElementById('cookie-alert');
cookieEl.style.display = 'block';
})
}
</script>
<!--<![endif]-->
</head>
<body>
<div id="cf-wrapper">
<div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
<div id="cf-error-details" class="cf-error-details-wrapper">
<div class="cf-wrapper cf-header cf-error-overview">
<h1 data-translate="block_headline">Sorry, you have been blocked</h1>
<h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> sso.garmin.com</h2>
</div><!-- /.header -->
<div class="cf-section cf-highlight">
<div class="cf-wrapper">
<div class="cf-screenshot-container cf-screenshot-full">
<span class="cf-no-screenshot error"></span>
</div>
</div>
</div><!-- /.captcha-container -->
<div class="cf-section cf-wrapper">
<div class="cf-columns two">
<div class="cf-column">
<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>
<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>
<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>
<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
<p class="text-13">
<span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">97a9b977caffdbc2</strong></span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
Your IP:
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
<span class="hidden" id="cf-footer-ip">47.150.230.21</span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
</span>
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
</p>
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
</div><!-- /.error-footer -->
</div><!-- /#cf-error-details -->
</div><!-- /#cf-wrapper -->
<script>
window._cf_translation = {};
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a9b977caffdbc2',t:'MTc1NzExNzIyOC4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>
<!--[if gte IE 10]><!-->
<script>
if (!navigator.cookieEnabled) {
window.addEventListener('DOMContentLoaded', function () {
var cookieEl = document.getElementById('cookie-alert');
cookieEl.style.display = 'block';
})
}
</script>
<!--<![endif]-->
</head>
<body>
<div id="cf-wrapper">
<div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
<div id="cf-error-details" class="cf-error-details-wrapper">
<div class="cf-wrapper cf-header cf-error-overview">
<h1 data-translate="block_headline">Sorry, you have been blocked</h1>
<h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> sso.garmin.com</h2>
</div><!-- /.header -->
<div class="cf-section cf-highlight">
<div class="cf-wrapper">
<div class="cf-screenshot-container cf-screenshot-full">
<span class="cf-no-screenshot error"></span>
</div>
</div>
</div><!-- /.captcha-container -->
<div class="cf-section cf-wrapper">
<div class="cf-columns two">
<div class="cf-column">
<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>
<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>
<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>
<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
<p class="text-13">
<span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">97a9c7bc4ed7ff84</strong></span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
Your IP:
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
<span class="hidden" id="cf-footer-ip">47.150.230.21</span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
</span>
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
</p>
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
</div><!-- /.error-footer -->
</div><!-- /#cf-error-details -->
</div><!-- /#cf-wrapper -->
<script>
window._cf_translation = {};
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a9c7bc4ed7ff84',t:'MTc1NzExNzgxMy4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>
<!--[if gte IE 10]><!-->
<script>
if (!navigator.cookieEnabled) {
window.addEventListener('DOMContentLoaded', function () {
var cookieEl = document.getElementById('cookie-alert');
cookieEl.style.display = 'block';
})
}
</script>
<!--<![endif]-->
</head>
<body>
<div id="cf-wrapper">
<div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
<div id="cf-error-details" class="cf-error-details-wrapper">
<div class="cf-wrapper cf-header cf-error-overview">
<h1 data-translate="block_headline">Sorry, you have been blocked</h1>
<h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> sso.garmin.com</h2>
</div><!-- /.header -->
<div class="cf-section cf-highlight">
<div class="cf-wrapper">
<div class="cf-screenshot-container cf-screenshot-full">
<span class="cf-no-screenshot error"></span>
</div>
</div>
</div><!-- /.captcha-container -->
<div class="cf-section cf-wrapper">
<div class="cf-columns two">
<div class="cf-column">
<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>
<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>
<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>
<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->
<div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
<p class="text-13">
<span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">97a9f0c2588a72e0</strong></span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
<span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
Your IP:
<button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
<span class="hidden" id="cf-footer-ip">47.150.230.21</span>
<span class="cf-footer-separator sm:hidden">&bull;</span>
</span>
<span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
</p>
<script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
</div><!-- /.error-footer -->
</div><!-- /#cf-error-details -->
</div><!-- /#cf-wrapper -->
<script>
window._cf_translation = {};
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a9f0c2588a72e0',t:'MTc1NzExOTQ5My4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

Binary file not shown.

View File

@@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width" />
<meta http-equiv="X-UA-Compatible" content="IE=edge;" />
<title>GARMIN Authentication Application</title>
<link href="/sso/css/GAuth.css?20210406" rel="stylesheet" type="text/css" media="all" />
<link rel="stylesheet" href=""/>
<script type="text/javascript" src="/sso/js/jquery/3.7.1/jquery.min.js?20210319"></script>
<script type="text/javascript">jQuery.noConflict();</script>
<script type="text/javascript" src="/sso/js/jquery-validate/1.16.0/jquery.validate.min.js?20210319"></script>
<script type="text/javascript" src="/sso/js/jsUtils.js?20210406"></script>
<script type="text/javascript" src="/sso/js/json2.js"></script>
<script type="text/javascript" src="/sso/js/consoleUtils.js?20210319"></script>
<script type="text/javascript" src="/sso/js/postmessage.js?20210319"></script>
<script type="text/javascript" src="/sso/js/popupWindow.js"></script>
<script type="text/javascript" src="/sso/js/base.js?20231020"></script>
<script type="text/javascript" src="/sso/js/gigyaUtils.js?20210319"></script>
<script type="text/javascript" src="/sso/js/login.js?20211102"></script>
<script type="text/javascript" src="/sso/js/reCaptchaUtil.js?20230706"></script>
<script>
var recaptchaSiteKey = null;
var reCaptchaURL = "\\\/sso\\\/reCaptcha?clientId=GarminConnect\u0026consumeServiceTicket=false\u0026embedWidget=true\u0026gauthHost=https%3A%2F%2Fsso.garmin.com%2Fsso\u0026generateExtraServiceTicket=true\u0026id=gauth-widget\u0026locale=en_US\u0026redirectAfterAccountCreationUrl=https%3A%2F%2Fconnect.garmin.com%2FoauthConfirm\u0026redirectAfterAccountLoginUrl=https%3A%2F%2Fconnect.garmin.com%2FoauthConfirm\u0026service=https%3A%2F%2Fconnect.garmin.com%2FoauthConfirm\u0026source=https%3A%2F%2Fsso.garmin.com%2Fsso";
var isRecaptchaEnabled = null;
var recaptchaToken = null;
</script>
<script type="text/javascript">
var parent_url = "https:\/\/sso.garmin.com\/sso";
var status = "";
var result = "";
var clientId = 'GarminConnect';
var embedWidget = true;
var isUsernameDefined = (false == true) || (false == true);
// Gigya callback to SocialSignInController for brand new social network users redirects to this page
// to popup Create or Link Social Account page, but has a possibly mangled source parameter
// where "?" is set as "<QM>", so translate it back to "?" here.
parent_url = parent_url.replace('<QM>', '?');
var parent_scheme = parent_url.substring(0, parent_url.indexOf("://"));
var parent_hostname = parent_url.substring(parent_scheme.length + 3, parent_url.length);
if (parent_hostname.indexOf("/") != -1) {
parent_hostname = parent_hostname.substring(0, parent_hostname.indexOf("/"));
}
var parentHost = parent_scheme + "://" + parent_hostname;
var createAccountConfigURL = '\/sso\/createNewAccount?clientId%3DGarminConnect%26consumeServiceTicket%3Dfalse%26embedWidget%3Dtrue%26gauthHost%3Dhttps%253A%252F%252Fsso.garmin.com%252Fsso%26generateExtraServiceTicket%3Dtrue%26id%3Dgauth-widget%26locale%3Den_US%26redirectAfterAccountCreationUrl%3Dhttps%253A%252F%252Fconnect.garmin.com%252FoauthConfirm%26redirectAfterAccountLoginUrl%3Dhttps%253A%252F%252Fconnect.garmin.com%252FoauthConfirm%26service%3Dhttps%253A%252F%252Fconnect.garmin.com%252FoauthConfirm%26source%3Dhttps%253A%252F%252Fsso.garmin.com%252Fsso';
var socialConfigURL = 'https://sso.garmin.com/sso/socialSignIn?clientId%3DGarminConnect%26consumeServiceTicket%3Dfalse%26embedWidget%3Dtrue%26gauthHost%3Dhttps%3A%2F%2Fsso.garmin.com%2Fsso%26generateExtraServiceTicket%3Dtrue%26id%3Dgauth-widget%26locale%3Den_US%26redirectAfterAccountCreationUrl%3Dhttps%3A%2F%2Fconnect.garmin.com%2FoauthConfirm%26redirectAfterAccountLoginUrl%3Dhttps%3A%2F%2Fconnect.garmin.com%2FoauthConfirm%26service%3Dhttps%3A%2F%2Fconnect.garmin.com%2FoauthConfirm%26source%3Dhttps%3A%2F%2Fsso.garmin.com%2Fsso';
var gigyaURL = "https://cdns.gigya.com/js/gigya.js?apiKey=2_R3ZGY8Bqlwwk3_63knoD9wA_m-Y19mAgW61bF_s5k9gymYnMEAtMrJiF5MjF-U7B";
if (createAccountConfigURL.indexOf('%253A%252F%252F') != -1) {
createAccountConfigURL = decodeURIComponent(createAccountConfigURL);
}
consoleInfo('signin.html embedWidget: true, createAccountConfigURL: \/sso\/createNewAccount?clientId%3DGarminConnect%26consumeServiceTicket%3Dfalse%26embedWidget%3Dtrue%26gauthHost%3Dhttps%253A%252F%252Fsso.garmin.com%252Fsso%26generateExtraServiceTicket%3Dtrue%26id%3Dgauth-widget%26locale%3Den_US%26redirectAfterAccountCreationUrl%3Dhttps%253A%252F%252Fconnect.garmin.com%252FoauthConfirm%26redirectAfterAccountLoginUrl%3Dhttps%253A%252F%252Fconnect.garmin.com%252FoauthConfirm%26service%3Dhttps%253A%252F%252Fconnect.garmin.com%252FoauthConfirm%26source%3Dhttps%253A%252F%252Fsso.garmin.com%252Fsso, socialEnabled: true, gigyaSupported: true, socialConfigURL(): https://sso.garmin.com/sso/socialSignIn?clientId%3DGarminConnect%26consumeServiceTicket%3Dfalse%26embedWidget%3Dtrue%26gauthHost%3Dhttps%3A%2F%2Fsso.garmin.com%2Fsso%26generateExtraServiceTicket%3Dtrue%26id%3Dgauth-widget%26locale%3Den_US%26redirectAfterAccountCreationUrl%3Dhttps%3A%2F%2Fconnect.garmin.com%2FoauthConfirm%26redirectAfterAccountLoginUrl%3Dhttps%3A%2F%2Fconnect.garmin.com%2FoauthConfirm%26service%3Dhttps%3A%2F%2Fconnect.garmin.com%2FoauthConfirm%26source%3Dhttps%3A%2F%2Fsso.garmin.com%2Fsso');
if (socialConfigURL.indexOf('%3A%2F%2F') != -1) {
socialConfigURL = decodeURIComponent(socialConfigURL);
}
if( status != null && status != ''){
send({'status':status});
}
jQuery(document).ready( function(){
consoleInfo("signin.html: setting field validation rules...");
jQuery("#username").rules("add",{
required: true,
messages: {
required: "Email is required."
}});
jQuery("#password").rules("add", {
required: true,
messages: {
required: "Password is required."
}
});
consoleInfo("signin.html: done setting field validation rules...");
});
XD.receiveMessage(function(m){
consoleInfo("signin.html: " + m.data + " received on " + window.location.host);
if (m && m.data) {
var md = m.data;
if (typeof(md) === 'string') {
md = JSON.parse(m.data);
}
if (md.setUsername) {
consoleInfo("signin.html: Setting username \"" + md.username + "\"...");
jQuery("#signInWithDiffLink").click(); // Ensure the normal login form is shown.
jQuery("#username").val(md.username);
jQuery("#password").focus();
}
}
}, parentHost);
</script>
</head>
<body>
<!-- begin GAuth component -->
<div id="GAuth-component">
<!-- begin login component-->
<div id="login-component" class="blueForm-basic">
<input type="hidden" id="queryString" value="clientId=GarminConnect&amp;consumeServiceTicket=false&amp;embedWidget=true&amp;gauthHost=https%3A%2F%2Fsso.garmin.com%2Fsso&amp;generateExtraServiceTicket=true&amp;id=gauth-widget&amp;locale=en_US&amp;redirectAfterAccountCreationUrl=https%3A%2F%2Fconnect.garmin.com%2FoauthConfirm&amp;redirectAfterAccountLoginUrl=https%3A%2F%2Fconnect.garmin.com%2FoauthConfirm&amp;service=https%3A%2F%2Fconnect.garmin.com%2FoauthConfirm&amp;source=https%3A%2F%2Fsso.garmin.com%2Fsso" />
<input type="hidden" id="contextPath" value="/sso" />
<!-- begin login form -->
<div id="login-state-default">
<h2>Sign In</h2>
<form method="post" id="login-form">
<div class="form-alert">
<div id="username-error" style="display:none;"></div>
<div id="password-error" style="display:none;"></div>
</div>
<div class="textfield">
<label for="username">Email</label>
<!-- If the lockToEmailAddress parameter is specified then we want to mark the field as readonly,
preload the email address, and disable the other input so that null isn't sent to the server. We'll
also style the field to have a darker grey background and disable the mouse pointer
-->
<!-- If the lockToEmailAddress parameter is NOT specified then keep the existing functionality and disable the readonly input field
-->
<input class="login_email" name="username" id="username" value="" type="email" spellcheck="false" autocorrect="off" autocapitalize="off"/>
</div>
<div class="textfield">
<label for="password">Password</label>
<a id="loginforgotpassword" class="login-forgot-password" style="cursor:pointer">(Forgot?)</a>
<input type="password" name="password" id="password" spellcheck="false" autocorrect="off" autocapitalize="off" />
<strong id="capslock-warning" class="information" title="Caps lock is on." style="display: none;">Caps lock is on.</strong>
</div>
<input type="hidden" name="embed" value="true"/>
<input type="hidden" name="_csrf" value="E40E9FF5C027499972C9CF65024778906C9844597CEA466BA7F12FD111B57968050F45514DAA93282D2DF3FB562B20866BD6" />
<button type="submit" id="login-btn-signin" class="btn1" accesskey="l">Sign In</button>
<!-- The existence of the "rememberme" parameter at all will remember the user! -->
</form>
</div>
<!-- end login form -->
<!-- begin Create Account message -->
<div id="login-create-account">
</div>
<!-- end Create Account message -->
<!-- begin Social Sign In component -->
<div id="SSI-component">
</div>
<!-- end Social Sign In component -->
<div class="clearfix"></div> <!-- Ensure that GAuth-component div's height is computed correctly. -->
</div>
<!-- end login component-->
</div>
<!-- end GAuth component -->
<script type="text/javascript">
jQuery(document).ready(function(){
resizePageOnLoad(jQuery("#GAuth-component").height());
if(isUsernameDefined == true){
// If the user's login just failed, redisplay the email/username specified, and focus them in the password field.
jQuery("#password").focus();
} else if(false == true && result != "PASSWORD_RESET_RESULT"){
// Otherwise focus them in the username field of the login dialog.
jQuery("#username").focus();
}
// Scroll to top of iframe to fix problem where Firefox 3.0-3.6 browsers initially show top of iframe cutoff.
location.href="#";
if(!embedWidget){
jQuery('.createAccountLink').click(function(){
send({'openLiteBox':'createAccountLink', 'popupUrl': createAccountConfigURL, 'popupTitle':'Create An Account', 'clientId':clientId});
});
}
});
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'97a8141f193919db',t:'MTc1NzA5OTk3MC4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

View File

@@ -32,7 +32,6 @@ package garth
import (
"context"
"errors"
"net/http"
"os"
"strconv"
@@ -41,15 +40,12 @@ import (
// Authenticator defines the authentication interface
type Authenticator interface {
// Login authenticates with Garmin services using OAuth1/OAuth2 hybrid flow
// Login authenticates with Garmin services using OAuth2 flow
Login(ctx context.Context, username, password, mfaToken string) (*Token, error)
// RefreshToken refreshes an expired OAuth2 access token
RefreshToken(ctx context.Context, refreshToken string) (*Token, error)
// ExchangeToken exchanges OAuth1 token for OAuth2 token
ExchangeToken(ctx context.Context, oauth1Token *OAuth1Token) (*Token, error)
// GetClient returns an authenticated HTTP client
GetClient() *http.Client
}
@@ -89,16 +85,3 @@ func NewClientOptionsFromEnv() ClientOptions {
return opts
}
// getRequestToken retrieves OAuth1 request token
// getRequestToken retrieves OAuth1 request token
func getRequestToken(a Authenticator, ctx context.Context) (*OAuth1Token, error) {
// Implementation will be added in next step
return nil, errors.New("not implemented")
}
// authorizeRequestToken authorizes OAuth1 token through SSO
func authorizeRequestToken(a Authenticator, ctx context.Context, token *OAuth1Token) error {
// Implementation will be added in next step
return errors.New("not implemented")
}

View File

@@ -8,49 +8,23 @@ import (
// Unified Token Definitions
// OAuth1Token represents OAuth1 credentials
type OAuth1Token struct {
Token string
Secret string
}
// OAuth2Token represents OAuth2 credentials
type OAuth2Token struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
ExpiresAt int64 `json:"expires_at"`
RefreshToken string `json:"refresh_token"`
Scope string `json:"scope"`
}
// IsExpired checks if the token has expired
func (t *OAuth2Token) IsExpired() bool {
return time.Now().After(time.Unix(t.ExpiresAt, 0))
}
// Token represents unified authentication credentials
// Token represents authentication credentials
type Token struct {
Domain string `json:"domain"`
OAuth1Token *OAuth1Token `json:"oauth1_token"`
OAuth2Token *OAuth2Token `json:"oauth2_token"`
UserProfile *UserProfile `json:"user_profile"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresAt int64 `json:"expires_at"`
Domain string `json:"domain"`
UserProfile *UserProfile `json:"user_profile"`
}
// IsExpired checks if the OAuth2 token has expired
// IsExpired checks if the token has expired (with 60 second buffer)
func (t *Token) IsExpired() bool {
if t.OAuth2Token == nil {
return true
}
return t.OAuth2Token.IsExpired()
return time.Now().Unix() >= (t.ExpiresAt - 60)
}
// NeedsRefresh checks if token needs refresh (within 5 min expiry window)
func (t *Token) NeedsRefresh() bool {
if t.OAuth2Token == nil {
return true
}
return time.Now().Add(5 * time.Minute).After(time.Unix(t.OAuth2Token.ExpiresAt, 0))
return time.Now().Unix() >= (t.ExpiresAt - 300)
}
// UserProfile represents Garmin user profile information