0 package gmi
1
2 import (
3 "gemigit/auth"
4 "gemigit/config"
5 "gemigit/db"
6 "gemigit/csrf"
7
8 "github.com/pitr/gig"
9 "github.com/pquerna/otp/totp"
10
11 "log"
12 "bytes"
13 "image/png"
14 )
15
16 var keys = make(map[string]string)
17
18 func otpRedirect(c gig.Context) error {
19 return c.NoContent(gig.StatusRedirectTemporary,
20 "/account/" + csrf.Token(c.CertHash() + "/otp"))
21 }
22
23 func CreateTOTP(c gig.Context) error {
24
25 user, exist := db.GetUser(c.CertHash())
26 if !exist {
27 return c.NoContent(gig.StatusBadRequest, "Invalid username")
28 }
29
30 key, err := totp.Generate(totp.GenerateOpts{
31 Issuer: config.Cfg.Title,
32 AccountName: user.Name,
33 })
34
35 if err != nil {
36 log.Println(err)
37 return c.NoContent(gig.StatusBadRequest, "Unexpected error")
38 }
39
40 var buf bytes.Buffer
41 img, err_ := key.Image(200, 200)
42 if err_ != nil {
43 log.Println(err)
44 return c.NoContent(gig.StatusBadRequest, "Unexpected error")
45 }
46 png.Encode(&buf, img)
47
48 keys[c.CertHash()] = key.Secret()
49
50 return c.Blob("image/png", buf.Bytes())
51 }
52
53 func ConfirmTOTP(c gig.Context) error {
54
55 user, exist := db.GetUser(c.CertHash())
56 if !exist {
57 return c.NoContent(gig.StatusBadRequest, "Invalid username")
58 }
59
60 query, err := c.QueryString()
61 if err != nil {
62 log.Println(err)
63 return c.NoContent(gig.StatusBadRequest, "Unexpected error")
64 }
65 if query == "" {
66 return c.NoContent(gig.StatusInput, "Code")
67 }
68
69 key, exist := keys[c.CertHash()]
70
71 valid := false
72 if exist {
73 valid = totp.Validate(query, key)
74 }
75 if !valid {
76 return c.NoContent(gig.StatusBadRequest, "Invalid code")
77 }
78
79 err = user.SetSecret(key)
80 if err != nil {
81 log.Println(err)
82 return c.NoContent(gig.StatusBadRequest, "Unexpected error")
83 }
84
85 return otpRedirect(c)
86 }
87
88 func LoginOTP(c gig.Context) error {
89
90 query, err := c.QueryString()
91 if err != nil {
92 log.Println(err)
93 return c.NoContent(gig.StatusBadRequest, "Unexpected error")
94 }
95 if query == "" {
96 return c.NoContent(gig.StatusInput, "Code")
97 }
98
99 err = auth.LoginOTP(c.CertHash(), query)
100 if err != nil && err.Error() == "wrong code" {
101 return c.NoContent(gig.StatusInput, "Code")
102 }
103 if err != nil {
104 return c.NoContent(gig.StatusBadRequest, err.Error())
105 }
106
107 return otpRedirect(c)
108 }
109
110 func RemoveTOTP(c gig.Context) error {
111
112 user, exist := db.GetUser(c.CertHash())
113 if !exist {
114 return c.NoContent(gig.StatusBadRequest, "Invalid username")
115 }
116
117 query, err := c.QueryString()
118 if err != nil {
119 log.Println(err)
120 return c.NoContent(gig.StatusBadRequest, "Unexpected error")
121 }
122 if query == "" {
123 return c.NoContent(gig.StatusInput, "Code")
124 }
125
126 valid := totp.Validate(query, user.Secret)
127 if !valid {
128 return c.NoContent(gig.StatusInput, "Code")
129 }
130
131 err = user.SetSecret("")
132 if err != nil {
133 log.Println(err)
134 return c.NoContent(gig.StatusBadRequest, "Unexpected error")
135 }
136
137 return otpRedirect(c)
138 }
139
140 func ShowOTP(c gig.Context) error {
141 user, exist := db.GetUser(c.CertHash())
142 if !exist {
143 return c.NoContent(gig.StatusBadRequest, "Invalid username")
144 }
145 data := struct {
146 Secret bool
147 }{
148 Secret: user.Secret != "",
149 }
150 return execT(c, "otp.gmi", data)
151 }
152