mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
@ -13,9 +13,9 @@ use std::{
|
||||
borrow::Cow,
|
||||
fmt::Display,
|
||||
iter::Sum,
|
||||
ops::{Add, Deref, Mul, Sub},
|
||||
ops::{Add, Mul, Sub},
|
||||
primitive::i64,
|
||||
str::{FromStr, SplitWhitespace},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use common_enums::enums;
|
||||
@ -29,7 +29,6 @@ use diesel::{
|
||||
AsExpression, FromSqlRow, Queryable,
|
||||
};
|
||||
use error_stack::{report, ResultExt};
|
||||
use masking::{ExposeInterface, PeekInterface};
|
||||
pub use primitive_wrappers::bool_wrappers::{
|
||||
AlwaysRequestExtendedAuthorization, ExtendedAuthorizationAppliedBool,
|
||||
RequestExtendedAuthorizationBool,
|
||||
@ -49,7 +48,6 @@ use crate::{
|
||||
self, MAX_DESCRIPTION_LENGTH, MAX_STATEMENT_DESCRIPTOR_LENGTH, PUBLISHABLE_KEY_LENGTH,
|
||||
},
|
||||
errors::{CustomResult, ParsingError, PercentageError, ValidationError},
|
||||
ext_traits::ConfigExt,
|
||||
fp_utils::when,
|
||||
};
|
||||
|
||||
@ -1102,11 +1100,6 @@ pub(crate) enum LengthStringError {
|
||||
MinLengthViolated(u16),
|
||||
}
|
||||
|
||||
impl<const MAX_LENGTH: u16, const MIN_LENGTH: u16> masking::SerializableSecret
|
||||
for LengthString<MAX_LENGTH, MIN_LENGTH>
|
||||
{
|
||||
}
|
||||
|
||||
impl<const MAX_LENGTH: u16, const MIN_LENGTH: u16> LengthString<MAX_LENGTH, MIN_LENGTH> {
|
||||
/// Generates new [MerchantReferenceId] from the given input string
|
||||
pub fn from(input_string: Cow<'static, str>) -> Result<Self, LengthStringError> {
|
||||
@ -1130,22 +1123,6 @@ impl<const MAX_LENGTH: u16, const MIN_LENGTH: u16> LengthString<MAX_LENGTH, MIN_
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MAX_LENGTH: u16, const MIN_LENGTH: u16> Display
|
||||
for LengthString<MAX_LENGTH, MIN_LENGTH>
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MAX_LENGTH: u16, const MIN_LENGTH: u16> Default
|
||||
for LengthString<MAX_LENGTH, MIN_LENGTH>
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self(String::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, const MAX_LENGTH: u16, const MIN_LENGTH: u16> Deserialize<'de>
|
||||
for LengthString<MAX_LENGTH, MIN_LENGTH>
|
||||
{
|
||||
@ -1158,13 +1135,6 @@ impl<'de, const MAX_LENGTH: u16, const MIN_LENGTH: u16> Deserialize<'de>
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MAX_LENGTH: u16, const MIN_LENGTH: u16> Deref for LengthString<MAX_LENGTH, MIN_LENGTH> {
|
||||
type Target = String;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB, const MAX_LENGTH: u16, const MIN_LENGTH: u16> FromSql<sql_types::Text, DB>
|
||||
for LengthString<MAX_LENGTH, MIN_LENGTH>
|
||||
where
|
||||
@ -1393,173 +1363,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize)]
|
||||
/// NewType for validating Names
|
||||
pub struct NameType(masking::Secret<LengthString<256, 0>>);
|
||||
|
||||
impl TryFrom<String> for NameType {
|
||||
type Error = error_stack::Report<ValidationError>;
|
||||
fn try_from(card_holder_name: String) -> Result<Self, Self::Error> {
|
||||
for char in card_holder_name.chars() {
|
||||
validate_character_in_card_holder_name(char)?;
|
||||
}
|
||||
let valid_length_name =
|
||||
LengthString::<256, 0>::from(card_holder_name.into()).map_err(|_| {
|
||||
report!(ValidationError::InvalidValue {
|
||||
message: "invalid length for name".to_string()
|
||||
})
|
||||
})?;
|
||||
Ok(Self(masking::Secret::new(valid_length_name)))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<masking::Secret<String>> for NameType {
|
||||
type Error = error_stack::Report<ValidationError>;
|
||||
fn try_from(masked_card_holder_name: masking::Secret<String>) -> Result<Self, Self::Error> {
|
||||
Self::try_from(masked_card_holder_name.expose())
|
||||
}
|
||||
}
|
||||
|
||||
impl NameType {
|
||||
/// This function is used to create NameType from a string without any validation
|
||||
pub fn get_unchecked(card_holder_name: String) -> Self {
|
||||
Self(masking::Secret::new(LengthString::<256, 0>::new_unchecked(
|
||||
card_holder_name,
|
||||
)))
|
||||
}
|
||||
|
||||
/// This function is used to create NameType from a secret of string without any validation
|
||||
pub fn get_unchecked_from_secret(card_holder_name: masking::Secret<String>) -> Self {
|
||||
Self(masking::Secret::new(LengthString::<256, 0>::new_unchecked(
|
||||
card_holder_name.expose(),
|
||||
)))
|
||||
}
|
||||
|
||||
/// Trim the name
|
||||
pub fn trim(&self) -> Self {
|
||||
let value = self.0.peek().trim().to_string();
|
||||
Self(masking::Secret::new(LengthString::<256, 0>::new_unchecked(
|
||||
value,
|
||||
)))
|
||||
}
|
||||
|
||||
/// Check if the string is empty
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.peek().is_empty()
|
||||
}
|
||||
|
||||
/// Split the string by whitespace
|
||||
pub fn split_whitespace(&self) -> SplitWhitespace<'_> {
|
||||
self.0.peek().split_whitespace()
|
||||
}
|
||||
|
||||
/// Split once at the first occurrence of the given character
|
||||
pub fn split_once(&self, delimiter: char) -> Option<(&str, &str)> {
|
||||
self.0.peek().split_once(delimiter)
|
||||
}
|
||||
|
||||
/// Split once at the last occurrence of the given character
|
||||
pub fn rsplit_once(&self, delimiter: char) -> Option<(&str, &str)> {
|
||||
self.0.peek().rsplit_once(delimiter)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NameType> for String {
|
||||
fn from(card_holder_name: NameType) -> Self {
|
||||
(*(card_holder_name.0.peek())).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&NameType> for String {
|
||||
fn from(card_holder_name: &NameType) -> Self {
|
||||
(*(card_holder_name.0.peek())).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for NameType {
|
||||
type Err = error_stack::Report<ValidationError>;
|
||||
|
||||
fn from_str(card_number: &str) -> Result<Self, Self::Err> {
|
||||
Self::try_from(card_number.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NameType> for masking::Secret<String> {
|
||||
fn from(card_holder_name: NameType) -> Self {
|
||||
Self::new(card_holder_name.0.peek().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&NameType> for masking::Secret<String> {
|
||||
fn from(card_holder_name: &NameType) -> Self {
|
||||
Self::new(card_holder_name.0.peek().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_character_in_card_holder_name(
|
||||
character: char,
|
||||
) -> Result<(), error_stack::Report<ValidationError>> {
|
||||
if character.is_alphabetic()
|
||||
|| character == ' '
|
||||
|| character == '.'
|
||||
|| character == '-'
|
||||
|| character == '\''
|
||||
|| character == '~'
|
||||
|| character == '`'
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(report!(ValidationError::InvalidValue {
|
||||
message: format!("invalid character found in card holder name: {}", character)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for NameType {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let card_holder_name = String::deserialize(deserializer)?;
|
||||
card_holder_name
|
||||
.try_into()
|
||||
.map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigExt for NameType {
|
||||
fn is_empty_after_trim(&self) -> bool {
|
||||
self.trim().is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod name_type_test {
|
||||
#![allow(clippy::unwrap_used)]
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_card_holder_name() {
|
||||
let valid_name = "Sakil Mostak".to_string();
|
||||
// no panic
|
||||
let card_holder_name = NameType::try_from("Sakil Mostak".to_string()).unwrap();
|
||||
|
||||
// will panic on unwrap
|
||||
let invalid_card_holder_name = NameType::try_from("$@k!l M*$t@k".to_string());
|
||||
|
||||
assert_eq!(String::from(card_holder_name.clone()), valid_name);
|
||||
assert!(invalid_card_holder_name.is_err());
|
||||
|
||||
let serialized = serde_json::to_string(&card_holder_name).unwrap();
|
||||
assert_eq!(&serialized, "\"Sakil Mostak\"");
|
||||
|
||||
let derialized = serde_json::from_str::<NameType>(&serialized).unwrap();
|
||||
assert_eq!(String::from(derialized), valid_name);
|
||||
|
||||
let invalid_deserialization = serde_json::from_str::<NameType>("$@k!l M*$t@k");
|
||||
assert!(invalid_deserialization.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
/// Browser information to be used for 3DS 2.0
|
||||
// If any of the field is PII, then we can make them as secret
|
||||
|
||||
Reference in New Issue
Block a user