diff --git a/migrations/2021-05-15-071534_users/up.sql b/migrations/2021-05-15-071534_users/up.sql index 4bfd3d80be..4da43640be 100644 --- a/migrations/2021-05-15-071534_users/up.sql +++ b/migrations/2021-05-15-071534_users/up.sql @@ -15,6 +15,9 @@ CREATE TABLE users ( email_address VARCHAR(255) NOT NULL, email_confirmed BOOLEAN NOT NULL DEFAULT false, + -- Gravatar image hashes are precomputed. + email_gravatar_hash CHAR(32) NOT NULL, + -- The profile of the user in markdown (user editable). profile_markdown TEXT NOT NULL, diff --git a/src/http_server/endpoints/users/create_account.rs b/src/http_server/endpoints/users/create_account.rs index 05eaf5a622..c9e303a132 100644 --- a/src/http_server/endpoints/users/create_account.rs +++ b/src/http_server/endpoints/users/create_account.rs @@ -19,6 +19,7 @@ use sqlx::error::DatabaseError; use sqlx::error::Error::Database; use sqlx::mysql::MySqlDatabaseError; use std::sync::Arc; +use crate::util::email_to_gravatar::email_to_gravatar; const NEW_USER_ROLE: &'static str = "new-user"; @@ -110,10 +111,12 @@ pub async fn create_account_handler( } }; - let username = request.username.to_lowercase(); - let display_name = request.username.to_string(); + let username = request.username.trim().to_lowercase(); + let display_name = request.username.trim().to_string(); - let email_address = request.email_address.to_lowercase(); + let email_address = request.email_address.trim().to_lowercase(); + + let email_gravatar_hash = email_to_gravatar(&email_address); let profile_markdown = ""; let profile_rendered_html = ""; @@ -127,6 +130,7 @@ INSERT INTO users ( username, display_name, email_address, + email_gravatar_hash, profile_markdown, profile_rendered_html, user_role_slug, @@ -135,12 +139,13 @@ INSERT INTO users ( ip_address_last_login, ip_address_last_update ) -VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) +VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) "#, user_token.to_string(), username, display_name, email_address, + email_gravatar_hash, profile_markdown, profile_rendered_html, NEW_USER_ROLE, diff --git a/src/http_server/endpoints/users/get_profile.rs b/src/http_server/endpoints/users/get_profile.rs index a88a766fdf..780a7d1c59 100644 --- a/src/http_server/endpoints/users/get_profile.rs +++ b/src/http_server/endpoints/users/get_profile.rs @@ -32,8 +32,7 @@ use md5::{Md5, Digest}; pub struct UserProfileRecord { pub user_token: String, pub username: String, - /// DO NOT LEAK THE EMAIL! - pub email_address: String, + pub email_gravatar_hash: String, pub display_name: String, pub profile_markdown: String, pub profile_rendered_html: String, @@ -50,8 +49,6 @@ pub struct UserProfileRecord { } /// This changes the record: -/// - removes email address -/// - adds gravatar_hash /// - changes banned to bool /// - changes hide_results_preference to bool /// - changes disable_gravatar to bool @@ -60,8 +57,7 @@ pub struct UserProfileRecordForResponse { pub user_token: String, pub username: String, pub display_name: String, - /// Gravatar hash was added - pub gravatar_hash: String, + pub email_gravatar_hash: String, pub profile_markdown: String, pub profile_rendered_html: String, pub user_role_slug: String, @@ -143,8 +139,8 @@ pub async fn get_profile_handler( SELECT users.token as user_token, username, - email_address, display_name, + email_gravatar_hash, profile_markdown, profile_rendered_html, user_role_slug, @@ -182,18 +178,11 @@ AND users.deleted_at IS NULL } }; - let email = profile_record.email_address.trim().to_lowercase(); - - let mut hasher = Md5::new(); - hasher.update(email); - let hash = hasher.finalize(); - let gravatar_hash = format!("{:x}", hash); - let profile_for_response = UserProfileRecordForResponse { user_token: profile_record.user_token.clone(), username: profile_record.username.clone(), display_name: profile_record.display_name.clone(), - gravatar_hash: gravatar_hash, + email_gravatar_hash: profile_record.email_gravatar_hash.clone(), profile_markdown: profile_record.profile_markdown.clone(), profile_rendered_html: profile_record.profile_rendered_html.clone(), user_role_slug: profile_record.user_role_slug.clone(), diff --git a/src/util/email_to_gravatar.rs b/src/util/email_to_gravatar.rs new file mode 100644 index 0000000000..26f4f0fea8 --- /dev/null +++ b/src/util/email_to_gravatar.rs @@ -0,0 +1,12 @@ +use md5::{Md5, Digest}; + +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 +} diff --git a/src/util/mod.rs b/src/util/mod.rs index 5bdef0899a..99cdea2fa8 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,3 +1,4 @@ pub mod anyhow_result; pub mod filesystem; -pub mod random_token; \ No newline at end of file +pub mod random_token; +pub mod email_to_gravatar; \ No newline at end of file