feat: rudimentary password change

This commit is contained in:
Per Stark
2025-03-20 22:00:06 +01:00
parent c3a14e6999
commit 385b1ff9de
5 changed files with 71 additions and 4 deletions

View File

@@ -84,7 +84,7 @@ impl User {
CREATE type::thing('user', $id) SET CREATE type::thing('user', $id) SET
email = $email, email = $email,
password = crypto::argon2::generate($password), password = crypto::argon2::generate($password),
admin = $count < 1, // Changed from == 0 to < 1 admin = $count < 1,
anonymous = false, anonymous = false,
created_at = $created_at, created_at = $created_at,
updated_at = $updated_at, updated_at = $updated_at,
@@ -103,6 +103,24 @@ impl User {
user.ok_or(AppError::Auth("User failed to create".into())) user.ok_or(AppError::Auth("User failed to create".into()))
} }
pub async fn patch_password(
email: &str,
password: &str,
db: &SurrealDbClient,
) -> Result<(), AppError> {
db.client
.query(
"UPDATE user
SET password = crypto::argon2::generate($password)
WHERE email = $email",
)
.bind(("email", email.to_owned()))
.bind(("password", password.to_owned()))
.await?;
Ok(())
}
pub async fn authenticate( pub async fn authenticate(
email: String, email: String,
password: String, password: String,

View File

@@ -18,7 +18,10 @@ use html_state::HtmlState;
use middleware_analytics::analytics_middleware; use middleware_analytics::analytics_middleware;
use middleware_auth::require_auth; use middleware_auth::require_auth;
use routes::{ use routes::{
account::{delete_account, set_api_key, show_account_page, update_timezone}, account::{
change_password, delete_account, set_api_key, show_account_page, show_change_password,
update_timezone,
},
admin_panel::{show_admin_panel, toggle_registration_status}, admin_panel::{show_admin_panel, toggle_registration_status},
chat::{ chat::{
message_response_stream::get_response_stream, new_chat_user_message, new_user_message, message_response_stream::get_response_stream, new_chat_user_message, new_user_message,
@@ -109,6 +112,10 @@ where
.route("/toggle-registrations", patch(toggle_registration_status)) .route("/toggle-registrations", patch(toggle_registration_status))
.route("/set-api-key", post(set_api_key)) .route("/set-api-key", post(set_api_key))
.route("/update-timezone", patch(update_timezone)) .route("/update-timezone", patch(update_timezone))
.route(
"/change-password",
get(show_change_password).patch(change_password),
)
.route("/delete-account", delete(delete_account)) .route("/delete-account", delete(delete_account))
.route_layer(from_fn_with_state(app_state.clone(), require_auth)); .route_layer(from_fn_with_state(app_state.clone(), require_auth));

View File

@@ -104,3 +104,38 @@ pub async fn update_timezone(
}, },
)) ))
} }
pub async fn show_change_password(
RequireUser(_user): RequireUser,
) -> Result<impl IntoResponse, HtmlError> {
Ok(TemplateResponse::new_template(
"auth/change_password_form.html",
{},
))
}
#[derive(Deserialize)]
pub struct NewPasswordForm {
old_password: String,
new_password: String,
}
pub async fn change_password(
State(state): State<HtmlState>,
RequireUser(user): RequireUser,
auth: AuthSessionType,
Form(form): Form<NewPasswordForm>,
) -> Result<impl IntoResponse, HtmlError> {
// Authenticate to make sure the password matches
let authenticated_user = User::authenticate(user.email, form.old_password, &state.db).await?;
User::patch_password(&authenticated_user.email, &form.new_password, &state.db).await?;
auth.cache_clear_user(user.id);
Ok(TemplateResponse::new_partial(
"auth/account_settings.html",
"change_password_section",
{},
))
}

View File

@@ -95,15 +95,17 @@
{% endblock %} {% endblock %}
</div> </div>
<div class="form-control mt-4"> <div class="form-control mt-4 hidden">
<button hx-post="/verify-email" class="btn btn-secondary w-full"> <button hx-post="/verify-email" class="btn btn-secondary w-full">
Verify Email Verify Email
</button> </button>
</div> </div>
<div class="form-control mt-4"> <div class="form-control mt-4">
<button hx-get="/change-password" class="btn btn-primary w-full"> {% block change_password_section %}
<button hx-get="/change-password" hx-swap="outerHTML" class="btn btn-primary w-full">
Change Password Change Password
</button> </button>
{% endblock %}
</div> </div>
<div class="form-control mt-4"> <div class="form-control mt-4">
<button hx-delete="/delete-account" <button hx-delete="/delete-account"

View File

@@ -0,0 +1,5 @@
<form hx-patch="/change-password" class="flex flex-col gap-1">
<input name="old_password" class="input w-full" type="password" placeholder="Enter old password"></input>
<input name="new_password" class="input w-full" type="password" placeholder="Enter new password"></input>
<button class="btn btn-primary w-full">Change Password</button>
</form>