-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathauth.go
112 lines (103 loc) · 3.26 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
package bot
import (
"context"
"crypto/ed25519"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
func SignAuthenticationTokenWithoutBody(method, uri string, user *SafeUser) (string, error) {
return SignAuthenticationToken(method, uri, "", user)
}
func SignAuthenticationToken(method, uri, body string, su *SafeUser) (string, error) {
return SignAuthenticationTokenWithRequestID(method, uri, body, UuidNewV4().String(), su)
}
func SignAuthenticationTokenWithRequestID(method, uri, body, requestID string, su *SafeUser) (string, error) {
expire := time.Now().UTC().Add(time.Hour * 24 * 30 * 3)
sum := sha256.Sum256([]byte(method + uri + body))
claims := jwt.MapClaims{
"uid": su.UserId,
"sid": su.SessionId,
"iat": time.Now().UTC().Unix(),
"exp": expire.Unix(),
"jti": requestID,
"sig": hex.EncodeToString(sum[:]),
"scp": "FULL",
}
priv, err := hex.DecodeString(su.SessionPrivateKey)
if err != nil {
return "", err
}
// more validate the private key
if len(priv) != 32 {
return "", fmt.Errorf("bad ed25519 private key %s", priv)
}
token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, claims)
return token.SignedString(ed25519.NewKeyFromSeed(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,
}
priv, err := hex.DecodeString(privateKey)
if err != nil {
return "", err
}
token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, claims)
return token.SignedString(ed25519.NewKeyFromSeed(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
}