feat: fetch merchant key store only once per session (#1400)

Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com>
This commit is contained in:
Kartikeya Hegde
2023-06-22 14:40:28 +05:30
committed by GitHub
parent 957d5e0f62
commit d321aa1f72
65 changed files with 979 additions and 498 deletions

View File

@ -5,7 +5,7 @@ use common_utils::{
ext_traits::ValueExt,
};
use error_stack::{report, FutureExt, ResultExt};
use masking::Secret; //PeekInterface
use masking::{PeekInterface, Secret};
use storage_models::enums;
use uuid::Uuid;
@ -21,7 +21,7 @@ use crate::{
types::{
self, api,
domain::{
self, merchant_key_store,
self,
types::{self as domain_types, AsyncLift},
},
storage,
@ -116,7 +116,7 @@ pub async fn create_merchant_account(
.attach_printable("Invalid routing algorithm given")?;
}
let key_store = merchant_key_store::MerchantKeyStore {
let key_store = domain::MerchantKeyStore {
merchant_id: req.merchant_id.clone(),
key: domain_types::encrypt(key.to_vec().into(), master_key)
.await
@ -131,12 +131,17 @@ pub async fn create_merchant_account(
.payment_response_hash_key
.or(Some(generate_cryptographically_secure_random_string(64)));
db.insert_merchant_key_store(key_store)
db.insert_merchant_key_store(key_store.clone(), &master_key.to_vec().into())
.await
.to_duplicate_response(errors::ApiErrorResponse::DuplicateMerchantAccount)?;
let parent_merchant_id =
get_parent_merchant(db, req.sub_merchants_enabled, req.parent_merchant_id).await?;
let parent_merchant_id = get_parent_merchant(
db,
req.sub_merchants_enabled,
req.parent_merchant_id,
&key_store,
)
.await?;
let merchant_account = async {
Ok(domain::MerchantAccount {
@ -174,7 +179,7 @@ pub async fn create_merchant_account(
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let merchant_account = db
.insert_merchant(merchant_account)
.insert_merchant(merchant_account, &key_store)
.await
.to_duplicate_response(errors::ApiErrorResponse::DuplicateMerchantAccount)?;
Ok(service_api::ApplicationResponse::Json(
@ -189,8 +194,16 @@ pub async fn get_merchant_account(
db: &dyn StorageInterface,
req: api::MerchantId,
) -> RouterResponse<api::MerchantAccountResponse> {
let key_store = db
.get_merchant_key_store_by_merchant_id(
&req.merchant_id,
&db.get_master_key().to_vec().into(),
)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
let merchant_account = db
.find_merchant_account_by_merchant_id(&req.merchant_id)
.find_merchant_account_by_merchant_id(&req.merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
@ -206,10 +219,13 @@ pub async fn merchant_account_update(
merchant_id: &String,
req: api::MerchantAccountUpdate,
) -> RouterResponse<api::MerchantAccountResponse> {
let key = domain_types::get_merchant_enc_key(db, merchant_id.clone())
let key_store = db
.get_merchant_key_store_by_merchant_id(
&req.merchant_id,
&db.get_master_key().to_vec().into(),
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to get data from merchant key store")?;
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
if &req.merchant_id != merchant_id {
Err(report!(errors::ValidationError::IncorrectValueProvided {
@ -244,11 +260,13 @@ pub async fn merchant_account_update(
})
.transpose()?;
let key = key_store.key.get_inner().peek();
let updated_merchant_account = storage::MerchantAccountUpdate::Update {
merchant_name: req
.merchant_name
.map(masking::Secret::new)
.async_lift(|inner| domain_types::encrypt_optional(inner, &key))
.async_lift(|inner| domain_types::encrypt_optional(inner, key))
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to encrypt merchant name")?,
@ -261,7 +279,7 @@ pub async fn merchant_account_update(
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to convert merchant_details to a value")?
.map(masking::Secret::new)
.async_lift(|inner| domain_types::encrypt_optional(inner, &key))
.async_lift(|inner| domain_types::encrypt_optional(inner, key))
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to encrypt merchant details")?,
@ -282,6 +300,7 @@ pub async fn merchant_account_update(
db,
req.sub_merchants_enabled,
req.parent_merchant_id,
&key_store,
)
.await?,
enable_payment_response_hash: req.enable_payment_response_hash,
@ -296,7 +315,7 @@ pub async fn merchant_account_update(
};
let response = db
.update_specific_fields_in_merchant(merchant_id, updated_merchant_account)
.update_specific_fields_in_merchant(merchant_id, updated_merchant_account, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
@ -327,6 +346,7 @@ async fn get_parent_merchant(
db: &dyn StorageInterface,
sub_merchants_enabled: Option<bool>,
parent_merchant: Option<String>,
key_store: &domain::MerchantKeyStore,
) -> RouterResult<Option<String>> {
Ok(match sub_merchants_enabled {
Some(true) => {
@ -339,7 +359,7 @@ async fn get_parent_merchant(
message: "If `sub_merchants_enabled` is `true`, then `parent_merchant_id` is mandatory".to_string(),
})
})
.map(|id| validate_merchant_id(db, id).change_context(
.map(|id| validate_merchant_id(db, id,key_store).change_context(
errors::ApiErrorResponse::InvalidDataValue { field_name: "parent_merchant_id" }
))?
.await?
@ -353,8 +373,9 @@ async fn get_parent_merchant(
async fn validate_merchant_id<S: Into<String>>(
db: &dyn StorageInterface,
merchant_id: S,
key_store: &domain::MerchantKeyStore,
) -> RouterResult<domain::MerchantAccount> {
db.find_merchant_account_by_merchant_id(&merchant_id.into())
db.find_merchant_account_by_merchant_id(&merchant_id.into(), key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)
}
@ -420,10 +441,10 @@ pub async fn create_payment_connector(
req: api::MerchantConnectorCreate,
merchant_id: &String,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
let key = domain_types::get_merchant_enc_key(store, merchant_id.clone())
let key_store = store
.get_merchant_key_store_by_merchant_id(merchant_id, &store.get_master_key().to_vec().into())
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to get key from merchant key store")?;
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
req.metadata
.clone()
@ -431,7 +452,7 @@ pub async fn create_payment_connector(
.transpose()?;
let merchant_account = store
.find_merchant_account_by_merchant_id(merchant_id)
.find_merchant_account_by_merchant_id(merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
@ -491,7 +512,7 @@ pub async fn create_payment_connector(
field_name: "connector_account_details",
},
)?,
&key,
key_store.key.peek(),
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
@ -511,7 +532,7 @@ pub async fn create_payment_connector(
};
let mca = store
.insert_merchant_connector_account(merchant_connector_account)
.insert_merchant_connector_account(merchant_connector_account, &key_store)
.await
.to_duplicate_response(
errors::ApiErrorResponse::DuplicateMerchantConnectorAccount {
@ -538,8 +559,16 @@ pub async fn retrieve_payment_connector(
merchant_id: String,
merchant_connector_id: String,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
let key_store = store
.get_merchant_key_store_by_merchant_id(
&merchant_id,
&store.get_master_key().to_vec().into(),
)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
let _merchant_account = store
.find_merchant_account_by_merchant_id(&merchant_id)
.find_merchant_account_by_merchant_id(&merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
@ -547,6 +576,7 @@ pub async fn retrieve_payment_connector(
.find_by_merchant_connector_account_merchant_id_merchant_connector_id(
&merchant_id,
&merchant_connector_id,
&key_store,
)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
@ -560,14 +590,26 @@ pub async fn list_payment_connectors(
store: &dyn StorageInterface,
merchant_id: String,
) -> RouterResponse<Vec<api_models::admin::MerchantConnectorResponse>> {
let key_store = store
.get_merchant_key_store_by_merchant_id(
&merchant_id,
&store.get_master_key().to_vec().into(),
)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
// Validate merchant account
store
.find_merchant_account_by_merchant_id(&merchant_id)
.find_merchant_account_by_merchant_id(&merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
let merchant_connector_accounts = store
.find_merchant_connector_account_by_merchant_id_and_disabled_list(&merchant_id, true)
.find_merchant_connector_account_by_merchant_id_and_disabled_list(
&merchant_id,
true,
&key_store,
)
.await
.to_not_found_response(errors::ApiErrorResponse::InternalServerError)?;
let mut response = vec![];
@ -586,12 +628,13 @@ pub async fn update_payment_connector(
merchant_connector_id: &str,
req: api_models::admin::MerchantConnectorUpdate,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
let key = domain_types::get_merchant_enc_key(db, merchant_id)
let key_store = db
.get_merchant_key_store_by_merchant_id(merchant_id, &db.get_master_key().to_vec().into())
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to get key from merchant key store")?;
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
let _merchant_account = db
.find_merchant_account_by_merchant_id(merchant_id)
.find_merchant_account_by_merchant_id(merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
@ -599,6 +642,7 @@ pub async fn update_payment_connector(
.find_by_merchant_connector_account_merchant_id_merchant_connector_id(
merchant_id,
merchant_connector_id,
&key_store,
)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
@ -631,7 +675,9 @@ pub async fn update_payment_connector(
merchant_connector_id: None,
connector_account_details: req
.connector_account_details
.async_lift(|inner| domain_types::encrypt_optional(inner, &key))
.async_lift(|inner| {
domain_types::encrypt_optional(inner, key_store.key.get_inner().peek())
})
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed while encrypting data")?,
@ -643,7 +689,7 @@ pub async fn update_payment_connector(
};
let updated_mca = db
.update_merchant_connector_account(mca, payment_connector.into())
.update_merchant_connector_account(mca, payment_connector.into(), &key_store)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable_lazy(|| {
@ -660,8 +706,13 @@ pub async fn delete_payment_connector(
merchant_id: String,
merchant_connector_id: String,
) -> RouterResponse<api::MerchantConnectorDeleteResponse> {
let key_store = db
.get_merchant_key_store_by_merchant_id(&merchant_id, &db.get_master_key().to_vec().into())
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
let _merchant_account = db
.find_merchant_account_by_merchant_id(&merchant_id)
.find_merchant_account_by_merchant_id(&merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
@ -687,9 +738,14 @@ pub async fn kv_for_merchant(
merchant_id: String,
enable: bool,
) -> RouterResponse<api_models::admin::ToggleKVResponse> {
let key_store = db
.get_merchant_key_store_by_merchant_id(&merchant_id, &db.get_master_key().to_vec().into())
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
// check if the merchant account exists
let merchant_account = db
.find_merchant_account_by_merchant_id(&merchant_id)
.find_merchant_account_by_merchant_id(&merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
@ -702,6 +758,7 @@ pub async fn kv_for_merchant(
storage::MerchantAccountUpdate::StorageSchemeUpdate {
storage_scheme: enums::MerchantStorageScheme::RedisKv,
},
&key_store,
)
.await
}
@ -711,6 +768,7 @@ pub async fn kv_for_merchant(
storage::MerchantAccountUpdate::StorageSchemeUpdate {
storage_scheme: enums::MerchantStorageScheme::PostgresOnly,
},
&key_store,
)
.await
}
@ -737,9 +795,14 @@ pub async fn check_merchant_account_kv_status(
db: &dyn StorageInterface,
merchant_id: String,
) -> RouterResponse<api_models::admin::ToggleKVResponse> {
let key_store = db
.get_merchant_key_store_by_merchant_id(&merchant_id, &db.get_master_key().to_vec().into())
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
// check if the merchant account exists
let merchant_account = db
.find_merchant_account_by_merchant_id(&merchant_id)
.find_merchant_account_by_merchant_id(&merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;