mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 09:07:09 +08:00
refactor(router): remove pii-encryption-script feature and use of timestamps for decryption (#1350)
This commit is contained in:
@ -101,7 +101,6 @@ admin_api_key = "test_admin" # admin API key for admin authentication. Only
|
|||||||
kms_encrypted_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the admin_api_key. Only applicable when KMS is enabled.
|
kms_encrypted_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the admin_api_key. Only applicable when KMS is enabled.
|
||||||
jwt_secret = "secret" # JWT secret used for user authentication. Only applicable when KMS is disabled.
|
jwt_secret = "secret" # JWT secret used for user authentication. Only applicable when KMS is disabled.
|
||||||
kms_encrypted_jwt_secret = "" # Base64-encoded (KMS encrypted) ciphertext of the jwt_secret. Only applicable when KMS is enabled.
|
kms_encrypted_jwt_secret = "" # Base64-encoded (KMS encrypted) ciphertext of the jwt_secret. Only applicable when KMS is enabled.
|
||||||
migration_encryption_timestamp = 0 # Timestamp to decide which entries are not encrypted in the database.
|
|
||||||
|
|
||||||
# Locker settings contain details for accessing a card locker, a
|
# Locker settings contain details for accessing a card locker, a
|
||||||
# PCI Compliant storage entity which stores payment method information
|
# PCI Compliant storage entity which stores payment method information
|
||||||
|
|||||||
@ -32,7 +32,6 @@ connection_timeout = 10
|
|||||||
|
|
||||||
[secrets]
|
[secrets]
|
||||||
admin_api_key = "test_admin"
|
admin_api_key = "test_admin"
|
||||||
migration_encryption_timestamp = 1682425530
|
|
||||||
master_enc_key = "73ad7bbbbc640c845a150f67d058b279849370cd2c1f3c67c4dd6c869213e13a"
|
master_enc_key = "73ad7bbbbc640c845a150f67d058b279849370cd2c1f3c67c4dd6c869213e13a"
|
||||||
|
|
||||||
[locker]
|
[locker]
|
||||||
|
|||||||
@ -16,8 +16,8 @@ kms = ["external_services/kms","dep:aws-config"]
|
|||||||
email = ["external_services/email","dep:aws-config"]
|
email = ["external_services/email","dep:aws-config"]
|
||||||
basilisk = ["kms"]
|
basilisk = ["kms"]
|
||||||
stripe = ["dep:serde_qs"]
|
stripe = ["dep:serde_qs"]
|
||||||
sandbox = ["kms", "stripe", "basilisk", "s3","email"]
|
sandbox = ["kms", "stripe", "basilisk", "s3", "email"]
|
||||||
production = ["kms", "stripe", "basilisk", "s3","pii-encryption-script","email"]
|
production = ["kms", "stripe", "basilisk", "s3", "email"]
|
||||||
olap = []
|
olap = []
|
||||||
oltp = []
|
oltp = []
|
||||||
kv_store = []
|
kv_store = []
|
||||||
@ -25,7 +25,6 @@ accounts_cache = []
|
|||||||
openapi = ["olap", "oltp"]
|
openapi = ["olap", "oltp"]
|
||||||
vergen = ["router_env/vergen"]
|
vergen = ["router_env/vergen"]
|
||||||
multiple_mca = ["api_models/multiple_mca"]
|
multiple_mca = ["api_models/multiple_mca"]
|
||||||
pii-encryption-script = []
|
|
||||||
dummy_connector = ["api_models/dummy_connector"]
|
dummy_connector = ["api_models/dummy_connector"]
|
||||||
external_access_dc = ["dummy_connector"]
|
external_access_dc = ["dummy_connector"]
|
||||||
detailed_errors = ["api_models/detailed_errors", "error-stack/serde"]
|
detailed_errors = ["api_models/detailed_errors", "error-stack/serde"]
|
||||||
|
|||||||
@ -36,24 +36,6 @@ async fn main() -> ApplicationResult<()> {
|
|||||||
|
|
||||||
let _guard = logger::setup(&conf.log);
|
let _guard = logger::setup(&conf.log);
|
||||||
|
|
||||||
#[cfg(feature = "pii-encryption-script")]
|
|
||||||
{
|
|
||||||
let store =
|
|
||||||
router::services::Store::new(&conf, false, tokio::sync::oneshot::channel().0).await;
|
|
||||||
|
|
||||||
// ^-------- KMS decryption of the master key is a fallible and the server will panic in
|
|
||||||
// the above mentioned line
|
|
||||||
|
|
||||||
router::scripts::pii_encryption::test_2_step_encryption(&store).await;
|
|
||||||
|
|
||||||
#[allow(clippy::expect_used)]
|
|
||||||
router::scripts::pii_encryption::encrypt_merchant_account_fields(&store)
|
|
||||||
.await
|
|
||||||
.expect("Failed while encrypting merchant account");
|
|
||||||
|
|
||||||
crate::logger::error!("Done with everything");
|
|
||||||
}
|
|
||||||
|
|
||||||
logger::info!("Application started [{:?}] [{:?}]", conf.server, conf.log);
|
logger::info!("Application started [{:?}] [{:?}]", conf.server, conf.log);
|
||||||
|
|
||||||
#[allow(clippy::expect_used)]
|
#[allow(clippy::expect_used)]
|
||||||
|
|||||||
@ -40,7 +40,6 @@ impl Default for super::settings::Secrets {
|
|||||||
kms_encrypted_jwt_secret: "".into(),
|
kms_encrypted_jwt_secret: "".into(),
|
||||||
#[cfg(feature = "kms")]
|
#[cfg(feature = "kms")]
|
||||||
kms_encrypted_admin_api_key: "".into(),
|
kms_encrypted_admin_api_key: "".into(),
|
||||||
migration_encryption_timestamp: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,8 +37,6 @@ pub enum Subcommand {
|
|||||||
#[cfg(feature = "openapi")]
|
#[cfg(feature = "openapi")]
|
||||||
/// Generate the OpenAPI specification file from code.
|
/// Generate the OpenAPI specification file from code.
|
||||||
GenerateOpenapiSpec,
|
GenerateOpenapiSpec,
|
||||||
#[cfg(feature = "pii-encryption-script")]
|
|
||||||
EncryptDatabase,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "kms")]
|
#[cfg(feature = "kms")]
|
||||||
@ -288,8 +286,6 @@ pub struct Secrets {
|
|||||||
pub kms_encrypted_jwt_secret: String,
|
pub kms_encrypted_jwt_secret: String,
|
||||||
#[cfg(feature = "kms")]
|
#[cfg(feature = "kms")]
|
||||||
pub kms_encrypted_admin_api_key: String,
|
pub kms_encrypted_admin_api_key: String,
|
||||||
|
|
||||||
pub migration_encryption_timestamp: i64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
|
|||||||
@ -239,7 +239,7 @@ pub async fn delete_customer(
|
|||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
.attach_printable("Failed while getting key for encryption")?;
|
.attach_printable("Failed while getting key for encryption")?;
|
||||||
let redacted_encrypted_value: Encryptable<masking::Secret<_>> =
|
let redacted_encrypted_value: Encryptable<masking::Secret<_>> =
|
||||||
Encryptable::encrypt(REDACTED.to_string().into(), &key, GcmAes256 {})
|
Encryptable::encrypt(REDACTED.to_string().into(), &key, GcmAes256)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ pub async fn delete_customer(
|
|||||||
let updated_customer = storage::CustomerUpdate::Update {
|
let updated_customer = storage::CustomerUpdate::Update {
|
||||||
name: Some(redacted_encrypted_value.clone()),
|
name: Some(redacted_encrypted_value.clone()),
|
||||||
email: Some(
|
email: Some(
|
||||||
Encryptable::encrypt(REDACTED.to_string().into(), &key, GcmAes256 {})
|
Encryptable::encrypt(REDACTED.to_string().into(), &key, GcmAes256)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?,
|
.change_context(errors::ApiErrorResponse::InternalServerError)?,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -74,16 +74,12 @@ pub trait StorageInterface:
|
|||||||
|
|
||||||
pub trait MasterKeyInterface {
|
pub trait MasterKeyInterface {
|
||||||
fn get_master_key(&self) -> &[u8];
|
fn get_master_key(&self) -> &[u8];
|
||||||
fn get_migration_timestamp(&self) -> i64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MasterKeyInterface for Store {
|
impl MasterKeyInterface for Store {
|
||||||
fn get_master_key(&self) -> &[u8] {
|
fn get_master_key(&self) -> &[u8] {
|
||||||
&self.master_key
|
&self.master_key
|
||||||
}
|
}
|
||||||
fn get_migration_timestamp(&self) -> i64 {
|
|
||||||
self.migration_timestamp
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default dummy key for MockDb
|
/// Default dummy key for MockDb
|
||||||
@ -94,10 +90,6 @@ impl MasterKeyInterface for MockDb {
|
|||||||
25, 26, 27, 28, 29, 30, 31, 32,
|
25, 26, 27, 28, 29, 30, 31, 32,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_migration_timestamp(&self) -> i64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use common_utils::ext_traits::AsyncExt;
|
|||||||
use error_stack::{IntoReport, ResultExt};
|
use error_stack::{IntoReport, ResultExt};
|
||||||
use storage_models::address::AddressUpdateInternal;
|
use storage_models::address::AddressUpdateInternal;
|
||||||
|
|
||||||
use super::{MasterKeyInterface, MockDb, Store};
|
use super::{MockDb, Store};
|
||||||
use crate::{
|
use crate::{
|
||||||
connection,
|
connection,
|
||||||
core::errors::{self, CustomResult},
|
core::errors::{self, CustomResult},
|
||||||
@ -58,7 +58,7 @@ impl AddressInterface for Store {
|
|||||||
.async_and_then(|address| async {
|
.async_and_then(|address| async {
|
||||||
let merchant_id = address.merchant_id.clone();
|
let merchant_id = address.merchant_id.clone();
|
||||||
address
|
address
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -78,7 +78,7 @@ impl AddressInterface for Store {
|
|||||||
.async_and_then(|address| async {
|
.async_and_then(|address| async {
|
||||||
let merchant_id = address.merchant_id.clone();
|
let merchant_id = address.merchant_id.clone();
|
||||||
address
|
address
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -101,7 +101,7 @@ impl AddressInterface for Store {
|
|||||||
.async_and_then(|address| async {
|
.async_and_then(|address| async {
|
||||||
let merchant_id = address.merchant_id.clone();
|
let merchant_id = address.merchant_id.clone();
|
||||||
address
|
address
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -130,7 +130,7 @@ impl AddressInterface for Store {
|
|||||||
let merchant_id = address.merchant_id.clone();
|
let merchant_id = address.merchant_id.clone();
|
||||||
output.push(
|
output.push(
|
||||||
address
|
address
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)?,
|
.change_context(errors::StorageError::DecryptionError)?,
|
||||||
)
|
)
|
||||||
@ -158,7 +158,7 @@ impl AddressInterface for MockDb {
|
|||||||
let merchant_id = address.merchant_id.clone();
|
let merchant_id = address.merchant_id.clone();
|
||||||
address
|
address
|
||||||
.clone()
|
.clone()
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -190,7 +190,7 @@ impl AddressInterface for MockDb {
|
|||||||
Some(address_updated) => {
|
Some(address_updated) => {
|
||||||
let merchant_id = address_updated.merchant_id.clone();
|
let merchant_id = address_updated.merchant_id.clone();
|
||||||
address_updated
|
address_updated
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ impl AddressInterface for MockDb {
|
|||||||
addresses.push(address.clone());
|
addresses.push(address.clone());
|
||||||
|
|
||||||
address
|
address
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -244,7 +244,7 @@ impl AddressInterface for MockDb {
|
|||||||
}) {
|
}) {
|
||||||
Some(address) => {
|
Some(address) => {
|
||||||
let address: domain::Address = address
|
let address: domain::Address = address
|
||||||
.convert(self, merchant_id, self.get_migration_timestamp())
|
.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)?;
|
.change_context(errors::StorageError::DecryptionError)?;
|
||||||
Ok(vec![address])
|
Ok(vec![address])
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use common_utils::ext_traits::AsyncExt;
|
|||||||
use error_stack::{IntoReport, ResultExt};
|
use error_stack::{IntoReport, ResultExt};
|
||||||
use masking::PeekInterface;
|
use masking::PeekInterface;
|
||||||
|
|
||||||
use super::{MasterKeyInterface, MockDb, Store};
|
use super::{MockDb, Store};
|
||||||
use crate::{
|
use crate::{
|
||||||
connection,
|
connection,
|
||||||
core::{
|
core::{
|
||||||
@ -72,7 +72,7 @@ impl CustomerInterface for Store {
|
|||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()?
|
.into_report()?
|
||||||
.async_map(|c| async {
|
.async_map(|c| async {
|
||||||
c.convert(self, merchant_id, self.get_migration_timestamp())
|
c.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -108,7 +108,7 @@ impl CustomerInterface for Store {
|
|||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|c| async {
|
.async_and_then(|c| async {
|
||||||
let merchant_id = c.merchant_id.clone();
|
let merchant_id = c.merchant_id.clone();
|
||||||
c.convert(self, &merchant_id, self.get_migration_timestamp())
|
c.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -128,7 +128,7 @@ impl CustomerInterface for Store {
|
|||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|c| async {
|
.async_and_then(|c| async {
|
||||||
let merchant_id = c.merchant_id.clone();
|
let merchant_id = c.merchant_id.clone();
|
||||||
c.convert(self, &merchant_id, self.get_migration_timestamp())
|
c.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -156,7 +156,7 @@ impl CustomerInterface for Store {
|
|||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|c| async {
|
.async_and_then(|c| async {
|
||||||
let merchant_id = c.merchant_id.clone();
|
let merchant_id = c.merchant_id.clone();
|
||||||
c.convert(self, &merchant_id, self.get_migration_timestamp())
|
c.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -194,7 +194,7 @@ impl CustomerInterface for MockDb {
|
|||||||
customer
|
customer
|
||||||
.async_map(|c| async {
|
.async_map(|c| async {
|
||||||
let merchant_id = c.merchant_id.clone();
|
let merchant_id = c.merchant_id.clone();
|
||||||
c.convert(self, &merchant_id, self.get_migration_timestamp())
|
c.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -236,7 +236,7 @@ impl CustomerInterface for MockDb {
|
|||||||
customers.push(customer.clone());
|
customers.push(customer.clone());
|
||||||
|
|
||||||
customer
|
customer
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ use crate::cache::{self, ACCOUNTS_CACHE};
|
|||||||
use crate::{
|
use crate::{
|
||||||
connection,
|
connection,
|
||||||
core::errors::{self, CustomResult},
|
core::errors::{self, CustomResult},
|
||||||
db::MasterKeyInterface,
|
|
||||||
types::{
|
types::{
|
||||||
domain::{
|
domain::{
|
||||||
self,
|
self,
|
||||||
@ -72,7 +71,7 @@ impl MerchantAccountInterface for Store {
|
|||||||
.await
|
.await
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()?
|
.into_report()?
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -93,7 +92,7 @@ impl MerchantAccountInterface for Store {
|
|||||||
{
|
{
|
||||||
fetch_func()
|
fetch_func()
|
||||||
.await?
|
.await?
|
||||||
.convert(self, merchant_id, self.get_migration_timestamp())
|
.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -102,7 +101,7 @@ impl MerchantAccountInterface for Store {
|
|||||||
{
|
{
|
||||||
super::cache::get_or_populate_in_memory(self, merchant_id, fetch_func, &ACCOUNTS_CACHE)
|
super::cache::get_or_populate_in_memory(self, merchant_id, fetch_func, &ACCOUNTS_CACHE)
|
||||||
.await?
|
.await?
|
||||||
.convert(self, merchant_id, self.get_migration_timestamp())
|
.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -124,7 +123,7 @@ impl MerchantAccountInterface for Store {
|
|||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|item| async {
|
.async_and_then(|item| async {
|
||||||
item.convert(self, &_merchant_id, self.get_migration_timestamp())
|
item.convert(self, &_merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -163,7 +162,7 @@ impl MerchantAccountInterface for Store {
|
|||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|item| async {
|
.async_and_then(|item| async {
|
||||||
item.convert(self, merchant_id, self.get_migration_timestamp())
|
item.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -197,7 +196,7 @@ impl MerchantAccountInterface for Store {
|
|||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|item| async {
|
.async_and_then(|item| async {
|
||||||
let merchant_id = item.merchant_id.clone();
|
let merchant_id = item.merchant_id.clone();
|
||||||
item.convert(self, &merchant_id, self.get_migration_timestamp())
|
item.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -248,7 +247,7 @@ impl MerchantAccountInterface for MockDb {
|
|||||||
accounts.push(account.clone());
|
accounts.push(account.clone());
|
||||||
|
|
||||||
account
|
account
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -264,7 +263,7 @@ impl MerchantAccountInterface for MockDb {
|
|||||||
.find(|account| account.merchant_id == merchant_id)
|
.find(|account| account.merchant_id == merchant_id)
|
||||||
.cloned()
|
.cloned()
|
||||||
.async_map(|a| async {
|
.async_map(|a| async {
|
||||||
a.convert(self, merchant_id, self.get_migration_timestamp())
|
a.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -7,7 +7,6 @@ use super::{MockDb, Store};
|
|||||||
use crate::{
|
use crate::{
|
||||||
connection,
|
connection,
|
||||||
core::errors::{self, CustomResult},
|
core::errors::{self, CustomResult},
|
||||||
db::MasterKeyInterface,
|
|
||||||
services::logger,
|
services::logger,
|
||||||
types::{
|
types::{
|
||||||
self,
|
self,
|
||||||
@ -166,7 +165,7 @@ impl MerchantConnectorAccountInterface for Store {
|
|||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|item| async {
|
.async_and_then(|item| async {
|
||||||
item.convert(self, merchant_id, self.get_migration_timestamp())
|
item.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -194,7 +193,7 @@ impl MerchantConnectorAccountInterface for Store {
|
|||||||
{
|
{
|
||||||
find_call()
|
find_call()
|
||||||
.await?
|
.await?
|
||||||
.convert(self, merchant_id, self.get_migration_timestamp())
|
.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DeserializationFailed)
|
.change_context(errors::StorageError::DeserializationFailed)
|
||||||
}
|
}
|
||||||
@ -203,7 +202,7 @@ impl MerchantConnectorAccountInterface for Store {
|
|||||||
{
|
{
|
||||||
cache::get_or_populate_redis(self, merchant_connector_id, find_call)
|
cache::get_or_populate_redis(self, merchant_connector_id, find_call)
|
||||||
.await?
|
.await?
|
||||||
.convert(self, merchant_id, self.get_migration_timestamp())
|
.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DeserializationFailed)
|
.change_context(errors::StorageError::DeserializationFailed)
|
||||||
}
|
}
|
||||||
@ -223,7 +222,7 @@ impl MerchantConnectorAccountInterface for Store {
|
|||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|item| async {
|
.async_and_then(|item| async {
|
||||||
let merchant_id = item.merchant_id.clone();
|
let merchant_id = item.merchant_id.clone();
|
||||||
item.convert(self, &merchant_id, self.get_migration_timestamp())
|
item.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -244,7 +243,7 @@ impl MerchantConnectorAccountInterface for Store {
|
|||||||
let mut output = Vec::with_capacity(items.len());
|
let mut output = Vec::with_capacity(items.len());
|
||||||
for item in items.into_iter() {
|
for item in items.into_iter() {
|
||||||
output.push(
|
output.push(
|
||||||
item.convert(self, merchant_id, self.get_migration_timestamp())
|
item.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)?,
|
.change_context(errors::StorageError::DecryptionError)?,
|
||||||
)
|
)
|
||||||
@ -271,7 +270,7 @@ impl MerchantConnectorAccountInterface for Store {
|
|||||||
.into_report()
|
.into_report()
|
||||||
.async_and_then(|item| async {
|
.async_and_then(|item| async {
|
||||||
let merchant_id = item.merchant_id.clone();
|
let merchant_id = item.merchant_id.clone();
|
||||||
item.convert(self, &merchant_id, self.get_migration_timestamp())
|
item.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
})
|
})
|
||||||
@ -324,7 +323,7 @@ impl MerchantConnectorAccountInterface for MockDb {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
account
|
account
|
||||||
.convert(self, merchant_id, self.get_migration_timestamp())
|
.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -367,7 +366,7 @@ impl MerchantConnectorAccountInterface for MockDb {
|
|||||||
};
|
};
|
||||||
accounts.push(account.clone());
|
accounts.push(account.clone());
|
||||||
account
|
account
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use error_stack::{IntoReport, ResultExt};
|
use error_stack::{IntoReport, ResultExt};
|
||||||
|
|
||||||
use super::MasterKeyInterface;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
connection,
|
connection,
|
||||||
core::errors::{self, CustomResult},
|
core::errors::{self, CustomResult},
|
||||||
@ -41,7 +40,7 @@ impl MerchantKeyStoreInterface for Store {
|
|||||||
.await
|
.await
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()?
|
.into_report()?
|
||||||
.convert(self, &merchant_id, self.get_migration_timestamp())
|
.convert(self, &merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
@ -57,7 +56,7 @@ impl MerchantKeyStoreInterface for Store {
|
|||||||
.await
|
.await
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.into_report()?
|
.into_report()?
|
||||||
.convert(self, merchant_id, self.get_migration_timestamp())
|
.convert(self, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::StorageError::DecryptionError)
|
.change_context(errors::StorageError::DecryptionError)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@ pub mod scheduler;
|
|||||||
pub mod middleware;
|
pub mod middleware;
|
||||||
#[cfg(feature = "openapi")]
|
#[cfg(feature = "openapi")]
|
||||||
pub mod openapi;
|
pub mod openapi;
|
||||||
pub mod scripts;
|
|
||||||
pub mod services;
|
pub mod services;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
#[cfg(feature = "pii-encryption-script")]
|
|
||||||
pub mod pii_encryption;
|
|
||||||
@ -1,421 +0,0 @@
|
|||||||
use async_bb8_diesel::AsyncConnection;
|
|
||||||
use common_utils::errors::CustomResult;
|
|
||||||
use diesel::{associations::HasTable, ExpressionMethods, Table};
|
|
||||||
use error_stack::{IntoReport, ResultExt};
|
|
||||||
use storage_models::{
|
|
||||||
address::Address,
|
|
||||||
customers::Customer,
|
|
||||||
merchant_account::MerchantAccount,
|
|
||||||
merchant_connector_account::MerchantConnectorAccount,
|
|
||||||
query::generics::generic_filter,
|
|
||||||
schema::{
|
|
||||||
address::dsl as ad_dsl, customers::dsl as cu_dsl, merchant_account::dsl as ma_dsl,
|
|
||||||
merchant_connector_account::dsl as mca_dsl,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
connection,
|
|
||||||
core::errors,
|
|
||||||
db::{
|
|
||||||
merchant_account::MerchantAccountInterface, merchant_key_store::MerchantKeyStoreInterface,
|
|
||||||
MasterKeyInterface,
|
|
||||||
},
|
|
||||||
services::{self, Store},
|
|
||||||
types::{
|
|
||||||
domain::{
|
|
||||||
self,
|
|
||||||
behaviour::{Conversion, ReverseConversion},
|
|
||||||
merchant_key_store, types,
|
|
||||||
},
|
|
||||||
storage,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub async fn create_merchant_key_store(
|
|
||||||
state: &Store,
|
|
||||||
merchant_id: &str,
|
|
||||||
key: Vec<u8>,
|
|
||||||
) -> CustomResult<(), errors::ApiErrorResponse> {
|
|
||||||
crate::logger::info!("Trying to create MerchantKeyStore for {}", merchant_id);
|
|
||||||
let master_key = state.get_master_key();
|
|
||||||
let key_store = merchant_key_store::MerchantKeyStore {
|
|
||||||
merchant_id: merchant_id.to_string(),
|
|
||||||
key: types::encrypt(key.into(), master_key)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
|
||||||
.attach_printable("Failed to decrypt data from key store")?,
|
|
||||||
created_at: common_utils::date_time::now(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match state.insert_merchant_key_store(key_store).await {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(err) => match err.current_context() {
|
|
||||||
errors::StorageError::DatabaseError(f) => match f.current_context() {
|
|
||||||
storage_models::errors::DatabaseError::UniqueViolation => Ok(()),
|
|
||||||
_ => Err(err.change_context(errors::ApiErrorResponse::InternalServerError)),
|
|
||||||
},
|
|
||||||
_ => Err(err.change_context(errors::ApiErrorResponse::InternalServerError)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn encrypt_merchant_account_fields(
|
|
||||||
state: &Store,
|
|
||||||
) -> CustomResult<(), errors::ApiErrorResponse> {
|
|
||||||
let conn = connection::pg_connection_write(state)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
let merchants: Vec<MerchantAccount> = generic_filter::<
|
|
||||||
<MerchantAccount as HasTable>::Table,
|
|
||||||
_,
|
|
||||||
<<MerchantAccount as HasTable>::Table as Table>::PrimaryKey,
|
|
||||||
_,
|
|
||||||
>(
|
|
||||||
&conn,
|
|
||||||
ma_dsl::merchant_id.eq(ma_dsl::merchant_id),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
for mer in merchants.iter() {
|
|
||||||
let key = services::generate_aes256_key()
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
create_merchant_key_store(state, &mer.merchant_id, key.to_vec()).await?;
|
|
||||||
}
|
|
||||||
let mut domain_merchants = Vec::with_capacity(merchants.len());
|
|
||||||
for mf in merchants.into_iter() {
|
|
||||||
let merchant_id = mf.merchant_id.clone();
|
|
||||||
let domain_merchant: domain::MerchantAccount = mf
|
|
||||||
.convert(state, &merchant_id, state.get_migration_timestamp())
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
domain_merchants.push(domain_merchant);
|
|
||||||
}
|
|
||||||
for m in domain_merchants {
|
|
||||||
let merchant_id = m.merchant_id.clone();
|
|
||||||
let updated_merchant_account = storage::MerchantAccountUpdate::Update {
|
|
||||||
merchant_name: m.merchant_name.clone(),
|
|
||||||
merchant_details: m.merchant_details.clone(),
|
|
||||||
return_url: None,
|
|
||||||
webhook_details: None,
|
|
||||||
sub_merchants_enabled: None,
|
|
||||||
parent_merchant_id: None,
|
|
||||||
primary_business_details: None,
|
|
||||||
enable_payment_response_hash: None,
|
|
||||||
payment_response_hash_key: None,
|
|
||||||
redirect_to_merchant_with_http_post: None,
|
|
||||||
routing_algorithm: None,
|
|
||||||
locker_id: None,
|
|
||||||
publishable_key: None,
|
|
||||||
metadata: None,
|
|
||||||
intent_fulfillment_time: None,
|
|
||||||
frm_routing_algorithm: None,
|
|
||||||
};
|
|
||||||
crate::logger::warn!("Started for {}", merchant_id);
|
|
||||||
state
|
|
||||||
.update_merchant(m, updated_merchant_account)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
encrypt_merchant_connector_account_fields(state, &merchant_id).await?;
|
|
||||||
encrypt_customer_fields(state, &merchant_id).await?;
|
|
||||||
encrypt_address_fields(state, &merchant_id).await?;
|
|
||||||
crate::logger::warn!("Done for {}", merchant_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn encrypt_merchant_connector_account_fields(
|
|
||||||
state: &Store,
|
|
||||||
merchant_id: &str,
|
|
||||||
) -> CustomResult<(), errors::ApiErrorResponse> {
|
|
||||||
crate::logger::warn!("Updating MerchantConnectorAccount for {}", merchant_id);
|
|
||||||
let conn = connection::pg_connection_write(state)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
let merchants: Vec<MerchantConnectorAccount> = generic_filter::<
|
|
||||||
<MerchantConnectorAccount as HasTable>::Table,
|
|
||||||
_,
|
|
||||||
<<MerchantConnectorAccount as HasTable>::Table as Table>::PrimaryKey,
|
|
||||||
_,
|
|
||||||
>(
|
|
||||||
&conn,
|
|
||||||
mca_dsl::merchant_id.eq(merchant_id.to_string()),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
let mut domain_merchants = Vec::with_capacity(merchants.len());
|
|
||||||
for m in merchants.into_iter() {
|
|
||||||
let merchant_id = m.merchant_id.clone();
|
|
||||||
let domain_merchant: domain::MerchantConnectorAccount = m
|
|
||||||
.convert(state, &merchant_id, state.get_migration_timestamp())
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
domain_merchants.push(domain_merchant);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.transaction_async::<(), async_bb8_diesel::ConnectionError, _, _>(|conn| async move {
|
|
||||||
for m in domain_merchants {
|
|
||||||
let updated_merchant_connector_account =
|
|
||||||
storage::MerchantConnectorAccountUpdate::Update {
|
|
||||||
merchant_id: None,
|
|
||||||
connector_name: None,
|
|
||||||
connector_type: None,
|
|
||||||
frm_configs: None,
|
|
||||||
test_mode: None,
|
|
||||||
disabled: None,
|
|
||||||
merchant_connector_id: None,
|
|
||||||
payment_methods_enabled: None,
|
|
||||||
metadata: None,
|
|
||||||
connector_account_details: Some(m.connector_account_details.clone()),
|
|
||||||
};
|
|
||||||
|
|
||||||
Conversion::convert(m)
|
|
||||||
.await
|
|
||||||
.map_err(|_| {
|
|
||||||
async_bb8_diesel::ConnectionError::Query(
|
|
||||||
diesel::result::Error::QueryBuilderError(
|
|
||||||
"Error while decrypting MerchantConnectorAccount".into(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.update(&conn, updated_merchant_connector_account.into())
|
|
||||||
.await
|
|
||||||
.map_err(|_| {
|
|
||||||
async_bb8_diesel::ConnectionError::Query(
|
|
||||||
diesel::result::Error::QueryBuilderError(
|
|
||||||
"Error while updating MerchantConnectorAccount".into(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.into_report()
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
crate::logger::warn!(
|
|
||||||
"Done: Updating MerchantConnectorAccount for {}",
|
|
||||||
merchant_id
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn encrypt_customer_fields(
|
|
||||||
state: &Store,
|
|
||||||
merchant_id: &str,
|
|
||||||
) -> CustomResult<(), errors::ApiErrorResponse> {
|
|
||||||
crate::logger::warn!("Updating Customer for {}", merchant_id);
|
|
||||||
let conn = connection::pg_connection_write(state)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
let merchants: Vec<Customer> = generic_filter::<
|
|
||||||
<Customer as HasTable>::Table,
|
|
||||||
_,
|
|
||||||
<<Customer as HasTable>::Table as Table>::PrimaryKey,
|
|
||||||
_,
|
|
||||||
>(
|
|
||||||
&conn,
|
|
||||||
cu_dsl::merchant_id.eq(merchant_id.to_string()),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
let mut domain_merchants = Vec::with_capacity(merchants.len());
|
|
||||||
for m in merchants.into_iter() {
|
|
||||||
let merchant_id = m.merchant_id.clone();
|
|
||||||
let domain_merchant: domain::Customer = m
|
|
||||||
.convert(state, &merchant_id, state.get_migration_timestamp())
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
domain_merchants.push(domain_merchant);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.transaction_async::<(), async_bb8_diesel::ConnectionError, _, _>(|conn| async move {
|
|
||||||
for m in domain_merchants {
|
|
||||||
let update_customer = storage::CustomerUpdate::Update {
|
|
||||||
name: m.name.clone(),
|
|
||||||
email: m.email.clone(),
|
|
||||||
phone: m.phone.clone(),
|
|
||||||
description: None,
|
|
||||||
metadata: None,
|
|
||||||
phone_country_code: None,
|
|
||||||
connector_customer: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Customer::update_by_customer_id_merchant_id(
|
|
||||||
&conn,
|
|
||||||
m.customer_id.to_string(),
|
|
||||||
m.merchant_id.to_string(),
|
|
||||||
update_customer.into(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|_| {
|
|
||||||
async_bb8_diesel::ConnectionError::Query(diesel::result::Error::QueryBuilderError(
|
|
||||||
"Error while updating Customer".into(),
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.into_report()
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
crate::logger::warn!("Done: Updating Customer for {}", merchant_id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn encrypt_address_fields(
|
|
||||||
state: &Store,
|
|
||||||
merchant_id: &str,
|
|
||||||
) -> CustomResult<(), errors::ApiErrorResponse> {
|
|
||||||
crate::logger::warn!("Updating Address for {}", merchant_id);
|
|
||||||
let conn = connection::pg_connection_write(state)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
let merchants: Vec<Address> = generic_filter::<
|
|
||||||
<Address as HasTable>::Table,
|
|
||||||
_,
|
|
||||||
<<Address as HasTable>::Table as Table>::PrimaryKey,
|
|
||||||
_,
|
|
||||||
>(
|
|
||||||
&conn,
|
|
||||||
ad_dsl::merchant_id.eq(merchant_id.to_string()),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
let mut domain_merchants = Vec::with_capacity(merchants.len());
|
|
||||||
for m in merchants.into_iter() {
|
|
||||||
let merchant_id = m.merchant_id.clone();
|
|
||||||
let domain_merchant: domain::Address = m
|
|
||||||
.convert(state, &merchant_id, state.get_migration_timestamp())
|
|
||||||
.await
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
domain_merchants.push(domain_merchant);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.transaction_async::<(), async_bb8_diesel::ConnectionError, _, _>(|conn| async move {
|
|
||||||
for m in domain_merchants {
|
|
||||||
let update_address = storage::address::AddressUpdate::Update {
|
|
||||||
line1: m.line1.clone(),
|
|
||||||
line2: m.line2.clone(),
|
|
||||||
line3: m.line3.clone(),
|
|
||||||
state: m.state.clone(),
|
|
||||||
zip: m.zip.clone(),
|
|
||||||
first_name: m.first_name.clone(),
|
|
||||||
last_name: m.last_name.clone(),
|
|
||||||
phone_number: m.phone_number.clone(),
|
|
||||||
city: None,
|
|
||||||
country: None,
|
|
||||||
country_code: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Address::update_by_address_id(&conn, m.address_id, update_address.into())
|
|
||||||
.await
|
|
||||||
.map_err(|_| {
|
|
||||||
async_bb8_diesel::ConnectionError::Query(
|
|
||||||
diesel::result::Error::QueryBuilderError(
|
|
||||||
"Error while updating Address".into(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.into_report()
|
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
|
||||||
|
|
||||||
crate::logger::warn!("Done: Updating Address for {}", merchant_id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// The functions runs at the start of the migration and tests, all the functional parts of
|
|
||||||
/// encryption.
|
|
||||||
///
|
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
pub async fn test_2_step_encryption(store: &Store) {
|
|
||||||
use masking::ExposeInterface;
|
|
||||||
let (encrypted_merchant_key, master_key) = {
|
|
||||||
let master_key = store.get_master_key();
|
|
||||||
let merchant_key: Vec<u8> = services::generate_aes256_key().unwrap().into();
|
|
||||||
let encrypted_merchant_key =
|
|
||||||
types::encrypt::<_, crate::pii::WithType>(merchant_key.into(), master_key)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.into_encrypted();
|
|
||||||
let encrypted_merchant_key =
|
|
||||||
storage_models::encryption::Encryption::new(encrypted_merchant_key);
|
|
||||||
(encrypted_merchant_key, master_key)
|
|
||||||
};
|
|
||||||
|
|
||||||
let dummy_data = "Hello, World!".to_string();
|
|
||||||
let encrypted_dummy_data = storage_models::encryption::Encryption::new(
|
|
||||||
types::encrypt::<_, crate::pii::WithType>(
|
|
||||||
masking::Secret::new(dummy_data.clone()),
|
|
||||||
&types::decrypt::<Vec<u8>, crate::pii::WithType>(
|
|
||||||
Some(encrypted_merchant_key.clone()),
|
|
||||||
master_key,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
.expose(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.into_encrypted(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let dummy_data_returned = types::decrypt::<String, crate::pii::WithType>(
|
|
||||||
Some(encrypted_dummy_data),
|
|
||||||
&types::decrypt::<Vec<u8>, crate::pii::WithType>(
|
|
||||||
Some(encrypted_merchant_key),
|
|
||||||
master_key,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
.expose(),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
.expose();
|
|
||||||
|
|
||||||
assert!(dummy_data_returned == dummy_data)
|
|
||||||
}
|
|
||||||
@ -119,7 +119,6 @@ pub struct Store {
|
|||||||
#[cfg(feature = "kv_store")]
|
#[cfg(feature = "kv_store")]
|
||||||
pub(crate) config: StoreConfig,
|
pub(crate) config: StoreConfig,
|
||||||
pub master_key: Vec<u8>,
|
pub master_key: Vec<u8>,
|
||||||
pub migration_timestamp: i64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "kv_store")]
|
#[cfg(feature = "kv_store")]
|
||||||
@ -183,7 +182,6 @@ impl Store {
|
|||||||
drainer_num_partitions: config.drainer.num_partitions,
|
drainer_num_partitions: config.drainer.num_partitions,
|
||||||
},
|
},
|
||||||
master_key: master_enc_key,
|
master_key: master_enc_key,
|
||||||
migration_timestamp: config.secrets.migration_encryption_timestamp,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,6 @@ impl behaviour::Conversion for Address {
|
|||||||
other: Self::DstType,
|
other: Self::DstType,
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, ValidationError> {
|
) -> CustomResult<Self, ValidationError> {
|
||||||
let key = types::get_merchant_enc_key(db, merchant_id)
|
let key = types::get_merchant_enc_key(db, merchant_id)
|
||||||
.await
|
.await
|
||||||
@ -83,9 +82,7 @@ impl behaviour::Conversion for Address {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
async {
|
async {
|
||||||
let modified_at = other.modified_at.assume_utc().unix_timestamp();
|
let inner_decrypt = |inner| types::decrypt(inner, &key);
|
||||||
let inner_decrypt =
|
|
||||||
|inner| types::decrypt(inner, &key, modified_at, migration_timestamp);
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id: Some(other.id),
|
id: Some(other.id),
|
||||||
address_id: other.address_id,
|
address_id: other.address_id,
|
||||||
|
|||||||
@ -13,7 +13,6 @@ pub trait Conversion {
|
|||||||
item: Self::DstType,
|
item: Self::DstType,
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, ValidationError>
|
) -> CustomResult<Self, ValidationError>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
@ -27,7 +26,6 @@ pub trait ReverseConversion<SrcType: Conversion> {
|
|||||||
self,
|
self,
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<SrcType, ValidationError>;
|
) -> CustomResult<SrcType, ValidationError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +35,7 @@ impl<T: Send, U: Conversion<DstType = T>> ReverseConversion<U> for T {
|
|||||||
self,
|
self,
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<U, ValidationError> {
|
) -> CustomResult<U, ValidationError> {
|
||||||
U::convert_back(self, db, merchant_id, migration_timestamp).await
|
U::convert_back(self, db, merchant_id).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,7 +55,6 @@ impl super::behaviour::Conversion for Customer {
|
|||||||
item: Self::DstType,
|
item: Self::DstType,
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, ValidationError>
|
) -> CustomResult<Self, ValidationError>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@ -66,12 +65,8 @@ impl super::behaviour::Conversion for Customer {
|
|||||||
message: "Failed while getting key from key store".to_string(),
|
message: "Failed while getting key from key store".to_string(),
|
||||||
})?;
|
})?;
|
||||||
async {
|
async {
|
||||||
let modified_at = item.modified_at.assume_utc().unix_timestamp();
|
let inner_decrypt = |inner| types::decrypt(inner, &key);
|
||||||
|
let inner_decrypt_email = |inner| types::decrypt(inner, &key);
|
||||||
let inner_decrypt =
|
|
||||||
|inner| types::decrypt(inner, &key, modified_at, migration_timestamp);
|
|
||||||
let inner_decrypt_email =
|
|
||||||
|inner| types::decrypt(inner, &key, modified_at, migration_timestamp);
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id: Some(item.id),
|
id: Some(item.id),
|
||||||
customer_id: item.customer_id,
|
customer_id: item.customer_id,
|
||||||
|
|||||||
@ -149,7 +149,6 @@ impl super::behaviour::Conversion for MerchantAccount {
|
|||||||
item: Self::DstType,
|
item: Self::DstType,
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, ValidationError>
|
) -> CustomResult<Self, ValidationError>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@ -160,7 +159,6 @@ impl super::behaviour::Conversion for MerchantAccount {
|
|||||||
message: "Failed while getting key from key store".to_string(),
|
message: "Failed while getting key from key store".to_string(),
|
||||||
})?;
|
})?;
|
||||||
async {
|
async {
|
||||||
let modified_at = item.modified_at.assume_utc().unix_timestamp();
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id: Some(item.id),
|
id: Some(item.id),
|
||||||
merchant_id: item.merchant_id,
|
merchant_id: item.merchant_id,
|
||||||
@ -170,15 +168,11 @@ impl super::behaviour::Conversion for MerchantAccount {
|
|||||||
redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
|
redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
|
||||||
merchant_name: item
|
merchant_name: item
|
||||||
.merchant_name
|
.merchant_name
|
||||||
.async_lift(|inner| {
|
.async_lift(|inner| types::decrypt(inner, &key))
|
||||||
types::decrypt(inner, &key, modified_at, migration_timestamp)
|
|
||||||
})
|
|
||||||
.await?,
|
.await?,
|
||||||
merchant_details: item
|
merchant_details: item
|
||||||
.merchant_details
|
.merchant_details
|
||||||
.async_lift(|inner| {
|
.async_lift(|inner| types::decrypt(inner, &key))
|
||||||
types::decrypt(inner, &key, modified_at, migration_timestamp)
|
|
||||||
})
|
|
||||||
.await?,
|
.await?,
|
||||||
webhook_details: item.webhook_details,
|
webhook_details: item.webhook_details,
|
||||||
sub_merchants_enabled: item.sub_merchants_enabled,
|
sub_merchants_enabled: item.sub_merchants_enabled,
|
||||||
|
|||||||
@ -89,14 +89,12 @@ impl behaviour::Conversion for MerchantConnectorAccount {
|
|||||||
other: Self::DstType,
|
other: Self::DstType,
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, ValidationError> {
|
) -> CustomResult<Self, ValidationError> {
|
||||||
let key = types::get_merchant_enc_key(db, merchant_id)
|
let key = types::get_merchant_enc_key(db, merchant_id)
|
||||||
.await
|
.await
|
||||||
.change_context(ValidationError::InvalidValue {
|
.change_context(ValidationError::InvalidValue {
|
||||||
message: "Error while getting key from keystore".to_string(),
|
message: "Error while getting key from keystore".to_string(),
|
||||||
})?;
|
})?;
|
||||||
let modified_at = other.modified_at.assume_utc().unix_timestamp();
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id: Some(other.id),
|
id: Some(other.id),
|
||||||
@ -105,9 +103,7 @@ impl behaviour::Conversion for MerchantConnectorAccount {
|
|||||||
connector_account_details: Encryptable::decrypt(
|
connector_account_details: Encryptable::decrypt(
|
||||||
other.connector_account_details,
|
other.connector_account_details,
|
||||||
&key,
|
&key,
|
||||||
GcmAes256 {},
|
GcmAes256,
|
||||||
modified_at,
|
|
||||||
migration_timestamp,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.change_context(ValidationError::InvalidValue {
|
.change_context(ValidationError::InvalidValue {
|
||||||
|
|||||||
@ -36,14 +36,13 @@ impl super::behaviour::Conversion for MerchantKeyStore {
|
|||||||
item: Self::DstType,
|
item: Self::DstType,
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
_merchant_id: &str,
|
_merchant_id: &str,
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, ValidationError>
|
) -> CustomResult<Self, ValidationError>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let key = &db.get_master_key();
|
let key = &db.get_master_key();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
key: Encryptable::decrypt(item.key, key, GcmAes256 {}, i64::MAX, migration_timestamp)
|
key: Encryptable::decrypt(item.key, key, GcmAes256)
|
||||||
.await
|
.await
|
||||||
.change_context(ValidationError::InvalidValue {
|
.change_context(ValidationError::InvalidValue {
|
||||||
message: "Failed while decrypting customer data".to_string(),
|
message: "Failed while decrypting customer data".to_string(),
|
||||||
|
|||||||
@ -23,12 +23,11 @@ pub trait TypeEncryption<
|
|||||||
key: &[u8],
|
key: &[u8],
|
||||||
crypt_algo: V,
|
crypt_algo: V,
|
||||||
) -> CustomResult<Self, errors::CryptoError>;
|
) -> CustomResult<Self, errors::CryptoError>;
|
||||||
|
|
||||||
async fn decrypt(
|
async fn decrypt(
|
||||||
encrypted_data: Encryption,
|
encrypted_data: Encryption,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
crypt_algo: V,
|
crypt_algo: V,
|
||||||
timestamp: i64,
|
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, errors::CryptoError>;
|
) -> CustomResult<Self, errors::CryptoError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,22 +53,9 @@ impl<
|
|||||||
encrypted_data: Encryption,
|
encrypted_data: Encryption,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
crypt_algo: V,
|
crypt_algo: V,
|
||||||
timestamp: i64,
|
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, errors::CryptoError> {
|
) -> CustomResult<Self, errors::CryptoError> {
|
||||||
let encrypted = encrypted_data.into_inner();
|
let encrypted = encrypted_data.into_inner();
|
||||||
|
let data = crypt_algo.decode_message(key, encrypted.clone())?;
|
||||||
let (data, encrypted) = if timestamp < migration_timestamp {
|
|
||||||
(
|
|
||||||
encrypted.clone(),
|
|
||||||
crypt_algo.encode_message(key, &encrypted)?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
crypt_algo.decode_message(key, encrypted.clone())?,
|
|
||||||
encrypted,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let value: String = std::str::from_utf8(&data)
|
let value: String = std::str::from_utf8(&data)
|
||||||
.into_report()
|
.into_report()
|
||||||
@ -106,21 +92,9 @@ impl<
|
|||||||
encrypted_data: Encryption,
|
encrypted_data: Encryption,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
crypt_algo: V,
|
crypt_algo: V,
|
||||||
timestamp: i64,
|
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, errors::CryptoError> {
|
) -> CustomResult<Self, errors::CryptoError> {
|
||||||
let encrypted = encrypted_data.into_inner();
|
let encrypted = encrypted_data.into_inner();
|
||||||
let (data, encrypted) = if timestamp < migration_timestamp {
|
let data = crypt_algo.decode_message(key, encrypted.clone())?;
|
||||||
(
|
|
||||||
encrypted.clone(),
|
|
||||||
crypt_algo.encode_message(key, &encrypted)?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
crypt_algo.decode_message(key, encrypted.clone())?,
|
|
||||||
encrypted,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let value: serde_json::Value = serde_json::from_slice(&data)
|
let value: serde_json::Value = serde_json::from_slice(&data)
|
||||||
.into_report()
|
.into_report()
|
||||||
@ -152,22 +126,10 @@ impl<
|
|||||||
encrypted_data: Encryption,
|
encrypted_data: Encryption,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
crypt_algo: V,
|
crypt_algo: V,
|
||||||
timestamp: i64,
|
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Self, errors::CryptoError> {
|
) -> CustomResult<Self, errors::CryptoError> {
|
||||||
let encrypted = encrypted_data.into_inner();
|
let encrypted = encrypted_data.into_inner();
|
||||||
|
let data = crypt_algo.decode_message(key, encrypted.clone())?;
|
||||||
|
|
||||||
let (data, encrypted) = if timestamp < migration_timestamp {
|
|
||||||
(
|
|
||||||
encrypted.clone(),
|
|
||||||
crypt_algo.encode_message(key, &encrypted)?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
crypt_algo.decode_message(key, encrypted.clone())?,
|
|
||||||
encrypted,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
Ok(Self::new(data.into(), encrypted))
|
Ok(Self::new(data.into(), encrypted))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +203,7 @@ where
|
|||||||
crypto::Encryptable<Secret<E, S>>: TypeEncryption<E, crypto::GcmAes256, S>,
|
crypto::Encryptable<Secret<E, S>>: TypeEncryption<E, crypto::GcmAes256, S>,
|
||||||
{
|
{
|
||||||
request::record_operation_time(
|
request::record_operation_time(
|
||||||
crypto::Encryptable::encrypt(inner, key, crypto::GcmAes256 {}),
|
crypto::Encryptable::encrypt(inner, key, crypto::GcmAes256),
|
||||||
&ENCRYPTION_TIME,
|
&ENCRYPTION_TIME,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@ -264,22 +226,12 @@ where
|
|||||||
pub async fn decrypt<T: Clone, S: masking::Strategy<T>>(
|
pub async fn decrypt<T: Clone, S: masking::Strategy<T>>(
|
||||||
inner: Option<Encryption>,
|
inner: Option<Encryption>,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
timestamp: i64,
|
|
||||||
migration_timestamp: i64,
|
|
||||||
) -> CustomResult<Option<crypto::Encryptable<Secret<T, S>>>, errors::CryptoError>
|
) -> CustomResult<Option<crypto::Encryptable<Secret<T, S>>>, errors::CryptoError>
|
||||||
where
|
where
|
||||||
crypto::Encryptable<Secret<T, S>>: TypeEncryption<T, crypto::GcmAes256, S>,
|
crypto::Encryptable<Secret<T, S>>: TypeEncryption<T, crypto::GcmAes256, S>,
|
||||||
{
|
{
|
||||||
request::record_operation_time(
|
request::record_operation_time(
|
||||||
inner.async_map(|item| {
|
inner.async_map(|item| crypto::Encryptable::decrypt(item, key, crypto::GcmAes256)),
|
||||||
crypto::Encryptable::decrypt(
|
|
||||||
item,
|
|
||||||
key,
|
|
||||||
crypto::GcmAes256 {},
|
|
||||||
timestamp,
|
|
||||||
migration_timestamp,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
&DECRYPTION_TIME,
|
&DECRYPTION_TIME,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
Reference in New Issue
Block a user