-
Notifications
You must be signed in to change notification settings - Fork 0
/
oauth.go
151 lines (128 loc) · 4.18 KB
/
oauth.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package gaudius
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"strconv"
"github.com/alecsavvy/gaudius/gen/discovery/models"
"github.com/golang-jwt/jwt"
"golang.org/x/crypto/sha3"
)
type OauthConfiguration struct {
Scope string
ApiKey string
RedirectURI string
AppOrigin string
State string
ResponseMode string
}
func (sdk *AudiusSdk) ConfigureOauth(config *OauthConfiguration) {
sdk.Oauth = config
}
func (sdk *AudiusSdk) OauthUrl() (string, error) {
config := sdk.Oauth
if config.Scope == "" {
config.Scope = "read"
}
scope := fmt.Sprintf("scope=%s", config.Scope)
if config.ApiKey == "" {
return "", errors.New("ApiKey is a required field for oauth configuration")
}
apiKey := fmt.Sprintf("api_key=%s", config.ApiKey)
if config.RedirectURI == "" {
return "", errors.New("RedirectURI is a required field for oauth configuration")
}
redirectUri := fmt.Sprintf("redirect_uri=%s", config.RedirectURI)
if config.ResponseMode == "" {
// default to query since servers can't read fragment fields
config.ResponseMode = "query"
}
responseMode := fmt.Sprintf("response_mode=%s", config.ResponseMode)
return fmt.Sprintf("https://audius.co/oauth/auth?%s&%s&%s&%s", scope, apiKey, redirectUri, responseMode), nil
}
// this is because the swagger spec has a string for a number iat and fails to serialize
// also, claims aren't marshallable
func ClaimsToDecodedUserToken(claims jwt.Claims) (*models.DecodedUserToken, error) {
claimsMap, ok := claims.(jwt.MapClaims)
if !ok {
return nil, errors.New("could not convert claims to map claims")
}
decodedToken := &models.DecodedUserToken{}
// Extract and assert the type of each field from claimsMap
if email, ok := claimsMap["email"].(string); ok {
decodedToken.Email = &email
}
if handle, ok := claimsMap["handle"].(string); ok {
decodedToken.Handle = &handle
}
if iat, ok := claimsMap["iat"].(float64); ok {
iatStr := strconv.FormatFloat(iat, 'f', 0, 64)
decodedToken.Iat = &iatStr
}
if name, ok := claimsMap["name"].(string); ok {
decodedToken.Name = &name
}
if profilePicture, ok := claimsMap["profilePicture"].(map[string]interface{}); ok {
profilePictureJSON, err := json.Marshal(profilePicture)
if err != nil {
return nil, errors.New(fmt.Sprintf("Error marshaling profile picture: %v", err))
}
profilePic := &models.ProfilePicture{}
err = json.Unmarshal(profilePictureJSON, profilePic)
if err != nil {
return nil, errors.New(fmt.Sprintf("Error unmarshaling profile picture into struct: %v", err))
}
decodedToken.ProfilePicture = profilePic
}
if sub, ok := claimsMap["sub"].(string); ok {
decodedToken.Sub = &sub
}
if userID, ok := claimsMap["userId"].(string); ok {
decodedToken.UserID = &userID
}
if verified, ok := claimsMap["verified"].(bool); ok {
decodedToken.Verified = &verified
}
return decodedToken, nil
}
type Keccak256SigningMethod struct{}
func (m *Keccak256SigningMethod) Alg() string {
return "keccak256"
}
func (m *Keccak256SigningMethod) Sign(signingString string, key interface{}) (string, error) {
// Convert the key to []byte if it's not already
var keyBytes []byte
switch k := key.(type) {
case []byte:
keyBytes = k
case string:
keyBytes = []byte(k)
default:
return "", jwt.ErrInvalidKeyType
}
// Create a Keccak256 hasher
hasher := sha3.NewLegacyKeccak256()
// Write the signingString to the hasher; this is the data you're signing
_, err := hasher.Write([]byte(signingString))
if err != nil {
return "", err
}
// Sum the hash, appending it to the keyBytes (if your signing logic requires the key in the hash)
signature := hasher.Sum(keyBytes)
// Convert the binary signature to a hex string for easier handling
signatureString := hex.EncodeToString(signature)
return signatureString, nil
}
func (m *Keccak256SigningMethod) Verify(signingString, signature string, key interface{}) error {
// Recreate the signature using the signingString and key, then compare it to the provided signature
newSig, err := m.Sign(signingString, key)
if err != nil {
return err
}
// Check if the new signature matches the provided signature
if hex.EncodeToString([]byte(newSig)) != signature {
return jwt.ErrSignatureInvalid
}
return nil
}