mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
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:
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user