-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauth.go
101 lines (85 loc) · 2.82 KB
/
auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package rd
import (
"encoding/json"
"fmt"
"time"
)
const (
authBaseUrl = "https://api.real-debrid.com/oauth/v2"
deviceUrl = authBaseUrl + "/device/code"
credentialsUrl = authBaseUrl + "/device/credentials"
tokenUrl = authBaseUrl + "/token"
defaultClientID = "X245A4XAIBGVM"
)
type (
AuthClient struct {
HTTPDoer
}
Verification struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
Interval int `json:"interval"`
ExpiresIn int `json:"expires_in"`
VerificationURL string `json:"verification_url"`
DirectVerificationURL string `json:"direct_verification_url"`
}
Secrets struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
}
)
func NewAuthClient(doer HTTPDoer) *AuthClient {
return &AuthClient{doer}
}
// StartAuthentication starts the authentication flow for the service
// RealDebrid API information: https://api.real-debrid.com/#device_auth_no_secret
func (c *AuthClient) StartAuthentication(clientID string) (v Verification, err error) {
resp, err := httpGet(c, deviceUrl, map[string]string{"client_id": clientID, "new_credentials": "yes"})
if err != nil {
return v, err
}
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&v)
return v, err
}
// ObtainSecret returns the HTTPClient ID and HTTPClient secret that are used for
// obtaining a valid token in the next step
func (c *AuthClient) ObtainSecret(deviceCode, clientID string) (secrets Secrets, err error) {
resp, err := httpGet(c, credentialsUrl, map[string]string{"client_id": clientID, "code": deviceCode})
if err != nil {
return secrets, err
}
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&secrets)
if secrets.ClientID == "" || secrets.ClientSecret == "" {
return secrets, fmt.Errorf("secrets not authorized")
}
return secrets, err
}
// ObtainAccessToken tries to get a new token from the service
func (c *AuthClient) ObtainAccessToken(clientID, secret, code string) (t Token, err error) {
resp, err := httpPostForm(c, tokenUrl, map[string]string{
"client_id": clientID,
"client_secret": secret,
"code": code,
"grant_type": "http://oauth.net/grant_type/device/1.0",
})
if err != nil {
return t, err
}
t.ObtainedAt = time.Now()
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&t)
return t, err
}
// RefreshAccessToken tries to refresh the given token and get a new one
func (c *AuthClient) RefreshAccessToken(token Token) (t Token, err error) {
if token.RefreshToken == "" {
return t, fmt.Errorf("cannot reauthorize without refresh token")
}
secrets, err := c.ObtainSecret(token.RefreshToken, defaultClientID)
if err != nil {
return t, err
}
return c.ObtainAccessToken(secrets.ClientID, secrets.ClientSecret, token.RefreshToken)
}