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
|
package api
import (
"bytes"
"fmt"
"image/png"
"github.com/gin-gonic/gin"
"github.com/pquerna/otp/totp"
"immae.eu/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Front/db"
)
func GenerateSecret(user db.User) (bytes.Buffer, string, error) {
var buf bytes.Buffer
key, err := totp.Generate(totp.GenerateOpts{
Issuer: "cryptoportfolio",
AccountName: user.Email,
Period: 30,
})
if err != nil {
return buf, "", err
}
qrImage, err := key.Image(200, 200)
if err != nil {
return buf, "", err
}
png.Encode(&buf, qrImage)
if err != nil {
return buf, "", err
}
return buf, key.Secret(), nil
}
type OtpEnrollmentQuery struct {
In struct {
User db.User
}
}
func (q OtpEnrollmentQuery) ValidateParams() *Error {
return nil
}
func (q OtpEnrollmentQuery) Run() (*bytes.Buffer, string, *Error) {
if q.In.User.OtpSecret != "" && q.In.User.IsOtpSetup == true {
return nil, "", &Error{OtpAlreadySetup, "otp is already setup", fmt.Errorf("otp already setup")}
}
buf, secret, err := GenerateSecret(q.In.User)
if err != nil {
return nil, "", NewInternalError(err)
}
err = db.SetOtpSecret(&q.In.User, secret, true)
if err != nil {
return nil, "", NewInternalError(err)
}
return &buf, secret, nil
}
type OtpValidateQuery struct {
In struct {
Pass string
User db.User
Claims JwtClaims
}
Out struct {
Token string `json:"token"`
}
}
func (q OtpValidateQuery) ValidateParams() *Error {
if q.In.Pass == "" {
return &Error{InvalidOtp, "invalid otp", fmt.Errorf("invalid otp '%v'", q.In.Pass)}
}
return nil
}
func (q OtpValidateQuery) Run() (interface{}, *Error) {
var err error
if q.In.User.OtpSecret == "" {
return nil, &Error{OtpNotSetup, "otp is not setup", fmt.Errorf("otp is not setup")}
}
if !totp.Validate(q.In.Pass, q.In.User.OtpSecret) {
return nil, &Error{InvalidOtp, "invalid otp", fmt.Errorf("invalid otp '%v'", q.In.Pass)}
} else if err := db.SetOtpSecret(&q.In.User, q.In.User.OtpSecret, false); err != nil {
return nil, NewInternalError(err)
}
q.In.Claims.Authorized = true
q.Out.Token, err = SignJwt(q.In.Claims)
if err != nil {
return nil, NewInternalError(err)
}
return q.Out, nil
}
func OtpAuth(c *gin.Context) *Error {
claims := GetClaims(c)
user := GetUser(c)
if user.IsOtpSetup == false || user.OtpSecret == "" {
return &Error{OtpNotSetup, "otp is not setup", fmt.Errorf("otp is not setup")}
}
if !claims.Authorized {
return &Error{NeedOtpValidation, "not authorized", fmt.Errorf("otp not authorized")}
}
return nil
}
|