Mercurial > gemma
comparison pkg/controllers/pwreset.go @ 501:c10c76c92797 metamorph-for-all
Use metamorphic database connections for auth.RunAs().
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 24 Aug 2018 15:30:31 +0200 |
parents | b2dc9c2f69e0 |
children | b96b1b258cfa |
comparison
equal
deleted
inserted
replaced
498:22e1bf563a04 | 501:c10c76c92797 |
---|---|
1 package controllers | 1 package controllers |
2 | 2 |
3 import ( | 3 import ( |
4 "bytes" | 4 "bytes" |
5 "context" | |
5 "database/sql" | 6 "database/sql" |
6 "encoding/hex" | 7 "encoding/hex" |
7 "log" | 8 "log" |
8 "net/http" | 9 "net/http" |
9 "os/exec" | 10 "os/exec" |
90 } | 91 } |
91 | 92 |
92 func removeOutdated() { | 93 func removeOutdated() { |
93 for { | 94 for { |
94 time.Sleep(cleanupPause) | 95 time.Sleep(cleanupPause) |
95 err := auth.RunAs(pwResetRole, func(db *sql.DB) error { | 96 err := auth.RunAs( |
96 good := time.Now().Add(-passwordResetValid) | 97 pwResetRole, context.Background(), |
97 _, err := db.Exec(cleanupRequestsSQL, good) | 98 func(conn *sql.Conn) error { |
98 return err | 99 good := time.Now().Add(-passwordResetValid) |
99 }) | 100 _, err := conn.ExecContext( |
101 context.Background(), cleanupRequestsSQL, good) | |
102 return err | |
103 }) | |
100 if err != nil { | 104 if err != nil { |
101 log.Printf("error: %v\n", err) | 105 log.Printf("error: %v\n", err) |
102 } | 106 } |
103 } | 107 } |
104 } | 108 } |
175 return | 179 return |
176 } | 180 } |
177 | 181 |
178 var hash, email string | 182 var hash, email string |
179 | 183 |
180 if err = auth.RunAs(pwResetRole, func(db *sql.DB) error { | 184 ctx := req.Context() |
181 | 185 |
182 var count int64 | 186 if err = auth.RunAs( |
183 if err := db.QueryRow(countRequestsSQL).Scan(&count); err != nil { | 187 pwResetRole, ctx, |
188 func(conn *sql.Conn) error { | |
189 | |
190 var count int64 | |
191 if err := conn.QueryRowContext( | |
192 ctx, countRequestsSQL).Scan(&count); err != nil { | |
193 return err | |
194 } | |
195 | |
196 // Limit total number of password requests. | |
197 if count >= maxPasswordResets { | |
198 return JSONError{ | |
199 Code: http.StatusServiceUnavailable, | |
200 Message: "Too much password reset request", | |
201 } | |
202 } | |
203 | |
204 err := conn.QueryRowContext(ctx, userExistsSQL, user.User).Scan(&email) | |
205 | |
206 switch { | |
207 case err == sql.ErrNoRows: | |
208 return JSONError{http.StatusNotFound, "User does not exist."} | |
209 case err != nil: | |
210 return err | |
211 } | |
212 | |
213 if err := conn.QueryRowContext( | |
214 ctx, countRequestsUserSQL, user.User).Scan(&count); err != nil { | |
215 return err | |
216 } | |
217 | |
218 // Limit requests per user | |
219 if count >= maxPasswordRequestsPerUser { | |
220 return JSONError{ | |
221 Code: http.StatusServiceUnavailable, | |
222 Message: "Too much password reset requests for user", | |
223 } | |
224 } | |
225 | |
226 hash = generateHash() | |
227 _, err = conn.ExecContext(ctx, insertRequestSQL, hash, user.User) | |
184 return err | 228 return err |
185 } | 229 }); err == nil { |
186 | |
187 // Limit total number of password requests. | |
188 if count >= maxPasswordResets { | |
189 return JSONError{ | |
190 Code: http.StatusServiceUnavailable, | |
191 Message: "Too much password reset request", | |
192 } | |
193 } | |
194 | |
195 err := db.QueryRow(userExistsSQL, user.User).Scan(&email) | |
196 | |
197 switch { | |
198 case err == sql.ErrNoRows: | |
199 return JSONError{http.StatusNotFound, "User does not exist."} | |
200 case err != nil: | |
201 return err | |
202 } | |
203 | |
204 if err := db.QueryRow(countRequestsUserSQL, user.User).Scan(&count); err != nil { | |
205 return err | |
206 } | |
207 | |
208 // Limit requests per user | |
209 if count >= maxPasswordRequestsPerUser { | |
210 return JSONError{ | |
211 Code: http.StatusServiceUnavailable, | |
212 Message: "Too much password reset requests for user", | |
213 } | |
214 } | |
215 | |
216 hash = generateHash() | |
217 _, err = db.Exec(insertRequestSQL, hash, user.User) | |
218 return err | |
219 }); err == nil { | |
220 body := requestMessageBody(useHTTPS(req), user.User, hash, req.Host) | 230 body := requestMessageBody(useHTTPS(req), user.User, hash, req.Host) |
221 | 231 |
222 if err = misc.SendMail(email, "Password Reset Link", body); err == nil { | 232 if err = misc.SendMail(email, "Password Reset Link", body); err == nil { |
223 jr.Result = &struct { | 233 jr.Result = &struct { |
224 SendTo string `json:"send-to"` | 234 SendTo string `json:"send-to"` |
240 return | 250 return |
241 } | 251 } |
242 | 252 |
243 var email, user, password string | 253 var email, user, password string |
244 | 254 |
245 if err = auth.RunAs(pwResetRole, func(db *sql.DB) error { | 255 ctx := req.Context() |
246 err := db.QueryRow(findRequestSQL, hash).Scan(&email, &user) | 256 |
247 switch { | 257 if err = auth.RunAs( |
248 case err == sql.ErrNoRows: | 258 pwResetRole, ctx, func(conn *sql.Conn) error { |
249 return JSONError{http.StatusNotFound, "No such hash"} | 259 err := conn.QueryRowContext(ctx, findRequestSQL, hash).Scan(&email, &user) |
250 case err != nil: | 260 switch { |
261 case err == sql.ErrNoRows: | |
262 return JSONError{http.StatusNotFound, "No such hash"} | |
263 case err != nil: | |
264 return err | |
265 } | |
266 password = generateNewPassword() | |
267 res, err := conn.ExecContext(ctx, updatePasswordSQL, password, user) | |
268 if err != nil { | |
269 return err | |
270 } | |
271 if n, err2 := res.RowsAffected(); err2 == nil && n == 0 { | |
272 return JSONError{http.StatusNotFound, "User not found"} | |
273 } | |
274 _, err = conn.ExecContext(ctx, deleteRequestSQL, hash) | |
251 return err | 275 return err |
252 } | 276 }); err == nil { |
253 password = generateNewPassword() | |
254 res, err := db.Exec(updatePasswordSQL, password, user) | |
255 if err != nil { | |
256 return err | |
257 } | |
258 if n, err2 := res.RowsAffected(); err2 == nil && n == 0 { | |
259 return JSONError{http.StatusNotFound, "User not found"} | |
260 } | |
261 _, err = db.Exec(deleteRequestSQL, hash) | |
262 return err | |
263 }); err == nil { | |
264 body := changedMessageBody(useHTTPS(req), user, password, req.Host) | 277 body := changedMessageBody(useHTTPS(req), user, password, req.Host) |
265 if err = misc.SendMail(email, "Password Reset Done", body); err == nil { | 278 if err = misc.SendMail(email, "Password Reset Done", body); err == nil { |
266 jr.Result = &struct { | 279 jr.Result = &struct { |
267 SendTo string `json:"send-to"` | 280 SendTo string `json:"send-to"` |
268 }{email} | 281 }{email} |