diff options
-rw-r--r-- | Cargo.lock | 10 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/error.rs | 10 | ||||
-rw-r--r-- | src/model.rs | 14 | ||||
-rw-r--r-- | src/routes.rs | 2 |
5 files changed, 31 insertions, 6 deletions
@@ -363,6 +363,15 @@ dependencies = [ ] [[package]] +name = "email_address" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2153bd83ebc09db15bcbdc3e2194d901804952e3dc96967e1cd3b0c5c32d112" +dependencies = [ + "serde", +] + +[[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1956,6 +1965,7 @@ dependencies = [ "axum", "axum-extra", "dotenvy", + "email_address", "http-body-util", "mime", "pgtemp", @@ -10,6 +10,7 @@ argon2 = { version = "0.5.3", features = ["std"] } axum = "0.7.4" axum-extra = { version = "0.9.2", features = ["typed-routing"] } dotenvy = "0.15.7" +email_address = "0.2.4" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.114" sqlx = { version = "0.7.3", features = ["postgres", "runtime-tokio", "uuid", "time"] } diff --git a/src/error.rs b/src/error.rs index 54075da..351c01a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -35,11 +35,11 @@ pub enum Error { #[error("User with that email already exists")] EmailExists, - #[error("Email is invalid")] - EmailInvalid, + #[error("Invalid email: {0}")] + EmailInvalid(#[from] email_address::Error), - #[error("Password is invalid")] - PasswordInvalid, + #[error("Invalid email or password")] + LoginInvalid, #[error("{0}")] Other(String), @@ -50,7 +50,7 @@ impl From<&Error> for StatusCode { match value { Error::UserNotFound => StatusCode::NOT_FOUND, Error::EmailExists => StatusCode::CONFLICT, - Error::EmailInvalid | Error::PasswordInvalid => StatusCode::UNPROCESSABLE_ENTITY, + Error::EmailInvalid(_) => StatusCode::UNPROCESSABLE_ENTITY, _ => StatusCode::INTERNAL_SERVER_ERROR, } } diff --git a/src/model.rs b/src/model.rs index 5f6111e..51ce493 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,7 +1,12 @@ +use std::str::FromStr; + use serde::{Deserialize, Serialize}; +use sqlx::FromRow; use time::OffsetDateTime; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)] +use crate::Error; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, FromRow)] #[serde(rename_all = "camelCase")] pub struct User { pub id: uuid::Uuid, @@ -28,6 +33,13 @@ pub struct RegisterSchema { pub password: String, } +impl RegisterSchema { + pub fn validate(&self) -> Result<(), Error> { + email_address::EmailAddress::from_str(&self.email)?; + Ok(()) + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct LoginSchema { pub email: String, diff --git a/src/routes.rs b/src/routes.rs index 0bf34b2..2692f1a 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -77,6 +77,8 @@ impl Register { State(state): State<Arc<AppState>>, Json(register_schema): Json<RegisterSchema>, ) -> impl IntoResponse { + register_schema.validate()?; + let exists: Option<bool> = sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM users WHERE email = $1)") .bind(register_schema.email.to_ascii_lowercase()) |