Reset Password (#1)
Implements reset password routes, views, and tests. Reviewed-on: #1
This commit is contained in:
@@ -57,6 +57,18 @@ public extension DatabaseClient.Users {
|
||||
guard let token = try await UserTokenModel.find(id, on: database)
|
||||
else { return }
|
||||
try await token.delete(on: database)
|
||||
} resetPassword: { id, request in
|
||||
database.logger.debug("Reset password: \(id)")
|
||||
|
||||
try request.validate()
|
||||
|
||||
guard let user = try await UserModel.find(id, on: database) else {
|
||||
throw Abort(.badRequest, reason: "User not found.")
|
||||
}
|
||||
|
||||
user.passwordHash = try User.hashPassword(request.password)
|
||||
try await user.save(on: database)
|
||||
|
||||
} token: { _ in
|
||||
guard let user = try await UserModel.query(on: database)
|
||||
.with(\.$token)
|
||||
@@ -134,11 +146,19 @@ extension User.Token {
|
||||
}
|
||||
}
|
||||
|
||||
extension User {
|
||||
|
||||
static func hashPassword(_ password: String) throws -> String {
|
||||
try Bcrypt.hash(password, cost: 12)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension User.Create {
|
||||
|
||||
func toModel() throws -> UserModel {
|
||||
try validate()
|
||||
return try .init(username: username, email: email, passwordHash: Bcrypt.hash(password, cost: 12))
|
||||
return try .init(username: username, email: email, passwordHash: User.hashPassword(password))
|
||||
}
|
||||
|
||||
func validate() throws {
|
||||
@@ -166,6 +186,18 @@ extension User.Login {
|
||||
}
|
||||
}
|
||||
|
||||
extension User.ResetPassword {
|
||||
|
||||
func validate() throws {
|
||||
guard password.count > 8 else {
|
||||
throw ValidationError(message: "Password should be more than 8 characters long.")
|
||||
}
|
||||
guard password == confirmPassword else {
|
||||
throw ValidationError(message: "Passwords do not match.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The user database model.
|
||||
///
|
||||
/// A user is someone who is able to login and generate PO's for employees. Generally a user should also
|
||||
@@ -228,6 +260,9 @@ final class UserModel: Model, @unchecked Sendable {
|
||||
)
|
||||
}
|
||||
|
||||
func verifyPassword(_ password: String) throws -> Bool {
|
||||
try Bcrypt.verify(password, created: passwordHash)
|
||||
}
|
||||
}
|
||||
|
||||
final class UserTokenModel: Model, Codable, @unchecked Sendable {
|
||||
@@ -273,7 +308,7 @@ public struct UserPasswordAuthenticator: AsyncBasicAuthenticator {
|
||||
guard let user = try await UserModel.query(on: request.db)
|
||||
.filter(\UserModel.$username == basic.username)
|
||||
.first(),
|
||||
try Bcrypt.verify(basic.password, created: user.passwordHash)
|
||||
try user.verifyPassword(basic.password)
|
||||
else {
|
||||
throw Abort(.unauthorized)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user