]> Untitled Git - lemmy.git/commitdiff
Limit password resets (#3344)
authorSander Saarend <sander@saarend.com>
Tue, 27 Jun 2023 09:20:53 +0000 (12:20 +0300)
committerGitHub <noreply@github.com>
Tue, 27 Jun 2023 09:20:53 +0000 (11:20 +0200)
crates/api/src/local_user/reset_password.rs
crates/db_schema/src/impls/password_reset_request.rs

index 3c07b2e4d4c94f6fc32a0b91b4a182a2b52c98f5..b5325608d0521bf75b7767e49445bb6fc7c6cbc9 100644 (file)
@@ -5,6 +5,7 @@ use lemmy_api_common::{
   person::{PasswordReset, PasswordResetResponse},
   utils::send_password_reset_email,
 };
+use lemmy_db_schema::source::password_reset_request::PasswordResetRequest;
 use lemmy_db_views::structs::LocalUserView;
 use lemmy_utils::error::LemmyError;
 
@@ -25,6 +26,16 @@ impl Perform for PasswordReset {
       .await
       .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_that_username_or_email"))?;
 
+    // Check for too many attempts (to limit potential abuse)
+    let recent_resets_count = PasswordResetRequest::get_recent_password_resets_count(
+      context.pool(),
+      local_user_view.local_user.id,
+    )
+    .await?;
+    if recent_resets_count >= 3 {
+      return Err(LemmyError::from_message("password_reset_limit_reached"));
+    }
+
     // Email the pure token to the user.
     send_password_reset_email(&local_user_view, context.pool(), context.settings()).await?;
     Ok(PasswordResetResponse {})
index ebe8a00ecff87738618c5327309caf65d94abbcb..85ad4cf01bcd41e8da0f7a58c6492d3eec3cd36a 100644 (file)
@@ -1,6 +1,11 @@
 use crate::{
   newtypes::LocalUserId,
-  schema::password_reset_request::dsl::{password_reset_request, published, token_encrypted},
+  schema::password_reset_request::dsl::{
+    local_user_id,
+    password_reset_request,
+    published,
+    token_encrypted,
+  },
   source::password_reset_request::{PasswordResetRequest, PasswordResetRequestForm},
   traits::Crud,
   utils::{get_conn, DbPool},
@@ -74,6 +79,19 @@ impl PasswordResetRequest {
       .first::<Self>(conn)
       .await
   }
+
+  pub async fn get_recent_password_resets_count(
+    pool: &DbPool,
+    user_id: LocalUserId,
+  ) -> Result<i64, Error> {
+    let conn = &mut get_conn(pool).await?;
+    password_reset_request
+      .filter(local_user_id.eq(user_id))
+      .filter(published.gt(now - 1.days()))
+      .count()
+      .get_result(conn)
+      .await
+  }
 }
 
 fn bytes_to_hex(bytes: Vec<u8>) -> String {