Skip to content

Commit

Permalink
create simple email validation
Browse files Browse the repository at this point in the history
  • Loading branch information
kaplanelad committed Dec 17, 2024
1 parent 916b92a commit e20cc5c
Show file tree
Hide file tree
Showing 12 changed files with 69 additions and 31 deletions.
19 changes: 10 additions & 9 deletions loco-new/base_template/Cargo.toml.t
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ loco-rs = { {{settings.loco_version_text}} {%- if not settings.features.default_
[dependencies]
loco-rs = { workspace = true {% if feature_list | length > 0 %}, features = {{feature_list}}{% endif %} }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_json = { version = "1" }
tokio = { version = "1.33.0", default-features = false, features = [
"rt-multi-thread",
] }
async-trait = "0.1.74"
axum = "0.7.5"
tracing = "0.1.40"
async-trait = { version = "0.1.74" }
axum = { version = "0.7.5" }
tracing = { version = "0.1.40" }
tracing-subscriber = { version = "0.3.17", features = ["env-filter", "json"] }
regex = { version = "1.11.1" }
{%- if settings.db %}
migration = { path = "migration" }
sea-orm = { version = "1.1.0", features = [
Expand All @@ -37,19 +38,19 @@ sea-orm = { version = "1.1.0", features = [
"runtime-tokio-rustls",
"macros",
] }
chrono = "0.4"
chrono = { version = "0.4" }
validator = { version = "0.19" }
uuid = { version = "1.6.0", features = ["v4"] }
{%- endif %}

{%- if settings.mailer %}
include_dir = "0.7"
include_dir = { version = "0.7" }
{%- endif %}

{%- if settings.asset %}
# view engine i18n
fluent-templates = { version = "0.8.0", features = ["tera"] }
unic-langid = "0.9.4"
unic-langid = { version = "0.9.4" }
# /view engine
{%- endif %}

Expand All @@ -67,6 +68,6 @@ required-features = []

[dev-dependencies]
loco-rs = { workspace = true, features = ["testing"] }
serial_test = "3.1.1"
rstest = "0.21.0"
serial_test = { version = "3.1.1" }
rstest = { version = "0.21.0" }
insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] }
28 changes: 23 additions & 5 deletions loco-new/base_template/src/controllers/auth.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
use axum::debug_handler;
use loco_rs::prelude::*;
use serde::{Deserialize, Serialize};

use crate::{
mailers::auth::AuthMailer,
models::{
Expand All @@ -10,6 +6,20 @@ use crate::{
},
views::auth::{CurrentResponse, LoginResponse},
};
use axum::debug_handler;
use loco_rs::prelude::*;
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::sync::OnceLock;

pub static EMAIL_DOMAIN_RE: OnceLock<Regex> = OnceLock::new();

fn get_allow_email_domain_re() -> &'static Regex {
EMAIL_DOMAIN_RE.get_or_init(|| {
Regex::new(r"@example\.com$|@gmail\.com$").expect("Failed to compile regex")
})
}

#[derive(Debug, Deserialize, Serialize)]
pub struct VerifyParams {
pub token: String,
Expand Down Expand Up @@ -168,6 +178,15 @@ async fn magic_link(
State(ctx): State<AppContext>,
Json(params): Json<MagicLinkParams>,
) -> Result<Response> {
let email_regex = get_allow_email_domain_re();
if !email_regex.is_match(&params.email) {
tracing::debug!(
email = params.email,
"The provided email is invalid or does not match the allowed domains"
);
return bad_request("invalid request");
}

let Ok(user) = users::Model::find_by_email(&ctx.db, &params.email).await else {
// we don't want to expose our users email. if the email is invalid we still
// returning success to the caller
Expand All @@ -185,7 +204,6 @@ async fn magic_link(
async fn magic_link_verify(
Path(token): Path<String>,
State(ctx): State<AppContext>,
// Json(params): Json<MagicLinkParams>,
) -> Result<Response> {
let Ok(user) = users::Model::find_by_magic_token(&ctx.db, &token).await else {
// we don't want to expose our users email. if the email is invalid we still
Expand Down
19 changes: 19 additions & 0 deletions loco-new/base_template/tests/requests/auth.rs.t
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,25 @@ async fn can_auth_with_magic_link() {
.await;
}

#[tokio::test]
#[serial]
async fn can_reject_invalid_email() {
configure_insta!();
request::<App, _, _>(|request, _ctx| async move {
let invalid_email = "user1@temp-mail.com";
let payload = serde_json::json!({
"email": invalid_email,
});
let response = request.post("/api/auth/magic-link").json(&payload).await;
assert_eq!(
response.status_code(),
400,
"Expected request with invalid email '{invalid_email}' to be blocked, but it was allowed."
);
})
.await;
}

#[tokio::test]
#[serial]
async fn can_reject_invalid_magic_link_token() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: loco-new/tests/templates/asset.rs
source: tests/templates/asset.rs
expression: "content.get(\"dependencies\").unwrap()"
---
{ async-trait = "0.1.74", axum = "0.7.5", serde_json = "1", tracing = "0.1.40", unic-langid = "0.9.4", fluent-templates = { features = ["tera"], version = "0.8.0" }, loco-rs = { workspace = true }, serde = { features = ["derive"], version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
{ async-trait = { version = "0.1.74" }, axum = { version = "0.7.5" }, fluent-templates = { features = ["tera"], version = "0.8.0" }, loco-rs = { workspace = true }, regex = { version = "1.11.1" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" }, unic-langid = { version = "0.9.4" } }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: loco-new/tests/templates/asset.rs
source: tests/templates/asset.rs
expression: "content.get(\"dependencies\").unwrap()"
---
{ async-trait = "0.1.74", axum = "0.7.5", serde_json = "1", tracing = "0.1.40", loco-rs = { workspace = true }, serde = { features = ["derive"], version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
{ async-trait = { version = "0.1.74" }, axum = { version = "0.7.5" }, loco-rs = { workspace = true }, regex = { version = "1.11.1" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: loco-new/tests/templates/asset.rs
source: tests/templates/asset.rs
expression: "content.get(\"dependencies\").unwrap()"
---
{ async-trait = "0.1.74", axum = "0.7.5", serde_json = "1", tracing = "0.1.40", unic-langid = "0.9.4", fluent-templates = { features = ["tera"], version = "0.8.0" }, loco-rs = { workspace = true }, serde = { features = ["derive"], version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
{ async-trait = { version = "0.1.74" }, axum = { version = "0.7.5" }, fluent-templates = { features = ["tera"], version = "0.8.0" }, loco-rs = { workspace = true }, regex = { version = "1.11.1" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" }, unic-langid = { version = "0.9.4" } }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: loco-new/tests/templates/db.rs
source: tests/templates/db.rs
expression: "content.get(\"dependencies\").unwrap()"
---
{ async-trait = "0.1.74", axum = "0.7.5", serde_json = "1", tracing = "0.1.40", loco-rs = { workspace = true }, serde = { features = ["derive"], version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
{ async-trait = { version = "0.1.74" }, axum = { version = "0.7.5" }, loco-rs = { workspace = true }, regex = { version = "1.11.1" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: loco-new/tests/templates/db.rs
source: tests/templates/db.rs
expression: "content.get(\"dependencies\").unwrap()"
---
{ async-trait = "0.1.74", axum = "0.7.5", chrono = "0.4", serde_json = "1", tracing = "0.1.40", loco-rs = { workspace = true }, migration = { path = "migration" }, sea-orm = { features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", "macros"], version = "1.1.0" }, serde = { features = ["derive"], version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" }, uuid = { features = ["v4"], version = "1.6.0" }, validator = { version = "0.19" } }
{ async-trait = { version = "0.1.74" }, axum = { version = "0.7.5" }, chrono = { version = "0.4" }, loco-rs = { workspace = true }, migration = { path = "migration" }, regex = { version = "1.11.1" }, sea-orm = { features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", "macros"], version = "1.1.0" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" }, uuid = { features = ["v4"], version = "1.6.0" }, validator = { version = "0.19" } }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: loco-new/tests/templates/db.rs
source: tests/templates/db.rs
expression: "content.get(\"dependencies\").unwrap()"
---
{ async-trait = "0.1.74", axum = "0.7.5", chrono = "0.4", serde_json = "1", tracing = "0.1.40", loco-rs = { workspace = true }, migration = { path = "migration" }, sea-orm = { features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", "macros"], version = "1.1.0" }, serde = { features = ["derive"], version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" }, uuid = { features = ["v4"], version = "1.6.0" }, validator = { version = "0.19" } }
{ async-trait = { version = "0.1.74" }, axum = { version = "0.7.5" }, chrono = { version = "0.4" }, loco-rs = { workspace = true }, migration = { path = "migration" }, regex = { version = "1.11.1" }, sea-orm = { features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls", "macros"], version = "1.1.0" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" }, uuid = { features = ["v4"], version = "1.6.0" }, validator = { version = "0.19" } }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: loco-new/tests/templates/mailer.rs
source: tests/templates/mailer.rs
expression: "content.get(\"dependencies\").unwrap()"
---
{ async-trait = "0.1.74", axum = "0.7.5", serde_json = "1", tracing = "0.1.40", loco-rs = { workspace = true }, serde = { features = ["derive"], version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
{ async-trait = { version = "0.1.74" }, axum = { version = "0.7.5" }, loco-rs = { workspace = true }, regex = { version = "1.11.1" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: loco-new/tests/templates/mailer.rs
source: tests/templates/mailer.rs
expression: "content.get(\"dependencies\").unwrap()"
---
{ async-trait = "0.1.74", axum = "0.7.5", include_dir = "0.7", serde_json = "1", tracing = "0.1.40", loco-rs = { workspace = true }, serde = { features = ["derive"], version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
{ async-trait = { version = "0.1.74" }, axum = { version = "0.7.5" }, include_dir = { version = "0.7" }, loco-rs = { workspace = true }, regex = { version = "1.11.1" }, serde = { features = ["derive"], version = "1" }, serde_json = { version = "1" }, tokio = { default-features = false, features = ["rt-multi-thread"], version = "1.33.0" }, tracing = { version = "0.1.40" }, tracing-subscriber = { features = ["env-filter", "json"], version = "0.3.17" } }
2 changes: 1 addition & 1 deletion src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub use crate::{
app::{AppContext, Initializer},
bgworker::{BackgroundWorker, Queue},
controller::{
format,
bad_request, format,
middleware::{
format::{Format, RespondTo},
remote_ip::RemoteIP,
Expand Down

0 comments on commit e20cc5c

Please sign in to comment.