Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ use std::fmt::Debug;

use common_utils::{consts, errors::CustomResult, events, ext_traits::ByteSliceExt};
use domain_types::{
connector_flow::{Authorize, Capture, PSync, RSync, Refund, RepeatPayment, SetupMandate, Void},
connector_flow::{
Authorize, Capture, PSync, PaymentMethodToken, RSync, Refund, RepeatPayment, SetupMandate,
Void,
},
connector_types::{
PaymentFlowData, PaymentVoidData, PaymentsAuthorizeData, PaymentsCaptureData,
PaymentsResponseData, PaymentsSyncData, RefundFlowData, RefundSyncData, RefundsData,
RefundsResponseData, RepeatPaymentData, ResponseId, SetupMandateRequestData,
PaymentFlowData, PaymentMethodTokenResponse, PaymentMethodTokenizationData,
PaymentVoidData, PaymentsAuthorizeData, PaymentsCaptureData, PaymentsResponseData,
PaymentsSyncData, RefundFlowData, RefundSyncData, RefundsData, RefundsResponseData,
RepeatPaymentData, ResponseId, SetupMandateRequestData,
},
payment_method_data::PaymentMethodDataTypes,
router_data::{ConnectorSpecificConfig, ErrorResponse},
Expand All @@ -25,11 +29,11 @@ use interfaces::{
};
use serde::Serialize;
use transformers::{
CheckoutErrorResponse, PaymentCaptureRequest, PaymentCaptureResponse, PaymentVoidRequest,
PaymentVoidResponse, PaymentsRequest, PaymentsRequest as SetupMandateRequest,
PaymentsRequest as RepeatPaymentRequest, PaymentsResponse, PaymentsResponse as PSyncResponse,
PaymentsResponse as SetupMandateResponse, PaymentsResponse as RepeatPaymentResponse,
RSyncResponse, RefundRequest, RefundResponse,
CheckoutErrorResponse, CheckoutTokenRequest, CheckoutTokenResponse, PaymentCaptureRequest,
PaymentCaptureResponse, PaymentVoidRequest, PaymentVoidResponse, PaymentsRequest,
PaymentsRequest as SetupMandateRequest, PaymentsRequest as RepeatPaymentRequest,
PaymentsResponse, PaymentsResponse as PSyncResponse, PaymentsResponse as SetupMandateResponse,
PaymentsResponse as RepeatPaymentResponse, RSyncResponse, RefundRequest, RefundResponse,
};

use super::macros;
Expand Down Expand Up @@ -112,6 +116,10 @@ impl<T: PaymentMethodDataTypes + Debug + Sync + Send + 'static + Serialize>
connector_types::RepeatPaymentV2<T> for Checkout<T>
{
}
impl<T: PaymentMethodDataTypes + Debug + Sync + Send + 'static + Serialize>
connector_types::PaymentTokenV2<T> for Checkout<T>
{
}
macros::create_all_prerequisites!(
connector_name: Checkout,
generic_type: T,
Expand Down Expand Up @@ -161,6 +169,12 @@ macros::create_all_prerequisites!(
flow: RSync,
response_body: RSyncResponse,
router_data: RouterDataV2<RSync, RefundFlowData, RefundSyncData, RefundsResponseData>,
),
(
flow: PaymentMethodToken,
request_body: CheckoutTokenRequest,
response_body: CheckoutTokenResponse,
router_data: RouterDataV2<PaymentMethodToken, PaymentFlowData, PaymentMethodTokenizationData<T>, PaymentMethodTokenResponse>,
)
],
amount_converters: [],
Expand All @@ -171,13 +185,38 @@ macros::create_all_prerequisites!(
) -> CustomResult<Vec<(String, Maskable<String>)>, IntegrationError> {
let mut header = vec![(
headers::CONTENT_TYPE.to_string(),
"application/json".to_string().into(),
self.common_get_content_type().to_string().into(),
)];
let mut auth_header = self.get_auth_header(&req.connector_config)?;
header.append(&mut auth_header);
Ok(header)
}

/// Headers for Checkout's `POST /tokens`.
///
/// Tokenization is the one Checkout endpoint that is authenticated with the account's
/// **public** key, which — counter-intuitively — lives in `api_key`, while the secret
/// key every other endpoint uses lives in `api_secret`. See the note on
/// [`transformers::CheckoutAuthType`]. Verified against the sandbox: `Bearer sk_...`
/// on `/tokens` returns 403, and `Bearer pk_...` on `/payments` returns 401. This is
/// why the flow cannot reuse [`Self::build_headers`].
pub fn build_tokenization_headers<F, FCD, Req, Res>(
&self,
req: &RouterDataV2<F, FCD, Req, Res>,
) -> CustomResult<Vec<(String, Maskable<String>)>, IntegrationError> {
let auth = transformers::CheckoutAuthType::try_from(&req.connector_config)?;
Ok(vec![
(
headers::CONTENT_TYPE.to_string(),
self.common_get_content_type().to_string().into(),
),
(
headers::AUTHORIZATION.to_string(),
format!("Bearer {}", auth.api_key.peek()).into_masked(),
),
])
}

pub fn connector_base_url_payments<'a, F, Req, Res>(
&self,
req: &'a RouterDataV2<F, PaymentFlowData, Req, Res>,
Expand Down Expand Up @@ -214,6 +253,9 @@ impl<T: PaymentMethodDataTypes + Debug + Sync + Send + 'static + Serialize> Conn
context: Default::default(),
},
)?;
// `api_secret` holds the **secret** key (`sk_...`) — used by every endpoint except
// `POST /tokens`, which takes the public key from `api_key`. See the note on
// [`transformers::CheckoutAuthType`]; the naming is inherited, not descriptive.
Ok(vec![(
headers::AUTHORIZATION.to_string(),
format!("Bearer {}", auth.api_secret.peek()).into_masked(),
Expand Down Expand Up @@ -536,6 +578,37 @@ macros::macro_connector_implementation!(
}
);

// Connector-decryption head: hand Checkout the raw Apple Pay / Google Pay payload and get a
// single-use `tok_...` back. The Authorize / SetupMandate tail then spends that token as
// `source.type = "token"` (see `build_wallet_token_source` in transformers.rs).
macros::macro_connector_implementation!(
connector_default_implementations: [get_content_type, get_error_response_v2],
connector: Checkout,
curl_request: Json(CheckoutTokenRequest),
curl_response: CheckoutTokenResponse,
flow_name: PaymentMethodToken,
resource_common_data: PaymentFlowData,
flow_request: PaymentMethodTokenizationData<T>,
flow_response: PaymentMethodTokenResponse,
http_method: Post,
generic_type: T,
[PaymentMethodDataTypes + Debug + Sync + Send + 'static + Serialize],
other_functions: {
fn get_headers(
&self,
req: &RouterDataV2<PaymentMethodToken, PaymentFlowData, PaymentMethodTokenizationData<T>, PaymentMethodTokenResponse>,
) -> CustomResult<Vec<(String, Maskable<String>)>, IntegrationError> {
self.build_tokenization_headers(req)
}
fn get_url(
&self,
req: &RouterDataV2<PaymentMethodToken, PaymentFlowData, PaymentMethodTokenizationData<T>, PaymentMethodTokenResponse>,
) -> CustomResult<String, IntegrationError> {
Ok(format!("{}tokens", self.connector_base_url_payments(req)))
}
}
);

impl<T: PaymentMethodDataTypes + Debug + Sync + Send + 'static + Serialize>
ConnectorErrorTypeMapping for Checkout<T>
{
Expand Down Expand Up @@ -677,7 +750,6 @@ macros::macro_connector_flow_status_impls!(
SubmitEvidence,
DefendDispute,
CreateOrder,
PaymentMethodToken,
PreAuthenticate,
Authenticate,
PostAuthenticate,
Expand Down
Loading
Loading