diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index a5dc3a83f2..cadae4fa45 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -9967,13 +9967,11 @@ }, "GpayTokenParameters": { "type": "object", - "required": [ - "gateway" - ], "properties": { "gateway": { "type": "string", - "description": "The name of the connector" + "description": "The name of the connector", + "nullable": true }, "gateway_merchant_id": { "type": "string", @@ -9987,6 +9985,16 @@ "stripe:publishableKey": { "type": "string", "nullable": true + }, + "protocol_version": { + "type": "string", + "description": "The protocol version for encryption", + "nullable": true + }, + "public_key": { + "type": "string", + "description": "The public key provided by the merchant", + "nullable": true } } }, diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 60be7f59d6..61892d1b29 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -12654,13 +12654,11 @@ }, "GpayTokenParameters": { "type": "object", - "required": [ - "gateway" - ], "properties": { "gateway": { "type": "string", - "description": "The name of the connector" + "description": "The name of the connector", + "nullable": true }, "gateway_merchant_id": { "type": "string", @@ -12674,6 +12672,16 @@ "stripe:publishableKey": { "type": "string", "nullable": true + }, + "protocol_version": { + "type": "string", + "description": "The protocol version for encryption", + "nullable": true + }, + "public_key": { + "type": "string", + "description": "The public key provided by the merchant", + "nullable": true } } }, diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index cc70520751..bec25529af 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -6085,7 +6085,8 @@ pub enum GpayBillingAddressFormat { #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] pub struct GpayTokenParameters { /// The name of the connector - pub gateway: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub gateway: Option, /// The merchant ID registered in the connector associated #[serde(skip_serializing_if = "Option::is_none")] pub gateway_merchant_id: Option, @@ -6096,6 +6097,13 @@ pub struct GpayTokenParameters { rename = "stripe:publishableKey" )] pub stripe_publishable_key: Option, + /// The protocol version for encryption + #[serde(skip_serializing_if = "Option::is_none")] + pub protocol_version: Option, + /// The public key provided by the merchant + #[serde(skip_serializing_if = "Option::is_none")] + #[schema(value_type = Option)] + pub public_key: Option>, } #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] @@ -6365,6 +6373,7 @@ pub struct GooglePayWalletDetails { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GooglePayDetails { pub provider_details: GooglePayProviderDetails, + pub cards: GpayAllowedMethodsParameters, } // Google Pay Provider Details can of two types: GooglePayMerchantDetails or GooglePayHyperSwitchDetails @@ -6383,6 +6392,7 @@ pub struct GooglePayMerchantDetails { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GooglePayMerchantInfo { pub merchant_name: String, + pub merchant_id: Option, pub tokenization_specification: GooglePayTokenizationSpecification, } @@ -6393,8 +6403,9 @@ pub struct GooglePayTokenizationSpecification { pub parameters: GooglePayTokenizationParameters, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, strum::Display)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[strum(serialize_all = "SCREAMING_SNAKE_CASE")] pub enum GooglePayTokenizationType { PaymentGateway, Direct, @@ -6402,10 +6413,13 @@ pub enum GooglePayTokenizationType { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GooglePayTokenizationParameters { - pub gateway: String, - pub public_key: Secret, - pub private_key: Secret, + pub gateway: Option, + pub public_key: Option>, + pub private_key: Option>, pub recipient_id: Option>, + pub gateway_merchant_id: Option>, + pub stripe_publishable_key: Option>, + pub stripe_version: Option>, } #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)] diff --git a/crates/router/src/configs/secrets_transformers.rs b/crates/router/src/configs/secrets_transformers.rs index f51a785eaa..65ac6adf5b 100644 --- a/crates/router/src/configs/secrets_transformers.rs +++ b/crates/router/src/configs/secrets_transformers.rs @@ -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, - secret_management_client: &dyn SecretManagementInterface, - ) -> CustomResult, 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, diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index d721a4db96..5445cb8697 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -99,7 +99,7 @@ pub struct Settings { pub payout_method_filters: ConnectorFilters, pub applepay_decrypt_keys: SecretStateContainer, pub paze_decrypt_keys: Option>, - pub google_pay_decrypt_keys: Option>, + pub google_pay_decrypt_keys: Option, pub multiple_api_version_supported_connectors: MultipleApiVersionSupportedConnectors, pub applepay_merchant_configs: SecretStateContainer, pub lock_settings: LockSettings, @@ -919,7 +919,7 @@ impl Settings { self.google_pay_decrypt_keys .as_ref() - .map(|x| x.get_inner().validate()) + .map(|x| x.validate()) .transpose()?; self.key_manager.get_inner().validate()?; diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs index 78641d7e33..b7cb7a91f2 100644 --- a/crates/router/src/connector/trustpay/transformers.rs +++ b/crates/router/src/connector/trustpay/transformers.rs @@ -1364,10 +1364,12 @@ impl From for api_models::payments::GpayTokenizat impl From 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, } } } diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs index 05d08f37dd..dc3c2d532e 100644 --- a/crates/router/src/consts.rs +++ b/crates/router/src/consts.rs @@ -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"; diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index 54cae42ceb..506ce55719 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -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")] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index c81a40216c..fd2950f506 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -4381,22 +4381,13 @@ fn get_google_pay_connector_wallet_details( state: &SessionState, merchant_connector_account: &helpers::MerchantConnectorAccountType, ) -> Option { - 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::( "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, pub google_pay_root_signing_keys: Secret, - pub google_pay_recipient_id: Option>, + pub google_pay_recipient_id: Secret, } #[derive(Clone, Debug)] diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 65688c5d46..f6e5d1e7f0 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -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 { + // 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::("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::("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::("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::("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 { + 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 = 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, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 28d843e235..39bbef1f3d 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -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, data: masking::Secret, @@ -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, @@ -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, - recipient_id: Option>, + recipient_id: masking::Secret, private_key: PKey, } @@ -5543,21 +5540,24 @@ fn filter_root_signing_keys( impl GooglePayTokenDecryptor { pub fn new( root_keys: masking::Secret, - recipient_id: Option>, + recipient_id: masking::Secret, private_key: masking::Secret, ) -> CustomResult { // 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 = root_keys - .expose() + let root_keys_vector: Vec = 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, 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,