Skip to content

Commit

Permalink
Improve password reset token expiry.
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrolGenhald committed Jun 30, 2023
1 parent ad18c03 commit c82f2d3
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 29 deletions.
20 changes: 2 additions & 18 deletions crates/api/src/local_user/change_password_after_reset.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
use crate::Perform;
use actix_web::web::Data;
use chrono::Duration;
use lemmy_api_common::{
context::LemmyContext,
person::{LoginResponse, PasswordChangeAfterReset},
utils::password_length_check,
};
use lemmy_db_schema::{
source::{
local_user::LocalUser,
password_reset_request::{PasswordResetRequest, PasswordResetRequestForm},
},
traits::Crud,
utils::naive_now,
source::{local_user::LocalUser, password_reset_request::PasswordResetRequest},
RegistrationMode,
};
use lemmy_db_views::structs::SiteView;
Expand Down Expand Up @@ -41,17 +35,7 @@ impl Perform for PasswordChangeAfterReset {

// Expire reset token
// TODO do this in a transaction along with the user update (blocked by https://github.com/LemmyNet/lemmy/issues/1161)
PasswordResetRequest::update(
context.pool(),
reset_request.id,
&PasswordResetRequestForm {
local_user_id: reset_request.local_user_id,
token_encrypted: reset_request.token_encrypted,
// Subtract a few seconds in case DB is on separate server and time isn't perfectly synced
expires_at: naive_now() - Duration::seconds(5),
},
)
.await?;
PasswordResetRequest::expire(context.pool(), reset_request.id).await?;

// Update the user with the new password
let password = data.password.clone();
Expand Down
38 changes: 27 additions & 11 deletions crates/db_schema/src/impls/password_reset_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,16 @@ impl Crud for PasswordResetRequest {
.first::<Self>(conn)
.await
}

async fn create(pool: &DbPool, form: &PasswordResetRequestForm) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
// Expire old tokens
// Subtract a few seconds in case DB is on separate server and time isn't perfectly synced
let expire_time = naive_now() - Duration::seconds(5);
diesel::update(
password_reset_request
.filter(local_user_id.eq(&form.local_user_id))
.filter(expires_at.gt(expire_time)),
)
.set(expires_at.eq(expire_time))
.execute(conn)
.await?;

insert_into(password_reset_request)
.values(form)
.get_result::<Self>(conn)
.await
}

async fn update(
pool: &DbPool,
password_reset_request_id: i32,
Expand Down Expand Up @@ -81,8 +72,12 @@ impl PasswordResetRequest {
expires_at: naive_now() + Duration::days(1),
};

// TODO do this in a transaction along with the new token creation (blocked by https://github.com/LemmyNet/lemmy/issues/1161)
Self::expire_all_for_user(pool, from_local_user_id).await?;

Self::create(pool, &form).await
}

pub async fn read_unexpired_from_token(
pool: &DbPool,
token: &str,
Expand All @@ -98,6 +93,27 @@ impl PasswordResetRequest {
.await
}

pub async fn expire(pool: &DbPool, password_reset_request_id: i32) -> Result<(), Error> {
let conn = &mut get_conn(pool).await?;
diesel::update(password_reset_request.find(password_reset_request_id))
.filter(expires_at.gt(now))
.set(expires_at.eq(now))
.execute(conn)
.await?;
Ok(())
}

pub async fn expire_all_for_user(pool: &DbPool, user_id: LocalUserId) -> Result<(), Error> {
let conn = &mut get_conn(pool).await?;
diesel::update(password_reset_request)
.filter(local_user_id.eq(user_id.0))
.filter(expires_at.gt(now))
.set(expires_at.eq(now))
.execute(conn)
.await?;
Ok(())
}

pub async fn get_recent_password_resets_count(
pool: &DbPool,
user_id: LocalUserId,
Expand Down

0 comments on commit c82f2d3

Please sign in to comment.