From 0115f96671548c9d10fe28e7061a87f6bce52cd8 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 11:28:53 -0400 Subject: [PATCH 1/9] Added endpoint constant --- src/callers/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/callers/mod.rs b/src/callers/mod.rs index 7a05735..5cfba11 100644 --- a/src/callers/mod.rs +++ b/src/callers/mod.rs @@ -15,4 +15,6 @@ pub mod endpoints { pub const LOGIN_SERVICE_USER: &str = "/api/v1/service/login"; /// Endpoint constant for refresh token pub const REFRESH_TOKEN: &str = "/api/v1/token/refresh"; + /// Endpoint constant for updating password + pub const UPDATE_PASSWORD: &str = "/api/v1/token/refresh"; } -- 2.47.3 From 74b9f90f57fd1d76502c3a57a69fc74da1d6f7f5 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 12:13:01 -0400 Subject: [PATCH 2/9] Saving changes --- src/callers/login.rs | 186 ++++++++++++++++++++++++++++++++++++++++ src/callers/register.rs | 2 +- src/repo/mod.rs | 25 ++++++ src/repo/service.rs | 25 ++++++ 4 files changed, 237 insertions(+), 1 deletion(-) diff --git a/src/callers/login.rs b/src/callers/login.rs index e39fc3d..c9030cd 100644 --- a/src/callers/login.rs +++ b/src/callers/login.rs @@ -37,6 +37,24 @@ pub mod request { pub struct RefreshTokenRequest { pub access_token: String, } + + #[derive(Deserialize, utoipa::ToSchema)] + pub struct UpdatePasswordRequest { + pub user_id: uuid::Uuid, + pub current_password: String, + pub updated_password: String, + pub confirmed_password: String, + } + + impl UpdatePasswordRequest { + pub fn is_valid(&self) -> bool { + if self.user_id.is_nil() || !self.current_password.is_empty() || !self.updated_password.is_empty() || !self.confirmed_password.is_empty() { + false + } else { + self.updated_password == self.confirmed_password + } + } + } } pub mod response { @@ -68,6 +86,12 @@ pub mod response { pub message: String, pub data: Vec, } + + #[derive(Deserialize, Serialize, utoipa::ToSchema)] + pub struct UpdatePasswordResponse { + pub message: String, + pub data: Vec + } } /// Endpoint for a user login @@ -509,3 +533,165 @@ pub async fn refresh_token( } } } + + +/// Endpoint for a updating password +#[utoipa::path( + post, + path = super::endpoints::UPDATE_PASSWORD, + request_body( + content = request::UpdatePasswordRequest, + description = "Data required to update password", + content_type = "application/json" + ), + responses( + (status = 200, description = "User login successful", body = response::UpdatePasswordResponse), + (status = 400, description = "Bad data", body = response::UpdatePasswordResponse), + (status = 500, description = "Something went wrong", body = response::UpdatePasswordResponse) + ) +)] +pub async fn update_password( + axum::Extension(pool): axum::Extension, + axum::Json(payload): axum::Json, +) -> (axum::http::StatusCode, axum::Json) { + if !payload.is_valid() { + ( + axum::http::StatusCode::BAD_REQUEST, + axum::Json(response::UpdatePasswordResponse { + message: String::from("Invalid passwords"), + data: Vec::new(), + }), + ) + } else { + + let verify_password = |current_password, hashed_password| -> Result { + match hashing::verify_password(current_password, hashed_password) { + Ok(matches) => { + Ok(matches) + } + Err(err) => Err(std::io::Error::other(err.to_string())), + } + }; + + match repo::user::get_with_id(&pool, &payload.user_id).await { + Ok(user) => { + let hashed_password = user.password.clone(); + match verify_password(&payload.current_password, hashed_password) { + Ok(matches) => { + if matches { + let (generate_salt, mut salt) = super::register::generate_the_salt(); + salt.id = repo::salt::insert(&pool, &salt).await.unwrap(); + let updated_hashed_password = match hashing::hash_password(&payload.updated_password, &generate_salt) { + Ok(hashed) => { + hashed + } + Err(err) => { + eprintln!("Error: {err:?}"); + String::new() + } + }; + + match repo::user::update_password(&pool, &user, &updated_hashed_password).await { + Ok(()) => { + (axum::http::StatusCode::OK, + axum::Json(response::UpdatePasswordResponse { + message: String::from(super::messages::SUCCESSFUL_MESSAGE), + data: vec![user.id], + })) + } + Err(err) => { + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: err.to_string(), + data: Vec::new(), + })) + } + } + } else { + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: String::from("Issue updating password"), + data: Vec::new(), + })) + } + } + Err(err) => { + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: err.to_string(), + data: Vec::new(), + }), + ) + } + } + } + Err(err) => { + println!("No User found, trying Service User: {err:?}"); + + // Try service user + match repo::service::get(&pool, &payload.user_id).await { + Ok(service_user) => { + let hashed_password = service_user.passphrase.clone(); + match verify_password(&payload.current_password, hashed_password) { + Ok(matches) => { + if matches { + let (generate_salt, mut salt) = super::register::generate_the_salt(); + salt.id = repo::salt::insert(&pool, &salt).await.unwrap(); + let updated_hashed_password = match hashing::hash_password(&payload.updated_password, &generate_salt) { + Ok(hashed) => { + hashed + } + Err(err) => { + eprintln!("Error: {err:?}"); + String::new() + } + }; + + match repo::service::update_passphrase(&pool, &service_user, &updated_hashed_password).await { + Ok(()) => { + (axum::http::StatusCode::OK, + axum::Json(response::UpdatePasswordResponse { + message: String::from(super::messages::SUCCESSFUL_MESSAGE), + data: vec![service_user.id], + })) + } + Err(err) => { + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: err.to_string(), + data: Vec::new(), + })) + } + } + } else { + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: String::from("Issue updating password"), + data: Vec::new(), + })) + } + } + Err(err) => { + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: err.to_string(), + data: Vec::new(), + }), + ) + } + } + } + Err(err) => { + (axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: err.to_string(), + data: Vec::new(), + })) + } + } + } + } + } +} diff --git a/src/callers/register.rs b/src/callers/register.rs index 3474d75..3ac4747 100644 --- a/src/callers/register.rs +++ b/src/callers/register.rs @@ -59,7 +59,7 @@ pub mod response { } } -fn generate_the_salt() -> ( +pub fn generate_the_salt() -> ( argon2::password_hash::SaltString, textsender_models::user::Salt, ) { diff --git a/src/repo/mod.rs b/src/repo/mod.rs index f7aeaad..373375c 100644 --- a/src/repo/mod.rs +++ b/src/repo/mod.rs @@ -104,6 +104,31 @@ pub mod user { } } + pub async fn update_password( + pool: &sqlx::PgPool, + user: &textsender_models::user::User, + updated_hashed_password: &String, + ) -> Result<(), sqlx::Error> { + match sqlx::query( + r#" + UPDATE "user" SET password = $1 WHERE id = $2 + "#, + ) + .bind(updated_hashed_password) + .bind(user.id) + .execute(pool) + .await { + Ok(row) => { + if row.rows_affected() > 0 { + Ok(()) + } else { + Err(sqlx::Error::RowNotFound) + } + } + Err(err) => Err(err), + } + } + pub async fn exists(pool: &sqlx::PgPool, username: &String) -> Result { let result = sqlx::query( r#" diff --git a/src/repo/service.rs b/src/repo/service.rs index 078751e..e1966bf 100644 --- a/src/repo/service.rs +++ b/src/repo/service.rs @@ -154,6 +154,31 @@ pub async fn update_last_login( } } +pub async fn update_passphrase( + pool: &sqlx::PgPool, + user: &textsender_models::user::ServiceUser, + updated_hashed_passphrase: &String, +) -> Result<(), sqlx::Error> { + match sqlx::query( + r#" + UPDATE "service_user" SET passphrase = $1 WHERE id = $2 + "#, + ) + .bind(updated_hashed_passphrase) + .bind(user.id) + .execute(pool) + .await { + Ok(row) => { + if row.rows_affected() > 0 { + Ok(()) + } else { + Err(sqlx::Error::RowNotFound) + } + } + Err(err) => Err(err), + } +} + pub async fn insert( pool: &sqlx::PgPool, service_user: &textsender_models::user::ServiceUser, -- 2.47.3 From dfae1be2eb3b87f0223e103356b6c8192309796d Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 12:13:15 -0400 Subject: [PATCH 3/9] Saving changes --- src/callers/login.rs | 164 ++++++++++++++++++++++++------------------- src/repo/mod.rs | 3 +- src/repo/service.rs | 3 +- 3 files changed, 96 insertions(+), 74 deletions(-) diff --git a/src/callers/login.rs b/src/callers/login.rs index c9030cd..1104cad 100644 --- a/src/callers/login.rs +++ b/src/callers/login.rs @@ -48,7 +48,11 @@ pub mod request { impl UpdatePasswordRequest { pub fn is_valid(&self) -> bool { - if self.user_id.is_nil() || !self.current_password.is_empty() || !self.updated_password.is_empty() || !self.confirmed_password.is_empty() { + if self.user_id.is_nil() + || !self.current_password.is_empty() + || !self.updated_password.is_empty() + || !self.confirmed_password.is_empty() + { false } else { self.updated_password == self.confirmed_password @@ -90,7 +94,7 @@ pub mod response { #[derive(Deserialize, Serialize, utoipa::ToSchema)] pub struct UpdatePasswordResponse { pub message: String, - pub data: Vec + pub data: Vec, } } @@ -534,7 +538,6 @@ pub async fn refresh_token( } } - /// Endpoint for a updating password #[utoipa::path( post, @@ -553,7 +556,10 @@ pub async fn refresh_token( pub async fn update_password( axum::Extension(pool): axum::Extension, axum::Json(payload): axum::Json, -) -> (axum::http::StatusCode, axum::Json) { +) -> ( + axum::http::StatusCode, + axum::Json, +) { if !payload.is_valid() { ( axum::http::StatusCode::BAD_REQUEST, @@ -563,16 +569,13 @@ pub async fn update_password( }), ) } else { - let verify_password = |current_password, hashed_password| -> Result { - match hashing::verify_password(current_password, hashed_password) { - Ok(matches) => { - Ok(matches) - } - Err(err) => Err(std::io::Error::other(err.to_string())), - } + match hashing::verify_password(current_password, hashed_password) { + Ok(matches) => Ok(matches), + Err(err) => Err(std::io::Error::other(err.to_string())), + } }; - + match repo::user::get_with_id(&pool, &payload.user_id).await { Ok(user) => { let hashed_password = user.password.clone(); @@ -581,49 +584,56 @@ pub async fn update_password( if matches { let (generate_salt, mut salt) = super::register::generate_the_salt(); salt.id = repo::salt::insert(&pool, &salt).await.unwrap(); - let updated_hashed_password = match hashing::hash_password(&payload.updated_password, &generate_salt) { - Ok(hashed) => { - hashed - } + let updated_hashed_password = match hashing::hash_password( + &payload.updated_password, + &generate_salt, + ) { + Ok(hashed) => hashed, Err(err) => { eprintln!("Error: {err:?}"); String::new() } }; - match repo::user::update_password(&pool, &user, &updated_hashed_password).await { - Ok(()) => { - (axum::http::StatusCode::OK, + match repo::user::update_password( + &pool, + &user, + &updated_hashed_password, + ) + .await + { + Ok(()) => ( + axum::http::StatusCode::OK, axum::Json(response::UpdatePasswordResponse { message: String::from(super::messages::SUCCESSFUL_MESSAGE), data: vec![user.id], - })) - } - Err(err) => { - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, + }), + ), + Err(err) => ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response::UpdatePasswordResponse { message: err.to_string(), data: Vec::new(), - })) - } + }), + ), } } else { - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, - axum::Json(response::UpdatePasswordResponse { - message: String::from("Issue updating password"), - data: Vec::new(), - })) + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: String::from("Issue updating password"), + data: Vec::new(), + }), + ) } } - Err(err) => { - ( - axum::http::StatusCode::INTERNAL_SERVER_ERROR, - axum::Json(response::UpdatePasswordResponse { - message: err.to_string(), - data: Vec::new(), - }), - ) - } + Err(err) => ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: err.to_string(), + data: Vec::new(), + }), + ), } } Err(err) => { @@ -636,60 +646,70 @@ pub async fn update_password( match verify_password(&payload.current_password, hashed_password) { Ok(matches) => { if matches { - let (generate_salt, mut salt) = super::register::generate_the_salt(); + let (generate_salt, mut salt) = + super::register::generate_the_salt(); salt.id = repo::salt::insert(&pool, &salt).await.unwrap(); - let updated_hashed_password = match hashing::hash_password(&payload.updated_password, &generate_salt) { - Ok(hashed) => { - hashed - } + let updated_hashed_password = match hashing::hash_password( + &payload.updated_password, + &generate_salt, + ) { + Ok(hashed) => hashed, Err(err) => { eprintln!("Error: {err:?}"); String::new() } }; - match repo::service::update_passphrase(&pool, &service_user, &updated_hashed_password).await { - Ok(()) => { - (axum::http::StatusCode::OK, + match repo::service::update_passphrase( + &pool, + &service_user, + &updated_hashed_password, + ) + .await + { + Ok(()) => ( + axum::http::StatusCode::OK, axum::Json(response::UpdatePasswordResponse { - message: String::from(super::messages::SUCCESSFUL_MESSAGE), + message: String::from( + super::messages::SUCCESSFUL_MESSAGE, + ), data: vec![service_user.id], - })) - } - Err(err) => { - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, + }), + ), + Err(err) => ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response::UpdatePasswordResponse { message: err.to_string(), data: Vec::new(), - })) - } + }), + ), } } else { - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, - axum::Json(response::UpdatePasswordResponse { - message: String::from("Issue updating password"), - data: Vec::new(), - })) + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: String::from("Issue updating password"), + data: Vec::new(), + }), + ) } } - Err(err) => { - ( + Err(err) => ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response::UpdatePasswordResponse { + message: err.to_string(), + data: Vec::new(), + }), + ), + } + } + Err(err) => ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response::UpdatePasswordResponse { message: err.to_string(), data: Vec::new(), }), - ) - } - } - } - Err(err) => { - (axum::http::StatusCode::INTERNAL_SERVER_ERROR, - axum::Json(response::UpdatePasswordResponse { - message: err.to_string(), - data: Vec::new(), - })) - } + ), } } } diff --git a/src/repo/mod.rs b/src/repo/mod.rs index 373375c..d0ff331 100644 --- a/src/repo/mod.rs +++ b/src/repo/mod.rs @@ -117,7 +117,8 @@ pub mod user { .bind(updated_hashed_password) .bind(user.id) .execute(pool) - .await { + .await + { Ok(row) => { if row.rows_affected() > 0 { Ok(()) diff --git a/src/repo/service.rs b/src/repo/service.rs index e1966bf..da80247 100644 --- a/src/repo/service.rs +++ b/src/repo/service.rs @@ -167,7 +167,8 @@ pub async fn update_passphrase( .bind(updated_hashed_passphrase) .bind(user.id) .execute(pool) - .await { + .await + { Ok(row) => { if row.rows_affected() > 0 { Ok(()) -- 2.47.3 From 18590b7e5c8df758767fe95a716585bd4fda7266 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 12:16:35 -0400 Subject: [PATCH 4/9] Making endpoint available --- src/callers/mod.rs | 2 +- src/lib.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/callers/mod.rs b/src/callers/mod.rs index 5cfba11..cbd82aa 100644 --- a/src/callers/mod.rs +++ b/src/callers/mod.rs @@ -16,5 +16,5 @@ pub mod endpoints { /// Endpoint constant for refresh token pub const REFRESH_TOKEN: &str = "/api/v1/token/refresh"; /// Endpoint constant for updating password - pub const UPDATE_PASSWORD: &str = "/api/v1/token/refresh"; + pub const UPDATE_PASSWORD: &str = "/api/v1/user/password/update"; } diff --git a/src/lib.rs b/src/lib.rs index 0a92e92..34841f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,6 +110,10 @@ pub mod init { callers::endpoints::REFRESH_TOKEN, post(callers::login::refresh_token), ) + .route( + callers::endpoints::UPDATE_PASSWORD, + post(callers::login::update_password), + ) .layer(cors::configure_cors().await) } -- 2.47.3 From dac9e3f2f8751f289b78d75605c508c8dd8b912a Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 12:33:53 -0400 Subject: [PATCH 5/9] Got it working --- src/callers/login.rs | 8 ++++---- src/lib.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/callers/login.rs b/src/callers/login.rs index 1104cad..60ad921 100644 --- a/src/callers/login.rs +++ b/src/callers/login.rs @@ -49,9 +49,9 @@ pub mod request { impl UpdatePasswordRequest { pub fn is_valid(&self) -> bool { if self.user_id.is_nil() - || !self.current_password.is_empty() - || !self.updated_password.is_empty() - || !self.confirmed_password.is_empty() + || self.current_password.is_empty() + || self.updated_password.is_empty() + || self.confirmed_password.is_empty() { false } else { @@ -540,7 +540,7 @@ pub async fn refresh_token( /// Endpoint for a updating password #[utoipa::path( - post, + patch, path = super::endpoints::UPDATE_PASSWORD, request_body( content = request::UpdatePasswordRequest, diff --git a/src/lib.rs b/src/lib.rs index 34841f0..fbfa407 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ pub mod token_stuff; pub mod init { use axum::{ Router, - routing::{get, post}, + routing::{get, patch, post}, }; use utoipa::OpenApi; @@ -112,7 +112,7 @@ pub mod init { ) .route( callers::endpoints::UPDATE_PASSWORD, - post(callers::login::update_password), + patch(callers::login::update_password), ) .layer(cors::configure_cors().await) } -- 2.47.3 From f122a04a672a898a394c9e64f901a106c63bec81 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 12:38:06 -0400 Subject: [PATCH 6/9] Adding test --- tests/tests.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/tests.rs b/tests/tests.rs index e861f47..3308872 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -671,3 +671,76 @@ async fn test_refresh_token() { } } } + +#[tokio::test] +async fn test_update_password() { + let tm_pool = db_mgr::get_pool().await.unwrap(); + let db_name = db_mgr::generate_db_name().await; + + match db_mgr::create_database(&tm_pool, &db_name).await { + Ok(_) => { + println!("Success"); + } + Err(e) => { + assert!(false, "Error: {:?}", e.to_string()); + } + } + + let pool = db_mgr::connect_to_db(&db_name).await.unwrap(); + + db::init::migrations(&pool).await; + + let app = init::routes().await.layer(axum::Extension(pool)); + + match flow::register_user(&app).await { + Ok(user) => match flow::login_user(&app, &user.username, TEST_PASSWORD).await { + Ok(login_result) => { + assert_eq!( + false, + login_result.access_token.is_empty(), + "Access token is empty when it should not be" + ); + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + }, + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + + match flow::register_service_user(&app).await { + Ok(user) => { + assert_eq!( + false, + user.id.is_nil(), + "The service user id should not be nil" + ); + match flow::login_service_user(&app, TEST_SERVICE_USERNAME, TEST_SERVICE_PASSPHRASE) + .await + { + Ok(login_result) => { + assert_eq!( + false, + login_result.access_token.is_empty(), + "Access token is empty when it should not be" + ); + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } + + match db_mgr::drop_database(&tm_pool, &db_name).await { + Ok(()) => {} + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } +} -- 2.47.3 From 5251758ea284ac7849b90766baf885a10c19d078 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 12:55:07 -0400 Subject: [PATCH 7/9] Fixing test --- tests/tests.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/tests.rs b/tests/tests.rs index 3308872..ae27688 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -171,6 +171,33 @@ pub mod requests { app.clone().oneshot(req).await } + + pub async fn update_password( + app: &axum::Router, + user_id: &uuid::Uuid, + current_password: &str, + updated_password: &str, + confirmed_password: &str, + ) -> Result { + let payload = serde_json::json!({ + "user_id": user_id, + "current_password": current_password, + "updated_password": updated_password, + "confirmed_password": confirmed_password, + }); + match axum::http::Request::builder() + .method(axum::http::Method::PATCH) + .uri(super::callers::endpoints::UPDATE_PASSWORD) + .header(axum::http::header::CONTENT_TYPE, "application/json") + .body(axum::body::Body::from(payload.to_string())) + { + Ok(req) => match app.clone().oneshot(req).await { + Ok(resp) => Ok(resp), + Err(err) => Err(axum::http::Error::from(err)), + }, + Err(err) => Err(err), + } + } } /// Test user firstname @@ -183,11 +210,15 @@ const TEST_USERNAME: &str = "BillyBob01"; const TEST_PASSWORD: &str = "923ndcry392qryudx328qrdy328r"; /// Test user phone number const TEST_PHONE_NUMBER: &str = "+10123456789"; +/// Test updated user password +const TEST_UPDATED_PASSWORD: &str = "3cnf29ry8q27i3yrc928qi37ryndxc2198q7yd9xzq12837e"; /// Test service username const TEST_SERVICE_USERNAME: &str = "swoon"; /// Test service passphrase const TEST_SERVICE_PASSPHRASE: &str = "4n5cf349tfy34w857ty39wq45nfdq23"; +/// Test updated service user passphrase +const TEST_SERVICE_UPDATED_PASSPHRASE: &str = "3487ncfyth934287fcrty32487fry32in7"; mod util { pub async fn convert_response( @@ -378,6 +409,50 @@ mod flow { Err(err) => Err(std::io::Error::other(err.to_string())), } } + + pub async fn update_password( + app: &axum::Router, + user_id: &uuid::Uuid, + current_password: &str, + updated_password: &str, + confirmed_password: &str, + ) -> Result { + match requests::update_password( + app, + user_id, + current_password, + updated_password, + confirmed_password, + ) + .await + { + Ok(response) => { + if axum::http::StatusCode::OK != response.status() { + Err(std::io::Error::other(format!( + "Status code is off {:?}", + response.status() + ))) + } else { + match util::convert_response::( + response, + ) + .await + { + Ok(response) => { + if response.data.len() > 0 { + let id = response.data[0].clone(); + Ok(id) + } else { + Err(std::io::Error::other("No data returned")) + } + } + Err(err) => Err(err), + } + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + } + } } #[tokio::test] @@ -700,6 +775,23 @@ async fn test_update_password() { login_result.access_token.is_empty(), "Access token is empty when it should not be" ); + + match flow::update_password( + &app, + &user.id, + TEST_PASSWORD, + TEST_UPDATED_PASSWORD, + TEST_UPDATED_PASSWORD, + ) + .await + { + Ok(id) => { + assert_eq!(id, user.id, "Ids do not match"); + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } } Err(err) => { assert!(false, "Error: {err:?}"); -- 2.47.3 From 2e9b6bb134c93ab2e2099a966ff2928c6e3fd2f8 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 12:59:10 -0400 Subject: [PATCH 8/9] Fixing test --- tests/tests.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index ae27688..e6e09b3 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -803,10 +803,10 @@ async fn test_update_password() { } match flow::register_service_user(&app).await { - Ok(user) => { + Ok(service_user) => { assert_eq!( false, - user.id.is_nil(), + service_user.id.is_nil(), "The service user id should not be nil" ); match flow::login_service_user(&app, TEST_SERVICE_USERNAME, TEST_SERVICE_PASSPHRASE) @@ -818,6 +818,23 @@ async fn test_update_password() { login_result.access_token.is_empty(), "Access token is empty when it should not be" ); + + match flow::update_password( + &app, + &service_user.id, + TEST_SERVICE_PASSPHRASE, + TEST_SERVICE_UPDATED_PASSPHRASE, + TEST_SERVICE_UPDATED_PASSPHRASE, + ) + .await + { + Ok(id) => { + assert_eq!(id, service_user.id, "Ids do not match"); + } + Err(err) => { + assert!(false, "Error: {err:?}"); + } + } } Err(err) => { assert!(false, "Error: {err:?}"); -- 2.47.3 From c03e2ba21473a3192d8c09a936b956644fe8d31d Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 12 Jun 2026 13:03:38 -0400 Subject: [PATCH 9/9] bump: textsender_auth --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbdfbb2..fbc37a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2213,7 +2213,7 @@ dependencies = [ [[package]] name = "textsender_auth" -version = "0.1.18" +version = "0.1.19" dependencies = [ "argon2", "async-std", diff --git a/Cargo.toml b/Cargo.toml index 8ac862d..173aa37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "textsender_auth" -version = "0.1.18" +version = "0.1.19" edition = "2024" rust-version = "1.95" -- 2.47.3