-
Notifications
You must be signed in to change notification settings - Fork 5
/
service.go
145 lines (117 loc) · 4.27 KB
/
service.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
package profile
import (
"crypto/rsa"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"time"
"github.com/getyoti/yoti-go-sdk/v3/cryptoutil"
"github.com/getyoti/yoti-go-sdk/v3/extra"
"github.com/getyoti/yoti-go-sdk/v3/requests"
"github.com/getyoti/yoti-go-sdk/v3/yotierror"
"github.com/getyoti/yoti-go-sdk/v3/yotiprotoattr"
)
func getProfileEndpoint(token, sdkID string) string {
return fmt.Sprintf("/profile/%s?appId=%s", token, sdkID)
}
// GetActivityDetails requests information about a Yoti user using the one time
// use token generated by the Yoti login process. Don't call this directly, use yoti.GetActivityDetails
func GetActivityDetails(httpClient requests.HttpClient, token, clientSdkId, apiUrl string, key *rsa.PrivateKey) (activity ActivityDetails, err error) {
if len(token) < 1 {
return activity, yotierror.InvalidTokenError
}
var decryptedToken string
decryptedToken, err = cryptoutil.DecryptToken(token, key)
if err != nil {
return activity, yotierror.TokenDecryptError
}
headers := requests.AuthKeyHeader(&key.PublicKey)
request, err := requests.SignedRequest{
Key: key,
HTTPMethod: http.MethodGet,
BaseURL: apiUrl,
Endpoint: getProfileEndpoint(decryptedToken, clientSdkId),
Headers: headers,
Body: nil,
}.Request()
if err != nil {
return
}
response, err := requests.Execute(httpClient, request, map[int]string{404: "Profile not found"}, yotierror.DefaultHTTPErrorMessages)
if err != nil {
return activity, err
}
responseBytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return
}
return handleSuccessfulResponse(responseBytes, key)
}
func handleSuccessfulResponse(responseBytes []byte, key *rsa.PrivateKey) (activityDetails ActivityDetails, err error) {
var parsedResponse = profileDO{}
if err = json.Unmarshal(responseBytes, &parsedResponse); err != nil {
return
}
if parsedResponse.Receipt.SharingOutcome != "SUCCESS" {
return activityDetails, handleUnsuccessfulShare(parsedResponse)
}
var userAttributeList, applicationAttributeList *yotiprotoattr.AttributeList
if userAttributeList, err = parseUserProfile(&parsedResponse.Receipt, key); err != nil {
return
}
if applicationAttributeList, err = parseApplicationProfile(&parsedResponse.Receipt, key); err != nil {
return
}
id := parsedResponse.Receipt.RememberMeID
userProfile := newUserProfile(userAttributeList)
applicationProfile := newApplicationProfile(applicationAttributeList)
var extraData *extra.Data
extraData, err = parseExtraData(&parsedResponse.Receipt, key, err)
timestamp, timestampErr := time.Parse(time.RFC3339Nano, parsedResponse.Receipt.Timestamp)
if timestampErr != nil {
err = yotierror.MultiError{This: errors.New("Unable to read timestamp. Error: " + timestampErr.Error()), Next: err}
}
activityDetails = ActivityDetails{
UserProfile: userProfile,
rememberMeID: id,
parentRememberMeID: parsedResponse.Receipt.ParentRememberMeID,
timestamp: timestamp,
receiptID: parsedResponse.Receipt.ReceiptID,
ApplicationProfile: applicationProfile,
extraData: extraData,
}
return activityDetails, err
}
func parseExtraData(receipt *receiptDO, key *rsa.PrivateKey, err error) (*extra.Data, error) {
decryptedExtraData, decryptErr := decryptExtraData(receipt, key)
if decryptErr != nil {
err = yotierror.MultiError{This: errors.New("Unable to decrypt ExtraData from the receipt. Error: " + decryptErr.Error()), Next: err}
}
extraData, parseErr := extra.NewExtraData(decryptedExtraData)
if parseErr != nil {
err = yotierror.MultiError{This: errors.New("Unable to parse ExtraData from the receipt. Error: " + parseErr.Error()), Next: err}
}
return extraData, err
}
func parseIsAgeVerifiedValue(byteValue []byte) (result *bool, err error) {
stringValue := string(byteValue)
var parseResult bool
parseResult, err = strconv.ParseBool(stringValue)
if err != nil {
return nil, err
}
result = &parseResult
return
}
func handleUnsuccessfulShare(parsedResponse profileDO) error {
if parsedResponse.ErrorDetails != nil && parsedResponse.ErrorDetails.ErrorCode != nil {
return yotierror.DetailedSharingFailureError{
Code: parsedResponse.ErrorDetails.ErrorCode,
Description: parsedResponse.ErrorDetails.Description,
}
}
return yotierror.SharingFailureError
}