mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 11:06:50 +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:
@ -15,6 +15,7 @@ kv_store = []
|
||||
async-bb8-diesel = { git = "https://github.com/jarnura/async-bb8-diesel", rev = "53b4ab901aab7635c8215fd1c2d542c8db443094" }
|
||||
diesel = { version = "2.1.5", features = ["postgres", "serde_json", "time", "64-column-tables"] }
|
||||
error-stack = "0.4.1"
|
||||
rustc-hash = "1.1.0"
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_json = "1.0.115"
|
||||
strum = { version = "0.26.2", features = ["derive"] }
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
use common_utils::id_type;
|
||||
use common_utils::{
|
||||
crypto::{self, Encryptable},
|
||||
encryption::Encryption,
|
||||
id_type,
|
||||
pii::EmailStrategy,
|
||||
types::keymanager::ToEncryptable,
|
||||
};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use masking::{Secret, SwitchStrategy};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{encryption::Encryption, enums, schema::address};
|
||||
use crate::{enums, schema::address};
|
||||
|
||||
#[derive(Clone, Debug, Insertable, Serialize, Deserialize, router_derive::DebugAsDisplay)]
|
||||
#[diesel(table_name = address)]
|
||||
@ -54,6 +62,62 @@ pub struct Address {
|
||||
pub email: Option<Encryption>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
// Intermediate struct to convert HashMap to Address
|
||||
pub struct EncryptableAddress {
|
||||
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<EncryptableAddress, Secret<String>, Encryption> for Address {
|
||||
fn to_encryptable(self) -> FxHashMap<String, Encryption> {
|
||||
let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default());
|
||||
self.line1.map(|x| map.insert("line1".to_string(), x));
|
||||
self.line2.map(|x| map.insert("line2".to_string(), x));
|
||||
self.line3.map(|x| map.insert("line3".to_string(), x));
|
||||
self.zip.map(|x| map.insert("zip".to_string(), x));
|
||||
self.state.map(|x| map.insert("state".to_string(), x));
|
||||
self.first_name
|
||||
.map(|x| map.insert("first_name".to_string(), x));
|
||||
self.last_name
|
||||
.map(|x| map.insert("last_name".to_string(), x));
|
||||
self.phone_number
|
||||
.map(|x| map.insert("phone_number".to_string(), x));
|
||||
self.email.map(|x| map.insert("email".to_string(), x));
|
||||
map
|
||||
}
|
||||
|
||||
fn from_encryptable(
|
||||
mut hashmap: FxHashMap<String, Encryptable<Secret<String>>>,
|
||||
) -> common_utils::errors::CustomResult<EncryptableAddress, common_utils::errors::ParsingError>
|
||||
{
|
||||
Ok(EncryptableAddress {
|
||||
line1: hashmap.remove("line1"),
|
||||
line2: hashmap.remove("line2"),
|
||||
line3: hashmap.remove("line3"),
|
||||
zip: hashmap.remove("zip"),
|
||||
state: hashmap.remove("state"),
|
||||
first_name: hashmap.remove("first_name"),
|
||||
last_name: hashmap.remove("last_name"),
|
||||
phone_number: hashmap.remove("phone_number"),
|
||||
email: hashmap.remove("email").map(|email| {
|
||||
let encryptable: Encryptable<Secret<String, EmailStrategy>> = Encryptable::new(
|
||||
email.clone().into_inner().switch_strategy(),
|
||||
email.into_encrypted(),
|
||||
);
|
||||
encryptable
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay, Serialize, Deserialize)]
|
||||
#[diesel(table_name = address)]
|
||||
pub struct AddressUpdateInternal {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use common_utils::pii;
|
||||
use common_utils::{encryption::Encryption, pii};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
|
||||
use crate::{encryption::Encryption, schema::business_profile};
|
||||
use crate::schema::business_profile;
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use common_utils::{id_type, pii};
|
||||
use common_utils::{encryption::Encryption, id_type, pii};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{encryption::Encryption, schema::customers};
|
||||
use crate::schema::customers;
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, Insertable, router_derive::DebugAsDisplay, serde::Deserialize, serde::Serialize,
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
use common_utils::pii::EncryptionStrategy;
|
||||
use diesel::{
|
||||
backend::Backend,
|
||||
deserialize::{self, FromSql, Queryable},
|
||||
serialize::ToSql,
|
||||
sql_types, AsExpression,
|
||||
};
|
||||
use masking::Secret;
|
||||
|
||||
#[derive(Debug, AsExpression, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
|
||||
#[diesel(sql_type = sql_types::Binary)]
|
||||
#[repr(transparent)]
|
||||
pub struct Encryption {
|
||||
inner: Secret<Vec<u8>, EncryptionStrategy>,
|
||||
}
|
||||
|
||||
impl<T: Clone> From<common_utils::crypto::Encryptable<T>> for Encryption {
|
||||
fn from(value: common_utils::crypto::Encryptable<T>) -> Self {
|
||||
Self::new(value.into_encrypted())
|
||||
}
|
||||
}
|
||||
|
||||
impl Encryption {
|
||||
pub fn new(item: Secret<Vec<u8>, EncryptionStrategy>) -> Self {
|
||||
Self { inner: item }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> Secret<Vec<u8>, EncryptionStrategy> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_inner(&self) -> &Secret<Vec<u8>, EncryptionStrategy> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> FromSql<sql_types::Binary, DB> for Encryption
|
||||
where
|
||||
DB: Backend,
|
||||
Secret<Vec<u8>, EncryptionStrategy>: FromSql<sql_types::Binary, DB>,
|
||||
{
|
||||
fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
|
||||
<Secret<Vec<u8>, EncryptionStrategy>>::from_sql(bytes).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> ToSql<sql_types::Binary, DB> for Encryption
|
||||
where
|
||||
DB: Backend,
|
||||
Secret<Vec<u8>, EncryptionStrategy>: ToSql<sql_types::Binary, DB>,
|
||||
{
|
||||
fn to_sql<'b>(
|
||||
&'b self,
|
||||
out: &mut diesel::serialize::Output<'b, '_, DB>,
|
||||
) -> diesel::serialize::Result {
|
||||
self.get_inner().to_sql(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> Queryable<sql_types::Binary, DB> for Encryption
|
||||
where
|
||||
DB: Backend,
|
||||
Secret<Vec<u8>, EncryptionStrategy>: FromSql<sql_types::Binary, DB>,
|
||||
{
|
||||
type Row = Secret<Vec<u8>, EncryptionStrategy>;
|
||||
fn build(row: Self::Row) -> deserialize::Result<Self> {
|
||||
Ok(Self { inner: row })
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,15 @@
|
||||
use common_utils::custom_serde;
|
||||
use common_utils::{
|
||||
crypto::OptionalEncryptableSecretString, custom_serde, encryption::Encryption,
|
||||
types::keymanager::ToEncryptable,
|
||||
};
|
||||
use diesel::{
|
||||
expression::AsExpression, AsChangeset, Identifiable, Insertable, Queryable, Selectable,
|
||||
};
|
||||
use masking::Secret;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{encryption::Encryption, enums as storage_enums, schema::events};
|
||||
use crate::{enums as storage_enums, schema::events};
|
||||
|
||||
#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
|
||||
#[diesel(table_name = events)]
|
||||
@ -59,6 +63,38 @@ pub struct Event {
|
||||
pub metadata: Option<EventMetadata>,
|
||||
}
|
||||
|
||||
pub struct EventWithEncryption {
|
||||
pub request: Option<Encryption>,
|
||||
pub response: Option<Encryption>,
|
||||
}
|
||||
|
||||
pub struct EncryptableEvent {
|
||||
pub request: OptionalEncryptableSecretString,
|
||||
pub response: OptionalEncryptableSecretString,
|
||||
}
|
||||
|
||||
impl ToEncryptable<EncryptableEvent, Secret<String>, Encryption> for EventWithEncryption {
|
||||
fn to_encryptable(self) -> rustc_hash::FxHashMap<String, Encryption> {
|
||||
let mut map = rustc_hash::FxHashMap::default();
|
||||
self.request.map(|x| map.insert("request".to_string(), x));
|
||||
self.response.map(|x| map.insert("response".to_string(), x));
|
||||
map
|
||||
}
|
||||
|
||||
fn from_encryptable(
|
||||
mut hashmap: rustc_hash::FxHashMap<
|
||||
String,
|
||||
common_utils::crypto::Encryptable<Secret<String>>,
|
||||
>,
|
||||
) -> common_utils::errors::CustomResult<EncryptableEvent, common_utils::errors::ParsingError>
|
||||
{
|
||||
Ok(EncryptableEvent {
|
||||
request: hashmap.remove("request"),
|
||||
response: hashmap.remove("response"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, AsExpression, diesel::FromSqlRow)]
|
||||
#[diesel(sql_type = diesel::sql_types::Jsonb)]
|
||||
pub enum EventMetadata {
|
||||
|
||||
@ -12,7 +12,6 @@ pub mod blocklist;
|
||||
pub mod blocklist_fingerprint;
|
||||
pub mod customers;
|
||||
pub mod dispute;
|
||||
pub mod encryption;
|
||||
pub mod enums;
|
||||
pub mod ephemeral_key;
|
||||
pub mod errors;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use common_utils::pii;
|
||||
use common_utils::{encryption::Encryption, pii};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
|
||||
use crate::{encryption::Encryption, enums as storage_enums, schema::merchant_account};
|
||||
use crate::{enums as storage_enums, schema::merchant_account};
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use common_utils::pii;
|
||||
use common_utils::{encryption::Encryption, pii};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use masking::Secret;
|
||||
|
||||
use crate::{encryption::Encryption, enums as storage_enums, schema::merchant_connector_account};
|
||||
use crate::{enums as storage_enums, schema::merchant_connector_account};
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use common_utils::custom_serde;
|
||||
use common_utils::{custom_serde, encryption::Encryption};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{encryption::Encryption, schema::merchant_key_store};
|
||||
use crate::schema::merchant_key_store;
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use common_enums::RequestIncrementalAuthorization;
|
||||
use common_utils::{id_type, pii, types::MinorUnit};
|
||||
use common_utils::{encryption::Encryption, id_type, pii, types::MinorUnit};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{encryption::Encryption, enums as storage_enums, schema::payment_intent};
|
||||
use crate::{enums as storage_enums, schema::payment_intent};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Identifiable, Queryable, Selectable, Serialize, Deserialize)]
|
||||
#[diesel(table_name = payment_intent, primary_key(payment_id, merchant_id), check_for_backend(diesel::pg::Pg))]
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use common_enums::MerchantStorageScheme;
|
||||
use common_utils::{id_type, pii};
|
||||
use common_utils::{encryption::Encryption, id_type, pii};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use masking::Secret;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{encryption::Encryption, enums as storage_enums, schema::payment_methods};
|
||||
use crate::{enums as storage_enums, schema::payment_methods};
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Selectable, Serialize, Deserialize,
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
use common_utils::pii;
|
||||
use common_utils::{encryption::Encryption, pii};
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use masking::Secret;
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{
|
||||
diesel_impl::OptionalDieselArray, encryption::Encryption, enums::TotpStatus, schema::users,
|
||||
};
|
||||
use crate::{diesel_impl::OptionalDieselArray, enums::TotpStatus, schema::users};
|
||||
|
||||
pub mod dashboard_metadata;
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use common_utils::encryption::Encryption;
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{encryption::Encryption, enums, schema::user_authentication_methods};
|
||||
use crate::{enums, schema::user_authentication_methods};
|
||||
|
||||
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
|
||||
#[diesel(table_name = user_authentication_methods, check_for_backend(diesel::pg::Pg))]
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use common_utils::encryption::Encryption;
|
||||
use diesel::{Identifiable, Insertable, Queryable, Selectable};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{encryption::Encryption, schema::user_key_store};
|
||||
use crate::schema::user_key_store;
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, serde::Serialize, serde::Deserialize, Identifiable, Queryable, Selectable,
|
||||
|
||||
Reference in New Issue
Block a user