Skip to content

Commit

Permalink
fix: remove experimental login command (#7)
Browse files Browse the repository at this point in the history
* fix: removed login command

* ci: increase golanglint-ci timeout

* docs: added PR template
  • Loading branch information
karl-cardenas-coding authored Jun 22, 2024
1 parent 0803c29 commit 709a5fa
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 194 deletions.
9 changes: 9 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Describe the Change

This PR .....

## Checklist

- [ ] Open Source License list updated? Use `make opensource` to update the list.

- [ ] License header updated? Use `make license` to update the header.
2 changes: 1 addition & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
- name: Run golangci-lint
uses: golangci/[email protected]
with:
args: -v
args: --verbose --timeout=2m

compile:
name: Compile validation
Expand Down
41 changes: 0 additions & 41 deletions cmd/login.go

This file was deleted.

152 changes: 0 additions & 152 deletions internal/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"io"
"log/slog"
"net/http"
"net/url"
"os"
"strings"
"time"
Expand Down Expand Up @@ -83,157 +82,6 @@ func RefreshToken(ctx context.Context, auth AuthRequest) (oauth2.Token, error) {

}

// GetToken is a function that triggers an Oauth flow that endusers can use to aquire a Whoop autentication token using their Whoop client and secret ID.
// The function logic is mostly copied from https://github.com/marekq/go-whoop with some minor modifications.
func GetToken(tokenFilePath string, client *http.Client) (string, error) {

// Set accessToken variable
accessToken := ""
clientID := os.Getenv("WHOOP_CLIENT_ID")
clientSecret := os.Getenv("WHOOP_CLIENT_SECRET")

if clientID == "" || clientSecret == "" {
return "", fmt.Errorf("ClientID and ClientSecret environment variables not set")

}

// Set token file path default
if tokenFilePath == "" {
tokenFilePath = DEFAULT_CREDENTIALS_FILE
}

config := &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
RedirectURL: DEFAULT_REDIRECT_URL,
Scopes: []string{
"offline",
"read:recovery",
"read:cycles",
"read:workout",
"read:sleep",
"read:profile",
"read:body_measurement",
},
Endpoint: getEndpoint(),
}

// Check if token.json file exists
if _, err := os.Stat(tokenFilePath); err == nil {

_, localToken, err := VerfyToken(tokenFilePath)
if err != nil {
slog.Error("Error reading local token", "msg", err)
return "", err
}

if !localToken.Valid() {

fmt.Println("Local token expired at " + localToken.Expiry.String() + " , refreshing...")

form := url.Values{}
form.Add("grant_type", "refresh_token")
form.Add("refresh_token", localToken.RefreshToken)
form.Add("client_id", clientID)
form.Add("client_secret", clientSecret)
form.Add("scope", "offline")

body := strings.NewReader(form.Encode())
req, err := http.NewRequest("POST", DEFAULT_ACCESS_TOKEN_URL, body)
if err != nil {
return "", err
}

req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if err != nil {
return "", err
}

if resp == nil {
return "", errors.New("empty response body from HTTP requests")
}

defer resp.Body.Close()

// Decode JSON
var tokenResponse AuthCredentials
err = json.NewDecoder(resp.Body).Decode(&tokenResponse)
if err != nil {
return "", err
}

// Marshal JSON
newToken := &oauth2.Token{
AccessToken: tokenResponse.AccessToken,
TokenType: tokenResponse.TokenType,
RefreshToken: tokenResponse.RefreshToken,
Expiry: time.Now().Local().Add(time.Second * time.Duration(tokenResponse.ExpiresIn)),
}

// Write token to file
err = writeLocalToken(tokenFilePath, newToken)
if err != nil {
return "", err
}

accessToken = tokenResponse.AccessToken

} else {

// Token is valid, use it without refresh
slog.Info("Local token valid till " + localToken.Expiry.String() + ", reused without refresh")
accessToken = localToken.AccessToken

}

} else {

// If token.json not present, start browser authentication flow
slog.Info("No token.json found, starting OAuth2 flow")

// Redirect user to consent page to ask for permission
authUrl := config.AuthCodeURL("stateidentifier", oauth2.AccessTypeOffline)
slog.Info("Visit the following URL for the auth dialog: \n\n" + authUrl + "\n")
slog.Info("Enter the response URL: ")

// Wait for user to paste in the response URL
var respUrl string
if _, err := fmt.Scan(&respUrl); err != nil {
return "", err
}

// Get response code from response URL string
parseUrl, err := url.Parse(respUrl)
if err != nil {
return "", errors.New("unable to parse URL value provided")
}

urlQuery := parseUrl.Query()
if urlQuery == nil {
return "", errors.New("unable to determine query parameters")
}

code := urlQuery.Get("code")

// Exchange response code for token
accessToken, err := config.Exchange(context.Background(), code)
if err != nil {
return "", err
}

// Write token to file
err = writeLocalToken(tokenFilePath, accessToken)
if err != nil {
return "", err
}

}

return accessToken, nil

}

// writeLocalToken creates file containing the Whoop authentication token
func writeLocalToken(filePath string, token *oauth2.Token) error {

Expand Down

0 comments on commit 709a5fa

Please sign in to comment.