diff options
author | Colin Reeder <vpzomtrrfrt@gmail.com> | 2020-09-26 13:53:24 -0600 |
---|---|---|
committer | Colin Reeder <vpzomtrrfrt@gmail.com> | 2020-09-26 13:53:24 -0600 |
commit | b6c67541127314c9d674083f595df059e8aa2c06 (patch) | |
tree | d42a6d7db89172c1f853b0b71ef6a44708726dbc | |
parent | e1683a89fd09948fa3931449e75af15a4398eb32 (diff) |
Split forgot_password routes into module
-rw-r--r-- | src/routes/api/forgot_password.rs | 108 | ||||
-rw-r--r-- | src/routes/api/mod.rs | 106 |
2 files changed, 110 insertions, 104 deletions
diff --git a/src/routes/api/forgot_password.rs b/src/routes/api/forgot_password.rs new file mode 100644 index 0000000..8a8504e --- /dev/null +++ b/src/routes/api/forgot_password.rs @@ -0,0 +1,108 @@ +use crate::UserLocalID; +use lettre::Tokio02Transport; +use rand::Rng; +use serde_derive::Deserialize; +use std::borrow::Cow; +use std::sync::Arc; + +struct ForgotPasswordKey { + value: i32, +} + +impl ForgotPasswordKey { + pub fn generate() -> Self { + Self { + value: rand::thread_rng().gen(), + } + } + + pub fn as_int(&self) -> i32 { + self.value + } + + pub fn to_str(&self) -> String { + bs58::encode(&self.value.to_be_bytes()).into_string() + } +} + +async fn route_unstable_forgot_password_keys_create( + _: (), + ctx: Arc<crate::RouteContext>, + req: hyper::Request<hyper::Body>, +) -> Result<hyper::Response<hyper::Body>, crate::Error> { + let lang = crate::get_lang_for_req(&req); + + if ctx.mailer.is_none() { + return Err(crate::Error::UserError(crate::simple_response( + hyper::StatusCode::INTERNAL_SERVER_ERROR, + lang.tr("email_not_configured", None).into_owned(), + ))); + } + + #[derive(Deserialize)] + struct ForgotPasswordBody<'a> { + email_address: Cow<'a, str>, + } + + let body = hyper::body::to_bytes(req.into_body()).await?; + let body: ForgotPasswordBody = serde_json::from_slice(&body)?; + + let db = ctx.db_pool.get().await?; + + let user_row = db.query_opt("SELECT id, username, email_address FROM person WHERE local AND LOWER(email_address) = LOWER($1)", &[&body.email_address]).await? + .ok_or_else(|| { + crate::Error::UserError(crate::simple_response( + hyper::StatusCode::BAD_REQUEST, + lang.tr("no_such_local_user_by_email", None).into_owned(), + )) + })?; + + let user_id = UserLocalID(user_row.get(0)); + let username: &str = user_row.get(1); + let user_email: &str = user_row.get(2); + + let user_email = lettre::Mailbox::new(None, user_email.parse()?); + + let key = ForgotPasswordKey::generate(); + db.execute( + "INSERT INTO forgot_password_key (key, person, created) VALUES ($1, $2, current_timestamp)", + &[&key.as_int(), &user_id], + ) + .await?; + + let msg_body = lang + .tr( + "email_content_forgot_password", + Some(&fluent::fluent_args!["key" => key.to_str(), "username" => username]), + ) + .into_owned(); + + let msg = lettre::Message::builder() + .date_now() + .subject("Forgot Password Request") + .from(ctx.mail_from.as_ref().unwrap().clone()) + .to(user_email) + .singlepart( + lettre::message::SinglePart::binary() + .header(lettre::message::header::ContentType::text_utf8()) + .body(msg_body), + )?; + + crate::spawn_task(async move { + ctx.mailer.as_ref().unwrap().send(msg).await?; + + Ok(()) + }); + + Ok(hyper::Response::builder() + .header(hyper::header::CONTENT_TYPE, "application/json") + .body("{}".into())?) +} + +pub fn route_forgot_password() -> crate::RouteNode<()> { + crate::RouteNode::new().with_child( + "keys", + crate::RouteNode::new() + .with_handler_async("POST", route_unstable_forgot_password_keys_create), + ) +} diff --git a/src/routes/api/mod.rs b/src/routes/api/mod.rs index af51521..88f64aa 100644 --- a/src/routes/api/mod.rs +++ b/src/routes/api/mod.rs @@ -1,7 +1,5 @@ use crate::routes::well_known::{FingerRequestQuery, FingerResponse}; use crate::{CommentLocalID, CommunityLocalID, PostLocalID, UserLocalID}; -use lettre::Tokio02Transport; -use rand::Rng; use serde_derive::{Deserialize, Serialize}; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; @@ -10,6 +8,7 @@ use std::sync::Arc; mod comments; mod communities; +mod forgot_password; mod posts; mod users; @@ -179,14 +178,7 @@ pub fn route_api() -> crate::RouteNode<()> { .with_child("posts", posts::route_posts()) .with_child("comments", comments::route_comments()) .with_child("users", users::route_users()) - .with_child( - "forgot_password", - crate::RouteNode::new().with_child( - "keys", - crate::RouteNode::new() - .with_handler_async("POST", route_unstable_forgot_password_keys_create), - ), - ), + .with_child("forgot_password", forgot_password::route_forgot_password()), ) } @@ -719,100 +711,6 @@ async fn route_unstable_misc_render_markdown( .body(output.into())?) } -struct ForgotPasswordKey { - value: i32, -} - -impl ForgotPasswordKey { - pub fn generate() -> Self { - Self { - value: rand::thread_rng().gen(), - } - } - - pub fn as_int(&self) -> i32 { - self.value - } - - pub fn to_str(&self) -> String { - bs58::encode(&self.value.to_be_bytes()).into_string() - } -} - -async fn route_unstable_forgot_password_keys_create( - _: (), - ctx: Arc<crate::RouteContext>, - req: hyper::Request<hyper::Body>, -) -> Result<hyper::Response<hyper::Body>, crate::Error> { - let lang = crate::get_lang_for_req(&req); - - if ctx.mailer.is_none() { - return Err(crate::Error::UserError(crate::simple_response( - hyper::StatusCode::INTERNAL_SERVER_ERROR, - lang.tr("email_not_configured", None).into_owned(), - ))); - } - - #[derive(Deserialize)] - struct ForgotPasswordBody<'a> { - email_address: Cow<'a, str>, - } - - let body = hyper::body::to_bytes(req.into_body()).await?; - let body: ForgotPasswordBody = serde_json::from_slice(&body)?; - - let db = ctx.db_pool.get().await?; - - let user_row = db.query_opt("SELECT id, username, email_address FROM person WHERE local AND LOWER(email_address) = LOWER($1)", &[&body.email_address]).await? - .ok_or_else(|| { - crate::Error::UserError(crate::simple_response( - hyper::StatusCode::BAD_REQUEST, - lang.tr("no_such_local_user_by_email", None).into_owned(), - )) - })?; - - let user_id = UserLocalID(user_row.get(0)); - let username: &str = user_row.get(1); - let user_email: &str = user_row.get(2); - - let user_email = lettre::Mailbox::new(None, user_email.parse()?); - - let key = ForgotPasswordKey::generate(); - db.execute( - "INSERT INTO forgot_password_key (key, person, created) VALUES ($1, $2, current_timestamp)", - &[&key.as_int(), &user_id], - ) - .await?; - - let msg_body = lang - .tr( - "email_content_forgot_password", - Some(&fluent::fluent_args!["key" => key.to_str(), "username" => username]), - ) - .into_owned(); - - let msg = lettre::Message::builder() - .date_now() - .subject("Forgot Password Request") - .from(ctx.mail_from.as_ref().unwrap().clone()) - .to(user_email) - .singlepart( - lettre::message::SinglePart::binary() - .header(lettre::message::header::ContentType::text_utf8()) - .body(msg_body), - )?; - - crate::spawn_task(async move { - ctx.mailer.as_ref().unwrap().send(msg).await?; - - Ok(()) - }); - - Ok(hyper::Response::builder() - .header(hyper::header::CONTENT_TYPE, "application/json") - .body("{}".into())?) -} - async fn handle_common_posts_list( stream: impl futures::stream::TryStream<Ok = tokio_postgres::Row, Error = tokio_postgres::Error> + Send, |