-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(apple-pay): add models for payloads received from client comm…
…unication with apple pay
- Loading branch information
1 parent
d996f08
commit cd0e753
Showing
9 changed files
with
376 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { ApplePayPaymentToken } from './ApplePayPaymentToken.js'; | ||
import type { ApplePayPaymentContact } from './ApplePayPaymentContact.js'; | ||
|
||
/** | ||
* The result of authorizing a payment request that contains payment information. | ||
* | ||
* Data in ApplePayPaymentToken is encrypted. Billing and shipping contact data are not encrypted. | ||
*/ | ||
export interface ApplePayPayment { | ||
/** | ||
* An object that contains the user's payment credentials. | ||
* | ||
*/ | ||
token?: ApplePayPaymentToken; | ||
|
||
/** | ||
* The shipping contact selected by the user for this transaction. | ||
* | ||
*/ | ||
billingContact?: ApplePayPaymentContact; | ||
|
||
/** | ||
* The billing contact selected by the user for this transaction. | ||
*/ | ||
shippingContact?: ApplePayPaymentContact; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/** | ||
* The result of authorizing a payment request that contains payment information. | ||
* | ||
* Data in ApplePayPaymentToken is encrypted. Billing and shipping contact data are not encrypted. | ||
*/ | ||
export interface ApplePayPaymentContact { | ||
/** | ||
* @description A phone number for the contact. | ||
*/ | ||
phoneNumber?: string; | ||
|
||
/** | ||
* @description An email address for the contact. | ||
*/ | ||
emailAddress?: string; | ||
|
||
/** | ||
* @description The contact’s given name. | ||
*/ | ||
givenName?: string; | ||
|
||
/** | ||
* @description The contact’s family name. | ||
*/ | ||
familyName?: string; | ||
|
||
/** | ||
* @description The phonetic spelling of the contact’s given name. | ||
*/ | ||
phoneticGivenName?: string; | ||
|
||
/** | ||
* @description The phonetic spelling of the contact’s family name. | ||
*/ | ||
phoneticFamilyName?: string; | ||
|
||
/** | ||
* @description The street portion of the address for the contact. | ||
*/ | ||
addressLines?: string[]; | ||
|
||
/** | ||
* @description The city for the contact. | ||
*/ | ||
locality?: string; | ||
|
||
/** | ||
* @description The zip code or postal code, where applicable, for the contact. | ||
*/ | ||
postalCode?: string; | ||
|
||
/** | ||
* @description The state for the contact. | ||
*/ | ||
administrativeArea?: string; | ||
|
||
/** | ||
* @description The subadministrative area (such as a county or other region) in a postal address. | ||
*/ | ||
subAdministrativeArea?: string; | ||
|
||
/** | ||
* @description The name of the country or region for the contact. | ||
*/ | ||
country?: string; | ||
|
||
/** | ||
* @description The contact’s two-letter ISO 3166 country code. | ||
*/ | ||
countryCode?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import type { ApplePayPaymentDataHeader } from './ApplePayPaymentDataHeader.js'; | ||
/** | ||
* An object that contains the user's payment credentials. | ||
* You access the payment token of an authorized payment request using the token property of the ApplePayPayment object. | ||
*/ | ||
export interface ApplePayPaymentData { | ||
/** | ||
* A base64 encoded string that contains custom data with the following structure: | ||
* | ||
* Payment Data Keys: | ||
* The decrypted payment data in the `data` value contains the following keys and values: | ||
* | ||
* - **applicationPrimaryAccountNumber** (string): Device-specific account number of the card that funds this transaction. | ||
* - **applicationExpirationDate** (string, date as a string): Card expiration date in the format YYMMDD. | ||
* - **currencyCode** (string): ISO 4217 numeric currency code, as a string to preserve leading zeros. | ||
* - **transactionAmount** (number): Transaction amount. | ||
* - **cardholderName** (string, optional): Cardholder name. | ||
* - **deviceManufacturerIdentifier** (string): Hex-encoded device manufacturer identifier. | ||
* - **paymentDataType** (string): Either "3DSecure" or "EMV". | ||
* - **paymentData** (dictionary): Detailed payment data; see Detailed Payment Data Keys (3D Secure) and Detailed Payment Data Keys (EMV). | ||
* - **authenticationResponses** (list): For a multitoken request, a list of submerchant responses that contain cryptograms. | ||
* - **merchantTokenIdentifier** (string): For a merchant token request, the provisioned merchant token identifier from the payment network. | ||
* - **merchantTokenMetadata** (MerchantTokenMetadata): For a merchant token request, this data contains card art and the token's last four digits and expiration date. | ||
* | ||
* The encoded string must be decoded and parsed according to the expected structure to access the individual values. | ||
* | ||
*/ | ||
data?: string; | ||
|
||
/** | ||
* Additional version-dependent information you use to decrypt and verify the payment | ||
*/ | ||
header?: ApplePayPaymentDataHeader; | ||
|
||
/** | ||
* detached PKCS #7 signature, Base64 encoded as a string. | ||
* Signature of the payment and header data. | ||
* The signature includes the signing certificate, its intermediate CA certificate, and information about the signing algorithm. | ||
* | ||
*/ | ||
signature?: string; | ||
|
||
/** | ||
* Version information about the payment token | ||
* The token uses EC_v1 for ECC-encrypted data and RSA_v1 for RSA-encrypted data. | ||
* | ||
*/ | ||
version?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
export interface ApplePayPaymentDataHeader { | ||
/** | ||
* Optional. Hash of the applicationData property of the original PKPaymentRequest object | ||
* for transactions that initiate in apps. For transactions that initiate in Apple Pay on the Web, | ||
* the value is the hash of applicationData in ApplePayPaymentRequest or of applicationData in ApplePayRequest. | ||
* This key is omitted if the value of that property is nil. | ||
* | ||
* @description SHA-256 hash, hex encoded as a string | ||
*/ | ||
applicationData?: string; | ||
|
||
/** | ||
* Ephemeral public key bytes. | ||
* | ||
* @description X.509 encoded key bytes, Base64 encoded as a string | ||
*/ | ||
ephemeralPublicKey?: string; | ||
|
||
/** | ||
* The symmetric key wrapped using your RSA public key. | ||
* | ||
* @description A Base64-encoded string | ||
*/ | ||
wrappedKey?: string; | ||
|
||
/** | ||
* Hash of the X.509 encoded public key bytes of the merchant's certificate. | ||
* | ||
* @description SHA-256 hash, Base64 encoded as a string | ||
*/ | ||
publicKeyHash?: string; | ||
|
||
/** | ||
* Transaction identifier, generated on the device. | ||
* | ||
* @description A hexadecimal identifier, as a string | ||
*/ | ||
transactionId?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import type { ApplePayPaymentMethodType } from './ApplePayPaymentMethodType.js'; | ||
import type { ApplePayPaymentContact } from './ApplePayPaymentContact.js'; | ||
/** | ||
* Information about the card used in the transaction. | ||
*/ | ||
export interface ApplePayPaymentMethod { | ||
/** | ||
* @description A string, suitable for display, that describes the card. | ||
*/ | ||
displayName?: string; | ||
|
||
/** | ||
* @description A string, suitable for display, that is the name of the payment network backing the card. | ||
*/ | ||
network?: string; | ||
|
||
/** | ||
* @description A string value representing the card's type of payment. | ||
*/ | ||
type?: ApplePayPaymentMethodType; | ||
|
||
/** | ||
* @description string|null The payment pass object currently selected to complete the payment. | ||
*/ | ||
paymentPass?: string; | ||
|
||
/** | ||
* @description The billing contact associated with the card. | ||
*/ | ||
billingContact?: ApplePayPaymentContact; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/** | ||
* A string that represents the type of the payment method. | ||
* | ||
* The type of card the customer uses to complete the transaction. | ||
*/ | ||
export enum ApplePayPaymentMethodType { | ||
DEBIT = 'debit', | ||
CREDIT = 'credit', | ||
PREPAID = 'prepaid', | ||
STORE = 'store', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import type { ApplePayPaymentData } from './ApplePayPaymentData.js'; | ||
import type { ApplePayPaymentMethod } from './ApplePayPaymentMethod.js'; | ||
|
||
/** | ||
* An object that contains the user's payment credentials. | ||
* | ||
* You access the payment token of an authorized payment request using the token property of the ApplePayPayment object. | ||
*/ | ||
export interface ApplePayPaymentToken { | ||
/** | ||
* | ||
* This data is used by your e-commerce back-end system, which decrypts it and submits it to your payment processor. | ||
* For a full guide on this data, see: | ||
* https://developer.apple.com/documentation/passkit_apple_pay_and_wallet/apple_pay/payment_token_format_reference | ||
* | ||
*/ | ||
paymentData?: ApplePayPaymentData; | ||
|
||
/** | ||
* @description An object that contains the user's payment credentials. | ||
* You access the payment token of an authorized payment request using the token property of the ApplePayPayment object. | ||
*/ | ||
paymentMethod?: ApplePayPaymentMethod; | ||
|
||
/** | ||
* @description A unique identifier for this payment. | ||
* This identifier is suitable for use in a receipt. | ||
*/ | ||
transactionIdentifier?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { describe, expect, test } from 'vitest'; | ||
import type { ApplePayPayment } from '../../models/applepay/ApplePayPayment.js'; | ||
import type { MobilePaymentMethodSpecificInput } from '../../models/MobilePaymentMethodSpecificInput.js'; | ||
import { ApplePayPaymentMethodType } from '../../models/applepay/ApplePayPaymentMethodType.js'; | ||
import { Network } from '../../models/Network.js'; | ||
import { applePayPaymentToMobilePaymentMethodSpecificInput } from '../../transformer/applepay.js'; | ||
|
||
describe('applepay transformer', () => { | ||
describe('applePayPaymentToMobilePaymentMethodSpecificInput', () => { | ||
test('converts a full ApplePayPayment correctly', () => { | ||
const payment: ApplePayPayment = { | ||
token: { | ||
paymentData: { | ||
data: 'data', | ||
header: { | ||
applicationData: undefined, | ||
publicKeyHash: 'hashhashhash', | ||
transactionId: 'transaction-101', | ||
}, | ||
signature: undefined, | ||
version: undefined, | ||
}, | ||
paymentMethod: { | ||
displayName: 'The name is...', | ||
network: 'MasterCard', | ||
type: ApplePayPaymentMethodType.CREDIT, | ||
paymentPass: undefined, | ||
billingContact: undefined, | ||
}, | ||
transactionIdentifier: 'transaction-101-cc', | ||
}, | ||
billingContact: { | ||
phoneNumber: '+1239452324', | ||
emailAddress: '[email protected]', | ||
givenName: 'John', | ||
familyName: 'Michell', | ||
phoneticGivenName: '', | ||
phoneticFamilyName: '', | ||
addressLines: ['Alarichtstraße 12'], | ||
locality: 'Berlin', | ||
postalCode: '12105', | ||
subAdministrativeArea: '', | ||
}, | ||
shippingContact: undefined, | ||
}; | ||
|
||
const expected: MobilePaymentMethodSpecificInput = { | ||
paymentProductId: 302, | ||
publicKeyHash: 'hashhashhash', | ||
ephemeralKey: undefined, | ||
paymentProduct302SpecificInput: { | ||
network: Network.MASTERCARD, | ||
token: { | ||
signature: undefined, | ||
header: { | ||
transactionId: 'transaction-101', | ||
applicationData: undefined, | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
expect(applePayPaymentToMobilePaymentMethodSpecificInput(payment)).toEqual(expected); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import type { ApplePayPayment } from '../models/applepay/ApplePayPayment.js'; | ||
import { ApplePaymentTokenVersion } from '../models/ApplePaymentTokenVersion.js'; | ||
import type { MobilePaymentMethodSpecificInput } from '../models/MobilePaymentMethodSpecificInput.js'; | ||
import { Network } from '../models/Network.js'; | ||
|
||
function networkFromString(value: string): Network { | ||
switch (value.toUpperCase()) { | ||
case Network.MASTERCARD: | ||
return Network.MASTERCARD; | ||
case Network.VISA: | ||
return Network.VISA; | ||
case Network.AMEX: | ||
return Network.AMEX; | ||
case Network.GIROCARD: | ||
return Network.GIROCARD; | ||
case Network.DISCOVER: | ||
return Network.DISCOVER; | ||
case Network.JCB: | ||
return Network.JCB; | ||
default: | ||
throw new TypeError(`'${value}' can't represent a Network`); | ||
} | ||
} | ||
|
||
function versionFromString(value: string): ApplePaymentTokenVersion { | ||
switch (value) { | ||
case ApplePaymentTokenVersion.EC_V1: | ||
return ApplePaymentTokenVersion.EC_V1; | ||
default: | ||
throw new TypeError(`'${value}' can't represent an ApplePaymentTokenVersion`); | ||
} | ||
} | ||
|
||
export function applePayPaymentToMobilePaymentMethodSpecificInput(payment: ApplePayPayment) { | ||
return { | ||
paymentProductId: 302, | ||
publicKeyHash: payment.token?.paymentData?.header?.publicKeyHash, | ||
ephemeralKey: payment.token?.paymentData?.header?.ephemeralPublicKey, | ||
paymentProduct302SpecificInput: { | ||
network: payment.token?.paymentMethod?.network | ||
? networkFromString(payment.token.paymentMethod.network) | ||
: undefined, | ||
token: { | ||
version: payment.token?.paymentData?.version ? versionFromString(payment.token.paymentData.version) : undefined, | ||
signature: payment.token?.paymentData?.signature, | ||
header: { | ||
transactionId: payment.token?.paymentData?.header?.transactionId, | ||
applicationData: payment.token?.paymentData?.header?.applicationData, | ||
}, | ||
}, | ||
}, | ||
}; | ||
} |