mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 18:17:13 +08:00 
			
		
		
		
	feat(core): add support to generate session token response from both connector_wallets_details and metadata (#7140)
				
					
				
			Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		| @ -199,24 +199,6 @@ impl SecretsHandler for settings::PazeDecryptConfig { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[async_trait::async_trait] | ||||
| impl SecretsHandler for settings::GooglePayDecryptConfig { | ||||
|     async fn convert_to_raw_secret( | ||||
|         value: SecretStateContainer<Self, SecuredSecret>, | ||||
|         secret_management_client: &dyn SecretManagementInterface, | ||||
|     ) -> CustomResult<SecretStateContainer<Self, RawSecret>, SecretsManagementError> { | ||||
|         let google_pay_decrypt_keys = value.get_inner(); | ||||
|  | ||||
|         let google_pay_root_signing_keys = secret_management_client | ||||
|             .get_secret(google_pay_decrypt_keys.google_pay_root_signing_keys.clone()) | ||||
|             .await?; | ||||
|  | ||||
|         Ok(value.transition_state(|_| Self { | ||||
|             google_pay_root_signing_keys, | ||||
|         })) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[async_trait::async_trait] | ||||
| impl SecretsHandler for settings::ApplepayMerchantConfigs { | ||||
|     async fn convert_to_raw_secret( | ||||
| @ -438,20 +420,6 @@ pub(crate) async fn fetch_raw_secrets( | ||||
|         None | ||||
|     }; | ||||
|  | ||||
|     #[allow(clippy::expect_used)] | ||||
|     let google_pay_decrypt_keys = if let Some(google_pay_keys) = conf.google_pay_decrypt_keys { | ||||
|         Some( | ||||
|             settings::GooglePayDecryptConfig::convert_to_raw_secret( | ||||
|                 google_pay_keys, | ||||
|                 secret_management_client, | ||||
|             ) | ||||
|             .await | ||||
|             .expect("Failed to decrypt google pay decrypt configs"), | ||||
|         ) | ||||
|     } else { | ||||
|         None | ||||
|     }; | ||||
|  | ||||
|     #[allow(clippy::expect_used)] | ||||
|     let applepay_merchant_configs = settings::ApplepayMerchantConfigs::convert_to_raw_secret( | ||||
|         conf.applepay_merchant_configs, | ||||
| @ -544,7 +512,7 @@ pub(crate) async fn fetch_raw_secrets( | ||||
|         payouts: conf.payouts, | ||||
|         applepay_decrypt_keys, | ||||
|         paze_decrypt_keys, | ||||
|         google_pay_decrypt_keys, | ||||
|         google_pay_decrypt_keys: conf.google_pay_decrypt_keys, | ||||
|         multiple_api_version_supported_connectors: conf.multiple_api_version_supported_connectors, | ||||
|         applepay_merchant_configs, | ||||
|         lock_settings: conf.lock_settings, | ||||
|  | ||||
| @ -99,7 +99,7 @@ pub struct Settings<S: SecretState> { | ||||
|     pub payout_method_filters: ConnectorFilters, | ||||
|     pub applepay_decrypt_keys: SecretStateContainer<ApplePayDecryptConfig, S>, | ||||
|     pub paze_decrypt_keys: Option<SecretStateContainer<PazeDecryptConfig, S>>, | ||||
|     pub google_pay_decrypt_keys: Option<SecretStateContainer<GooglePayDecryptConfig, S>>, | ||||
|     pub google_pay_decrypt_keys: Option<GooglePayDecryptConfig>, | ||||
|     pub multiple_api_version_supported_connectors: MultipleApiVersionSupportedConnectors, | ||||
|     pub applepay_merchant_configs: SecretStateContainer<ApplepayMerchantConfigs, S>, | ||||
|     pub lock_settings: LockSettings, | ||||
| @ -919,7 +919,7 @@ impl Settings<SecuredSecret> { | ||||
|  | ||||
|         self.google_pay_decrypt_keys | ||||
|             .as_ref() | ||||
|             .map(|x| x.get_inner().validate()) | ||||
|             .map(|x| x.validate()) | ||||
|             .transpose()?; | ||||
|  | ||||
|         self.key_manager.get_inner().validate()?; | ||||
|  | ||||
| @ -1364,10 +1364,12 @@ impl From<GpayTokenizationSpecification> for api_models::payments::GpayTokenizat | ||||
| impl From<GpayTokenParameters> for api_models::payments::GpayTokenParameters { | ||||
|     fn from(value: GpayTokenParameters) -> Self { | ||||
|         Self { | ||||
|             gateway: value.gateway, | ||||
|             gateway: Some(value.gateway), | ||||
|             gateway_merchant_id: Some(value.gateway_merchant_id.expose()), | ||||
|             stripe_version: None, | ||||
|             stripe_publishable_key: None, | ||||
|             public_key: None, | ||||
|             protocol_version: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -220,3 +220,9 @@ pub const DEFAULT_PAYMENT_METHOD_SESSION_EXPIRY: u32 = 15 * 60; // 15 minutes | ||||
|  | ||||
| /// Authorize flow identifier used for performing GSM operations | ||||
| pub const AUTHORIZE_FLOW_STR: &str = "Authorize"; | ||||
|  | ||||
| /// Protocol Version for encrypted Google Pay Token | ||||
| pub(crate) const PROTOCOL: &str = "ECv2"; | ||||
|  | ||||
| /// Sender ID for Google Pay Decryption | ||||
| pub(crate) const SENDER_ID: &[u8] = b"Google"; | ||||
|  | ||||
| @ -246,8 +246,6 @@ pub enum PazeDecryptionError { | ||||
|  | ||||
| #[derive(Debug, thiserror::Error)] | ||||
| pub enum GooglePayDecryptionError { | ||||
|     #[error("Recipient ID not found")] | ||||
|     RecipientIdNotFound, | ||||
|     #[error("Invalid expiration time")] | ||||
|     InvalidExpirationTime, | ||||
|     #[error("Failed to base64 decode input data")] | ||||
|  | ||||
| @ -4381,22 +4381,13 @@ fn get_google_pay_connector_wallet_details( | ||||
|     state: &SessionState, | ||||
|     merchant_connector_account: &helpers::MerchantConnectorAccountType, | ||||
| ) -> Option<GooglePayPaymentProcessingDetails> { | ||||
|     let google_pay_root_signing_keys = | ||||
|         state | ||||
|             .conf | ||||
|             .google_pay_decrypt_keys | ||||
|             .as_ref() | ||||
|             .map(|google_pay_keys| { | ||||
|                 google_pay_keys | ||||
|                     .get_inner() | ||||
|                     .google_pay_root_signing_keys | ||||
|                     .clone() | ||||
|             }); | ||||
|     match ( | ||||
|         google_pay_root_signing_keys, | ||||
|         merchant_connector_account.get_connector_wallets_details(), | ||||
|     ) { | ||||
|         (Some(google_pay_root_signing_keys), Some(wallet_details)) => { | ||||
|     let google_pay_root_signing_keys = state | ||||
|         .conf | ||||
|         .google_pay_decrypt_keys | ||||
|         .as_ref() | ||||
|         .map(|google_pay_keys| google_pay_keys.google_pay_root_signing_keys.clone()); | ||||
|     match merchant_connector_account.get_connector_wallets_details() { | ||||
|         Some(wallet_details) => { | ||||
|             let google_pay_wallet_details = wallet_details | ||||
|                 .parse_value::<api_models::payments::GooglePayWalletDetails>( | ||||
|                     "GooglePayWalletDetails", | ||||
| @ -4407,31 +4398,43 @@ fn get_google_pay_connector_wallet_details( | ||||
|  | ||||
|             google_pay_wallet_details | ||||
|                 .ok() | ||||
|                 .map( | ||||
|                 .and_then( | ||||
|                     |google_pay_wallet_details| { | ||||
|                         match google_pay_wallet_details | ||||
|                         .google_pay | ||||
|                         .provider_details { | ||||
|                             api_models::payments::GooglePayProviderDetails::GooglePayMerchantDetails(merchant_details) => { | ||||
|                                 GooglePayPaymentProcessingDetails { | ||||
|                                     google_pay_private_key: merchant_details | ||||
|                                 match ( | ||||
|                                     merchant_details | ||||
|                                         .merchant_info | ||||
|                                         .tokenization_specification | ||||
|                                         .parameters | ||||
|                                         .private_key, | ||||
|                                     google_pay_root_signing_keys, | ||||
|                                     google_pay_recipient_id: merchant_details | ||||
|                                     merchant_details | ||||
|                                         .merchant_info | ||||
|                                         .tokenization_specification | ||||
|                                         .parameters | ||||
|                                         .recipient_id, | ||||
|                                 } | ||||
|                                     ) { | ||||
|                                         (Some(google_pay_private_key), Some(google_pay_root_signing_keys), Some(google_pay_recipient_id)) => { | ||||
|                                             Some(GooglePayPaymentProcessingDetails { | ||||
|                                                 google_pay_private_key, | ||||
|                                                 google_pay_root_signing_keys, | ||||
|                                                 google_pay_recipient_id | ||||
|                                             }) | ||||
|                                         } | ||||
|                                         _ => { | ||||
|                                             logger::warn!("One or more of the following fields are missing in GooglePayMerchantDetails: google_pay_private_key, google_pay_root_signing_keys, google_pay_recipient_id"); | ||||
|                                             None | ||||
|                                         } | ||||
|                                     } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 ) | ||||
|         } | ||||
|         _ => None, | ||||
|         None => None, | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -4557,7 +4560,7 @@ pub struct PazePaymentProcessingDetails { | ||||
| pub struct GooglePayPaymentProcessingDetails { | ||||
|     pub google_pay_private_key: Secret<String>, | ||||
|     pub google_pay_root_signing_keys: Secret<String>, | ||||
|     pub google_pay_recipient_id: Option<Secret<String>>, | ||||
|     pub google_pay_recipient_id: Secret<String>, | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Debug)] | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use api_models::payments as payment_types; | ||||
| use api_models::{admin as admin_types, payments as payment_types}; | ||||
| use async_trait::async_trait; | ||||
| use common_utils::{ | ||||
|     ext_traits::ByteSliceExt, | ||||
| @ -8,10 +8,11 @@ use common_utils::{ | ||||
| use error_stack::{Report, ResultExt}; | ||||
| #[cfg(feature = "v2")] | ||||
| use hyperswitch_domain_models::payments::PaymentIntentData; | ||||
| use masking::ExposeInterface; | ||||
| use masking::{ExposeInterface, ExposeOptionInterface}; | ||||
|  | ||||
| use super::{ConstructFlowSpecificData, Feature}; | ||||
| use crate::{ | ||||
|     consts::PROTOCOL, | ||||
|     core::{ | ||||
|         errors::{self, ConnectorErrorExt, RouterResult}, | ||||
|         payments::{self, access_token, helpers, transformers, PaymentData}, | ||||
| @ -828,6 +829,21 @@ fn create_gpay_session_token( | ||||
|     connector: &api::ConnectorData, | ||||
|     business_profile: &domain::Profile, | ||||
| ) -> RouterResult<types::PaymentsSessionRouterData> { | ||||
|     // connector_wallet_details is being parse into admin types to check specifically if google_pay field is present | ||||
|     // this is being done because apple_pay details from metadata is also being filled into connector_wallets_details | ||||
|     let connector_wallets_details = router_data | ||||
|         .connector_wallets_details | ||||
|         .clone() | ||||
|         .parse_value::<admin_types::ConnectorWalletDetails>("ConnectorWalletDetails") | ||||
|         .change_context(errors::ConnectorError::NoConnectorWalletDetails) | ||||
|         .attach_printable(format!( | ||||
|             "cannot parse connector_wallets_details from the given value {:?}", | ||||
|             router_data.connector_wallets_details | ||||
|         )) | ||||
|         .change_context(errors::ApiErrorResponse::InvalidDataFormat { | ||||
|             field_name: "connector_wallets_details".to_string(), | ||||
|             expected_format: "admin_types_connector_wallets_details_format".to_string(), | ||||
|         })?; | ||||
|     let connector_metadata = router_data.connector_meta_data.clone(); | ||||
|     let delayed_response = is_session_response_delayed(state, connector); | ||||
|  | ||||
| @ -849,18 +865,6 @@ fn create_gpay_session_token( | ||||
|             ..router_data.clone() | ||||
|         }) | ||||
|     } else { | ||||
|         let gpay_data = connector_metadata | ||||
|             .clone() | ||||
|             .parse_value::<payment_types::GpaySessionTokenData>("GpaySessionTokenData") | ||||
|             .change_context(errors::ConnectorError::NoConnectorMetaData) | ||||
|             .attach_printable(format!( | ||||
|                 "cannot parse gpay metadata from the given value {connector_metadata:?}" | ||||
|             )) | ||||
|             .change_context(errors::ApiErrorResponse::InvalidDataFormat { | ||||
|                 field_name: "connector_metadata".to_string(), | ||||
|                 expected_format: "gpay_metadata_format".to_string(), | ||||
|             })?; | ||||
|  | ||||
|         let always_collect_billing_details_from_wallet_connector = business_profile | ||||
|             .always_collect_billing_details_from_wallet_connector | ||||
|             .unwrap_or(false); | ||||
| @ -883,27 +887,6 @@ fn create_gpay_session_token( | ||||
|             false | ||||
|         }; | ||||
|  | ||||
|         let billing_address_parameters = | ||||
|             is_billing_details_required.then_some(payment_types::GpayBillingAddressParameters { | ||||
|                 phone_number_required: is_billing_details_required, | ||||
|                 format: payment_types::GpayBillingAddressFormat::FULL, | ||||
|             }); | ||||
|  | ||||
|         let gpay_allowed_payment_methods = gpay_data | ||||
|             .data | ||||
|             .allowed_payment_methods | ||||
|             .into_iter() | ||||
|             .map( | ||||
|                 |allowed_payment_methods| payment_types::GpayAllowedPaymentMethods { | ||||
|                     parameters: payment_types::GpayAllowedMethodsParameters { | ||||
|                         billing_address_required: Some(is_billing_details_required), | ||||
|                         billing_address_parameters: billing_address_parameters.clone(), | ||||
|                         ..allowed_payment_methods.parameters | ||||
|                     }, | ||||
|                     ..allowed_payment_methods | ||||
|                 }, | ||||
|             ) | ||||
|             .collect(); | ||||
|         let required_amount_type = StringMajorUnitForConnector; | ||||
|         let google_pay_amount = required_amount_type | ||||
|             .convert( | ||||
| @ -945,39 +928,186 @@ fn create_gpay_session_token( | ||||
|                 false | ||||
|             }; | ||||
|  | ||||
|         Ok(types::PaymentsSessionRouterData { | ||||
|             response: Ok(types::PaymentsResponseData::SessionResponse { | ||||
|                 session_token: payment_types::SessionToken::GooglePay(Box::new( | ||||
|                     payment_types::GpaySessionTokenResponse::GooglePaySession( | ||||
|                         payment_types::GooglePaySessionResponse { | ||||
|                             merchant_info: gpay_data.data.merchant_info, | ||||
|                             allowed_payment_methods: gpay_allowed_payment_methods, | ||||
|                             transaction_info, | ||||
|                             connector: connector.connector_name.to_string(), | ||||
|                             sdk_next_action: payment_types::SdkNextAction { | ||||
|                                 next_action: payment_types::NextActionCall::Confirm, | ||||
|                             }, | ||||
|                             delayed_session_token: false, | ||||
|                             secrets: None, | ||||
|                             shipping_address_required: required_shipping_contact_fields, | ||||
|                             // We pass Email as a required field irrespective of | ||||
|                             // collect_billing_details_from_wallet_connector or | ||||
|                             // collect_shipping_details_from_wallet_connector as it is common to both. | ||||
|                             email_required: required_shipping_contact_fields | ||||
|                                 || is_billing_details_required, | ||||
|                             shipping_address_parameters: | ||||
|                                 api_models::payments::GpayShippingAddressParameters { | ||||
|                                     phone_number_required: required_shipping_contact_fields, | ||||
|         if connector_wallets_details.google_pay.is_some() { | ||||
|             let gpay_data = router_data | ||||
|                 .connector_wallets_details | ||||
|                 .clone() | ||||
|                 .parse_value::<payment_types::GooglePayWalletDetails>("GooglePayWalletDetails") | ||||
|                 .change_context(errors::ConnectorError::NoConnectorWalletDetails) | ||||
|                 .attach_printable(format!( | ||||
|                     "cannot parse gpay connector_wallets_details from the given value {:?}", | ||||
|                     router_data.connector_wallets_details | ||||
|                 )) | ||||
|                 .change_context(errors::ApiErrorResponse::InvalidDataFormat { | ||||
|                     field_name: "connector_wallets_details".to_string(), | ||||
|                     expected_format: "gpay_connector_wallets_details_format".to_string(), | ||||
|                 })?; | ||||
|  | ||||
|             let payment_types::GooglePayProviderDetails::GooglePayMerchantDetails(gpay_info) = | ||||
|                 gpay_data.google_pay.provider_details.clone(); | ||||
|  | ||||
|             let gpay_allowed_payment_methods = get_allowed_payment_methods_from_cards( | ||||
|                 gpay_data, | ||||
|                 &gpay_info.merchant_info.tokenization_specification, | ||||
|                 is_billing_details_required, | ||||
|             )?; | ||||
|  | ||||
|             Ok(types::PaymentsSessionRouterData { | ||||
|                 response: Ok(types::PaymentsResponseData::SessionResponse { | ||||
|                     session_token: payment_types::SessionToken::GooglePay(Box::new( | ||||
|                         payment_types::GpaySessionTokenResponse::GooglePaySession( | ||||
|                             payment_types::GooglePaySessionResponse { | ||||
|                                 merchant_info: payment_types::GpayMerchantInfo { | ||||
|                                     merchant_name: gpay_info.merchant_info.merchant_name, | ||||
|                                     merchant_id: gpay_info.merchant_info.merchant_id, | ||||
|                                 }, | ||||
|                                 allowed_payment_methods: vec![gpay_allowed_payment_methods], | ||||
|                                 transaction_info, | ||||
|                                 connector: connector.connector_name.to_string(), | ||||
|                                 sdk_next_action: payment_types::SdkNextAction { | ||||
|                                     next_action: payment_types::NextActionCall::Confirm, | ||||
|                                 }, | ||||
|                                 delayed_session_token: false, | ||||
|                                 secrets: None, | ||||
|                                 shipping_address_required: required_shipping_contact_fields, | ||||
|                                 // We pass Email as a required field irrespective of | ||||
|                                 // collect_billing_details_from_wallet_connector or | ||||
|                                 // collect_shipping_details_from_wallet_connector as it is common to both. | ||||
|                                 email_required: required_shipping_contact_fields | ||||
|                                     || is_billing_details_required, | ||||
|                                 shipping_address_parameters: | ||||
|                                     api_models::payments::GpayShippingAddressParameters { | ||||
|                                         phone_number_required: required_shipping_contact_fields, | ||||
|                                     }, | ||||
|                             }, | ||||
|                         ), | ||||
|                     )), | ||||
|                 }), | ||||
|                 ..router_data.clone() | ||||
|             }) | ||||
|         } else { | ||||
|             let billing_address_parameters = is_billing_details_required.then_some( | ||||
|                 payment_types::GpayBillingAddressParameters { | ||||
|                     phone_number_required: is_billing_details_required, | ||||
|                     format: payment_types::GpayBillingAddressFormat::FULL, | ||||
|                 }, | ||||
|             ); | ||||
|  | ||||
|             let gpay_data = connector_metadata | ||||
|                 .clone() | ||||
|                 .parse_value::<payment_types::GpaySessionTokenData>("GpaySessionTokenData") | ||||
|                 .change_context(errors::ConnectorError::NoConnectorMetaData) | ||||
|                 .attach_printable(format!( | ||||
|                     "cannot parse gpay metadata from the given value {connector_metadata:?}" | ||||
|                 )) | ||||
|                 .change_context(errors::ApiErrorResponse::InvalidDataFormat { | ||||
|                     field_name: "connector_metadata".to_string(), | ||||
|                     expected_format: "gpay_metadata_format".to_string(), | ||||
|                 })?; | ||||
|  | ||||
|             let gpay_allowed_payment_methods = gpay_data | ||||
|                 .data | ||||
|                 .allowed_payment_methods | ||||
|                 .into_iter() | ||||
|                 .map( | ||||
|                     |allowed_payment_methods| payment_types::GpayAllowedPaymentMethods { | ||||
|                         parameters: payment_types::GpayAllowedMethodsParameters { | ||||
|                             billing_address_required: Some(is_billing_details_required), | ||||
|                             billing_address_parameters: billing_address_parameters.clone(), | ||||
|                             ..allowed_payment_methods.parameters | ||||
|                         }, | ||||
|                     ), | ||||
|                 )), | ||||
|             }), | ||||
|             ..router_data.clone() | ||||
|         }) | ||||
|                         ..allowed_payment_methods | ||||
|                     }, | ||||
|                 ) | ||||
|                 .collect(); | ||||
|  | ||||
|             Ok(types::PaymentsSessionRouterData { | ||||
|                 response: Ok(types::PaymentsResponseData::SessionResponse { | ||||
|                     session_token: payment_types::SessionToken::GooglePay(Box::new( | ||||
|                         payment_types::GpaySessionTokenResponse::GooglePaySession( | ||||
|                             payment_types::GooglePaySessionResponse { | ||||
|                                 merchant_info: gpay_data.data.merchant_info, | ||||
|                                 allowed_payment_methods: gpay_allowed_payment_methods, | ||||
|                                 transaction_info, | ||||
|                                 connector: connector.connector_name.to_string(), | ||||
|                                 sdk_next_action: payment_types::SdkNextAction { | ||||
|                                     next_action: payment_types::NextActionCall::Confirm, | ||||
|                                 }, | ||||
|                                 delayed_session_token: false, | ||||
|                                 secrets: None, | ||||
|                                 shipping_address_required: required_shipping_contact_fields, | ||||
|                                 // We pass Email as a required field irrespective of | ||||
|                                 // collect_billing_details_from_wallet_connector or | ||||
|                                 // collect_shipping_details_from_wallet_connector as it is common to both. | ||||
|                                 email_required: required_shipping_contact_fields | ||||
|                                     || is_billing_details_required, | ||||
|                                 shipping_address_parameters: | ||||
|                                     api_models::payments::GpayShippingAddressParameters { | ||||
|                                         phone_number_required: required_shipping_contact_fields, | ||||
|                                     }, | ||||
|                             }, | ||||
|                         ), | ||||
|                     )), | ||||
|                 }), | ||||
|                 ..router_data.clone() | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Card Type for Google Pay Allowerd Payment Methods | ||||
| pub(crate) const CARD: &str = "CARD"; | ||||
|  | ||||
| fn get_allowed_payment_methods_from_cards( | ||||
|     gpay_info: payment_types::GooglePayWalletDetails, | ||||
|     gpay_token_specific_data: &payment_types::GooglePayTokenizationSpecification, | ||||
|     is_billing_details_required: bool, | ||||
| ) -> RouterResult<payment_types::GpayAllowedPaymentMethods> { | ||||
|     let billing_address_parameters = | ||||
|         is_billing_details_required.then_some(payment_types::GpayBillingAddressParameters { | ||||
|             phone_number_required: is_billing_details_required, | ||||
|             format: payment_types::GpayBillingAddressFormat::FULL, | ||||
|         }); | ||||
|  | ||||
|     let protocol_version: Option<String> = gpay_token_specific_data | ||||
|         .parameters | ||||
|         .public_key | ||||
|         .as_ref() | ||||
|         .map(|_| PROTOCOL.to_string()); | ||||
|  | ||||
|     Ok(payment_types::GpayAllowedPaymentMethods { | ||||
|         parameters: payment_types::GpayAllowedMethodsParameters { | ||||
|             billing_address_required: Some(is_billing_details_required), | ||||
|             billing_address_parameters: billing_address_parameters.clone(), | ||||
|             ..gpay_info.google_pay.cards | ||||
|         }, | ||||
|         payment_method_type: CARD.to_string(), | ||||
|         tokenization_specification: payment_types::GpayTokenizationSpecification { | ||||
|             token_specification_type: gpay_token_specific_data.tokenization_type.to_string(), | ||||
|             parameters: payment_types::GpayTokenParameters { | ||||
|                 protocol_version, | ||||
|                 public_key: gpay_token_specific_data.parameters.public_key.clone(), | ||||
|                 gateway: gpay_token_specific_data.parameters.gateway.clone(), | ||||
|                 gateway_merchant_id: gpay_token_specific_data | ||||
|                     .parameters | ||||
|                     .gateway_merchant_id | ||||
|                     .clone() | ||||
|                     .expose_option(), | ||||
|                 stripe_publishable_key: gpay_token_specific_data | ||||
|                     .parameters | ||||
|                     .stripe_publishable_key | ||||
|                     .clone() | ||||
|                     .expose_option(), | ||||
|                 stripe_version: gpay_token_specific_data | ||||
|                     .parameters | ||||
|                     .stripe_version | ||||
|                     .clone() | ||||
|                     .expose_option(), | ||||
|             }, | ||||
|         }, | ||||
|     }) | ||||
| } | ||||
|  | ||||
| fn is_session_response_delayed( | ||||
|     state: &routes::SessionState, | ||||
|     connector: &api::ConnectorData, | ||||
|  | ||||
| @ -47,8 +47,8 @@ use openssl::{ | ||||
| }; | ||||
| #[cfg(feature = "v2")] | ||||
| use redis_interface::errors::RedisError; | ||||
| use ring::hmac; | ||||
| use router_env::{instrument, logger, tracing}; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use uuid::Uuid; | ||||
| use x509_parser::parse_x509_certificate; | ||||
|  | ||||
| @ -5267,7 +5267,7 @@ where | ||||
|     Ok(connector_data_list) | ||||
| } | ||||
|  | ||||
| #[derive(Debug, serde::Serialize, serde::Deserialize)] | ||||
| #[derive(Debug, Serialize, Deserialize)] | ||||
| pub struct ApplePayData { | ||||
|     version: masking::Secret<String>, | ||||
|     data: masking::Secret<String>, | ||||
| @ -5275,7 +5275,7 @@ pub struct ApplePayData { | ||||
|     header: ApplePayHeader, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, serde::Serialize, serde::Deserialize)] | ||||
| #[derive(Debug, Serialize, Deserialize)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct ApplePayHeader { | ||||
|     ephemeral_public_key: masking::Secret<String>, | ||||
| @ -5430,13 +5430,10 @@ impl ApplePayData { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub(crate) const SENDER_ID: &[u8] = b"Google"; | ||||
| pub(crate) const PROTOCOL: &str = "ECv2"; | ||||
|  | ||||
| // Structs for keys and the main decryptor | ||||
| pub struct GooglePayTokenDecryptor { | ||||
|     root_signing_keys: Vec<GooglePayRootSigningKey>, | ||||
|     recipient_id: Option<masking::Secret<String>>, | ||||
|     recipient_id: masking::Secret<String>, | ||||
|     private_key: PKey<openssl::pkey::Private>, | ||||
| } | ||||
|  | ||||
| @ -5543,21 +5540,24 @@ fn filter_root_signing_keys( | ||||
| impl GooglePayTokenDecryptor { | ||||
|     pub fn new( | ||||
|         root_keys: masking::Secret<String>, | ||||
|         recipient_id: Option<masking::Secret<String>>, | ||||
|         recipient_id: masking::Secret<String>, | ||||
|         private_key: masking::Secret<String>, | ||||
|     ) -> CustomResult<Self, errors::GooglePayDecryptionError> { | ||||
|         // base64 decode the private key | ||||
|         let decoded_key = BASE64_ENGINE | ||||
|             .decode(private_key.expose()) | ||||
|             .change_context(errors::GooglePayDecryptionError::Base64DecodingFailed)?; | ||||
|         // base64 decode the root signing keys | ||||
|         let decoded_root_signing_keys = BASE64_ENGINE | ||||
|             .decode(root_keys.expose()) | ||||
|             .change_context(errors::GooglePayDecryptionError::Base64DecodingFailed)?; | ||||
|         // create a private key from the decoded key | ||||
|         let private_key = PKey::private_key_from_pkcs8(&decoded_key) | ||||
|             .change_context(errors::GooglePayDecryptionError::KeyDeserializationFailed) | ||||
|             .attach_printable("cannot convert private key from decode_key")?; | ||||
|  | ||||
|         // parse the root signing keys | ||||
|         let root_keys_vector: Vec<GooglePayRootSigningKey> = root_keys | ||||
|             .expose() | ||||
|         let root_keys_vector: Vec<GooglePayRootSigningKey> = decoded_root_signing_keys | ||||
|             .parse_struct("GooglePayRootSigningKey") | ||||
|             .change_context(errors::GooglePayDecryptionError::DeserializationFailed)?; | ||||
|  | ||||
| @ -5663,13 +5663,13 @@ impl GooglePayTokenDecryptor { | ||||
|         } | ||||
|  | ||||
|         // get the sender id i.e. Google | ||||
|         let sender_id = String::from_utf8(SENDER_ID.to_vec()) | ||||
|         let sender_id = String::from_utf8(consts::SENDER_ID.to_vec()) | ||||
|             .change_context(errors::GooglePayDecryptionError::DeserializationFailed)?; | ||||
|  | ||||
|         // construct the signed data | ||||
|         let signed_data = self.construct_signed_data_for_intermediate_signing_key_verification( | ||||
|             &sender_id, | ||||
|             PROTOCOL, | ||||
|             consts::PROTOCOL, | ||||
|             encrypted_data.intermediate_signing_key.signed_key.peek(), | ||||
|         )?; | ||||
|  | ||||
| @ -5770,7 +5770,7 @@ impl GooglePayTokenDecryptor { | ||||
|             .change_context(errors::GooglePayDecryptionError::DerivingEcKeyFailed)?; | ||||
|  | ||||
|         // get the sender id i.e. Google | ||||
|         let sender_id = String::from_utf8(SENDER_ID.to_vec()) | ||||
|         let sender_id = String::from_utf8(consts::SENDER_ID.to_vec()) | ||||
|             .change_context(errors::GooglePayDecryptionError::DeserializationFailed)?; | ||||
|  | ||||
|         // serialize the signed message to string | ||||
| @ -5780,7 +5780,7 @@ impl GooglePayTokenDecryptor { | ||||
|         // construct the signed data | ||||
|         let signed_data = self.construct_signed_data_for_signature_verification( | ||||
|             &sender_id, | ||||
|             PROTOCOL, | ||||
|             consts::PROTOCOL, | ||||
|             &signed_message, | ||||
|         )?; | ||||
|  | ||||
| @ -5827,11 +5827,7 @@ impl GooglePayTokenDecryptor { | ||||
|         protocol_version: &str, | ||||
|         signed_key: &str, | ||||
|     ) -> CustomResult<Vec<u8>, errors::GooglePayDecryptionError> { | ||||
|         let recipient_id = self | ||||
|             .recipient_id | ||||
|             .clone() | ||||
|             .ok_or(errors::GooglePayDecryptionError::RecipientIdNotFound)? | ||||
|             .expose(); | ||||
|         let recipient_id = self.recipient_id.clone().expose(); | ||||
|         let length_of_sender_id = u32::try_from(sender_id.len()) | ||||
|             .change_context(errors::GooglePayDecryptionError::ParsingFailed)?; | ||||
|         let length_of_recipient_id = u32::try_from(recipient_id.len()) | ||||
| @ -5911,13 +5907,14 @@ impl GooglePayTokenDecryptor { | ||||
|  | ||||
|         // derive 64 bytes for the output key (symmetric encryption + MAC key) | ||||
|         let mut output_key = vec![0u8; 64]; | ||||
|         hkdf.expand(SENDER_ID, &mut output_key).map_err(|err| { | ||||
|             logger::error!( | ||||
|         hkdf.expand(consts::SENDER_ID, &mut output_key) | ||||
|             .map_err(|err| { | ||||
|                 logger::error!( | ||||
|                 "Failed to derive the shared ephemeral key for Google Pay decryption flow: {:?}", | ||||
|                 err | ||||
|             ); | ||||
|             report!(errors::GooglePayDecryptionError::DerivingSharedEphemeralKeyFailed) | ||||
|         })?; | ||||
|                 report!(errors::GooglePayDecryptionError::DerivingSharedEphemeralKeyFailed) | ||||
|             })?; | ||||
|  | ||||
|         Ok(output_key) | ||||
|     } | ||||
| @ -5930,8 +5927,8 @@ impl GooglePayTokenDecryptor { | ||||
|         tag: &[u8], | ||||
|         encrypted_message: &[u8], | ||||
|     ) -> CustomResult<(), errors::GooglePayDecryptionError> { | ||||
|         let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, mac_key); | ||||
|         hmac::verify(&hmac_key, encrypted_message, tag) | ||||
|         let hmac_key = ring::hmac::Key::new(ring::hmac::HMAC_SHA256, mac_key); | ||||
|         ring::hmac::verify(&hmac_key, encrypted_message, tag) | ||||
|             .change_context(errors::GooglePayDecryptionError::HmacVerificationFailed) | ||||
|     } | ||||
|  | ||||
| @ -6024,7 +6021,7 @@ pub fn decrypt_paze_token( | ||||
|     Ok(parsed_decrypted) | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] | ||||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct JwsBody { | ||||
|     pub payload_id: String, | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Sakil Mostak
					Sakil Mostak