Skip to content

Commit

Permalink
fix: certificate decode failed when creating the session token for ap…
Browse files Browse the repository at this point in the history
…plepay (#1385)
  • Loading branch information
Narayanbhat166 committed Jun 9, 2023
1 parent 638fc42 commit 8497c55
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 25 deletions.
6 changes: 6 additions & 0 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,12 @@ pub struct ApplepaySessionRequest {
pub initiative_context: String,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ConnectorMetadata {
pub apple_pay: Option<ApplePayMetadata>,
pub google_pay: Option<GpayMetaData>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ApplepaySessionTokenData {
#[serde(rename = "apple_pay")]
Expand Down
35 changes: 35 additions & 0 deletions crates/router/src/core/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,36 @@ fn get_business_details_wrapper(
}
}

fn validate_certificate_in_mca_metadata(
connector_metadata: Secret<serde_json::Value>,
) -> RouterResult<()> {
let parsed_connector_metadata = connector_metadata
.parse_value::<api_models::payments::ConnectorMetadata>("ApplepaySessionTokenData")
.change_context(errors::ParsingError::StructParseFailure("Metadata"))
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
field_name: "metadata".to_string(),
expected_format: "connector metadata".to_string(),
})?;

parsed_connector_metadata
.apple_pay
.map(|applepay_metadata| {
let api_models::payments::SessionTokenInfo {
certificate,
certificate_keys,
..
} = applepay_metadata.session_token_data;
helpers::create_identity_from_certificate_and_key(certificate, certificate_keys)
.change_context(errors::ApiErrorResponse::InvalidDataValue {
field_name: "certificate/certificate key",
})
.map(|_identity_result| ())
})
.transpose()?;

Ok(())
}

pub async fn create_payment_connector(
store: &dyn StorageInterface,
req: api::MerchantConnectorCreate,
Expand All @@ -390,6 +420,11 @@ pub async fn create_payment_connector(
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to get key from merchant key store")?;

req.metadata
.clone()
.map(validate_certificate_in_mca_metadata)
.transpose()?;

let merchant_account = store
.find_merchant_account_by_merchant_id(merchant_id)
.await
Expand Down
28 changes: 28 additions & 0 deletions crates/router/src/core/payments/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::borrow::Cow;

use base64::Engine;
use common_utils::{
ext_traits::{AsyncExt, ByteSliceExt, ValueExt},
fp_utils, generate_id, pii,
Expand Down Expand Up @@ -46,6 +47,33 @@ use crate::{
},
};

pub fn create_identity_from_certificate_and_key(
encoded_certificate: String,
encoded_certificate_key: String,
) -> Result<reqwest::Identity, error_stack::Report<errors::ApiClientError>> {
let decoded_certificate = consts::BASE64_ENGINE
.decode(encoded_certificate)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;

let decoded_certificate_key = consts::BASE64_ENGINE
.decode(encoded_certificate_key)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;

let certificate = String::from_utf8(decoded_certificate)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;

let certificate_key = String::from_utf8(decoded_certificate_key)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;

reqwest::Identity::from_pkcs8_pem(certificate.as_bytes(), certificate_key.as_bytes())
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)
}

pub fn filter_mca_based_on_business_details(
merchant_connector_accounts: Vec<domain::MerchantConnectorAccount>,
payment_intent: Option<&storage_models::payment_intent::PaymentIntent>,
Expand Down
34 changes: 9 additions & 25 deletions crates/router/src/services/api/client.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use base64::Engine;
use error_stack::{IntoReport, ResultExt};
use once_cell::sync::OnceCell;

use crate::{
configs::settings::{Locker, Proxy},
consts,
core::errors::{self, CustomResult},
core::{
errors::{self, CustomResult},
payments,
},
};

static NON_PROXIED_CLIENT: OnceCell<reqwest::Client> = OnceCell::new();
Expand Down Expand Up @@ -74,30 +75,13 @@ pub(super) fn create_client(
client_certificate_key: Option<String>,
) -> CustomResult<reqwest::Client, errors::ApiClientError> {
match (client_certificate, client_certificate_key) {
(Some(encoded_cert), Some(encoded_cert_key)) => {
(Some(encoded_certificate), Some(encoded_certificate_key)) => {
let client_builder = get_client_builder(proxy_config, should_bypass_proxy)?;

let decoded_cert = consts::BASE64_ENGINE
.decode(encoded_cert)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
let decoded_cert_key = consts::BASE64_ENGINE
.decode(encoded_cert_key)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;

let certificate = String::from_utf8(decoded_cert)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
let certificate_key = String::from_utf8(decoded_cert_key)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
let identity = reqwest::Identity::from_pkcs8_pem(
certificate.as_bytes(),
certificate_key.as_bytes(),
)
.into_report()
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
let identity = payments::helpers::create_identity_from_certificate_and_key(
encoded_certificate,
encoded_certificate_key,
)?;

client_builder
.identity(identity)
Expand Down

0 comments on commit 8497c55

Please sign in to comment.