From 2d0f77af590de70d228a1bdbaab0c937e596c090 Mon Sep 17 00:00:00 2001 From: Nutomic <me@nutomic.com> Date: Wed, 2 Aug 2023 19:02:53 +0200 Subject: [PATCH] Dont use sha hash for password reset token (fixes #3491) (#3795) --- Cargo.lock | 2 -- Cargo.toml | 1 - crates/api_common/src/utils.rs | 3 +- crates/apub/Cargo.toml | 1 - crates/db_schema/Cargo.toml | 2 -- .../src/impls/password_reset_request.rs | 36 ++++--------------- crates/db_schema/src/schema.rs | 2 +- .../src/source/password_reset_request.rs | 4 +-- .../down.sql | 1 + .../up.sql | 1 + 10 files changed, 13 insertions(+), 40 deletions(-) create mode 100644 migrations/2023-08-02-144930_password-reset-token/down.sql create mode 100644 migrations/2023-08-02-144930_password-reset-token/up.sql diff --git a/Cargo.lock b/Cargo.lock index bac96d5e..98a89095 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2678,7 +2678,6 @@ dependencies = [ "serde_json", "serde_with", "serial_test", - "sha2", "strum_macros", "task-local-extensions", "tokio", @@ -2711,7 +2710,6 @@ dependencies = [ "serde_json", "serde_with", "serial_test", - "sha2", "strum", "strum_macros", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 405ed9d4..424c10e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,6 @@ diesel_ltree = "0.3.0" typed-builder = "0.15.0" serial_test = "2.0.0" tokio = { version = "1.29.1", features = ["full"] } -sha2 = "0.10.7" regex = "1.9.0" once_cell = "1.18.0" diesel-derive-newtype = "2.1.0" diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 5a678191..6bdc3028 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -342,9 +342,8 @@ pub async fn send_password_reset_email( let token = uuid::Uuid::new_v4().to_string(); // Insert the row - let token2 = token.clone(); let local_user_id = user.local_user.id; - PasswordResetRequest::create_token(pool, local_user_id, &token2).await?; + PasswordResetRequest::create_token(pool, local_user_id, token.clone()).await?; let email = &user.local_user.email.clone().expect("email"); let lang = get_interface_language(user); diff --git a/crates/apub/Cargo.toml b/crates/apub/Cargo.toml index cdddea4f..ebdf3245 100644 --- a/crates/apub/Cargo.toml +++ b/crates/apub/Cargo.toml @@ -33,7 +33,6 @@ http = { workspace = true } futures = { workspace = true } itertools = { workspace = true } uuid = { workspace = true } -sha2 = { workspace = true } async-trait = { workspace = true } anyhow = { workspace = true } reqwest = { workspace = true } diff --git a/crates/db_schema/Cargo.toml b/crates/db_schema/Cargo.toml index a5d3e21f..3370a559 100644 --- a/crates/db_schema/Cargo.toml +++ b/crates/db_schema/Cargo.toml @@ -22,7 +22,6 @@ full = [ "bcrypt", "lemmy_utils", "activitypub_federation", - "sha2", "regex", "once_cell", "serde_json", @@ -60,7 +59,6 @@ diesel-async = { workspace = true, features = [ "postgres", "deadpool", ], optional = true } -sha2 = { workspace = true, optional = true } regex = { workspace = true, optional = true } once_cell = { workspace = true, optional = true } diesel_ltree = { workspace = true, optional = true } diff --git a/crates/db_schema/src/impls/password_reset_request.rs b/crates/db_schema/src/impls/password_reset_request.rs index 9daaa166..a5a8fc49 100644 --- a/crates/db_schema/src/impls/password_reset_request.rs +++ b/crates/db_schema/src/impls/password_reset_request.rs @@ -1,11 +1,6 @@ use crate::{ newtypes::LocalUserId, - schema::password_reset_request::dsl::{ - local_user_id, - password_reset_request, - published, - token_encrypted, - }, + schema::password_reset_request::dsl::{local_user_id, password_reset_request, published, token}, source::password_reset_request::{PasswordResetRequest, PasswordResetRequestForm}, traits::Crud, utils::{get_conn, DbPool}, @@ -17,7 +12,6 @@ use diesel::{ QueryDsl, }; use diesel_async::RunQueryDsl; -use sha2::{Digest, Sha256}; #[async_trait] impl Crud for PasswordResetRequest { @@ -49,29 +43,22 @@ impl PasswordResetRequest { pub async fn create_token( pool: &mut DbPool<'_>, from_local_user_id: LocalUserId, - token: &str, + token_: String, ) -> Result<PasswordResetRequest, Error> { - let mut hasher = Sha256::new(); - hasher.update(token); - let token_hash: String = bytes_to_hex(hasher.finalize().to_vec()); - let form = PasswordResetRequestForm { local_user_id: from_local_user_id, - token_encrypted: token_hash, + token: token_, }; Self::create(pool, &form).await } pub async fn read_from_token( pool: &mut DbPool<'_>, - token: &str, + token_: &str, ) -> Result<PasswordResetRequest, Error> { let conn = &mut get_conn(pool).await?; - let mut hasher = Sha256::new(); - hasher.update(token); - let token_hash: String = bytes_to_hex(hasher.finalize().to_vec()); password_reset_request - .filter(token_encrypted.eq(token_hash)) + .filter(token.eq(token_)) .filter(published.gt(now - 1.days())) .first::<Self>(conn) .await @@ -91,14 +78,6 @@ impl PasswordResetRequest { } } -fn bytes_to_hex(bytes: Vec<u8>) -> String { - let mut str = String::new(); - for byte in bytes { - str = format!("{str}{byte:02x}"); - } - str -} - #[cfg(test)] mod tests { #![allow(clippy::unwrap_used)] @@ -142,17 +121,16 @@ mod tests { let inserted_local_user = LocalUser::create(pool, &new_local_user).await.unwrap(); let token = "nope"; - let token_encrypted_ = "ca3704aa0b06f5954c79ee837faa152d84d6b2d42838f0637a15eda8337dbdce"; let inserted_password_reset_request = - PasswordResetRequest::create_token(pool, inserted_local_user.id, token) + PasswordResetRequest::create_token(pool, inserted_local_user.id, token.to_string()) .await .unwrap(); let expected_password_reset_request = PasswordResetRequest { id: inserted_password_reset_request.id, local_user_id: inserted_local_user.id, - token_encrypted: token_encrypted_.to_string(), + token: token.to_string(), published: inserted_password_reset_request.published, }; diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index d6e2cf69..7106b1c9 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -535,7 +535,7 @@ diesel::table! { diesel::table! { password_reset_request (id) { id -> Int4, - token_encrypted -> Text, + token -> Text, published -> Timestamp, local_user_id -> Int4, } diff --git a/crates/db_schema/src/source/password_reset_request.rs b/crates/db_schema/src/source/password_reset_request.rs index 6c28c649..6e1b572d 100644 --- a/crates/db_schema/src/source/password_reset_request.rs +++ b/crates/db_schema/src/source/password_reset_request.rs @@ -7,7 +7,7 @@ use crate::schema::password_reset_request; #[cfg_attr(feature = "full", diesel(table_name = password_reset_request))] pub struct PasswordResetRequest { pub id: i32, - pub token_encrypted: String, + pub token: String, pub published: chrono::NaiveDateTime, pub local_user_id: LocalUserId, } @@ -16,5 +16,5 @@ pub struct PasswordResetRequest { #[cfg_attr(feature = "full", diesel(table_name = password_reset_request))] pub struct PasswordResetRequestForm { pub local_user_id: LocalUserId, - pub token_encrypted: String, + pub token: String, } diff --git a/migrations/2023-08-02-144930_password-reset-token/down.sql b/migrations/2023-08-02-144930_password-reset-token/down.sql new file mode 100644 index 00000000..5f938da2 --- /dev/null +++ b/migrations/2023-08-02-144930_password-reset-token/down.sql @@ -0,0 +1 @@ +alter table password_reset_request rename column token to token_encrypted; diff --git a/migrations/2023-08-02-144930_password-reset-token/up.sql b/migrations/2023-08-02-144930_password-reset-token/up.sql new file mode 100644 index 00000000..0bdd1655 --- /dev/null +++ b/migrations/2023-08-02-144930_password-reset-token/up.sql @@ -0,0 +1 @@ +alter table password_reset_request rename column token_encrypted to token; -- 2.44.1