feat: encryption service integration to support batch encryption and decryption (#5164)

Co-authored-by: dracarys18 <karthikey.hegde@juspay.in>
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Arjun Karthik
2024-07-19 13:08:58 +05:30
committed by GitHub
parent c698921c41
commit 33298b3808
127 changed files with 4239 additions and 1378 deletions

View File

@ -1,5 +1,12 @@
use common_utils::{crypto, custom_serde, id_type, pii};
use masking::Secret;
use common_utils::{
crypto, custom_serde,
encryption::Encryption,
id_type,
pii::{self, EmailStrategy},
types::keymanager::ToEncryptable,
};
use euclid::dssa::graph::euclid_graph_prelude::FxHashMap;
use masking::{ExposeInterface, Secret, SwitchStrategy};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
@ -40,6 +47,85 @@ pub struct CustomerRequest {
pub metadata: Option<pii::SecretSerdeValue>,
}
pub struct CustomerRequestWithEmail {
pub name: Option<Secret<String>>,
pub email: Option<pii::Email>,
pub phone: Option<Secret<String>>,
}
pub struct CustomerRequestWithEncryption {
pub name: Option<Encryption>,
pub phone: Option<Encryption>,
pub email: Option<Encryption>,
}
pub struct EncryptableCustomer {
pub name: crypto::OptionalEncryptableName,
pub phone: crypto::OptionalEncryptablePhone,
pub email: crypto::OptionalEncryptableEmail,
}
impl ToEncryptable<EncryptableCustomer, Secret<String>, Encryption>
for CustomerRequestWithEncryption
{
fn to_encryptable(self) -> FxHashMap<String, Encryption> {
let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default());
self.name.map(|x| map.insert("name".to_string(), x));
self.phone.map(|x| map.insert("phone".to_string(), x));
self.email.map(|x| map.insert("email".to_string(), x));
map
}
fn from_encryptable(
mut hashmap: FxHashMap<String, crypto::Encryptable<Secret<String>>>,
) -> common_utils::errors::CustomResult<EncryptableCustomer, common_utils::errors::ParsingError>
{
Ok(EncryptableCustomer {
name: hashmap.remove("name"),
phone: hashmap.remove("phone"),
email: hashmap.remove("email").map(|email| {
let encryptable: crypto::Encryptable<Secret<String, EmailStrategy>> =
crypto::Encryptable::new(
email.clone().into_inner().switch_strategy(),
email.into_encrypted(),
);
encryptable
}),
})
}
}
impl ToEncryptable<EncryptableCustomer, Secret<String>, Secret<String>>
for CustomerRequestWithEmail
{
fn to_encryptable(self) -> FxHashMap<String, Secret<String>> {
let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default());
self.name.map(|x| map.insert("name".to_string(), x));
self.phone.map(|x| map.insert("phone".to_string(), x));
self.email
.map(|x| map.insert("email".to_string(), x.expose().switch_strategy()));
map
}
fn from_encryptable(
mut hashmap: FxHashMap<String, crypto::Encryptable<Secret<String>>>,
) -> common_utils::errors::CustomResult<EncryptableCustomer, common_utils::errors::ParsingError>
{
Ok(EncryptableCustomer {
name: hashmap.remove("name"),
email: hashmap.remove("email").map(|email| {
let encryptable: crypto::Encryptable<Secret<String, EmailStrategy>> =
crypto::Encryptable::new(
email.clone().into_inner().switch_strategy(),
email.into_encrypted(),
);
encryptable
}),
phone: hashmap.remove("phone"),
})
}
}
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct CustomerResponse {
/// The identifier for the customer object

View File

@ -11,10 +11,11 @@ use common_utils::{
ext_traits::{ConfigExt, Encode},
hashing::HashedString,
id_type,
pii::{self, Email},
types::{MinorUnit, StringMajorUnit},
pii::{self, Email, EmailStrategy},
types::{keymanager::ToEncryptable, MinorUnit, StringMajorUnit},
};
use masking::{PeekInterface, Secret, WithType};
use euclid::dssa::graph::euclid_graph_prelude::FxHashMap;
use masking::{ExposeInterface, PeekInterface, Secret, SwitchStrategy, WithType};
use router_derive::Setter;
use serde::{
de::{self, Unexpected, Visitor},
@ -3187,6 +3188,72 @@ impl AddressDetails {
}
}
pub struct AddressDetailsWithPhone {
pub address: Option<AddressDetails>,
pub phone_number: Option<Secret<String>>,
pub email: Option<Email>,
}
pub struct EncryptableAddressDetails {
pub line1: crypto::OptionalEncryptableSecretString,
pub line2: crypto::OptionalEncryptableSecretString,
pub line3: crypto::OptionalEncryptableSecretString,
pub state: crypto::OptionalEncryptableSecretString,
pub zip: crypto::OptionalEncryptableSecretString,
pub first_name: crypto::OptionalEncryptableSecretString,
pub last_name: crypto::OptionalEncryptableSecretString,
pub phone_number: crypto::OptionalEncryptableSecretString,
pub email: crypto::OptionalEncryptableEmail,
}
impl ToEncryptable<EncryptableAddressDetails, Secret<String>, Secret<String>>
for AddressDetailsWithPhone
{
fn from_encryptable(
mut hashmap: FxHashMap<String, crypto::Encryptable<Secret<String>>>,
) -> common_utils::errors::CustomResult<
EncryptableAddressDetails,
common_utils::errors::ParsingError,
> {
Ok(EncryptableAddressDetails {
line1: hashmap.remove("line1"),
line2: hashmap.remove("line2"),
line3: hashmap.remove("line3"),
state: hashmap.remove("state"),
zip: hashmap.remove("zip"),
first_name: hashmap.remove("first_name"),
last_name: hashmap.remove("last_name"),
phone_number: hashmap.remove("phone_number"),
email: hashmap.remove("email").map(|x| {
let inner: Secret<String, EmailStrategy> = x.clone().into_inner().switch_strategy();
crypto::Encryptable::new(inner, x.into_encrypted())
}),
})
}
fn to_encryptable(self) -> FxHashMap<String, Secret<String>> {
let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default());
self.address.map(|address| {
address.line1.map(|x| map.insert("line1".to_string(), x));
address.line2.map(|x| map.insert("line2".to_string(), x));
address.line3.map(|x| map.insert("line3".to_string(), x));
address.state.map(|x| map.insert("state".to_string(), x));
address.zip.map(|x| map.insert("zip".to_string(), x));
address
.first_name
.map(|x| map.insert("first_name".to_string(), x));
address
.last_name
.map(|x| map.insert("last_name".to_string(), x));
});
self.email
.map(|x| map.insert("email".to_string(), x.expose().switch_strategy()));
self.phone_number
.map(|x| map.insert("phone_number".to_string(), x));
map
}
}
#[derive(Debug, Clone, Default, Eq, PartialEq, ToSchema, serde::Deserialize, serde::Serialize)]
pub struct PhoneDetails {
/// The contact number