mirror of
https://github.com/stoatchat/rust-authifier.git
synced 2026-06-30 22:08:36 -04:00
187 lines
5.2 KiB
Rust
187 lines
5.2 KiB
Rust
/// Resend account verification email
|
|
/// POST /account/reverify
|
|
use mongodb::bson::doc;
|
|
use mongodb::options::{Collation, FindOneOptions};
|
|
use rocket::serde::json::Json;
|
|
use rocket::State;
|
|
|
|
use crate::entities::*;
|
|
use crate::logic::Auth;
|
|
use crate::util::{EmptyResponse, Error, Result};
|
|
|
|
/// # Resend Information
|
|
#[derive(Serialize, Deserialize, JsonSchema)]
|
|
pub struct DataResendVerification {
|
|
/// Email associated with the account
|
|
pub email: String,
|
|
/// Captcha verification code
|
|
pub captcha: Option<String>,
|
|
}
|
|
|
|
/// # Resend Verification
|
|
///
|
|
/// Resend account creation verification email.
|
|
#[openapi(tag = "Account")]
|
|
#[post("/reverify", data = "<data>")]
|
|
pub async fn resend_verification(
|
|
auth: &State<Auth>,
|
|
data: Json<DataResendVerification>,
|
|
) -> Result<EmptyResponse> {
|
|
let data = data.into_inner();
|
|
|
|
// Perform validation on given data.
|
|
auth.check_captcha(data.captcha).await?;
|
|
auth.validate_email(&data.email).await?;
|
|
|
|
// From this point on, do not report failure to the
|
|
// remote client, as this will open us up to user enumeration.
|
|
|
|
// Try to find the relevant account.
|
|
if let Some(mut account) = Account::find_one(
|
|
&auth.db,
|
|
doc! { "email": data.email },
|
|
FindOneOptions::builder()
|
|
.collation(Collation::builder().locale("en").strength(2).build())
|
|
.build(),
|
|
)
|
|
.await
|
|
.map_err(|_| Error::DatabaseError {
|
|
operation: "find_one",
|
|
with: "account",
|
|
})? {
|
|
if let AccountVerification::Pending { .. } = &account.verification {
|
|
// Send out verification email and update verification object.
|
|
account.verification = auth
|
|
.generate_email_verification(account.email.clone())
|
|
.await;
|
|
|
|
// Commit to database.
|
|
account.save_to_db(&auth.db).await?;
|
|
}
|
|
}
|
|
|
|
// Never fail this route,
|
|
// You may open the application to email enumeration otherwise.
|
|
Ok(EmptyResponse)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::test::*;
|
|
|
|
#[cfg(feature = "async-std-runtime")]
|
|
#[async_std::test]
|
|
async fn success() {
|
|
use chrono::Utc;
|
|
use mongodb::bson::DateTime;
|
|
|
|
let (db, auth) =
|
|
for_test_with_config("resend_verification::success", test_smtp_config().await).await;
|
|
|
|
let mut account = auth
|
|
.create_account(
|
|
"resend_verification@smtp.test".into(),
|
|
"password".into(),
|
|
false,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
account.verification = AccountVerification::Pending {
|
|
token: "".into(),
|
|
expiry: DateTime(Utc::now()),
|
|
};
|
|
|
|
account.save(&db, None).await.unwrap();
|
|
|
|
let client = bootstrap_rocket_with_auth(
|
|
auth,
|
|
routes![
|
|
crate::web::account::resend_verification::resend_verification,
|
|
crate::web::account::verify_email::verify_email
|
|
],
|
|
)
|
|
.await;
|
|
|
|
let res = client
|
|
.post("/reverify")
|
|
.header(ContentType::JSON)
|
|
.body(
|
|
json!({
|
|
"email": "resend_verification@smtp.test",
|
|
})
|
|
.to_string(),
|
|
)
|
|
.dispatch()
|
|
.await;
|
|
|
|
assert_eq!(res.status(), Status::NoContent);
|
|
|
|
let mail = assert_email_sendria("resend_verification@smtp.test".into()).await;
|
|
let res = client
|
|
.post(format!("/verify/{}", mail.code.expect("`code`")))
|
|
.dispatch()
|
|
.await;
|
|
|
|
assert_eq!(res.status(), Status::NoContent);
|
|
}
|
|
|
|
#[cfg(feature = "async-std-runtime")]
|
|
#[async_std::test]
|
|
async fn success_unknown() {
|
|
let (_, auth) = for_test_with_config(
|
|
"resend_verification::success_unknown",
|
|
test_smtp_config().await,
|
|
)
|
|
.await;
|
|
let client = bootstrap_rocket_with_auth(
|
|
auth,
|
|
routes![crate::web::account::resend_verification::resend_verification],
|
|
)
|
|
.await;
|
|
|
|
let res = client
|
|
.post("/reverify")
|
|
.header(ContentType::JSON)
|
|
.body(
|
|
json!({
|
|
"email": "smtptest1@insrt.uk",
|
|
})
|
|
.to_string(),
|
|
)
|
|
.dispatch()
|
|
.await;
|
|
|
|
assert_eq!(res.status(), Status::NoContent);
|
|
}
|
|
|
|
#[cfg(feature = "async-std-runtime")]
|
|
#[async_std::test]
|
|
async fn fail_bad_email() {
|
|
let client = bootstrap_rocket(
|
|
"resend_verification",
|
|
"fail_bad_email",
|
|
routes![crate::web::account::resend_verification::resend_verification],
|
|
)
|
|
.await;
|
|
|
|
let res = client
|
|
.post("/reverify")
|
|
.header(ContentType::JSON)
|
|
.body(
|
|
json!({
|
|
"email": "invalid",
|
|
})
|
|
.to_string(),
|
|
)
|
|
.dispatch()
|
|
.await;
|
|
|
|
assert_eq!(res.status(), Status::BadRequest);
|
|
assert_eq!(
|
|
res.into_string().await,
|
|
Some("{\"type\":\"IncorrectData\",\"with\":\"email\"}".into())
|
|
);
|
|
}
|
|
}
|