-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathfastotp.go
173 lines (142 loc) · 4.37 KB
/
fastotp.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package fastotp
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
httpclient "github.com/CeoFred/fast-otp/lib"
)
const (
baseURL = "https://api.fastotp.co"
)
// FastOTP is the main struct for the FastOtp package.
type FastOTP struct {
apiKey string
baseURL string
client HttpClient
}
// ErrorResponse is the error struct for the FastOtp package.
type ErrorResponse struct {
Errors map[string][]string `json:"errors"`
Message string `json:"message"`
}
// OTP is the struct for the OTP object.
type OTP struct {
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
UpdatedAt time.Time `json:"updated_at"`
DeliveryDetails DeliveryDetails `json:"delivery_details"`
ID string `json:"id"`
Identifier string `json:"identifier"`
Status OTPStatus `json:"status"`
Type OTPType `json:"type"`
DeliveryMethods []string `json:"delivery_methods"`
}
// OTPResponse is the struct for the OTP response object.
type OTPResponse struct {
OTP OTP `json:"otp"`
}
// DeliveryDetails is the struct for the DeliveryDetails object.
type DeliveryDetails struct {
Email string `json:"email"`
}
// OTPDelivery is the struct for the OtpDelivery object.
type OTPDelivery map[string]string
// GenerateOTPPayload is the struct for the GenerateOTPPayload object.
type GenerateOTPPayload struct {
Delivery OTPDelivery `json:"delivery"`
Identifier string `json:"identifier"`
Type OTPType `json:"type"`
TokenLength int `json:"token_length"`
Validity int `json:"validity"`
}
// ValidateOTPPayload is the struct for the ValidateOTPPayload object.
type ValidateOTPPayload struct {
Identifier string `json:"identifier"`
Token string `json:"token"`
}
// NewFastOTP creates a new FastOtp instance.
func NewFastOTP(apiKey string) *FastOTP {
return &FastOTP{
apiKey: apiKey,
baseURL: baseURL,
client: httpclient.NewAPIClient(baseURL, apiKey),
}
}
func (f *FastOTP) GenerateOTP(ctx context.Context, payload GenerateOTPPayload) (*OTP, error) {
resp, err := f.client.Post(ctx, "/generate", payload)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var errorResponse ErrorResponse
if err := json.NewDecoder(resp.Body).Decode(&errorResponse); err != nil {
return nil, err
}
if len(errorResponse.Errors) > 0 {
return nil, formatValidationError(errorResponse.Errors)
}
return nil, fmt.Errorf("API error: %s", errorResponse.Message)
}
var otpResponse OTPResponse
if err := json.NewDecoder(resp.Body).Decode(&otpResponse); err != nil {
return nil, err
}
return &otpResponse.OTP, nil
}
func (f *FastOTP) ValidateOTP(ctx context.Context, payload ValidateOTPPayload) (*OTP, error) {
resp, err := f.client.Post(ctx, "/validate", payload)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var errorResponse ErrorResponse
if err := json.NewDecoder(resp.Body).Decode(&errorResponse); err != nil {
return nil, err
}
if len(errorResponse.Errors) > 0 {
return nil, formatValidationError(errorResponse.Errors)
}
return nil, fmt.Errorf("API error: %s", errorResponse.Message)
}
var otpResponse OTPResponse
if err := json.NewDecoder(resp.Body).Decode(&otpResponse); err != nil {
return nil, err
}
return &otpResponse.OTP, nil
}
// GetOtp gets a new otp
func (f *FastOTP) GetOtp(ctx context.Context, id string) (*OTP, error) {
resp, err := f.client.Get(ctx, id)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var errorResponse ErrorResponse
if err := json.NewDecoder(resp.Body).Decode(&errorResponse); err != nil {
return nil, err
}
if len(errorResponse.Errors) > 0 {
return nil, formatValidationError(errorResponse.Errors)
}
return nil, fmt.Errorf("API error: %s", errorResponse.Message)
}
var otpResponse OTPResponse
if err := json.NewDecoder(resp.Body).Decode(&otpResponse); err != nil {
return nil, err
}
return &otpResponse.OTP, nil
}
func formatValidationError(errors map[string][]string) error {
var errorMessage string
for field, fieldErrors := range errors {
for _, err := range fieldErrors {
errorMessage += fmt.Sprintf("%s: %s\n", field, err)
}
}
return fmt.Errorf("validation errors:\n%s", errorMessage)
}