-
Notifications
You must be signed in to change notification settings - Fork 26
/
auth.go
121 lines (113 loc) · 3.46 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package bot
import (
"context"
"crypto/ed25519"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/pem"
"fmt"
"time"
"github.com/golang-jwt/jwt"
)
func SignAuthenticationTokenWithoutBody(uid, sid, privateKey, method, uri string) (string, error) {
return SignAuthenticationToken(uid, sid, privateKey, method, uri, "")
}
func SignAuthenticationToken(uid, sid, privateKey, method, uri, body string) (string, error) {
expire := time.Now().UTC().Add(time.Hour * 24 * 30 * 3)
sum := sha256.Sum256([]byte(method + uri + body))
claims := jwt.MapClaims{
"uid": uid,
"sid": sid,
"iat": time.Now().UTC().Unix(),
"exp": expire.Unix(),
"jti": UuidNewV4().String(),
"sig": hex.EncodeToString(sum[:]),
"scp": "FULL",
}
priv, err := base64.RawURLEncoding.DecodeString(privateKey)
if err != nil {
block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return "", fmt.Errorf("bad RSA private pem format %s", privateKey)
}
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}
token := jwt.NewWithClaims(jwt.SigningMethodRS512, claims)
return token.SignedString(key)
}
// more validate the private key
if len(priv) != 64 {
return "", fmt.Errorf("bad ed25519 private key %s", priv)
}
token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, claims)
return token.SignedString(ed25519.PrivateKey(priv))
}
func SignOauthAccessToken(appID, authorizationID, privateKey, method, uri, body, scp string, requestID string) (string, error) {
expire := time.Now().UTC().Add(time.Hour * 24 * 30 * 3)
sum := sha256.Sum256([]byte(method + uri + body))
claims := jwt.MapClaims{
"iss": appID,
"aid": authorizationID,
"iat": time.Now().UTC().Unix(),
"exp": expire.Unix(),
"sig": hex.EncodeToString(sum[:]),
"scp": scp,
"jti": requestID,
}
kb, err := base64.RawURLEncoding.DecodeString(privateKey)
if err != nil {
return "", err
}
priv := ed25519.PrivateKey(kb)
token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, claims)
return token.SignedString(priv)
}
// OAuthGetAccessToken get the access token of a user
// ed25519 is optional, only use it when you want to sign OAuth access token locally
func OAuthGetAccessToken(ctx context.Context, clientID, clientSecret string, authorizationCode string, codeVerifier string, ed25519 string) (string, string, string, error) {
params, err := json.Marshal(map[string]string{
"client_id": clientID,
"client_secret": clientSecret,
"code": authorizationCode,
"code_verifier": codeVerifier,
"ed25519": ed25519,
})
if err != nil {
return "", "", "", BadDataError(ctx)
}
body, err := Request(ctx, "POST", "/oauth/token", params, "")
if err != nil {
return "", "", "", ServerError(ctx, err)
}
var resp struct {
Data struct {
Scope string `json:"scope"`
AccessToken string `json:"access_token"`
Ed25519 string `json:"ed25519"`
AuthorizationID string `json:"authorization_id"`
} `json:"data"`
Error Error `json:"error"`
}
err = json.Unmarshal(body, &resp)
if err != nil {
return "", "", "", BadDataError(ctx)
}
if resp.Error.Code > 0 {
if resp.Error.Code == 401 {
return "", "", "", AuthorizationError(ctx)
}
if resp.Error.Code == 403 {
return "", "", "", ForbiddenError(ctx)
}
return "", "", "", ServerError(ctx, resp.Error)
}
if ed25519 == "" {
return resp.Data.AccessToken, resp.Data.Scope, "", nil
}
return resp.Data.Ed25519, resp.Data.Scope, resp.Data.AuthorizationID, nil
}