+56
-9
server/handle_account_signin.go
+56
-9
server/handle_account_signin.go
···
2
3
import (
4
"errors"
5
"strings"
6
7
"github.com/bluesky-social/indigo/atproto/syntax"
8
"github.com/gorilla/sessions"
···
15
)
16
17
type OauthSigninInput struct {
18
-
Username string `form:"username"`
19
-
Password string `form:"password"`
20
-
QueryParams string `form:"query_params"`
21
}
22
23
func (s *Server) getSessionRepoOrErr(e echo.Context) (*models.RepoActor, *sessions.Session, error) {
···
44
func getFlashesFromSession(e echo.Context, sess *sessions.Session) map[string]any {
45
defer sess.Save(e.Request(), e.Response())
46
return map[string]any{
47
-
"errors": sess.Flashes("error"),
48
-
"successes": sess.Flashes("success"),
49
}
50
}
51
···
83
idtype = "email"
84
}
85
86
// TODO: we should make this a helper since we do it for the base create_session as well
87
var repo models.RepoActor
88
var err error
···
101
sess.AddFlash("Something went wrong!", "error")
102
}
103
sess.Save(e.Request(), e.Response())
104
-
return e.Redirect(303, "/account/signin")
105
}
106
107
if err := bcrypt.CompareHashAndPassword([]byte(repo.Password), []byte(req.Password)); err != nil {
···
111
sess.AddFlash("Something went wrong!", "error")
112
}
113
sess.Save(e.Request(), e.Response())
114
-
return e.Redirect(303, "/account/signin")
115
}
116
117
sess.Options = &sessions.Options{
···
127
return err
128
}
129
130
-
if req.QueryParams != "" {
131
-
return e.Redirect(303, "/oauth/authorize?"+req.QueryParams)
132
} else {
133
return e.Redirect(303, "/account")
134
}
···
2
3
import (
4
"errors"
5
+
"fmt"
6
"strings"
7
+
"time"
8
9
"github.com/bluesky-social/indigo/atproto/syntax"
10
"github.com/gorilla/sessions"
···
17
)
18
19
type OauthSigninInput struct {
20
+
Username string `form:"username"`
21
+
Password string `form:"password"`
22
+
AuthFactorToken string `form:"token"`
23
+
QueryParams string `form:"query_params"`
24
}
25
26
func (s *Server) getSessionRepoOrErr(e echo.Context) (*models.RepoActor, *sessions.Session, error) {
···
47
func getFlashesFromSession(e echo.Context, sess *sessions.Session) map[string]any {
48
defer sess.Save(e.Request(), e.Response())
49
return map[string]any{
50
+
"errors": sess.Flashes("error"),
51
+
"successes": sess.Flashes("success"),
52
+
"tokenrequired": sess.Flashes("tokenrequired"),
53
}
54
}
55
···
87
idtype = "email"
88
}
89
90
+
queryParams := ""
91
+
if req.QueryParams != "" {
92
+
queryParams = fmt.Sprintf("?%s", req.QueryParams)
93
+
}
94
+
95
// TODO: we should make this a helper since we do it for the base create_session as well
96
var repo models.RepoActor
97
var err error
···
110
sess.AddFlash("Something went wrong!", "error")
111
}
112
sess.Save(e.Request(), e.Response())
113
+
return e.Redirect(303, "/account/signin"+queryParams)
114
}
115
116
if err := bcrypt.CompareHashAndPassword([]byte(repo.Password), []byte(req.Password)); err != nil {
···
120
sess.AddFlash("Something went wrong!", "error")
121
}
122
sess.Save(e.Request(), e.Response())
123
+
return e.Redirect(303, "/account/signin"+queryParams)
124
+
}
125
+
126
+
// if repo requires auth factor token and one hasn't been provided, return error prompting for one
127
+
if repo.EmailAuthFactor && req.AuthFactorToken == "" {
128
+
err = s.createAndSendAuthCode(ctx, repo)
129
+
if err != nil {
130
+
sess.AddFlash("Something went wrong!", "error")
131
+
sess.Save(e.Request(), e.Response())
132
+
return e.Redirect(303, "/account/signin"+queryParams)
133
+
}
134
+
135
+
sess.AddFlash("requires 2FA token", "tokenrequired")
136
+
sess.Save(e.Request(), e.Response())
137
+
return e.Redirect(303, "/account/signin"+queryParams)
138
+
}
139
+
140
+
// if auth factor is required, now check that the one provided is valid
141
+
if repo.EmailAuthFactor {
142
+
if repo.AuthCode == nil || repo.AuthCodeExpiresAt == nil {
143
+
err = s.createAndSendAuthCode(ctx, repo)
144
+
if err != nil {
145
+
sess.AddFlash("Something went wrong!", "error")
146
+
sess.Save(e.Request(), e.Response())
147
+
return e.Redirect(303, "/account/signin"+queryParams)
148
+
}
149
+
150
+
sess.AddFlash("requires 2FA token", "tokenrequired")
151
+
sess.Save(e.Request(), e.Response())
152
+
return e.Redirect(303, "/account/signin"+queryParams)
153
+
}
154
+
155
+
if *repo.AuthCode != req.AuthFactorToken {
156
+
return helpers.InvalidTokenError(e)
157
+
}
158
+
159
+
if time.Now().UTC().After(*repo.AuthCodeExpiresAt) {
160
+
return helpers.ExpiredTokenError(e)
161
+
}
162
}
163
164
sess.Options = &sessions.Options{
···
174
return err
175
}
176
177
+
if queryParams != "" {
178
+
return e.Redirect(303, "/oauth/authorize"+queryParams)
179
} else {
180
return e.Redirect(303, "/account")
181
}
+8
-8
server/handle_server_create_session.go
+8
-8
server/handle_server_create_session.go
···
87
return helpers.ServerError(e, nil)
88
}
89
90
// if repo requires auth factor token and one hasn't been provided, return error prompting for one
91
if repo.EmailAuthFactor && (req.AuthFactorToken == nil || *req.AuthFactorToken == "") {
92
err = s.createAndSendAuthCode(ctx, repo)
···
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
···
117
if time.Now().UTC().After(*repo.AuthCodeExpiresAt) {
118
return helpers.ExpiredTokenError(e)
119
}
120
-
}
121
-
122
-
if err := bcrypt.CompareHashAndPassword([]byte(repo.Password), []byte(req.Password)); err != nil {
123
-
if err != bcrypt.ErrMismatchedHashAndPassword {
124
-
logger.Error("erorr comparing hash and password", "error", err)
125
-
}
126
-
return helpers.InputError(e, to.StringPtr("InvalidRequest"))
127
}
128
129
sess, err := s.createSession(ctx, &repo.Repo)
···
87
return helpers.ServerError(e, nil)
88
}
89
90
+
if err := bcrypt.CompareHashAndPassword([]byte(repo.Password), []byte(req.Password)); err != nil {
91
+
if err != bcrypt.ErrMismatchedHashAndPassword {
92
+
logger.Error("erorr comparing hash and password", "error", err)
93
+
}
94
+
return helpers.InputError(e, to.StringPtr("InvalidRequest"))
95
+
}
96
+
97
// if repo requires auth factor token and one hasn't been provided, return error prompting for one
98
if repo.EmailAuthFactor && (req.AuthFactorToken == nil || *req.AuthFactorToken == "") {
99
err = s.createAndSendAuthCode(ctx, repo)
···
110
if repo.AuthCode == nil || repo.AuthCodeExpiresAt == nil {
111
err = s.createAndSendAuthCode(ctx, repo)
112
if err != nil {
113
+
logger.Error("sending auth code", "error", err)
114
return helpers.ServerError(e, nil)
115
}
116
···
124
if time.Now().UTC().After(*repo.AuthCodeExpiresAt) {
125
return helpers.ExpiredTokenError(e)
126
}
127
}
128
129
sess, err := s.createSession(ctx, &repo.Repo)
+4
server/templates/signin.html
+4
server/templates/signin.html
···
26
type="password"
27
placeholder="Password"
28
/>
29
+
{{ if .flashes.tokenrequired }}
30
+
<br />
31
+
<input name="token" id="token" placeholder="Enter your 2FA token" />
32
+
{{ end }}
33
<input name="query_params" type="hidden" value="{{ .QueryParams }}" />
34
<button class="primary" type="submit" value="Login">Login</button>
35
</form>