@agent-cards/sdk 0.24.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +61 -4
- package/dist/adyen-merchant-hosted.generated.d.ts +1 -1
- package/dist/adyen-merchant-hosted.generated.js +128 -35
- package/dist/agent-amount.generated.js +1 -1
- package/dist/aurus.d.ts +33 -0
- package/dist/aurus.js +75 -0
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/capabilities.generated.js +1 -1
- package/dist/card-fields.generated.js +1756 -433
- package/dist/cardlink-vpos.d.ts +43 -0
- package/dist/cardlink-vpos.js +90 -0
- package/dist/cdp.js +13 -0
- package/dist/checkout-com.generated.js +5 -1
- package/dist/client.d.ts +66 -0
- package/dist/client.js +66 -0
- package/dist/cybersource-flex.generated.d.ts +39 -1
- package/dist/cybersource-flex.generated.js +100 -11
- package/dist/eghl.d.ts +40 -0
- package/dist/eghl.js +72 -0
- package/dist/gmo.generated.js +7 -2
- package/dist/hosted-entry.js +2 -0
- package/dist/paddle-tokenex.generated.js +7 -2
- package/dist/payrails.generated.js +7 -2
- package/dist/pre-claim.d.ts +2 -0
- package/dist/pre-claim.js +46 -2
- package/dist/preflight-catalog.json +154 -1
- package/dist/preflight-schemas.json +14 -0
- package/dist/preflight.generated.d.ts +5 -0
- package/dist/preflight.generated.js +40 -3
- package/dist/preparation.d.ts +7 -0
- package/dist/preparation.js +21 -0
- package/dist/primer.generated.js +1778 -455
- package/dist/shiji-sts.generated.js +7 -2
- package/dist/stripe-checkout.generated.js +1741 -470
- package/dist/substitutions.generated.js +94 -1
- package/dist/tap-payments.generated.js +7 -2
- package/dist/twoc2p.generated.js +7 -2
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cardlink's VPOS (the redirect payment page Greek banks give their merchants: Eurobank's paycenter on
|
|
3
|
+
* vpos.eurocommerce.gr, Cardlink's own on ecommerce.cardlink.gr, Nexi Greece's on www.alphaecommerce.gr), as this SDK
|
|
4
|
+
* reads it.
|
|
5
|
+
*
|
|
6
|
+
* The merchant's order page posts a signed entry form, top-level, to https://<host>/vpos/shophandlermpi, and the VPOS
|
|
7
|
+
* answers with its card page, whose form posts the card back to that same URL. The entry carries no card, and it is the
|
|
8
|
+
* one request this SDK pauses: the cardholder's device repeats it over the end-to-end TLS relay and fills the card into
|
|
9
|
+
* the page the VPOS returns to it (payment-core processors/cardlink_vpos.js). Every other POST the agent's browser makes
|
|
10
|
+
* to these hosts carries a card the agent typed or leads to a page that asks for one: the card page's own post and its
|
|
11
|
+
* card check, which share the entry's URL and carry the page's own fields, and anything posted to Cardlink's test
|
|
12
|
+
* hosts. This SDK aborts every one of them, so a placeholder card never reaches the VPOS.
|
|
13
|
+
*
|
|
14
|
+
* CARDLINK_VPOS_ENTRY_HOSTS is payment-core's CARDLINK_VPOS_HOSTS, and isCardlinkVposEntryUrl is payment-core's
|
|
15
|
+
* isCardlinkVposEntryUrl; cardlink-vpos.test.mjs pins both to payment-core.
|
|
16
|
+
*/
|
|
17
|
+
export declare const CARDLINK_VPOS_PSP = "cardlink_vpos";
|
|
18
|
+
export declare const CARDLINK_VPOS_ENTRY_HOSTS: readonly string[];
|
|
19
|
+
export declare const CARDLINK_VPOS_TEST_HOSTS: readonly string[];
|
|
20
|
+
/**
|
|
21
|
+
* Whether a URL is an entry exactly as a merchant's form action writes it: https, one of the three live hosts in lower
|
|
22
|
+
* case, the default port, no credentials, the path /vpos/shophandlermpi, and no query or fragment, not even an empty one.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isCardlinkVposEntryUrl(raw: unknown): boolean;
|
|
25
|
+
/** Whether a URL is on one of the VPOS's hosts, live or test: https, no credentials, any port, any case, a trailing dot or not. */
|
|
26
|
+
export declare function isCardlinkVposHost(raw: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Whether a body reads as a merchant's entry and never as the card page's post: a form whose every pair decodes, that
|
|
29
|
+
* names a mid and a digest, and that carries none of the card page's fields or a card field. payment-core's entry rules
|
|
30
|
+
* judge the rest at create.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isCardlinkVposEntryBody(body: string | null | undefined): boolean;
|
|
33
|
+
/** The one request on the VPOS's hosts this SDK pauses: a POST of an entry body to an entry URL. */
|
|
34
|
+
export declare function isCardlinkVposEntry(url: string, method: string, body: string | null | undefined): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Whether an adapter must hand this request to the pre-claim gates: it is on one of the VPOS's hosts and this build's
|
|
37
|
+
* registry serves the entry. The card page's posts share the entry's URL, so the CDP adapter pauses them through the
|
|
38
|
+
* recognizer's host patterns, and attachToPlaywright's route predicate asks this, so both adapters show the gates every
|
|
39
|
+
* request to a VPOS host once the lane is armed.
|
|
40
|
+
*/
|
|
41
|
+
export declare function isArmedCardlinkVposUrl(vault: {
|
|
42
|
+
isCardRequest(url: string, method?: string): boolean;
|
|
43
|
+
} | undefined, url: string): boolean;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cardlink's VPOS (the redirect payment page Greek banks give their merchants: Eurobank's paycenter on
|
|
3
|
+
* vpos.eurocommerce.gr, Cardlink's own on ecommerce.cardlink.gr, Nexi Greece's on www.alphaecommerce.gr), as this SDK
|
|
4
|
+
* reads it.
|
|
5
|
+
*
|
|
6
|
+
* The merchant's order page posts a signed entry form, top-level, to https://<host>/vpos/shophandlermpi, and the VPOS
|
|
7
|
+
* answers with its card page, whose form posts the card back to that same URL. The entry carries no card, and it is the
|
|
8
|
+
* one request this SDK pauses: the cardholder's device repeats it over the end-to-end TLS relay and fills the card into
|
|
9
|
+
* the page the VPOS returns to it (payment-core processors/cardlink_vpos.js). Every other POST the agent's browser makes
|
|
10
|
+
* to these hosts carries a card the agent typed or leads to a page that asks for one: the card page's own post and its
|
|
11
|
+
* card check, which share the entry's URL and carry the page's own fields, and anything posted to Cardlink's test
|
|
12
|
+
* hosts. This SDK aborts every one of them, so a placeholder card never reaches the VPOS.
|
|
13
|
+
*
|
|
14
|
+
* CARDLINK_VPOS_ENTRY_HOSTS is payment-core's CARDLINK_VPOS_HOSTS, and isCardlinkVposEntryUrl is payment-core's
|
|
15
|
+
* isCardlinkVposEntryUrl; cardlink-vpos.test.mjs pins both to payment-core.
|
|
16
|
+
*/
|
|
17
|
+
export const CARDLINK_VPOS_PSP = 'cardlink_vpos';
|
|
18
|
+
export const CARDLINK_VPOS_ENTRY_HOSTS = Object.freeze(['vpos.eurocommerce.gr', 'ecommerce.cardlink.gr', 'www.alphaecommerce.gr']);
|
|
19
|
+
export const CARDLINK_VPOS_TEST_HOSTS = Object.freeze(['eurocommerce-test.cardlink.gr', 'ecommerce-test.cardlink.gr',
|
|
20
|
+
'alphaecommerce-test.cardlink.gr']);
|
|
21
|
+
const ENTRY_PATH = '/vpos/shophandlermpi';
|
|
22
|
+
// An entry URL, for asking whether this build's registry serves the entry.
|
|
23
|
+
const PROBE = 'https://vpos.eurocommerce.gr/vpos/shophandlermpi';
|
|
24
|
+
// A field of the card page's form or of its card check, or any card field: an entry never carries one.
|
|
25
|
+
const PAGE_FIELD = /^(?:card[._]|cvv|cmd$|trid$|st$|paystep$|paymentmethod$|startbonus$|bonusdata$|what$|tds2_)/i;
|
|
26
|
+
/**
|
|
27
|
+
* Whether a URL is an entry exactly as a merchant's form action writes it: https, one of the three live hosts in lower
|
|
28
|
+
* case, the default port, no credentials, the path /vpos/shophandlermpi, and no query or fragment, not even an empty one.
|
|
29
|
+
*/
|
|
30
|
+
export function isCardlinkVposEntryUrl(raw) {
|
|
31
|
+
if (typeof raw !== 'string' || raw.length > 256 || raw.includes('?') || raw.includes('#'))
|
|
32
|
+
return false;
|
|
33
|
+
let url;
|
|
34
|
+
try {
|
|
35
|
+
url = new URL(raw);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return url.href === raw && url.protocol === 'https:' && !url.port && !url.username && !url.password
|
|
41
|
+
&& CARDLINK_VPOS_ENTRY_HOSTS.includes(url.hostname) && url.pathname === ENTRY_PATH;
|
|
42
|
+
}
|
|
43
|
+
/** Whether a URL is on one of the VPOS's hosts, live or test: https, no credentials, any port, any case, a trailing dot or not. */
|
|
44
|
+
export function isCardlinkVposHost(raw) {
|
|
45
|
+
let url;
|
|
46
|
+
try {
|
|
47
|
+
url = new URL(raw);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const host = url.hostname.toLowerCase().replace(/\.$/, '');
|
|
53
|
+
return url.protocol === 'https:' && !url.username && !url.password && (CARDLINK_VPOS_ENTRY_HOSTS.includes(host) || CARDLINK_VPOS_TEST_HOSTS.includes(host));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Whether a body reads as a merchant's entry and never as the card page's post: a form whose every pair decodes, that
|
|
57
|
+
* names a mid and a digest, and that carries none of the card page's fields or a card field. payment-core's entry rules
|
|
58
|
+
* judge the rest at create.
|
|
59
|
+
*/
|
|
60
|
+
export function isCardlinkVposEntryBody(body) {
|
|
61
|
+
if (typeof body !== 'string' || body === '')
|
|
62
|
+
return false;
|
|
63
|
+
const names = [];
|
|
64
|
+
for (const chunk of body.split('&')) {
|
|
65
|
+
const eq = chunk.indexOf('=');
|
|
66
|
+
if (eq < 1)
|
|
67
|
+
return false;
|
|
68
|
+
try {
|
|
69
|
+
names.push(decodeURIComponent(chunk.slice(0, eq).replace(/\+/g, ' ')));
|
|
70
|
+
decodeURIComponent(chunk.slice(eq + 1).replace(/\+/g, ' '));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return names.includes('mid') && names.includes('digest') && !names.some((name) => PAGE_FIELD.test(name));
|
|
77
|
+
}
|
|
78
|
+
/** The one request on the VPOS's hosts this SDK pauses: a POST of an entry body to an entry URL. */
|
|
79
|
+
export function isCardlinkVposEntry(url, method, body) {
|
|
80
|
+
return String(method).toUpperCase() === 'POST' && isCardlinkVposEntryUrl(url) && isCardlinkVposEntryBody(body);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Whether an adapter must hand this request to the pre-claim gates: it is on one of the VPOS's hosts and this build's
|
|
84
|
+
* registry serves the entry. The card page's posts share the entry's URL, so the CDP adapter pauses them through the
|
|
85
|
+
* recognizer's host patterns, and attachToPlaywright's route predicate asks this, so both adapters show the gates every
|
|
86
|
+
* request to a VPOS host once the lane is armed.
|
|
87
|
+
*/
|
|
88
|
+
export function isArmedCardlinkVposUrl(vault, url) {
|
|
89
|
+
return isCardlinkVposHost(url) && typeof vault?.isCardRequest === 'function' && vault.isCardRequest(PROBE, 'POST');
|
|
90
|
+
}
|
package/dist/cdp.js
CHANGED
|
@@ -27,6 +27,8 @@ import { isArmedRedsysUrl } from './redsys.js';
|
|
|
27
27
|
import { isArmedPrzelewy24Url } from './przelewy24.js';
|
|
28
28
|
import { isArmedBarionUrl } from './barion.js';
|
|
29
29
|
import { isArmedPayplugUrl } from './payplug.js';
|
|
30
|
+
import { isArmedCardlinkVposUrl } from './cardlink-vpos.js';
|
|
31
|
+
import { isArmedEghlUrl } from './eghl.js';
|
|
30
32
|
import { isArmedQuickpayUrl } from './quickpay.js';
|
|
31
33
|
import { COMGATE_CARD_PATTERNS, isArmedComgateUrl, servesComgate } from './comgate.js';
|
|
32
34
|
import { isArmedEximbayUrl } from './eximbay.js';
|
|
@@ -2453,6 +2455,11 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2453
2455
|
&& params?.frameId === pageTargetId && typeof params?.url === 'string') {
|
|
2454
2456
|
committedTopUrl = params.url.split('#')[0];
|
|
2455
2457
|
}
|
|
2458
|
+
// A history update that leaves the prepared page's origin, path and query as they were (a single-page
|
|
2459
|
+
// checkout's replaceState to its own URL, a hash change) is the same document, and keeps the preparation.
|
|
2460
|
+
if (method === 'Page.navigatedWithinDocument' && sessionId === pageSessionId && preparationFrameId && params?.frameId === preparationFrameId
|
|
2461
|
+
&& preparationGate.keepsDocument(params.url))
|
|
2462
|
+
return;
|
|
2456
2463
|
if (((method === 'Page.frameNavigated' && !params.frame?.parentId) || (method === 'Page.navigatedWithinDocument' && preparationFrameId && params.frameId === preparationFrameId)) && sessionId === pageSessionId) {
|
|
2457
2464
|
preparationGate.invalidate('merchant_document_changed');
|
|
2458
2465
|
mercadoCheckout.invalidate();
|
|
@@ -4029,6 +4036,12 @@ export async function attachToPlaywright(page, opts) {
|
|
|
4029
4036
|
// Every request to PayPlug's page host once its entry is served (payplug.ts): the page's card post reaches the
|
|
4030
4037
|
// PayPlug gate and fails.
|
|
4031
4038
|
|| isArmedPayplugUrl(opts.vault, url.toString())
|
|
4039
|
+
// Every request to the VPOS's hosts once its entry is served (cardlink-vpos.ts): the card page's post, which shares
|
|
4040
|
+
// the entry's URL, reaches the Cardlink gate and fails.
|
|
4041
|
+
|| isArmedCardlinkVposUrl(opts.vault, url.toString())
|
|
4042
|
+
// Every request to eGHL's hosts once its entry is served (eghl.ts): the card page's post, which shares the entry's
|
|
4043
|
+
// address, reaches the eGHL gate and fails.
|
|
4044
|
+
|| isArmedEghlUrl(opts.vault, url.toString())
|
|
4032
4045
|
// Every request to an NMI host whose entry is served (ekashu.ts), as attachToCdp arms the
|
|
4033
4046
|
// host: the card page's post and its 3-D Secure calls reach the NMI gate and fail.
|
|
4034
4047
|
|| isArmedEkashuUrl(opts.vault, url.toString())
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: a4f45fd0e69b19e8cb2da463b865012950ae5bcc9971c01d3e348a7de1a255ef
|
|
4
4
|
// src/checkout-com.js
|
|
5
5
|
var ENDPOINTS = Object.freeze({
|
|
6
6
|
production: ["https://api.checkout.com/tokens", "https://card-acquisition-gateway.checkout.com/tokens"],
|
|
7
7
|
sandbox: ["https://api.sandbox.checkout.com/tokens", "https://card-acquisition-gateway.sandbox.checkout.com/tokens"]
|
|
8
8
|
});
|
|
9
|
+
var MERCHANT_ENDPOINT = /^https:\/\/(?:[a-z0-9]+\.)?(?:api(\.sandbox)?\.checkout\.com\/tokens|devices\.api(\.sandbox)?\.checkout\.com\/(?:cag\/)?tokens)$/;
|
|
9
10
|
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
10
11
|
var own = (value, name) => Object.prototype.hasOwnProperty.call(value, name);
|
|
11
12
|
var keys = (value, allowed) => record(value) && Object.keys(value).every((name) => allowed.includes(name));
|
|
@@ -123,6 +124,9 @@ function checkoutComEnvironment(url) {
|
|
|
123
124
|
return "production";
|
|
124
125
|
if (ENDPOINTS.sandbox.includes(url))
|
|
125
126
|
return "sandbox";
|
|
127
|
+
const merchant = typeof url === "string" ? MERCHANT_ENDPOINT.exec(url) : null;
|
|
128
|
+
if (merchant?.[0] === url)
|
|
129
|
+
return merchant[1] || merchant[2] ? "sandbox" : "production";
|
|
126
130
|
return void 0;
|
|
127
131
|
}
|
|
128
132
|
var ADDRESS_TEXT = ["address_line1", "address_line2", "city", "state", "zip", "name"];
|
package/dist/client.d.ts
CHANGED
|
@@ -507,6 +507,34 @@ export declare const SUPPORTED_REGISTRY_FEATURES: readonly string[];
|
|
|
507
507
|
* authorize() needs the agent's pair, and the API holds its amount to the price. Served on the same
|
|
508
508
|
* terms, and the API holds the lane to Agentcard's own company.
|
|
509
509
|
*
|
|
510
|
+
* `aurus_one_time_token`: the card request Aurus Pay's ecom card frame (O'Reilly Auto Parts) sends to
|
|
511
|
+
* pecst<NN>.aurusepay.com/storeservices/ecom/oneTimeToken, the card sealed in the frame under a public key its own
|
|
512
|
+
* script carries. This build pauses it only when Aurus's card frame sent it (aurus.ts aurusPreClaim); the same
|
|
513
|
+
* request from the store's page or another frame fails in the browser before anything is created. The request
|
|
514
|
+
* names no amount, so authorize() needs the agent's pair, above zero. The cardholder's device does not seal for
|
|
515
|
+
* Aurus yet (payment-core processors/aurus.js), so a paused request opens no approval that pays.
|
|
516
|
+
*
|
|
517
|
+
* `viva_smart_checkout_chargetoken`: the card request Viva Wallet's Smart Checkout page sends as one
|
|
518
|
+
* JSON request to www.vivapayments.com/web2/checkout/v2/chargetokens (demo.vivapayments.com in test),
|
|
519
|
+
* on Pay, after the page's own reCAPTCHA run. This build pauses only the page's own card body at that
|
|
520
|
+
* exact URL (payment-core processors/viva_wallet.js); a body that keeps the card, pays with a stored
|
|
521
|
+
* card, converts the currency or is the page's second try after a decline fails in the browser before
|
|
522
|
+
* anything is created. The cardholder's device sends the card through Agentcard's checkout relay, since
|
|
523
|
+
* the page's request answers no other origin, and the page gets Viva's single-use charge token as
|
|
524
|
+
* payment-core's judge rebuilt it; the page then charges that token card free. The body names its
|
|
525
|
+
* amount, which the API holds to the agent's pair, and the API pays a live token only for an order
|
|
526
|
+
* payment-core pins. Served on the same terms, and the API holds the lane to Agentcard's own company.
|
|
527
|
+
*
|
|
528
|
+
* `paystack_pinned_key`: the charge Paystack's hosted checkout sends as one form POST to
|
|
529
|
+
* standard.paystack.co/charge/, the card only as `clientdata`, RSA ciphertext under the one key
|
|
530
|
+
* Paystack's page carries. This build pauses only the card page's own charge at that exact URL
|
|
531
|
+
* (payment-core processors/paystack.js); a charge that keeps the card, starts a plan or carries a PIN
|
|
532
|
+
* fails in the browser before anything is created. The cardholder's device encrypts the real card under
|
|
533
|
+
* the same pinned key and sends the charge itself, and the page gets Paystack's answer: paid, declined,
|
|
534
|
+
* or the issuer's 3-D Secure step, which the page then runs in the agent's browser. The charge names
|
|
535
|
+
* no amount, so authorize() needs the agent's pair, above zero. Served on the same terms, and the API
|
|
536
|
+
* holds the lane to Agentcard's own company.
|
|
537
|
+
*
|
|
510
538
|
* `usaepay_payment_key`: the card request USAePay's Pay.js card frame sends as one JSON request to
|
|
511
539
|
* www.usaepay.com/api/v2/pub/payment_keys (secure.usaepay.com alike; sandbox.usaepay.com in test), under
|
|
512
540
|
* the merchant's public key in its Authorization. This build pauses only the frame's own card body at
|
|
@@ -555,6 +583,31 @@ export declare const SUPPORTED_REGISTRY_FEATURES: readonly string[];
|
|
|
555
583
|
* approves. Served on the same terms: only to a build that lists it, for a company Agentcard turned
|
|
556
584
|
* ProcessOut on for.
|
|
557
585
|
*
|
|
586
|
+
* `monei_card_token`: the card request MONEI's card frame sends from MONEI's payment page
|
|
587
|
+
* (secure.monei.com/payments/<id>) to api.monei.com/v1/tokens, with the payment's id and the card. This
|
|
588
|
+
* build pauses only the frame's own body for a payment at that exact URL (payment-core
|
|
589
|
+
* processors/monei.js); MONEI's account flow, Click to Pay and a wallet on the same URL fail in the
|
|
590
|
+
* browser before anything is created. The request names neither the merchant nor the amount, so the API
|
|
591
|
+
* reads MONEI's own record of the payment and holds the agent's pair, above zero
|
|
592
|
+
* (agent-amount-processors.json), to MONEI's amount exactly. The cardholder's device sends the card to
|
|
593
|
+
* MONEI itself and the frame gets back MONEI's payment token alone, rebuilt by payment-core's judge.
|
|
594
|
+
* Served on the same terms: only to a build that lists it, for a company Agentcard turned MONEI on for.
|
|
595
|
+
*
|
|
596
|
+
* `frisbii_card_token`: the card request Frisbii Checkout's hosted payment page (checkout.reepay.com or
|
|
597
|
+
* checkout.frisbii.com, as an overlay, an embedded frame or a full window) sends to
|
|
598
|
+
* card.reepay.com or card.frisbii.com /v1/token/?session=<id>, with the merchant's public key and the
|
|
599
|
+
* card. This build pauses only the page's own body at that exact URL (payment-core
|
|
600
|
+
* processors/frisbii.js); any other body on it, one that keeps the card on file included, fails in the
|
|
601
|
+
* browser before anything is created. The page's two other card paths, a stored card's token
|
|
602
|
+
* (/v1/token/cof/) and Click to Pay (/v1/token/create_click_to_pay), are held and refused whatever
|
|
603
|
+
* their body, so neither leaves the browser either. The request names the amount only when
|
|
604
|
+
* the session carries 3-D Secure data, so the agent's pair is required, above zero
|
|
605
|
+
* (agent-amount-processors.json), and the API refuses it when it differs from the page's own. The
|
|
606
|
+
* cardholder's device sends the card to Frisbii
|
|
607
|
+
* itself and the page gets back Frisbii's card token or 3-D Secure step alone, rebuilt by payment-core's
|
|
608
|
+
* judge. Served on the same terms: only to a build that lists it, for a company Agentcard turned Frisbii
|
|
609
|
+
* on for.
|
|
610
|
+
*
|
|
558
611
|
* `aps_custom_merchant_page`: Amazon Payment Services' custom merchant page, whose own card form
|
|
559
612
|
* posts top-level to /FortAPI/paymentPage on checkout.payfort.com (sbcheckout.payfort.com on APS's
|
|
560
613
|
* sandbox) with service_command=TOKENIZATION. This build pauses that navigation; the cardholder's
|
|
@@ -598,6 +651,19 @@ export declare const SUPPORTED_REGISTRY_FEATURES: readonly string[];
|
|
|
598
651
|
* zero. Served only to a build that lists it, and the API turns PayPlug on for Agentcard's own
|
|
599
652
|
* company alone.
|
|
600
653
|
*
|
|
654
|
+
* `cardlink_vpos_hosted_payment_page`: Cardlink's VPOS, the payment page of Eurobank, Cardlink and Nexi
|
|
655
|
+
* Greece, whose card-free signed entry (a form post to /vpos/shophandlermpi on one of the three hosts) this build
|
|
656
|
+
* pauses for the cardholder's device, and whose card page's post and card check on the same URL this build never
|
|
657
|
+
* lets the agent's browser send (pre-claim.ts, cardlink-vpos.ts). Served only to a build that lists it, and the API
|
|
658
|
+
* turns the lane on for Agentcard's own company alone.
|
|
659
|
+
*
|
|
660
|
+
* `eghl_hosted_payment_page`: eGHL's payment page (ADAPTIS, formerly eGHL, on securepay.e-ghl.com), whose card-free
|
|
661
|
+
* entry (a GET of /IPG/payment.aspx with the payment in its query, which the merchant's checkout or eGHL's Shopify app
|
|
662
|
+
* sends the buyer to) this build pauses for the cardholder's device by its exact URL (hosted-entry.ts), and whose card
|
|
663
|
+
* page's post to the same address this build never lets the agent's browser send (pre-claim.ts, eghl.ts). The entry
|
|
664
|
+
* names its amount, and the API holds the agent's pair to it exactly. Served only to a build that lists it, and the API
|
|
665
|
+
* turns the lane on for Agentcard's own company alone.
|
|
666
|
+
*
|
|
601
667
|
* `paymob_checkout_pay`: the card payment Paymob's own checkout sends, from Unified Checkout
|
|
602
668
|
* (<country>.checkout.paymob.com) or from the Pixel card frame a merchant's page embeds, as JSON to
|
|
603
669
|
* https://<accept|uae|ksa|oman>.paymob.com/api/acceptance/payments/pay. This build pauses only the
|
package/dist/client.js
CHANGED
|
@@ -501,6 +501,34 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
|
|
|
501
501
|
* authorize() needs the agent's pair, and the API holds its amount to the price. Served on the same
|
|
502
502
|
* terms, and the API holds the lane to Agentcard's own company.
|
|
503
503
|
*
|
|
504
|
+
* `aurus_one_time_token`: the card request Aurus Pay's ecom card frame (O'Reilly Auto Parts) sends to
|
|
505
|
+
* pecst<NN>.aurusepay.com/storeservices/ecom/oneTimeToken, the card sealed in the frame under a public key its own
|
|
506
|
+
* script carries. This build pauses it only when Aurus's card frame sent it (aurus.ts aurusPreClaim); the same
|
|
507
|
+
* request from the store's page or another frame fails in the browser before anything is created. The request
|
|
508
|
+
* names no amount, so authorize() needs the agent's pair, above zero. The cardholder's device does not seal for
|
|
509
|
+
* Aurus yet (payment-core processors/aurus.js), so a paused request opens no approval that pays.
|
|
510
|
+
*
|
|
511
|
+
* `viva_smart_checkout_chargetoken`: the card request Viva Wallet's Smart Checkout page sends as one
|
|
512
|
+
* JSON request to www.vivapayments.com/web2/checkout/v2/chargetokens (demo.vivapayments.com in test),
|
|
513
|
+
* on Pay, after the page's own reCAPTCHA run. This build pauses only the page's own card body at that
|
|
514
|
+
* exact URL (payment-core processors/viva_wallet.js); a body that keeps the card, pays with a stored
|
|
515
|
+
* card, converts the currency or is the page's second try after a decline fails in the browser before
|
|
516
|
+
* anything is created. The cardholder's device sends the card through Agentcard's checkout relay, since
|
|
517
|
+
* the page's request answers no other origin, and the page gets Viva's single-use charge token as
|
|
518
|
+
* payment-core's judge rebuilt it; the page then charges that token card free. The body names its
|
|
519
|
+
* amount, which the API holds to the agent's pair, and the API pays a live token only for an order
|
|
520
|
+
* payment-core pins. Served on the same terms, and the API holds the lane to Agentcard's own company.
|
|
521
|
+
*
|
|
522
|
+
* `paystack_pinned_key`: the charge Paystack's hosted checkout sends as one form POST to
|
|
523
|
+
* standard.paystack.co/charge/, the card only as `clientdata`, RSA ciphertext under the one key
|
|
524
|
+
* Paystack's page carries. This build pauses only the card page's own charge at that exact URL
|
|
525
|
+
* (payment-core processors/paystack.js); a charge that keeps the card, starts a plan or carries a PIN
|
|
526
|
+
* fails in the browser before anything is created. The cardholder's device encrypts the real card under
|
|
527
|
+
* the same pinned key and sends the charge itself, and the page gets Paystack's answer: paid, declined,
|
|
528
|
+
* or the issuer's 3-D Secure step, which the page then runs in the agent's browser. The charge names
|
|
529
|
+
* no amount, so authorize() needs the agent's pair, above zero. Served on the same terms, and the API
|
|
530
|
+
* holds the lane to Agentcard's own company.
|
|
531
|
+
*
|
|
504
532
|
* `usaepay_payment_key`: the card request USAePay's Pay.js card frame sends as one JSON request to
|
|
505
533
|
* www.usaepay.com/api/v2/pub/payment_keys (secure.usaepay.com alike; sandbox.usaepay.com in test), under
|
|
506
534
|
* the merchant's public key in its Authorization. This build pauses only the frame's own card body at
|
|
@@ -549,6 +577,31 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
|
|
|
549
577
|
* approves. Served on the same terms: only to a build that lists it, for a company Agentcard turned
|
|
550
578
|
* ProcessOut on for.
|
|
551
579
|
*
|
|
580
|
+
* `monei_card_token`: the card request MONEI's card frame sends from MONEI's payment page
|
|
581
|
+
* (secure.monei.com/payments/<id>) to api.monei.com/v1/tokens, with the payment's id and the card. This
|
|
582
|
+
* build pauses only the frame's own body for a payment at that exact URL (payment-core
|
|
583
|
+
* processors/monei.js); MONEI's account flow, Click to Pay and a wallet on the same URL fail in the
|
|
584
|
+
* browser before anything is created. The request names neither the merchant nor the amount, so the API
|
|
585
|
+
* reads MONEI's own record of the payment and holds the agent's pair, above zero
|
|
586
|
+
* (agent-amount-processors.json), to MONEI's amount exactly. The cardholder's device sends the card to
|
|
587
|
+
* MONEI itself and the frame gets back MONEI's payment token alone, rebuilt by payment-core's judge.
|
|
588
|
+
* Served on the same terms: only to a build that lists it, for a company Agentcard turned MONEI on for.
|
|
589
|
+
*
|
|
590
|
+
* `frisbii_card_token`: the card request Frisbii Checkout's hosted payment page (checkout.reepay.com or
|
|
591
|
+
* checkout.frisbii.com, as an overlay, an embedded frame or a full window) sends to
|
|
592
|
+
* card.reepay.com or card.frisbii.com /v1/token/?session=<id>, with the merchant's public key and the
|
|
593
|
+
* card. This build pauses only the page's own body at that exact URL (payment-core
|
|
594
|
+
* processors/frisbii.js); any other body on it, one that keeps the card on file included, fails in the
|
|
595
|
+
* browser before anything is created. The page's two other card paths, a stored card's token
|
|
596
|
+
* (/v1/token/cof/) and Click to Pay (/v1/token/create_click_to_pay), are held and refused whatever
|
|
597
|
+
* their body, so neither leaves the browser either. The request names the amount only when
|
|
598
|
+
* the session carries 3-D Secure data, so the agent's pair is required, above zero
|
|
599
|
+
* (agent-amount-processors.json), and the API refuses it when it differs from the page's own. The
|
|
600
|
+
* cardholder's device sends the card to Frisbii
|
|
601
|
+
* itself and the page gets back Frisbii's card token or 3-D Secure step alone, rebuilt by payment-core's
|
|
602
|
+
* judge. Served on the same terms: only to a build that lists it, for a company Agentcard turned Frisbii
|
|
603
|
+
* on for.
|
|
604
|
+
*
|
|
552
605
|
* `aps_custom_merchant_page`: Amazon Payment Services' custom merchant page, whose own card form
|
|
553
606
|
* posts top-level to /FortAPI/paymentPage on checkout.payfort.com (sbcheckout.payfort.com on APS's
|
|
554
607
|
* sandbox) with service_command=TOKENIZATION. This build pauses that navigation; the cardholder's
|
|
@@ -592,6 +645,19 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
|
|
|
592
645
|
* zero. Served only to a build that lists it, and the API turns PayPlug on for Agentcard's own
|
|
593
646
|
* company alone.
|
|
594
647
|
*
|
|
648
|
+
* `cardlink_vpos_hosted_payment_page`: Cardlink's VPOS, the payment page of Eurobank, Cardlink and Nexi
|
|
649
|
+
* Greece, whose card-free signed entry (a form post to /vpos/shophandlermpi on one of the three hosts) this build
|
|
650
|
+
* pauses for the cardholder's device, and whose card page's post and card check on the same URL this build never
|
|
651
|
+
* lets the agent's browser send (pre-claim.ts, cardlink-vpos.ts). Served only to a build that lists it, and the API
|
|
652
|
+
* turns the lane on for Agentcard's own company alone.
|
|
653
|
+
*
|
|
654
|
+
* `eghl_hosted_payment_page`: eGHL's payment page (ADAPTIS, formerly eGHL, on securepay.e-ghl.com), whose card-free
|
|
655
|
+
* entry (a GET of /IPG/payment.aspx with the payment in its query, which the merchant's checkout or eGHL's Shopify app
|
|
656
|
+
* sends the buyer to) this build pauses for the cardholder's device by its exact URL (hosted-entry.ts), and whose card
|
|
657
|
+
* page's post to the same address this build never lets the agent's browser send (pre-claim.ts, eghl.ts). The entry
|
|
658
|
+
* names its amount, and the API holds the agent's pair to it exactly. Served only to a build that lists it, and the API
|
|
659
|
+
* turns the lane on for Agentcard's own company alone.
|
|
660
|
+
*
|
|
595
661
|
* `paymob_checkout_pay`: the card payment Paymob's own checkout sends, from Unified Checkout
|
|
596
662
|
* (<country>.checkout.paymob.com) or from the Pixel card frame a merchant's page embeds, as JSON to
|
|
597
663
|
* https://<accept|uae|ksa|oman>.paymob.com/api/acceptance/payments/pay. This build pauses only the
|
|
@@ -12,6 +12,19 @@ declare var CybersourceFlexError: {
|
|
|
12
12
|
};
|
|
13
13
|
declare function isVerifiedCaptureContext(value: any): boolean;
|
|
14
14
|
declare function flexHostEnvironment(hostname: any): "production" | "sandbox" | null;
|
|
15
|
+
declare var UNIFIED_CHECKOUT_HOSTS: Readonly<{
|
|
16
|
+
production: "up.cybersource.com";
|
|
17
|
+
sandbox: "testup.cybersource.com";
|
|
18
|
+
}>;
|
|
19
|
+
declare var UNIFIED_CHECKOUT_REVIEWED_CLIENT_VERSIONS: readonly string[];
|
|
20
|
+
declare var UNIFIED_CHECKOUT_FRAMES: readonly string[];
|
|
21
|
+
declare function unifiedCheckoutHostEnvironment(hostname: any): "production" | "sandbox" | null;
|
|
22
|
+
declare function parseUnifiedCheckoutFrame(rawUrl: any): Readonly<{
|
|
23
|
+
environment: "production" | "sandbox";
|
|
24
|
+
frame: string;
|
|
25
|
+
asset: string;
|
|
26
|
+
captureContext: string;
|
|
27
|
+
}> | null;
|
|
15
28
|
declare var CYBERSOURCE_FLEX_PSP: string;
|
|
16
29
|
declare var CYBERSOURCE_FLEX_CONTENT_TYPE: string;
|
|
17
30
|
declare var CYBERSOURCE_FLEX_TOKENS_URLS: Readonly<{
|
|
@@ -38,6 +51,7 @@ declare function verifyCaptureContext(jwt: any, { crypto, now }?: {}): Promise<R
|
|
|
38
51
|
modulusBytes: number;
|
|
39
52
|
index: any;
|
|
40
53
|
contextType: any;
|
|
54
|
+
clientVersion: any;
|
|
41
55
|
allowedCardNetworks: readonly any[] | null;
|
|
42
56
|
targetOrigins: readonly any[];
|
|
43
57
|
iat: any;
|
|
@@ -76,6 +90,29 @@ declare function buildCardPlaintext(verified: any, card: any, { fields, trigger,
|
|
|
76
90
|
trigger?: string | undefined;
|
|
77
91
|
}): string;
|
|
78
92
|
declare function sealForContext(verified: any, plaintext: any, { crypto }?: {}): Promise<string>;
|
|
93
|
+
declare function verifyUnifiedCheckoutContext(jwt: any, { crypto, now }?: {}): Promise<Readonly<{
|
|
94
|
+
raw: any;
|
|
95
|
+
signingKid: any;
|
|
96
|
+
environment: any;
|
|
97
|
+
origin: string;
|
|
98
|
+
path: string;
|
|
99
|
+
url: string;
|
|
100
|
+
jwk: Readonly<{
|
|
101
|
+
kty: "RSA";
|
|
102
|
+
n: any;
|
|
103
|
+
e: any;
|
|
104
|
+
kid: any;
|
|
105
|
+
}>;
|
|
106
|
+
modulusBytes: number;
|
|
107
|
+
index: any;
|
|
108
|
+
contextType: any;
|
|
109
|
+
clientVersion: any;
|
|
110
|
+
allowedCardNetworks: readonly any[] | null;
|
|
111
|
+
targetOrigins: readonly any[];
|
|
112
|
+
iat: any;
|
|
113
|
+
exp: any;
|
|
114
|
+
}>>;
|
|
115
|
+
declare function buildUnifiedCheckoutPlaintext(verified: any, card: any, { billTo, now }?: {}): string;
|
|
79
116
|
declare var CYBERSOURCE_FLEX_REFUSAL_REASONS: readonly string[];
|
|
80
117
|
declare function cybersourceFlexRefusalCode(text: any): string | null;
|
|
81
118
|
declare function isCybersourceFlexTokenShape(text: any): boolean;
|
|
@@ -107,6 +144,7 @@ declare function admitCybersourceFlexPreparation(prepared: any, { crypto, now }?
|
|
|
107
144
|
modulusBytes: number;
|
|
108
145
|
index: any;
|
|
109
146
|
contextType: any;
|
|
147
|
+
clientVersion: any;
|
|
110
148
|
allowedCardNetworks: readonly any[] | null;
|
|
111
149
|
targetOrigins: readonly any[];
|
|
112
150
|
iat: any;
|
|
@@ -115,4 +153,4 @@ declare function admitCybersourceFlexPreparation(prepared: any, { crypto, now }?
|
|
|
115
153
|
fields: readonly string[];
|
|
116
154
|
}>>;
|
|
117
155
|
declare function sameCybersourceFlexPreparation(prepared: any, request: any): boolean;
|
|
118
|
-
export { CYBERSOURCE_FLEX_CAPTURE_CONTEXT_MAX_LENGTH, CYBERSOURCE_FLEX_CONTENT_TYPE, CYBERSOURCE_FLEX_PRESEAL_TRIGGER, CYBERSOURCE_FLEX_PSP, CYBERSOURCE_FLEX_REFUSAL_REASONS, CYBERSOURCE_FLEX_REVIEWED_IFRAME_VERSIONS, CYBERSOURCE_FLEX_RULES_SOURCE, CYBERSOURCE_FLEX_SIGNING_KEYS, CYBERSOURCE_FLEX_TEST_PANS, CYBERSOURCE_FLEX_TOKENS_URLS, CybersourceFlexError, admitCybersourceFlexPreparation, assertCybersourceFlexTemplate, buildCardPlaintext, cybersourceFlexEnvironment, flexHostEnvironment as cybersourceFlexHostEnvironment, cybersourceFlexPreparationUrl, cybersourceFlexRefusalCode, cybersourceFlexTemplateKid, detectCardTypes, isCybersourceFlexMediaType, isCybersourceFlexRequest, isCybersourceFlexTemplateBody, isCybersourceFlexTokenShape, isPreparedCybersourceFlexRequest, isVerifiedCaptureContext, parseMicroformFragment, sameCybersourceFlexPreparation, sealForContext, transientTokenFacts, transientTokenSigned, verifyCaptureContext };
|
|
156
|
+
export { CYBERSOURCE_FLEX_CAPTURE_CONTEXT_MAX_LENGTH, CYBERSOURCE_FLEX_CONTENT_TYPE, CYBERSOURCE_FLEX_PRESEAL_TRIGGER, CYBERSOURCE_FLEX_PSP, CYBERSOURCE_FLEX_REFUSAL_REASONS, CYBERSOURCE_FLEX_REVIEWED_IFRAME_VERSIONS, CYBERSOURCE_FLEX_RULES_SOURCE, CYBERSOURCE_FLEX_SIGNING_KEYS, CYBERSOURCE_FLEX_TEST_PANS, CYBERSOURCE_FLEX_TOKENS_URLS, CybersourceFlexError, UNIFIED_CHECKOUT_FRAMES, UNIFIED_CHECKOUT_HOSTS, UNIFIED_CHECKOUT_REVIEWED_CLIENT_VERSIONS, admitCybersourceFlexPreparation, assertCybersourceFlexTemplate, buildCardPlaintext, buildUnifiedCheckoutPlaintext, cybersourceFlexEnvironment, flexHostEnvironment as cybersourceFlexHostEnvironment, cybersourceFlexPreparationUrl, cybersourceFlexRefusalCode, cybersourceFlexTemplateKid, detectCardTypes, isCybersourceFlexMediaType, isCybersourceFlexRequest, isCybersourceFlexTemplateBody, isCybersourceFlexTokenShape, isPreparedCybersourceFlexRequest, isVerifiedCaptureContext, parseMicroformFragment, parseUnifiedCheckoutFrame, sameCybersourceFlexPreparation, sealForContext, transientTokenFacts, transientTokenSigned, unifiedCheckoutHostEnvironment, verifyCaptureContext, verifyUnifiedCheckoutContext };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: a9a624dbdd5a025d710f99e5ce83a985e4561b4db6d3e60dc427b5e406e4b653
|
|
4
4
|
// src/cybersource-flex-rules.js
|
|
5
5
|
var CYBERSOURCE_FLEX_RULES_SOURCE = Object.freeze({ version: "2.12.1", sha256: "8429ebae83e9745cd53ad8ff0d9ba69bee0087c1435ed0695a25444bed418327" });
|
|
6
6
|
var CYBERSOURCE_FLEX_RULES = [
|
|
@@ -201,6 +201,7 @@ async function sealCompactJwe(jwk, plaintext, { crypto }) {
|
|
|
201
201
|
}
|
|
202
202
|
// src/cybersource-flex-context.js
|
|
203
203
|
var FLEX_TOKENS_PATH = "/flex/v2/tokens";
|
|
204
|
+
var UNIFIED_CHECKOUT_TOKENS_PATH = "/flex/v2/tokens/uc";
|
|
204
205
|
var FLEX_HOSTS = Object.freeze({ production: "flex.cybersource.com", sandbox: "testflex.cybersource.com" });
|
|
205
206
|
var CAPTURE_CONTEXT_MAX_LENGTH = 16384;
|
|
206
207
|
var CLOCK_SKEW_MS = 6e4;
|
|
@@ -233,7 +234,8 @@ function origins(value) {
|
|
|
233
234
|
return Object.freeze([]);
|
|
234
235
|
return Object.freeze(value.filter((origin) => typeof origin === "string" && origin.length <= 2048).slice(0, 16));
|
|
235
236
|
}
|
|
236
|
-
async function verifyContextWithKeys(jwt, keys, { crypto, now } = {}) {
|
|
237
|
+
async function verifyContextWithKeys(jwt, keys, { crypto, now, kind = "microform" } = {}) {
|
|
238
|
+
const unified = kind === "unified_checkout";
|
|
237
239
|
const [encodedHeader] = compactParts(jwt, 3, CAPTURE_CONTEXT_MAX_LENGTH, "format");
|
|
238
240
|
const peek = jsonFromBytes(base64UrlToBytes(encodedHeader), "format");
|
|
239
241
|
const kid = peek.kid;
|
|
@@ -254,8 +256,9 @@ async function verifyContextWithKeys(jwt, keys, { crypto, now } = {}) {
|
|
|
254
256
|
if (!record(flx))
|
|
255
257
|
refuse("format", "the capture context has no Flex section.");
|
|
256
258
|
const origin = `https://${host}`;
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
+
const path = unified ? UNIFIED_CHECKOUT_TOKENS_PATH : FLEX_TOKENS_PATH;
|
|
260
|
+
const url = `${origin}${path}`;
|
|
261
|
+
if (unified ? flx.origin !== origin || flx.tokensUrl !== url || own(flx, "path") : flx.origin !== origin || flx.path !== FLEX_TOKENS_PATH || own(flx, "tokensUrl") && flx.tokensUrl !== url) {
|
|
259
262
|
refuse("url_mismatch", `the capture context does not send the card to ${url}.`);
|
|
260
263
|
}
|
|
261
264
|
const jwk = flx.jwk;
|
|
@@ -271,21 +274,22 @@ async function verifyContextWithKeys(jwt, keys, { crypto, now } = {}) {
|
|
|
271
274
|
refuse("expired", "the capture context has expired.");
|
|
272
275
|
}
|
|
273
276
|
const ctx = Array.isArray(payload.ctx) ? payload.ctx : [];
|
|
274
|
-
const index = ctx.findIndex((entry) => record(entry) && typeof entry.type === "string" && /^mf
|
|
277
|
+
const index = ctx.findIndex((entry) => record(entry) && typeof entry.type === "string" && (unified ? /^uc-/ : /^mf-/).test(entry.type));
|
|
275
278
|
if (index < 0)
|
|
276
|
-
refuse("microform", "the capture context is not a Microform context.");
|
|
279
|
+
refuse("microform", unified ? "the capture context is not a Unified Checkout context." : "the capture context is not a Microform context.");
|
|
277
280
|
const data = record(ctx[index].data) ? ctx[index].data : {};
|
|
278
281
|
const context = Object.freeze({
|
|
279
282
|
raw: jwt,
|
|
280
283
|
signingKid: kid,
|
|
281
284
|
environment,
|
|
282
285
|
origin,
|
|
283
|
-
path
|
|
286
|
+
path,
|
|
284
287
|
url,
|
|
285
288
|
jwk: Object.freeze({ kty: "RSA", n: jwk.n, e: jwk.e, kid: jwk.kid }),
|
|
286
289
|
modulusBytes: Math.ceil(bits / 8),
|
|
287
290
|
index,
|
|
288
291
|
contextType: ctx[index].type,
|
|
292
|
+
clientVersion: unified && typeof data.clientVersion === "string" && data.clientVersion.length <= 32 ? data.clientVersion : null,
|
|
289
293
|
allowedCardNetworks: networks(data.allowedCardNetworks),
|
|
290
294
|
targetOrigins: origins(data.targetOrigins),
|
|
291
295
|
iat: Number.isFinite(payload.iat) ? payload.iat : null,
|
|
@@ -294,6 +298,51 @@ async function verifyContextWithKeys(jwt, keys, { crypto, now } = {}) {
|
|
|
294
298
|
VERIFIED.add(context);
|
|
295
299
|
return context;
|
|
296
300
|
}
|
|
301
|
+
// src/cybersource-unified-checkout.js
|
|
302
|
+
var UNIFIED_CHECKOUT_HOSTS = Object.freeze({ production: "up.cybersource.com", sandbox: "testup.cybersource.com" });
|
|
303
|
+
var UNIFIED_CHECKOUT_REVIEWED_CLIENT_VERSIONS = Object.freeze(["1.8.2"]);
|
|
304
|
+
var UNIFIED_CHECKOUT_FRAMES = Object.freeze(["mce", "orc", "ga"]);
|
|
305
|
+
var FRAME_PATH = /^\/uc\/v1\/assets\/([A-Za-z0-9_-]{16,1024})\/(mce|orc|ga)\/(mce|orc|ga)\.html$/;
|
|
306
|
+
var FRAGMENT_MAX_LENGTH = CAPTURE_CONTEXT_MAX_LENGTH + 4096;
|
|
307
|
+
function unifiedCheckoutHostEnvironment(hostname) {
|
|
308
|
+
const host = String(hostname ?? "").toLowerCase();
|
|
309
|
+
if (host === UNIFIED_CHECKOUT_HOSTS.production)
|
|
310
|
+
return "production";
|
|
311
|
+
if (host === UNIFIED_CHECKOUT_HOSTS.sandbox)
|
|
312
|
+
return "sandbox";
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
function parseUnifiedCheckoutFrame(rawUrl) {
|
|
316
|
+
if (typeof rawUrl !== "string" || rawUrl.length > FRAGMENT_MAX_LENGTH + 2048)
|
|
317
|
+
return null;
|
|
318
|
+
let url;
|
|
319
|
+
try {
|
|
320
|
+
url = new URL(rawUrl);
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
const environment = unifiedCheckoutHostEnvironment(url.hostname);
|
|
326
|
+
const path = FRAME_PATH.exec(url.pathname);
|
|
327
|
+
if (url.protocol !== "https:" || url.port || url.username || url.password || !environment || !path || path[2] !== path[3])
|
|
328
|
+
return null;
|
|
329
|
+
const fragment = url.hash.slice(1);
|
|
330
|
+
if (!fragment || fragment.length > FRAGMENT_MAX_LENGTH)
|
|
331
|
+
return null;
|
|
332
|
+
let value;
|
|
333
|
+
try {
|
|
334
|
+
value = JSON.parse(decodeURIComponent(fragment));
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
340
|
+
return null;
|
|
341
|
+
const ctx = value.ctx;
|
|
342
|
+
if (typeof ctx !== "string" || ctx.length < 1 || ctx.length > CAPTURE_CONTEXT_MAX_LENGTH)
|
|
343
|
+
return null;
|
|
344
|
+
return Object.freeze({ environment, frame: path[2], asset: path[1], captureContext: ctx });
|
|
345
|
+
}
|
|
297
346
|
// src/cybersource-flex.js
|
|
298
347
|
var CYBERSOURCE_FLEX_PSP = "cybersource_flex";
|
|
299
348
|
var CYBERSOURCE_FLEX_CONTENT_TYPE = "application/jwt; charset=utf-8";
|
|
@@ -343,11 +392,11 @@ function cybersourceFlexEnvironment(url) {
|
|
|
343
392
|
return "sandbox";
|
|
344
393
|
return void 0;
|
|
345
394
|
}
|
|
346
|
-
var
|
|
395
|
+
var FRAGMENT_MAX_LENGTH2 = 16384;
|
|
347
396
|
var IFRAME_PATH = /^\/microform\/bundle\/v(\d+\.\d+\.\d+)\/iframe\.html$/;
|
|
348
397
|
var FIELD_TYPES = Object.freeze(["number", "securityCode"]);
|
|
349
398
|
function parseMicroformFragment(rawUrl) {
|
|
350
|
-
if (typeof rawUrl !== "string" || rawUrl.length >
|
|
399
|
+
if (typeof rawUrl !== "string" || rawUrl.length > FRAGMENT_MAX_LENGTH2 + 2048)
|
|
351
400
|
return null;
|
|
352
401
|
let url;
|
|
353
402
|
try {
|
|
@@ -361,7 +410,7 @@ function parseMicroformFragment(rawUrl) {
|
|
|
361
410
|
if (url.protocol !== "https:" || url.port || url.username || url.password || !environment || !path)
|
|
362
411
|
return null;
|
|
363
412
|
const fragment = url.hash.slice(1);
|
|
364
|
-
if (!fragment || fragment.length >
|
|
413
|
+
if (!fragment || fragment.length > FRAGMENT_MAX_LENGTH2)
|
|
365
414
|
return null;
|
|
366
415
|
let value;
|
|
367
416
|
try {
|
|
@@ -556,6 +605,46 @@ async function sealForContext(verified, plaintext, { crypto } = {}) {
|
|
|
556
605
|
refuse("context", "the capture context was not verified on this device.");
|
|
557
606
|
return sealCompactJwe(verified.jwk, plaintext, { crypto });
|
|
558
607
|
}
|
|
608
|
+
function verifyUnifiedCheckoutContext(jwt, { crypto, now } = {}) {
|
|
609
|
+
return verifyContextWithKeys(jwt, CYBERSOURCE_FLEX_SIGNING_KEYS, { crypto, now, kind: "unified_checkout" });
|
|
610
|
+
}
|
|
611
|
+
var BILL_TO_NAME = /^[^\u0000-\u001f\u007f<>]{1,60}$/;
|
|
612
|
+
var BILL_TO_EMAIL = /^[^\s@<>]{1,64}@[^\s@<>]{1,190}$/;
|
|
613
|
+
function buildUnifiedCheckoutPlaintext(verified, card, { billTo, now } = {}) {
|
|
614
|
+
if (!isVerifiedCaptureContext(verified) || !/^uc-/.test(verified.contextType))
|
|
615
|
+
refuse("context", "the capture context was not verified as a Unified Checkout context on this device.");
|
|
616
|
+
if (!UNIFIED_CHECKOUT_REVIEWED_CLIENT_VERSIONS.includes(verified.clientVersion))
|
|
617
|
+
refuse("microform_version", "this Unified Checkout client version was not reviewed.");
|
|
618
|
+
const first = billTo?.firstName;
|
|
619
|
+
const last = billTo?.lastName;
|
|
620
|
+
const email = billTo?.email;
|
|
621
|
+
if (typeof first !== "string" || !BILL_TO_NAME.test(first) || typeof last !== "string" || !BILL_TO_NAME.test(last) || email !== void 0 && (typeof email !== "string" || !BILL_TO_EMAIL.test(email)))
|
|
622
|
+
refuse("fields", "the billing name or email is not one the card entry takes.");
|
|
623
|
+
const normalized = flexCard(card, typeof now === "function" ? now() : Date.now());
|
|
624
|
+
const detected = detectCardTypes(normalized.number, verified.allowedCardNetworks ?? void 0);
|
|
625
|
+
if (detected.codes.length === 0)
|
|
626
|
+
refuse("card_network", "this merchant's CyberSource form does not accept this card network.");
|
|
627
|
+
if (!detected.valid)
|
|
628
|
+
refuse("card_invalid", "the card number fails its network's length or check digit.");
|
|
629
|
+
if (detected.securityCode.required && !new RegExp(`^[0-9]{${detected.securityCode.length}}$`).test(normalized.cvc)) {
|
|
630
|
+
refuse("card_security_code", "the security code has the wrong length for this card.");
|
|
631
|
+
}
|
|
632
|
+
const data = {
|
|
633
|
+
PANENTRY: {
|
|
634
|
+
orderInformation: { billTo: { firstName: first, lastName: last, ...email !== void 0 ? { email } : {} } },
|
|
635
|
+
paymentInformation: { card: {
|
|
636
|
+
number: normalized.number,
|
|
637
|
+
expirationMonth: normalized.expirationMonth,
|
|
638
|
+
expirationYear: normalized.expirationYear,
|
|
639
|
+
securityCode: normalized.cvc,
|
|
640
|
+
type: detected.codes[0]
|
|
641
|
+
} }
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
const plaintext = JSON.stringify({ data, context: verified.raw, index: 0 }).replace(/[\u0080-\uffff]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
645
|
+
asciiBytes(plaintext, "card_ascii");
|
|
646
|
+
return plaintext;
|
|
647
|
+
}
|
|
559
648
|
var TOKEN_MAX_LENGTH = 8192;
|
|
560
649
|
var CYBERSOURCE_FLEX_REFUSAL_REASONS = Object.freeze([
|
|
561
650
|
"VALIDATION_ERROR",
|
|
@@ -728,4 +817,4 @@ function sameCybersourceFlexPreparation(prepared, request) {
|
|
|
728
817
|
const theirs = new Set(two.fields);
|
|
729
818
|
return mine.size === one.fields.length && theirs.size === two.fields.length && mine.size === theirs.size && [...mine].every((field) => theirs.has(field));
|
|
730
819
|
}
|
|
731
|
-
export { CYBERSOURCE_FLEX_CAPTURE_CONTEXT_MAX_LENGTH, CYBERSOURCE_FLEX_CONTENT_TYPE, CYBERSOURCE_FLEX_PRESEAL_TRIGGER, CYBERSOURCE_FLEX_PSP, CYBERSOURCE_FLEX_REFUSAL_REASONS, CYBERSOURCE_FLEX_REVIEWED_IFRAME_VERSIONS, CYBERSOURCE_FLEX_RULES_SOURCE, CYBERSOURCE_FLEX_SIGNING_KEYS, CYBERSOURCE_FLEX_TEST_PANS, CYBERSOURCE_FLEX_TOKENS_URLS, CybersourceFlexError, admitCybersourceFlexPreparation, assertCybersourceFlexTemplate, buildCardPlaintext, cybersourceFlexEnvironment, flexHostEnvironment as cybersourceFlexHostEnvironment, cybersourceFlexPreparationUrl, cybersourceFlexRefusalCode, cybersourceFlexTemplateKid, detectCardTypes, isCybersourceFlexMediaType, isCybersourceFlexRequest, isCybersourceFlexTemplateBody, isCybersourceFlexTokenShape, isPreparedCybersourceFlexRequest, isVerifiedCaptureContext, parseMicroformFragment, sameCybersourceFlexPreparation, sealForContext, transientTokenFacts, transientTokenSigned, verifyCaptureContext };
|
|
820
|
+
export { CYBERSOURCE_FLEX_CAPTURE_CONTEXT_MAX_LENGTH, CYBERSOURCE_FLEX_CONTENT_TYPE, CYBERSOURCE_FLEX_PRESEAL_TRIGGER, CYBERSOURCE_FLEX_PSP, CYBERSOURCE_FLEX_REFUSAL_REASONS, CYBERSOURCE_FLEX_REVIEWED_IFRAME_VERSIONS, CYBERSOURCE_FLEX_RULES_SOURCE, CYBERSOURCE_FLEX_SIGNING_KEYS, CYBERSOURCE_FLEX_TEST_PANS, CYBERSOURCE_FLEX_TOKENS_URLS, CybersourceFlexError, UNIFIED_CHECKOUT_FRAMES, UNIFIED_CHECKOUT_HOSTS, UNIFIED_CHECKOUT_REVIEWED_CLIENT_VERSIONS, admitCybersourceFlexPreparation, assertCybersourceFlexTemplate, buildCardPlaintext, buildUnifiedCheckoutPlaintext, cybersourceFlexEnvironment, flexHostEnvironment as cybersourceFlexHostEnvironment, cybersourceFlexPreparationUrl, cybersourceFlexRefusalCode, cybersourceFlexTemplateKid, detectCardTypes, isCybersourceFlexMediaType, isCybersourceFlexRequest, isCybersourceFlexTemplateBody, isCybersourceFlexTokenShape, isPreparedCybersourceFlexRequest, isVerifiedCaptureContext, parseMicroformFragment, parseUnifiedCheckoutFrame, sameCybersourceFlexPreparation, sealForContext, transientTokenFacts, transientTokenSigned, unifiedCheckoutHostEnvironment, verifyCaptureContext, verifyUnifiedCheckoutContext };
|