+2
models/models.go
+2
models/models.go
+29
-14
server/handle_server_create_session.go
+29
-14
server/handle_server_create_session.go
···
1
1
package server
2
2
3
3
import (
4
+
"context"
4
5
"errors"
5
6
"fmt"
6
7
"strings"
···
88
89
89
90
// if repo requires auth factor token and one hasn't been provided, return error prompting for one
90
91
if repo.EmailAuthFactor && (req.AuthFactorToken == nil || *req.AuthFactorToken == "") {
91
-
code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5))
92
-
eat := time.Now().Add(10 * time.Minute).UTC()
93
-
94
-
if err := s.db.Exec(ctx, "UPDATE repos SET email_update_code = ?, email_update_code_expires_at = ? WHERE did = ?", nil, code, eat, repo.Repo.Did).Error; err != nil {
95
-
s.logger.Error("error updating repo", "error", err)
96
-
return helpers.ServerError(e, nil)
97
-
}
98
-
99
-
if err := s.sendEmailUpdate(repo.Email, repo.Handle, code); err != nil {
100
-
s.logger.Error("error sending email", "error", err)
92
+
err = s.createAndSendAuthCode(ctx, repo)
93
+
if err != nil {
94
+
s.logger.Error("sending auth code", "error", err)
101
95
return helpers.ServerError(e, nil)
102
96
}
103
97
···
106
100
107
101
// if auth factor is required, now check that the one provided is valid
108
102
if repo.EmailAuthFactor {
109
-
if repo.EmailUpdateCode == nil || repo.EmailUpdateCodeExpiresAt == nil {
110
-
return helpers.InvalidTokenError(e)
103
+
if repo.AuthCode == nil || repo.AuthCodeExpiresAt == nil {
104
+
err = s.createAndSendAuthCode(ctx, repo)
105
+
if err != nil {
106
+
s.logger.Error("sending auth code", "error", err)
107
+
return helpers.ServerError(e, nil)
108
+
}
109
+
110
+
return helpers.InputError(e, to.StringPtr("AuthFactorTokenRequired"))
111
111
}
112
112
113
-
if *repo.EmailUpdateCode != *req.AuthFactorToken {
113
+
if *repo.AuthCode != *req.AuthFactorToken {
114
114
return helpers.InvalidTokenError(e)
115
115
}
116
116
117
-
if time.Now().UTC().After(*repo.EmailUpdateCodeExpiresAt) {
117
+
if time.Now().UTC().After(*repo.AuthCodeExpiresAt) {
118
118
return helpers.ExpiredTokenError(e)
119
119
}
120
120
}
···
144
144
Status: repo.Status(),
145
145
})
146
146
}
147
+
148
+
func (s *Server) createAndSendAuthCode(ctx context.Context, repo models.RepoActor) error {
149
+
code := fmt.Sprintf("%s-%s", helpers.RandomVarchar(5), helpers.RandomVarchar(5))
150
+
eat := time.Now().Add(10 * time.Minute).UTC()
151
+
152
+
if err := s.db.Exec(ctx, "UPDATE repos SET auth_code = ?, auth_code_expires_at = ? WHERE did = ?", nil, code, eat, repo.Repo.Did).Error; err != nil {
153
+
return fmt.Errorf("updating repo: %w", err)
154
+
}
155
+
156
+
if err := s.sendAuthCode(repo.Email, repo.Handle, code); err != nil {
157
+
return fmt.Errorf("sending email: %w", err)
158
+
}
159
+
160
+
return nil
161
+
}
+19
server/mail.go
+19
server/mail.go
···
96
96
97
97
return nil
98
98
}
99
+
100
+
func (s *Server) sendAuthCode(email, handle, code string) error {
101
+
if s.mail == nil {
102
+
return nil
103
+
}
104
+
105
+
s.mailLk.Lock()
106
+
defer s.mailLk.Unlock()
107
+
108
+
s.mail.To(email)
109
+
s.mail.Subject("2FA code for " + s.config.Hostname)
110
+
s.mail.Plain().Set(fmt.Sprintf("Hello %s. Your 2FA code is %s. This code will expire in ten minutes.", handle, code))
111
+
112
+
if err := s.mail.Send(); err != nil {
113
+
return err
114
+
}
115
+
116
+
return nil
117
+
}