mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 09:28:11 +00:00
reuse email validation
This commit is contained in:
1 parent
654bd160ef
commit
d1ada07bf3
9 files changed
+100
-91
No files matched your search
@@ -1,34 +0,0 @@
|
||||
use md5::{Digest, Md5};
|
||||
|
||||
pub fn email_to_gravatar(email_address: &str) -> String {
|
||||
let email = email_address.trim().to_lowercase();
|
||||
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(email);
|
||||
let hash = hasher.finalize();
|
||||
let gravatar_hash = format!("{:x}", hash);
|
||||
|
||||
gravatar_hash
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::email::email_to_gravatar::email_to_gravatar;
|
||||
|
||||
#[test]
|
||||
fn test_gravatar() {
|
||||
// Email 1
|
||||
assert_eq!(email_to_gravatar("example@example.com"), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
assert_eq!(email_to_gravatar("EXAMPLE@EXAMPLE.COM"), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
assert_eq!(email_to_gravatar(" example@example.com \n "), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
|
||||
// Email 2
|
||||
assert_eq!(email_to_gravatar("echelon@gmail.com"), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
assert_eq!(email_to_gravatar("ECHELON@GMAIL.COM"), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
assert_eq!(email_to_gravatar(" ECHELON@GMAIL.COM "), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
|
||||
// Misc
|
||||
assert_eq!(email_to_gravatar(""), "d41d8cd98f00b204e9800998ecf8427e".to_string());
|
||||
assert_eq!(email_to_gravatar(" "), "d41d8cd98f00b204e9800998ecf8427e".to_string());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
use md5::{Digest, Md5};
|
||||
|
||||
pub fn email_to_gravatar_hash(email_address: &str) -> String {
|
||||
let email = email_address.trim().to_lowercase();
|
||||
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(email);
|
||||
let hash = hasher.finalize();
|
||||
let gravatar_hash = format!("{:x}", hash);
|
||||
|
||||
gravatar_hash
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::email::email_to_gravatar_hash::email_to_gravatar_hash;
|
||||
|
||||
#[test]
|
||||
fn test_gravatar() {
|
||||
// Email 1
|
||||
assert_eq!(email_to_gravatar_hash("example@example.com"), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
assert_eq!(email_to_gravatar_hash("EXAMPLE@EXAMPLE.COM"), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
assert_eq!(email_to_gravatar_hash(" example@example.com \n "), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
|
||||
// Email 2
|
||||
assert_eq!(email_to_gravatar_hash("echelon@gmail.com"), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
assert_eq!(email_to_gravatar_hash("ECHELON@GMAIL.COM"), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
assert_eq!(email_to_gravatar_hash(" ECHELON@GMAIL.COM "), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
|
||||
// Misc
|
||||
assert_eq!(email_to_gravatar_hash(""), "d41d8cd98f00b204e9800998ecf8427e".to_string());
|
||||
assert_eq!(email_to_gravatar_hash(" "), "d41d8cd98f00b204e9800998ecf8427e".to_string());
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
pub mod email_to_gravatar;
|
||||
pub mod email_to_gravatar_hash;
|
||||
pub mod generate_random_synthetic_email;
|
||||
pub mod validate_email_address;
|
||||
pub mod validate_email_address_format;
|
||||
Whitespace-only changes.
@@ -0,0 +1,55 @@
|
||||
|
||||
/// Basic email format validation
|
||||
pub fn validate_email_address_format(email: &str) -> Result<(), String> {
|
||||
let email = email.trim();
|
||||
|
||||
if email.is_empty() {
|
||||
return Err("email address cannot be empty".to_string());
|
||||
}
|
||||
|
||||
if email.len() > 255 {
|
||||
return Err("email address is too long".to_string());
|
||||
}
|
||||
|
||||
// Basic format check: must contain exactly one @ with content on both sides
|
||||
let at_count = email.matches('@').count();
|
||||
if at_count != 1 {
|
||||
return Err("email address must contain exactly one @".to_string());
|
||||
}
|
||||
|
||||
let parts: Vec<&str> = email.split('@').collect();
|
||||
if parts.len() != 2 {
|
||||
return Err("invalid email format".to_string());
|
||||
}
|
||||
|
||||
let local = parts[0];
|
||||
let domain = parts[1];
|
||||
|
||||
if local.is_empty() {
|
||||
return Err("email address must have content before @".to_string());
|
||||
}
|
||||
|
||||
if domain.is_empty() {
|
||||
return Err("email address must have a domain after @".to_string());
|
||||
}
|
||||
|
||||
// Domain must contain at least one dot
|
||||
if !domain.contains('.') {
|
||||
return Err("email domain must contain a dot".to_string());
|
||||
}
|
||||
|
||||
// Domain cannot start or end with a dot
|
||||
if domain.starts_with('.') || domain.ends_with('.') {
|
||||
return Err("email domain cannot start or end with a dot".to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_invalid_empty() {
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -18,7 +18,7 @@ use sqlx::{Acquire, MySql};
|
||||
use std::collections::HashMap;
|
||||
use stripe_checkout::checkout_session::{CreateCheckoutSession, CreateCheckoutSessionAutomaticTax, CreateCheckoutSessionLineItems, CreateCheckoutSessionSavedPaymentMethodOptions, CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters, CreateCheckoutSessionSavedPaymentMethodOptionsPaymentMethodSave, CreateCheckoutSessionSubscriptionData};
|
||||
use stripe_shared::{CheckoutSession, CheckoutSessionMode, PriceId};
|
||||
use users::email::email_to_gravatar::email_to_gravatar;
|
||||
use users::email::email_to_gravatar_hash::email_to_gravatar_hash;
|
||||
use users::email::generate_random_synthetic_email::generate_random_synthetic_email;
|
||||
use users::username::generate_random_username::generate_random_username;
|
||||
|
||||
@@ -57,7 +57,7 @@ pub (super) async fn user_creation_case(
|
||||
// NB: We try a few times to make sure we don't hit an email/username collision.
|
||||
|
||||
let user_email_address = generate_random_synthetic_email();
|
||||
let user_email_gravatar_hash = email_to_gravatar(&user_email_address);
|
||||
let user_email_gravatar_hash = email_to_gravatar_hash(&user_email_address);
|
||||
|
||||
let display_name = generate_random_username();
|
||||
let username = display_name.trim().to_lowercase();
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ use password::bcrypt_hash_password::bcrypt_hash_password;
|
||||
use sqlx::MySqlPool;
|
||||
use tokens::tokens::user_sessions::UserSessionToken;
|
||||
use user_input_common::check_for_slurs::contains_slurs;
|
||||
use users::email::email_to_gravatar::email_to_gravatar;
|
||||
use users::email::email_to_gravatar_hash::email_to_gravatar_hash;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(ToSchema, Deserialize)]
|
||||
@@ -185,7 +185,7 @@ pub async fn create_account_handler(
|
||||
|
||||
let email_address = request.email_address.trim().to_lowercase();
|
||||
|
||||
let email_gravatar_hash = email_to_gravatar(&email_address);
|
||||
let email_gravatar_hash = email_to_gravatar_hash(&email_address);
|
||||
|
||||
let ip_address = get_request_ip(&http_request);
|
||||
|
||||
|
||||
+3
-49
@@ -16,11 +16,11 @@ use artcraft_api_defs::users::edit_email::{EditEmailRequest, EditEmailResponse};
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::http_server::web_utils::user_session::require_user_session_using_connection::require_user_session_using_connection;
|
||||
use crate::state::server_state::ServerState;
|
||||
use hashing::md5::email_to_gravatar_hash::email_to_gravatar_hash;
|
||||
use http_server_common::request::get_request_ip::get_request_ip;
|
||||
use mysql_queries::queries::users::user::update::update_email::{update_email, UpdateEmailArgs, UpdateEmailError};
|
||||
use mysql_queries::utils::transactor::Transactor;
|
||||
|
||||
use users::email::email_to_gravatar_hash::email_to_gravatar_hash;
|
||||
use users::email::validate_email_address_format::validate_email_address_format;
|
||||
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum EditEmailError {
|
||||
@@ -56,52 +56,6 @@ impl fmt::Display for EditEmailError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Basic email format validation
|
||||
fn validate_email(email: &str) -> Result<(), String> {
|
||||
let email = email.trim();
|
||||
|
||||
if email.is_empty() {
|
||||
return Err("email address cannot be empty".to_string());
|
||||
}
|
||||
|
||||
if email.len() > 255 {
|
||||
return Err("email address is too long".to_string());
|
||||
}
|
||||
|
||||
// Basic format check: must contain exactly one @ with content on both sides
|
||||
let at_count = email.matches('@').count();
|
||||
if at_count != 1 {
|
||||
return Err("email address must contain exactly one @".to_string());
|
||||
}
|
||||
|
||||
let parts: Vec<&str> = email.split('@').collect();
|
||||
if parts.len() != 2 {
|
||||
return Err("invalid email format".to_string());
|
||||
}
|
||||
|
||||
let local = parts[0];
|
||||
let domain = parts[1];
|
||||
|
||||
if local.is_empty() {
|
||||
return Err("email address must have content before @".to_string());
|
||||
}
|
||||
|
||||
if domain.is_empty() {
|
||||
return Err("email address must have a domain after @".to_string());
|
||||
}
|
||||
|
||||
// Domain must contain at least one dot
|
||||
if !domain.contains('.') {
|
||||
return Err("email domain must contain a dot".to_string());
|
||||
}
|
||||
|
||||
// Domain cannot start or end with a dot
|
||||
if domain.starts_with('.') || domain.ends_with('.') {
|
||||
return Err("email domain cannot start or end with a dot".to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Edit email address of the current user.
|
||||
#[utoipa::path(
|
||||
@@ -126,7 +80,7 @@ pub async fn edit_email_handler(
|
||||
{
|
||||
let email_address = request.email_address.trim().to_lowercase();
|
||||
|
||||
if let Err(reason) = validate_email(&email_address) {
|
||||
if let Err(reason) = validate_email_address_format(&email_address) {
|
||||
return Err(EditEmailError::BadInput(format!("bad email: {}", &reason)));
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ use mysql_queries::queries::users::user::create::create_account_from_google_sso:
|
||||
use mysql_queries::utils::transactor::Transactor;
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::{Acquire, MySql};
|
||||
use users::email::email_to_gravatar::email_to_gravatar;
|
||||
use users::email::email_to_gravatar_hash::email_to_gravatar_hash;
|
||||
use users::username::generate_random_username::generate_random_username;
|
||||
|
||||
pub struct CreateArgs<'a> {
|
||||
@@ -40,7 +40,7 @@ pub async fn handle_new_sso_account_for_new_user(
|
||||
let user_feature_flags = studio_feature_flags();
|
||||
|
||||
let ip_address = get_request_ip(&args.http_request);
|
||||
let user_email_gravatar_hash = email_to_gravatar(&args.user_email_address);
|
||||
let user_email_gravatar_hash = email_to_gravatar_hash(&args.user_email_address);
|
||||
|
||||
let mut maybe_source = get_request_signup_source_enum(&args.http_request);
|
||||
|
||||
|
||||
Reference in new issue
Block a user