From 35f0517efdd4e50bcd4e153a9fdd7926553af9c6 Mon Sep 17 00:00:00 2001 From: kenken714 Date: Tue, 29 Oct 2024 17:05:30 +0900 Subject: [PATCH 1/2] feat: POST /reset-password/request --- src/handler.rs | 6 +++++- src/handler/authentication.rs | 37 +++++++++++++++++++++++++++++++++++ src/repository/jwt.rs | 17 ++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/handler.rs b/src/handler.rs index 2921d50..dcd6b1d 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -12,7 +12,11 @@ pub fn make_router(app_state: Repository) -> Router { let authentication_router = Router::new() .route("/signup/request", post(authentication::sign_up_request)) .route("/signup", post(authentication::sign_up)) - .route("/login", post(authentication::login)); + .route("/login", post(authentication::login)) + .route( + "/reset-password/request", + post(authentication::reset_password_request), + ); let users_router = Router::new() .route("/me", get(users::get_me).put(users::put_me)) diff --git a/src/handler/authentication.rs b/src/handler/authentication.rs index eb1983f..c961340 100644 --- a/src/handler/authentication.rs +++ b/src/handler/authentication.rs @@ -140,3 +140,40 @@ pub async fn login( Ok((StatusCode::OK, headers)) } + +#[derive(Deserialize)] +pub struct ResetPasswordRequest { + email: String, +} + +pub async fn reset_password_request( + State(state): State, + Json(body): Json, +) -> Result { + let user_address = body + .email + .parse::
() + .map_err(|_| StatusCode::BAD_REQUEST)?; + + // 既に登録されているメールアドレスのとき、正常時と同じステータスコードを返すが実際にメールを送信しない + if let Ok(false) = state.is_exist_email(&body.email).await { + return Ok(StatusCode::CREATED); + } + + let jwt = state + .encode_email_reset_password_jwt(&body.email) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + let message = format!( + "これはテストメールです。 +以下のリンクをクリックしてください。 +https://link/{jwt}" + ); + + crate::utils::mail::send_email(user_address, "traOJudgeパスワードリセット", &message) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + Ok(StatusCode::CREATED) +} diff --git a/src/repository/jwt.rs b/src/repository/jwt.rs index dfba375..aac8e94 100644 --- a/src/repository/jwt.rs +++ b/src/repository/jwt.rs @@ -99,6 +99,23 @@ impl Repository { claims.to_jwt() } + pub async fn encode_email_reset_password_jwt(&self, email: &str) -> anyhow::Result { + let exp = (Utc::now() + Duration::minutes(60)).timestamp(); + let iat = Utc::now().timestamp(); + let nbf = Utc::now().timestamp(); + + let claims = EmailToken { + exp, + iat, + nbf, + user_id: None, + email: email.to_string(), + action: Action::reset_password, + }; + + claims.to_jwt() + } + pub async fn verify_email_jwt(&self, jwt: &str) -> anyhow::Result<()> { EmailToken::verify(jwt) } From 32c06f06e6c5e7ea5efc5c9a6b35e60227709d11 Mon Sep 17 00:00:00 2001 From: kenken714 Date: Tue, 29 Oct 2024 17:42:49 +0900 Subject: [PATCH 2/2] fix; comment --- src/handler.rs | 2 +- src/handler/authentication.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/handler.rs b/src/handler.rs index 94b31cc..51fd73f 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -18,7 +18,7 @@ pub fn make_router(app_state: Repository) -> Router { "/reset-password/request", post(authentication::reset_password_request), ); - + let users_router = Router::new() .route("/me", get(users::get_me).put(users::put_me)) .route("/me/email", put(users::put_me_email)) diff --git a/src/handler/authentication.rs b/src/handler/authentication.rs index 67622a6..7f10eed 100644 --- a/src/handler/authentication.rs +++ b/src/handler/authentication.rs @@ -179,7 +179,7 @@ pub async fn reset_password_request( .parse::
() .map_err(|_| StatusCode::BAD_REQUEST)?; - // 既に登録されているメールアドレスのとき、正常時と同じステータスコードを返すが実際にメールを送信しない + // 登録されていないメールアドレスのとき、正常時と同じステータスコードを返すが実際にメールを送信しない if let Ok(false) = state.is_exist_email(&body.email).await { return Ok(StatusCode::CREATED); }