fix(masking): mask email while logging SQL query (#4436)

This commit is contained in:
Kartikeya Hegde
2024-04-23 16:48:35 +05:30
committed by GitHub
parent 5ce0535bb6
commit 4c81a664c9
8 changed files with 56 additions and 51 deletions

View File

@ -1,4 +1,5 @@
use async_bb8_diesel::AsyncRunQueryDsl; use async_bb8_diesel::AsyncRunQueryDsl;
use common_utils::pii;
use diesel::{ use diesel::{
associations::HasTable, debug_query, result::Error as DieselError, ExpressionMethods, associations::HasTable, debug_query, result::Error as DieselError, ExpressionMethods,
JoinOnDsl, QueryDsl, JoinOnDsl, QueryDsl,
@ -26,7 +27,10 @@ impl UserNew {
} }
impl User { impl User {
pub async fn find_by_user_email(conn: &PgPooledConn, user_email: &str) -> StorageResult<Self> { pub async fn find_by_user_email(
conn: &PgPooledConn,
user_email: &pii::Email,
) -> StorageResult<Self> {
generics::generic_find_one::<<Self as HasTable>::Table, _, _>( generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
conn, conn,
users_dsl::email.eq(user_email.to_owned()), users_dsl::email.eq(user_email.to_owned()),
@ -62,7 +66,7 @@ impl User {
pub async fn update_by_user_email( pub async fn update_by_user_email(
conn: &PgPooledConn, conn: &PgPooledConn,
user_email: &str, user_email: &pii::Email,
user_update: UserUpdate, user_update: UserUpdate,
) -> StorageResult<Self> { ) -> StorageResult<Self> {
generics::generic_update_with_unique_predicate_get_result::< generics::generic_update_with_unique_predicate_get_result::<

View File

@ -106,7 +106,7 @@ pub async fn signin_without_invite_checks(
) -> UserResponse<user_api::DashboardEntryResponse> { ) -> UserResponse<user_api::DashboardEntryResponse> {
let user_from_db: domain::UserFromStorage = state let user_from_db: domain::UserFromStorage = state
.store .store
.find_user_by_email(request.email.clone().expose().expose().as_str()) .find_user_by_email(&request.email)
.await .await
.map_err(|e| { .map_err(|e| {
if e.current_context().is_db_not_found() { if e.current_context().is_db_not_found() {
@ -134,7 +134,7 @@ pub async fn signin(
) -> UserResponse<user_api::SignInResponse> { ) -> UserResponse<user_api::SignInResponse> {
let user_from_db: domain::UserFromStorage = state let user_from_db: domain::UserFromStorage = state
.store .store
.find_user_by_email(request.email.clone().expose().expose().as_str()) .find_user_by_email(&request.email)
.await .await
.map_err(|e| { .map_err(|e| {
if e.current_context().is_db_not_found() { if e.current_context().is_db_not_found() {
@ -177,10 +177,7 @@ pub async fn connect_account(
state: AppState, state: AppState,
request: user_api::ConnectAccountRequest, request: user_api::ConnectAccountRequest,
) -> UserResponse<user_api::ConnectAccountResponse> { ) -> UserResponse<user_api::ConnectAccountResponse> {
let find_user = state let find_user = state.store.find_user_by_email(&request.email).await;
.store
.find_user_by_email(request.email.clone().expose().expose().as_str())
.await;
if let Ok(found_user) = find_user { if let Ok(found_user) = find_user {
let user_from_db: domain::UserFromStorage = found_user.into(); let user_from_db: domain::UserFromStorage = found_user.into();
@ -340,7 +337,7 @@ pub async fn forgot_password(
let user_from_db = state let user_from_db = state
.store .store
.find_user_by_email(user_email.get_secret().expose().as_str()) .find_user_by_email(&user_email.into_inner())
.await .await
.map_err(|e| { .map_err(|e| {
if e.current_context().is_db_not_found() { if e.current_context().is_db_not_found() {
@ -389,7 +386,9 @@ pub async fn reset_password(
let user = state let user = state
.store .store
.update_user_by_email( .update_user_by_email(
email_token.get_email(), &email_token
.get_email()
.change_context(UserErrors::InternalServerError)?,
storage_user::UserUpdate::AccountUpdate { storage_user::UserUpdate::AccountUpdate {
name: None, name: None,
password: Some(hash_password), password: Some(hash_password),
@ -462,7 +461,7 @@ pub async fn invite_user(
let invitee_user = state let invitee_user = state
.store .store
.find_user_by_email(invitee_email.clone().get_secret().expose().as_str()) .find_user_by_email(&invitee_email.clone().into_inner())
.await; .await;
if let Ok(invitee_user) = invitee_user { if let Ok(invitee_user) = invitee_user {
@ -684,7 +683,7 @@ async fn handle_invitation(
let invitee_email = domain::UserEmail::from_pii_email(request.email.clone())?; let invitee_email = domain::UserEmail::from_pii_email(request.email.clone())?;
let invitee_user = state let invitee_user = state
.store .store
.find_user_by_email(invitee_email.clone().get_secret().expose().as_str()) .find_user_by_email(&invitee_email.into_inner())
.await; .await;
if let Ok(invitee_user) = invitee_user { if let Ok(invitee_user) = invitee_user {
@ -882,7 +881,7 @@ pub async fn resend_invite(
let invitee_email = domain::UserEmail::from_pii_email(request.email)?; let invitee_email = domain::UserEmail::from_pii_email(request.email)?;
let user: domain::UserFromStorage = state let user: domain::UserFromStorage = state
.store .store
.find_user_by_email(invitee_email.clone().get_secret().expose().as_str()) .find_user_by_email(&invitee_email.clone().into_inner())
.await .await
.map_err(|e| { .map_err(|e| {
if e.current_context().is_db_not_found() { if e.current_context().is_db_not_found() {
@ -949,7 +948,11 @@ pub async fn accept_invite_from_email(
let user: domain::UserFromStorage = state let user: domain::UserFromStorage = state
.store .store
.find_user_by_email(email_token.get_email()) .find_user_by_email(
&email_token
.get_email()
.change_context(UserErrors::InternalServerError)?,
)
.await .await
.change_context(UserErrors::InternalServerError)? .change_context(UserErrors::InternalServerError)?
.into(); .into();
@ -1326,7 +1329,11 @@ pub async fn verify_email_without_invite_checks(
auth::blacklist::check_email_token_in_blacklist(&state, &token).await?; auth::blacklist::check_email_token_in_blacklist(&state, &token).await?;
let user = state let user = state
.store .store
.find_user_by_email(email_token.get_email()) .find_user_by_email(
&email_token
.get_email()
.change_context(UserErrors::InternalServerError)?,
)
.await .await
.change_context(UserErrors::InternalServerError)?; .change_context(UserErrors::InternalServerError)?;
let user = state let user = state
@ -1362,7 +1369,11 @@ pub async fn verify_email(
let user = state let user = state
.store .store
.find_user_by_email(email_token.get_email()) .find_user_by_email(
&email_token
.get_email()
.change_context(UserErrors::InternalServerError)?,
)
.await .await
.change_context(UserErrors::InternalServerError)?; .change_context(UserErrors::InternalServerError)?;
@ -1411,7 +1422,7 @@ pub async fn send_verification_mail(
let user_email = domain::UserEmail::try_from(req.email)?; let user_email = domain::UserEmail::try_from(req.email)?;
let user = state let user = state
.store .store
.find_user_by_email(user_email.clone().get_secret().expose().as_str()) .find_user_by_email(&user_email.into_inner())
.await .await
.map_err(|e| { .map_err(|e| {
if e.current_context().is_db_not_found() { if e.current_context().is_db_not_found() {

View File

@ -1,7 +1,6 @@
use api_models::{user as user_api, user_role as user_role_api}; use api_models::{user as user_api, user_role as user_role_api};
use diesel_models::{enums::UserStatus, user_role::UserRoleUpdate}; use diesel_models::{enums::UserStatus, user_role::UserRoleUpdate};
use error_stack::{report, ResultExt}; use error_stack::{report, ResultExt};
use masking::ExposeInterface;
use router_env::logger; use router_env::logger;
use crate::{ use crate::{
@ -230,12 +229,7 @@ pub async fn delete_user_role(
) -> UserResponse<()> { ) -> UserResponse<()> {
let user_from_db: domain::UserFromStorage = state let user_from_db: domain::UserFromStorage = state
.store .store
.find_user_by_email( .find_user_by_email(&domain::UserEmail::from_pii_email(request.email)?.into_inner())
domain::UserEmail::from_pii_email(request.email)?
.get_secret()
.expose()
.as_str(),
)
.await .await
.map_err(|e| { .map_err(|e| {
if e.current_context().is_db_not_found() { if e.current_context().is_db_not_found() {

View File

@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use common_enums::enums::MerchantStorageScheme; use common_enums::enums::MerchantStorageScheme;
use common_utils::errors::CustomResult; use common_utils::{errors::CustomResult, pii};
use data_models::payments::{ use data_models::payments::{
payment_attempt::PaymentAttemptInterface, payment_intent::PaymentIntentInterface, payment_attempt::PaymentAttemptInterface, payment_intent::PaymentIntentInterface,
}; };
@ -2269,7 +2269,7 @@ impl UserInterface for KafkaStore {
async fn find_user_by_email( async fn find_user_by_email(
&self, &self,
user_email: &str, user_email: &pii::Email,
) -> CustomResult<storage::User, errors::StorageError> { ) -> CustomResult<storage::User, errors::StorageError> {
self.diesel_store.find_user_by_email(user_email).await self.diesel_store.find_user_by_email(user_email).await
} }
@ -2293,7 +2293,7 @@ impl UserInterface for KafkaStore {
async fn update_user_by_email( async fn update_user_by_email(
&self, &self,
user_email: &str, user_email: &pii::Email,
user: storage::UserUpdate, user: storage::UserUpdate,
) -> CustomResult<storage::User, errors::StorageError> { ) -> CustomResult<storage::User, errors::StorageError> {
self.diesel_store self.diesel_store

View File

@ -7,6 +7,7 @@ use super::MockDb;
use crate::{ use crate::{
connection, connection,
core::errors::{self, CustomResult}, core::errors::{self, CustomResult},
pii,
services::Store, services::Store,
}; };
pub mod sample_data; pub mod sample_data;
@ -20,7 +21,7 @@ pub trait UserInterface {
async fn find_user_by_email( async fn find_user_by_email(
&self, &self,
user_email: &str, user_email: &pii::Email,
) -> CustomResult<storage::User, errors::StorageError>; ) -> CustomResult<storage::User, errors::StorageError>;
async fn find_user_by_id( async fn find_user_by_id(
@ -36,7 +37,7 @@ pub trait UserInterface {
async fn update_user_by_email( async fn update_user_by_email(
&self, &self,
user_email: &str, user_email: &pii::Email,
user: storage::UserUpdate, user: storage::UserUpdate,
) -> CustomResult<storage::User, errors::StorageError>; ) -> CustomResult<storage::User, errors::StorageError>;
@ -68,7 +69,7 @@ impl UserInterface for Store {
#[instrument(skip_all)] #[instrument(skip_all)]
async fn find_user_by_email( async fn find_user_by_email(
&self, &self,
user_email: &str, user_email: &pii::Email,
) -> CustomResult<storage::User, errors::StorageError> { ) -> CustomResult<storage::User, errors::StorageError> {
let conn = connection::pg_connection_write(self).await?; let conn = connection::pg_connection_write(self).await?;
storage::User::find_by_user_email(&conn, user_email) storage::User::find_by_user_email(&conn, user_email)
@ -102,7 +103,7 @@ impl UserInterface for Store {
#[instrument(skip_all)] #[instrument(skip_all)]
async fn update_user_by_email( async fn update_user_by_email(
&self, &self,
user_email: &str, user_email: &pii::Email,
user: storage::UserUpdate, user: storage::UserUpdate,
) -> CustomResult<storage::User, errors::StorageError> { ) -> CustomResult<storage::User, errors::StorageError> {
let conn = connection::pg_connection_write(self).await?; let conn = connection::pg_connection_write(self).await?;
@ -168,20 +169,16 @@ impl UserInterface for MockDb {
async fn find_user_by_email( async fn find_user_by_email(
&self, &self,
user_email: &str, user_email: &pii::Email,
) -> CustomResult<storage::User, errors::StorageError> { ) -> CustomResult<storage::User, errors::StorageError> {
let users = self.users.lock().await; let users = self.users.lock().await;
let user_email_pii: common_utils::pii::Email = user_email
.to_string()
.try_into()
.map_err(|_| errors::StorageError::MockDbError)?;
users users
.iter() .iter()
.find(|user| user.email == user_email_pii) .find(|user| user.email.eq(user_email))
.cloned() .cloned()
.ok_or( .ok_or(
errors::StorageError::ValueNotFound(format!( errors::StorageError::ValueNotFound(format!(
"No user available for email = {user_email}" "No user available for email = {user_email:?}"
)) ))
.into(), .into(),
) )
@ -246,17 +243,13 @@ impl UserInterface for MockDb {
async fn update_user_by_email( async fn update_user_by_email(
&self, &self,
user_email: &str, user_email: &pii::Email,
update_user: storage::UserUpdate, update_user: storage::UserUpdate,
) -> CustomResult<storage::User, errors::StorageError> { ) -> CustomResult<storage::User, errors::StorageError> {
let mut users = self.users.lock().await; let mut users = self.users.lock().await;
let user_email_pii: common_utils::pii::Email = user_email
.to_string()
.try_into()
.map_err(|_| errors::StorageError::MockDbError)?;
users users
.iter_mut() .iter_mut()
.find(|user| user.email == user_email_pii) .find(|user| user.email.eq(user_email))
.map(|user| { .map(|user| {
*user = match &update_user { *user = match &update_user {
storage::UserUpdate::VerifyUser => storage::User { storage::UserUpdate::VerifyUser => storage::User {
@ -282,7 +275,7 @@ impl UserInterface for MockDb {
}) })
.ok_or( .ok_or(
errors::StorageError::ValueNotFound(format!( errors::StorageError::ValueNotFound(format!(
"No user available for user_email = {user_email}" "No user available for user_email = {user_email:?}"
)) ))
.into(), .into(),
) )

View File

@ -1,5 +1,8 @@
use api_models::user::dashboard_metadata::ProdIntent; use api_models::user::dashboard_metadata::ProdIntent;
use common_utils::errors::CustomResult; use common_utils::{
errors::{self, CustomResult},
pii,
};
use error_stack::ResultExt; use error_stack::ResultExt;
use external_services::email::{EmailContents, EmailData, EmailError}; use external_services::email::{EmailContents, EmailData, EmailError};
use masking::{ExposeInterface, PeekInterface, Secret}; use masking::{ExposeInterface, PeekInterface, Secret};
@ -167,8 +170,8 @@ impl EmailToken {
jwt::generate_jwt(&token_payload, settings).await jwt::generate_jwt(&token_payload, settings).await
} }
pub fn get_email(&self) -> &str { pub fn get_email(&self) -> CustomResult<pii::Email, errors::ParsingError> {
self.email.as_str() pii::Email::try_from(self.email.clone())
} }
pub fn get_merchant_id(&self) -> Option<&str> { pub fn get_merchant_id(&self) -> Option<&str> {

View File

@ -515,7 +515,7 @@ impl NewUser {
pub async fn check_if_already_exists_in_db(&self, state: AppState) -> UserResult<()> { pub async fn check_if_already_exists_in_db(&self, state: AppState) -> UserResult<()> {
if state if state
.store .store
.find_user_by_email(self.get_email().into_inner().expose().expose().as_str()) .find_user_by_email(&self.get_email().into_inner())
.await .await
.is_ok() .is_ok()
{ {

View File

@ -4,7 +4,7 @@ use api_models::user as user_api;
use common_utils::errors::CustomResult; use common_utils::errors::CustomResult;
use diesel_models::{enums::UserStatus, user_role::UserRole}; use diesel_models::{enums::UserStatus, user_role::UserRole};
use error_stack::ResultExt; use error_stack::ResultExt;
use masking::{ExposeInterface, Secret}; use masking::Secret;
use crate::{ use crate::{
core::errors::{StorageError, UserErrors, UserResult}, core::errors::{StorageError, UserErrors, UserResult},
@ -180,7 +180,7 @@ pub async fn get_user_from_db_by_email(
) -> CustomResult<UserFromStorage, StorageError> { ) -> CustomResult<UserFromStorage, StorageError> {
state state
.store .store
.find_user_by_email(email.get_secret().expose().as_str()) .find_user_by_email(&email.into_inner())
.await .await
.map(UserFromStorage::from) .map(UserFromStorage::from)
} }