Skip to content

Commit 97a12b8

Browse files
authored
refactor: use globalping-go & cleanup (#180)
1 parent e1fb906 commit 97a12b8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1867
-2942
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,5 @@ dist/
4040

4141
# binaries not committed
4242
bin/
43+
44+
.DS_Store

globalping/auth.go renamed to api/auth.go

Lines changed: 81 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
package globalping
1+
package api
22

33
import (
4+
"context"
45
"crypto/rand"
56
"crypto/sha256"
67
"encoding/base64"
@@ -11,9 +12,9 @@ import (
1112
"strconv"
1213
"strings"
1314
"time"
14-
)
1515

16-
var timeNow = time.Now
16+
"github.com/jsdelivr/globalping-cli/storage"
17+
)
1718

1819
var (
1920
ErrTypeExchangeFailed = "exchange_failed"
@@ -24,14 +25,6 @@ var (
2425
ErrTypeNotAuthorized = "not_authorized"
2526
)
2627

27-
type Token struct {
28-
AccessToken string `json:"access_token"`
29-
TokenType string `json:"token_type,omitempty"`
30-
RefreshToken string `json:"refresh_token,omitempty"`
31-
ExpiresIn int64 `json:"expires_in,omitempty"`
32-
Expiry time.Time `json:"expiry,omitempty"`
33-
}
34-
3528
type AuthorizeError struct {
3629
Code int `json:"-"`
3730
ErrorType string `json:"error"`
@@ -47,23 +40,28 @@ type AuthorizeResponse struct {
4740
CallbackURL string
4841
}
4942

50-
func (c *client) Authorize(callback func(error)) (*AuthorizeResponse, error) {
43+
func (c *client) Authorize(ctx context.Context, callback func(error)) (*AuthorizeResponse, error) {
5144
verifier := generateVerifier()
5245
mux := http.NewServeMux()
5346
server := &http.Server{
5447
Handler: mux,
5548
}
5649
callbackURL := ""
5750
mux.HandleFunc("/callback", func(w http.ResponseWriter, req *http.Request) {
58-
req.ParseForm()
59-
token, err := c.exchange(req.Form, verifier, callbackURL)
51+
err := req.ParseForm()
52+
if err != nil {
53+
http.Error(w, "Bad Request", http.StatusBadRequest)
54+
callback(&AuthorizeError{ErrorType: "failed to parse form", Description: err.Error()})
55+
return
56+
}
57+
token, err := c.exchange(ctx, req.Form, verifier, callbackURL)
6058
if err != nil {
6159
http.Redirect(w, req, c.dashboardURL+"/authorize/error", http.StatusFound)
6260
} else {
6361
http.Redirect(w, req, c.dashboardURL+"/authorize/success", http.StatusFound)
6462
}
6563
go func() {
66-
server.Shutdown(req.Context())
64+
server.Shutdown(context.Background())
6765
if err == nil {
6866
c.updateToken(token)
6967
}
@@ -105,9 +103,9 @@ func (c *client) Authorize(callback func(error)) (*AuthorizeResponse, error) {
105103
}, nil
106104
}
107105

108-
func (c *client) TokenIntrospection(token string) (*IntrospectionResponse, error) {
106+
func (c *client) TokenIntrospection(ctx context.Context, token string) (*IntrospectionResponse, error) {
109107
if token == "" {
110-
t, err := c.getToken()
108+
t, err := c.getToken(ctx)
111109
if err != nil {
112110
return nil, &AuthorizeError{
113111
ErrorType: ErrTypeNotAuthorized,
@@ -124,25 +122,25 @@ func (c *client) TokenIntrospection(token string) (*IntrospectionResponse, error
124122
Description: "client is not authorized",
125123
}
126124
}
127-
return c.introspection(token)
125+
return c.introspection(ctx, token)
128126
}
129127

130-
func (c *client) Logout() error {
128+
func (c *client) Logout(ctx context.Context) error {
131129
c.mu.RLock()
132130
t := c.token
133131
c.mu.RUnlock()
134132
if t == nil {
135133
return nil
136134
}
137-
err := c.RevokeToken(t.RefreshToken)
135+
err := c.RevokeToken(ctx, t.RefreshToken)
138136
if err != nil {
139137
return err
140138
}
141139
c.updateToken(nil)
142140
return nil
143141
}
144142

145-
func (c *client) exchange(form url.Values, verifier string, redirect string) (*Token, error) {
143+
func (c *client) exchange(ctx context.Context, form url.Values, verifier string, redirect string) (*storage.Token, error) {
146144
if form.Get("error") != "" {
147145
return nil, &AuthorizeError{
148146
ErrorType: form.Get("error"),
@@ -163,7 +161,7 @@ func (c *client) exchange(form url.Values, verifier string, redirect string) (*T
163161
q.Set("code_verifier", verifier)
164162
q.Set("grant_type", "authorization_code")
165163
q.Set("redirect_uri", redirect)
166-
req, err := http.NewRequest("POST", c.authURL+"/oauth/token", strings.NewReader(q.Encode()))
164+
req, err := http.NewRequestWithContext(ctx, "POST", c.authURL+"/oauth/token", strings.NewReader(q.Encode()))
167165
if err != nil {
168166
return nil, &AuthorizeError{
169167
ErrorType: ErrTypeExchangeFailed,
@@ -188,7 +186,7 @@ func (c *client) exchange(form url.Values, verifier string, redirect string) (*T
188186
json.NewDecoder(resp.Body).Decode(err)
189187
return nil, err
190188
}
191-
t := &Token{}
189+
t := &storage.Token{}
192190
err = json.NewDecoder(resp.Body).Decode(t)
193191
if err != nil {
194192
return nil, &AuthorizeError{
@@ -200,18 +198,18 @@ func (c *client) exchange(form url.Values, verifier string, redirect string) (*T
200198
t.TokenType = "Bearer"
201199
}
202200
if t.ExpiresIn != 0 {
203-
t.Expiry = timeNow().Add(time.Duration(t.ExpiresIn) * time.Second)
201+
t.Expiry = c.utils.Now().Add(time.Duration(t.ExpiresIn) * time.Second)
204202
}
205203
return t, nil
206204
}
207205

208-
func (c *client) getToken() (*Token, error) {
209-
c.mu.RLock()
210-
defer c.mu.RUnlock()
206+
func (c *client) getToken(ctx context.Context) (*storage.Token, error) {
207+
c.mu.Lock()
208+
defer c.mu.Unlock()
211209
if c.token == nil {
212210
return nil, nil
213211
}
214-
if !c.token.Expiry.Before(timeNow()) {
212+
if !c.token.Expiry.Before(c.utils.Now()) {
215213
return c.token, nil
216214
}
217215
if c.token.RefreshToken == "" {
@@ -220,47 +218,47 @@ func (c *client) getToken() (*Token, error) {
220218
Description: "empty refresh token",
221219
}
222220
}
223-
t, err := c.refreshToken(c.token.RefreshToken)
221+
t, err := c.refreshToken(ctx, c.token.RefreshToken)
224222
if err != nil {
225223
e, ok := err.(*AuthorizeError)
226-
if ok && e.ErrorType == ErrTypeInvalidGrant && c.onTokenRefresh != nil {
227-
c.onTokenRefresh(nil)
224+
if ok && e.ErrorType == ErrTypeInvalidGrant {
225+
c.saveToken(nil)
228226
}
229227
return nil, err
230228
}
229+
231230
c.token = t
232-
if c.onTokenRefresh != nil {
233-
c.onTokenRefresh(&Token{
234-
AccessToken: t.AccessToken,
235-
TokenType: t.TokenType,
236-
RefreshToken: t.RefreshToken,
237-
ExpiresIn: t.ExpiresIn,
238-
Expiry: t.Expiry,
239-
})
240-
}
231+
c.saveToken(&storage.Token{
232+
AccessToken: t.AccessToken,
233+
TokenType: t.TokenType,
234+
RefreshToken: t.RefreshToken,
235+
ExpiresIn: t.ExpiresIn,
236+
Expiry: t.Expiry,
237+
})
238+
241239
return t, nil
242240
}
243241

244-
func (c *client) updateToken(t *Token) {
242+
func (c *client) updateToken(t *storage.Token) {
245243
c.mu.Lock()
246244
defer c.mu.Unlock()
245+
247246
c.token = t
248-
if c.onTokenRefresh != nil {
249-
if t == nil {
250-
c.onTokenRefresh(nil)
251-
} else {
252-
c.onTokenRefresh(&Token{
253-
AccessToken: t.AccessToken,
254-
TokenType: t.TokenType,
255-
RefreshToken: t.RefreshToken,
256-
ExpiresIn: t.ExpiresIn,
257-
Expiry: t.Expiry,
258-
})
259-
}
247+
if t == nil {
248+
c.saveToken(nil)
249+
return
260250
}
251+
252+
c.saveToken(&storage.Token{
253+
AccessToken: t.AccessToken,
254+
TokenType: t.TokenType,
255+
RefreshToken: t.RefreshToken,
256+
ExpiresIn: t.ExpiresIn,
257+
Expiry: t.Expiry,
258+
})
261259
}
262260

263-
func (c *client) tryToRefreshToken(refreshToken string) bool {
261+
func (c *client) tryToRefreshToken(ctx context.Context, refreshToken string) bool {
264262
c.mu.Lock()
265263
defer c.mu.Unlock()
266264
if c.token == nil {
@@ -270,38 +268,37 @@ func (c *client) tryToRefreshToken(refreshToken string) bool {
270268
if c.token.RefreshToken != refreshToken {
271269
return false
272270
}
273-
token, err := c.refreshToken(c.token.RefreshToken)
271+
272+
token, err := c.refreshToken(ctx, c.token.RefreshToken)
274273
if err != nil {
275274
e, ok := err.(*AuthorizeError)
276275
// If the refresh token is invalid, clear the token
277-
if ok && e.ErrorType == ErrTypeInvalidGrant && c.onTokenRefresh != nil {
276+
if ok && e.ErrorType == ErrTypeInvalidGrant {
278277
c.token = nil
279-
if c.onTokenRefresh != nil {
280-
c.onTokenRefresh(nil)
281-
}
278+
c.saveToken(nil)
282279
}
283280
return false
284281
}
282+
285283
c.token = token
286-
if c.onTokenRefresh != nil {
287-
c.onTokenRefresh(&Token{
288-
AccessToken: token.AccessToken,
289-
TokenType: token.TokenType,
290-
RefreshToken: token.RefreshToken,
291-
ExpiresIn: token.ExpiresIn,
292-
Expiry: token.Expiry,
293-
})
294-
}
284+
c.saveToken(&storage.Token{
285+
AccessToken: token.AccessToken,
286+
TokenType: token.TokenType,
287+
RefreshToken: token.RefreshToken,
288+
ExpiresIn: token.ExpiresIn,
289+
Expiry: token.Expiry,
290+
})
291+
295292
return true
296293
}
297294

298-
func (c *client) refreshToken(token string) (*Token, error) {
295+
func (c *client) refreshToken(ctx context.Context, token string) (*storage.Token, error) {
299296
q := url.Values{}
300297
q.Set("client_id", c.authClientId)
301298
q.Set("client_secret", c.authClientSecret)
302299
q.Set("refresh_token", token)
303300
q.Set("grant_type", "refresh_token")
304-
req, err := http.NewRequest("POST", c.authURL+"/oauth/token", strings.NewReader(q.Encode()))
301+
req, err := http.NewRequestWithContext(ctx, "POST", c.authURL+"/oauth/token", strings.NewReader(q.Encode()))
305302
if err != nil {
306303
return nil, &AuthorizeError{
307304
ErrorType: ErrTypeRefreshFailed,
@@ -326,7 +323,7 @@ func (c *client) refreshToken(token string) (*Token, error) {
326323
json.NewDecoder(resp.Body).Decode(err)
327324
return nil, err
328325
}
329-
t := &Token{}
326+
t := &storage.Token{}
330327
err = json.NewDecoder(resp.Body).Decode(t)
331328
if err != nil {
332329
return nil, &AuthorizeError{
@@ -338,11 +335,19 @@ func (c *client) refreshToken(token string) (*Token, error) {
338335
t.TokenType = "Bearer"
339336
}
340337
if t.ExpiresIn != 0 {
341-
t.Expiry = timeNow().Add(time.Duration(t.ExpiresIn) * time.Second)
338+
t.Expiry = c.utils.Now().Add(time.Duration(t.ExpiresIn) * time.Second)
342339
}
343340
return t, nil
344341
}
345342

343+
func (c *client) saveToken(token *storage.Token) {
344+
c.storage.GetProfile().Token = token
345+
err := c.storage.SaveConfig()
346+
if err != nil {
347+
c.printer.ErrPrintf("Error: Token was refreshed but failed to save to storage: %v\n", err)
348+
}
349+
}
350+
346351
// https://datatracker.ietf.org/doc/html/rfc7662#section-2.1
347352
type IntrospectionResponse struct {
348353
// Required fields
@@ -362,9 +367,9 @@ type IntrospectionResponse struct {
362367
Jti string `json:"jti"` // JWT ID
363368
}
364369

365-
func (c *client) introspection(token string) (*IntrospectionResponse, error) {
370+
func (c *client) introspection(ctx context.Context, token string) (*IntrospectionResponse, error) {
366371
form := url.Values{"token": {token}}.Encode()
367-
req, err := http.NewRequest("POST", c.authURL+"/oauth/token/introspect", strings.NewReader(form))
372+
req, err := http.NewRequestWithContext(ctx, "POST", c.authURL+"/oauth/token/introspect", strings.NewReader(form))
368373
if err != nil {
369374
return nil, &AuthorizeError{
370375
ErrorType: ErrTypeIntrospectionFailed,
@@ -400,12 +405,12 @@ func (c *client) introspection(token string) (*IntrospectionResponse, error) {
400405
return ires, nil
401406
}
402407

403-
func (c *client) RevokeToken(token string) error {
408+
func (c *client) RevokeToken(ctx context.Context, token string) error {
404409
if token == "" {
405410
return nil
406411
}
407412
form := url.Values{"token": {token}}.Encode()
408-
req, err := http.NewRequest("POST", c.authURL+"/oauth/token/revoke", strings.NewReader(form))
413+
req, err := http.NewRequestWithContext(ctx, "POST", c.authURL+"/oauth/token/revoke", strings.NewReader(form))
409414
if err != nil {
410415
return &AuthorizeError{
411416
ErrorType: ErrTypeRevokeFailed,

0 commit comments

Comments
 (0)