Add route to update password with email token

This commit is contained in:
Christoph Hagen 2022-10-12 19:30:43 +02:00
parent 4e9675c284
commit ff916945df
2 changed files with 58 additions and 0 deletions

View File

@ -114,7 +114,42 @@ final class SQLiteDatabase {
/**
Change the password of a user with a recovery token
Possible errors:
- `404`: Reset token not found or expired
*/
func updatePassword(password: String, forResetToken token: String, in database: Database) async throws {
// 1. Find and validate the reset request
let reset: PasswordReset? = try await PasswordReset.query(on: database)
.filter(\.$resetToken == token)
.first()
guard let reset else {
throw Abort(.expectationFailed)
}
guard reset.expiryDate.timeIntervalSinceNow > 0 else {
throw Abort(.expectationFailed)
}
// 2. Update the user password
let user = try await reset.$user.get(on: database)
user.passwordHash = password
try await user.save(on: database)
// 3. Delete the reset request
try await PasswordReset
.query(on: database)
.filter(\.$resetToken == token)
.delete()
}
func passwordHashForExistingPlayer(named name: PlayerName, in database: Database) async throws -> PasswordHash {
try await User
.query(on: database)
.filter(\.$name == name)
.first()
.unwrap(or: Abort(.notFound))
.passwordHash
}
func deletePlayer(named name: PlayerName, in database: Database) async throws {
let user = try await user(named: name, in: database)
try await tables.leaveTable(player: user, in: database)

View File

@ -83,6 +83,29 @@ func requestPlayerPasswordReset(_ app: Application) {
return .ok
}
}
/**
Use a token from a password reset email to change the password.
Headers:
- `token`: The one-time recovery token
- `password`: The new password for the user
Possible responses:
- `200`: Success, password changed
- `400`: Missing token or password header
- `404`: Player name not found or no email registered
- `424`: Password could not be hashed
*/
func resetPlayerPasswordWithEmailToken(_ app: Application) {
app.post("player", "reset") { req async throws -> HTTPResponseStatus in
let token = try req.header(.token)
let hash = try req.hashedPassword() // errors: 400, 424
try await server.updatePassword(password: hash, forResetToken: token, in: req.db)
return .ok
}
}
/**
Delete a player.