@agent-cards/sdk 0.20.0 → 0.22.0
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 +51 -0
- package/PREFLIGHT.md +34 -0
- package/README.md +1217 -15
- package/dist/aci.d.ts +173 -0
- package/dist/aci.generated.d.ts +87 -0
- package/dist/aci.generated.js +306 -0
- package/dist/aci.js +371 -0
- package/dist/adyen-merchant-hosted.generated.d.ts +3 -3
- package/dist/adyen-merchant-hosted.generated.js +283 -49
- package/dist/agentcard.d.ts +9 -2
- package/dist/agentcard.js +4 -2
- package/dist/amadeus-checkout.generated.d.ts +57 -0
- package/dist/amadeus-checkout.generated.js +549 -0
- package/dist/amadeus.d.ts +41 -0
- package/dist/amadeus.js +81 -0
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/card-endpoint.d.ts +177 -0
- package/dist/card-endpoint.js +286 -0
- package/dist/card-fields.generated.d.ts +5 -3
- package/dist/card-fields.generated.js +284 -7
- package/dist/cdp.d.ts +6 -1
- package/dist/cdp.js +983 -147
- package/dist/client.d.ts +493 -13
- package/dist/client.js +1100 -82
- package/dist/creditguard.generated.d.ts +79 -0
- package/dist/creditguard.generated.js +662 -0
- package/dist/cse-body.js +11 -1
- package/dist/cybersource-flex.d.ts +183 -0
- package/dist/cybersource-flex.generated.d.ts +92 -0
- package/dist/cybersource-flex.generated.js +689 -0
- package/dist/cybersource-flex.js +275 -0
- package/dist/datatrans.d.ts +96 -0
- package/dist/datatrans.generated.d.ts +64 -0
- package/dist/datatrans.generated.js +426 -0
- package/dist/datatrans.js +178 -0
- package/dist/elavon-converge.d.ts +37 -0
- package/dist/elavon-converge.generated.d.ts +49 -0
- package/dist/elavon-converge.generated.js +439 -0
- package/dist/elavon-converge.js +84 -0
- package/dist/eprotect.d.ts +152 -0
- package/dist/eprotect.generated.d.ts +77 -0
- package/dist/eprotect.generated.js +498 -0
- package/dist/eprotect.js +222 -0
- package/dist/gmo.d.ts +63 -0
- package/dist/gmo.generated.d.ts +60 -0
- package/dist/gmo.generated.js +586 -0
- package/dist/gmo.js +119 -0
- package/dist/hosted-form.d.ts +3 -2
- package/dist/hosted-form.js +3 -2
- package/dist/index.d.ts +19 -3
- package/dist/index.js +6 -1
- package/dist/juspay-gate.d.ts +82 -0
- package/dist/juspay-gate.js +126 -0
- package/dist/juspay.generated.d.ts +89 -0
- package/dist/juspay.generated.js +705 -0
- package/dist/lifecycle.d.ts +62 -6
- package/dist/lifecycle.js +123 -8
- package/dist/merchant-card-endpoints.generated.d.ts +63 -0
- package/dist/merchant-card-endpoints.generated.js +1103 -0
- package/dist/merchant-hosted.d.ts +4 -1
- package/dist/merchant-hosted.js +5 -2
- package/dist/merchant-session-probe.d.ts +48 -0
- package/dist/merchant-session-probe.js +53 -0
- package/dist/merchant-session.generated.d.ts +69 -0
- package/dist/merchant-session.generated.js +919 -0
- package/dist/payrails.d.ts +133 -0
- package/dist/payrails.generated.d.ts +73 -0
- package/dist/payrails.generated.js +596 -0
- package/dist/payrails.js +305 -0
- package/dist/pelecard.d.ts +32 -0
- package/dist/pelecard.generated.d.ts +32 -0
- package/dist/pelecard.generated.js +283 -0
- package/dist/pelecard.js +42 -0
- package/dist/pre-claim.d.ts +84 -3
- package/dist/pre-claim.js +987 -9
- package/dist/preflight-catalog.json +2310 -263
- package/dist/preflight-schemas.json +187 -6
- package/dist/preflight.generated.d.ts +1 -1
- package/dist/preflight.generated.js +247 -4
- package/dist/preparation.d.ts +5 -2
- package/dist/preparation.js +36 -10
- package/dist/prepared-processor.d.ts +86 -5
- package/dist/prepared-processor.js +157 -6
- package/dist/primer.d.ts +53 -0
- package/dist/primer.generated.d.ts +38 -0
- package/dist/primer.generated.js +624 -0
- package/dist/primer.js +82 -0
- package/dist/registry.d.ts +114 -12
- package/dist/registry.js +85 -11
- package/dist/shiji-sts.d.ts +144 -0
- package/dist/shiji-sts.generated.d.ts +72 -0
- package/dist/shiji-sts.generated.js +913 -0
- package/dist/shiji-sts.js +222 -0
- package/dist/stripe-checkout.generated.d.ts +1 -1
- package/dist/stripe-checkout.generated.js +735 -10
- package/dist/stripe-setup.d.ts +16 -0
- package/dist/stripe-setup.js +61 -0
- package/dist/substitutions.generated.js +187 -29
- package/dist/verifone.d.ts +68 -0
- package/dist/verifone.generated.d.ts +51 -0
- package/dist/verifone.generated.js +1401 -0
- package/dist/verifone.js +119 -0
- package/dist/voice-types.d.ts +27 -0
- package/dist/voice.d.ts +6 -1
- package/dist/voice.js +6 -1
- package/dist/wspay.d.ts +41 -0
- package/dist/wspay.generated.d.ts +41 -0
- package/dist/wspay.generated.js +370 -0
- package/dist/wspay.js +65 -0
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +3 -3
|
@@ -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: f3bee23e52b029d04c67ea1b9249334bd649c09b46367ee3c8afcb841a7cb50d
|
|
4
4
|
// src/deep-freeze.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -205,9 +205,10 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
205
205
|
// Accept.js. PAN@ securePaymentContainerRequest.data.token.cardNumber.
|
|
206
206
|
// Auth is body-level (merchantAuthentication: apiLoginID + clientKey) — nothing to replay.
|
|
207
207
|
// NOTE: prod is api2, not api. `api.authorize.net` is the server-side AIM/API host and is
|
|
208
|
-
// deliberately NOT allowlisted
|
|
209
|
-
// (secure2.authorize.net/gateway/transact.dll)
|
|
210
|
-
//
|
|
208
|
+
// deliberately NOT allowlisted: a browser never posts a PAN there. SIM and DPM
|
|
209
|
+
// (secure2.authorize.net/gateway/transact.dll) are deprecated by Authorize.Net, not retired, and
|
|
210
|
+
// post the card as a top-level form navigation rather than an XHR: the separate
|
|
211
|
+
// authorize_net_dpm entry (mode hosted_form) covers them, on hosts this entry never shares.
|
|
211
212
|
// Coverage caveat: AcceptUI (the hosted lightbox) renders its fields inside an
|
|
212
213
|
// accept.authorize.net iframe, so that POST is cross-origin to the merchant page and an
|
|
213
214
|
// in-page hook cannot observe it. This entry covers the Accept.js custom-fields path, which
|
|
@@ -232,6 +233,35 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
232
233
|
encoding: "json",
|
|
233
234
|
passthroughHeaders: ["^accept$"]
|
|
234
235
|
},
|
|
236
|
+
{
|
|
237
|
+
psp: "worldpay_eprotect",
|
|
238
|
+
// Worldpay eProtect (Vantiv / Litle PayPage), not Access Worldpay above.
|
|
239
|
+
// The first card request that is a GET: the vendor's eProtect-api / litle-api scripts (and the
|
|
240
|
+
// Worldpay iframe, which runs them) inject ONE JSONP <script> whose query carries the PAN and CVV
|
|
241
|
+
// RSA-encrypted under the vendor's per-environment key. eprotect.js holds the query grammar,
|
|
242
|
+
// the pinned keys and the answer rules; recognition also requires isEprotectTokenRequest, so
|
|
243
|
+
// ppstats, script files, payframes and every other /eProtect/paypage query stay unrecognized.
|
|
244
|
+
// The alternation is wrapped (the EBANX rule) and the path has a right-edge guard for the SDK's
|
|
245
|
+
// unanchored test.
|
|
246
|
+
match: "(?:request\\.eprotect\\.vantivcnp\\.com|request\\.eprotect\\.vantivprelive\\.com)/eProtect/paypage(?![\\w/.-])",
|
|
247
|
+
hosts: ["^request\\.eprotect\\.vantivcnp\\.com$", "^request\\.eprotect\\.vantivprelive\\.com$"],
|
|
248
|
+
// Pre-live (certification) host: sandbox rows only, and only the guide's test cards on the device.
|
|
249
|
+
sandboxHosts: ["^request\\.eprotect\\.vantivprelive\\.com$"],
|
|
250
|
+
hostEnvironmentPinned: true,
|
|
251
|
+
// Ships dark: served only to an SDK that declares this capability, and gated off for every org
|
|
252
|
+
// until an operator allowlists one (CHECKOUT_GATED_PROCESSOR_ORGS).
|
|
253
|
+
capability: "worldpay_eprotect_jsonp",
|
|
254
|
+
// Merchant deadlines are 10 to 15 s with a 5 s failover, so the cardholder approves before Pay.
|
|
255
|
+
preparationRequired: true,
|
|
256
|
+
// `encoding` describes the query, since the request has no body. No captured header is ever
|
|
257
|
+
// replayed, and the card rides in the query of one GET whose answer is JSONP.
|
|
258
|
+
encoding: "form",
|
|
259
|
+
passthroughHeaders: [],
|
|
260
|
+
request: { method: "GET", cardIn: "query", response: "jsonp" },
|
|
261
|
+
// The api3 failover host re-sends the same query after 5 s. The SDK aborts it; it is never a
|
|
262
|
+
// destination, so it is in no `hosts`, manifest, CSP or relay list.
|
|
263
|
+
abortHosts: ["^secondary\\.eprotect\\.vantivcnp\\.com$"]
|
|
264
|
+
},
|
|
235
265
|
{
|
|
236
266
|
psp: "nuvei",
|
|
237
267
|
// Safecharge Fields. PAN@ paymentOption.card.cardNumber.
|
|
@@ -247,7 +277,20 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
247
277
|
hosts: ["^secure\\.safecharge\\.com$", "^ppp-test\\.safecharge\\.com$"],
|
|
248
278
|
sandboxHosts: ["^ppp-test\\.safecharge\\.com$"],
|
|
249
279
|
encoding: "json",
|
|
250
|
-
passthroughHeaders: []
|
|
280
|
+
passthroughHeaders: [],
|
|
281
|
+
// Where Nuvei's own scripts put the card, read from safecharge.js and
|
|
282
|
+
// fields/sfc_inner_card.min.js: paymentOption.card on all three endpoints,
|
|
283
|
+
// and cardData when Nuvei Fields' getToken posts cardTokenization.do. The
|
|
284
|
+
// initPayment and clientPayment endpoints also pay without a card: with a
|
|
285
|
+
// ccTempToken the merchant's server issued (Air France completes its Nuvei
|
|
286
|
+
// payments this way, behind Amadeus), a saved userPaymentOptionId, a wallet
|
|
287
|
+
// or an APM. createPayment sends each of those to initPayment first and then
|
|
288
|
+
// to clientPayment, so both continue untouched. A tokenization without a
|
|
289
|
+
// card is refused. So is a payment without a card once the attachment has
|
|
290
|
+
// handed Nuvei the card: its token may be one Nuvei minted from the
|
|
291
|
+
// approved card (checkout client.ts withoutCard).
|
|
292
|
+
jsonCardFields: [["paymentOption", "card", "cardNumber"], ["cardData", "cardNumber"]],
|
|
293
|
+
passWithoutCard: "(?:secure|ppp-test)\\.safecharge\\.com/ppp/api/v1/(?:clientPayment|websdk/initPaymentWithCardTokenization)\\.do"
|
|
251
294
|
},
|
|
252
295
|
// bluesnap: DELIBERATELY NOT SHIPPED — it cannot be intercepted at all. Its tokenizer is a PUT, and isCardRequest
|
|
253
296
|
// gates on POST — but accepting PUT is not enough on its own. hpf.js fires the
|
|
@@ -517,6 +560,139 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
517
560
|
encoding: "json",
|
|
518
561
|
passthroughHeaders: ["^authorization$", "^x-gp-version$"]
|
|
519
562
|
},
|
|
563
|
+
{
|
|
564
|
+
psp: "authorize_net_dpm",
|
|
565
|
+
// Authorize.Net Direct Post Method and SIM with a relay response: deprecated by Authorize.Net, still
|
|
566
|
+
// served, end of life "to be determined" (upgrade guide; SIM guide ch. 3 and app. C; sdk-php 1.9.9
|
|
567
|
+
// AuthorizeNetDPM, sdk-dotnet 1.8.1 DPMFormGenerator, sdk-ruby 1.8.1, sdk-java 1.8.0). The merchant's
|
|
568
|
+
// own card form (DPM), or Authorize.Net's hosted form the merchant frames (SIM, x_show_form=pf_receipt),
|
|
569
|
+
// posts ONE form navigation, application/x-www-form-urlencoded, to /gateway/transact.dll with the
|
|
570
|
+
// plaintext card in x_card_num, x_exp_date (one field: MMYY, MM/YY, MM-YY, MMYYYY, MM/YYYY or
|
|
571
|
+
// MM-YYYY) and, only when the merchant collects it, x_card_code. Beside it rides the merchant's
|
|
572
|
+
// fingerprint: x_login (the public API Login ID), x_fp_sequence, x_fp_timestamp and x_fp_hash, an HMAC
|
|
573
|
+
// over login^sequence^timestamp^amount^currency under the merchant's Signature Key. Authorize.Net
|
|
574
|
+
// refuses it after 1 hour (97), spends it once (98) and refuses a changed amount (99). It POSTs the
|
|
575
|
+
// result to x_relay_url server to server, then answers whichever browser submitted with the
|
|
576
|
+
// merchant's relay page. No cookie, no auth header and no encryption, so this is Tranzila's
|
|
577
|
+
// hosted_form: the cardholder's device rebuilds and submits the same form and the paused navigation
|
|
578
|
+
// resolves with the synthetic page. No relay and no prepare(): the create refuses a fingerprint more
|
|
579
|
+
// than 40 minutes old or more than 15 minutes ahead instead (authorize-net-dpm.js, with the rest of
|
|
580
|
+
// the template policy). Authorize.Net reads field names without regard to case (live forms post
|
|
581
|
+
// x_Background_URL and x_cust_ID), so every key comparison for this entry ignores case.
|
|
582
|
+
// The same URL without a card continues untouched: SIM step 1 (x_show_form=PAYMENT_FORM), an eCheck
|
|
583
|
+
// (x_method=ECHECK) and Visa Checkout on the SIM form. NOT here: api2 and apitest (Accept.js, the
|
|
584
|
+
// authorize_net entry); never armed: cardpresent., api., accept., captcha., account. and
|
|
585
|
+
// sandbox.authorize.net. Hosts are the three literal labels. test.authorize.net is Authorize.Net's
|
|
586
|
+
// sandbox gateway, pinned to test rows and documented test cards (S7).
|
|
587
|
+
// Ships dark: served only to a client that declares authorize_net_dpm_form, gated off for every org
|
|
588
|
+
// until an operator allowlists one, and never sent by autopilot (EXCLUDED_OPERATIONS).
|
|
589
|
+
capability: "authorize_net_dpm_form",
|
|
590
|
+
match: "(secure2|secure|test)\\.authorize\\.net/gateway/transact\\.dll(?![\\w/.-])",
|
|
591
|
+
hosts: ["^secure2\\.authorize\\.net$", "^secure\\.authorize\\.net$", "^test\\.authorize\\.net$"],
|
|
592
|
+
sandboxHosts: ["^test\\.authorize\\.net$"],
|
|
593
|
+
hostEnvironmentPinned: true,
|
|
594
|
+
// The endpoint is the bare URL: a query string or a fragment, even an empty one, is not this
|
|
595
|
+
// endpoint (recognition.js resolveRecognizerForUrl), so the create, the vault and the enclave all
|
|
596
|
+
// refuse it. transact.dll can read a query parameter as a form field, which would carry x_tran_key,
|
|
597
|
+
// x_type or x_relay_url past the template policy, and the URL is stored with the row.
|
|
598
|
+
bareEndpoint: true,
|
|
599
|
+
encoding: "form",
|
|
600
|
+
passthroughHeaders: [],
|
|
601
|
+
caseInsensitiveFormKeys: true,
|
|
602
|
+
cardFields: ["x_card_num"],
|
|
603
|
+
passWithoutCard: "(secure2|secure|test)\\.authorize\\.net/gateway/transact\\.dll",
|
|
604
|
+
mode: "hosted_form",
|
|
605
|
+
hostedForm: {
|
|
606
|
+
required: ["x_login", "x_amount", "x_fp_sequence", "x_fp_timestamp", "x_fp_hash", "x_relay_response"],
|
|
607
|
+
// One composed expiry field, written in the width and separator of the agent's dummy.
|
|
608
|
+
card: { number: "x_card_num", expiry: "x_exp_date", cvc: "x_card_code" },
|
|
609
|
+
// Filled only when the template carries the key; never added.
|
|
610
|
+
optional: ["cvc"],
|
|
611
|
+
amount: { sum: "x_amount", currency: "x_currency_code" },
|
|
612
|
+
// Authorize.Net spends a fingerprint once, so the fingerprint is the submission.
|
|
613
|
+
dedupe: ["x_login", "x_fp_sequence", "x_fp_timestamp", "x_fp_hash"],
|
|
614
|
+
// Absent or empty also means AUTH_CAPTURE.
|
|
615
|
+
sale: { key: "x_type", values: ["AUTH_CAPTURE"] },
|
|
616
|
+
callbackUrls: ["x_relay_url", "x_receipt_link_url", "x_cancel_url"],
|
|
617
|
+
policy: "authorize_net_dpm"
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
psp: "primer",
|
|
622
|
+
// Primer Web SDK v2 (Headless Checkout and hosted fields): Printful (printful.com) loads
|
|
623
|
+
// sdk.primer.io/web/v2.63.0; GetYourGuide (getyourguide.com) tokenizes with Primer's hosted fields and
|
|
624
|
+
// Primer routes the token to Adyen, Checkout.com or J.P. Morgan server side. PAN@ paymentInstrument.number,
|
|
625
|
+
// with cvv, expirationMonth (MM) and expirationYear (YYYY) beside it. Primer's hidden api-controller iframe
|
|
626
|
+
// (origin https://sdk.primer.io) resolves the core's "$.cardNumber-card" placeholders and POSTs plaintext
|
|
627
|
+
// JSON to `${pciUrl}/payment-instruments`, with the session's primer-client-token and no client-side
|
|
628
|
+
// encryption. pciUrl comes from the session: sdk.api.sandbox.primer.io (Primer's iOS client-token fixture),
|
|
629
|
+
// sdk.api.primer.io (production, inferred from the same naming and DNS; confirmed on first observation).
|
|
630
|
+
// The same URL also tokenizes PayPal, Apple Pay, Google Pay and Klarna with no card: jsonCardFields and
|
|
631
|
+
// passWithoutCard let those continue untouched. The siblings on the host (/{id}/exchange for a saved card,
|
|
632
|
+
// /{id}/vault, /payments, /3ds, /three-d-secure, /client-session) never carry a new card, and the
|
|
633
|
+
// right-edge boundary and the exact-URL rule in resolveRecognizerForUrl keep them out. primer.js judges the
|
|
634
|
+
// whole request, refuses a body that asks Primer to save the card (tokenType MULTI_USE, paymentFlow VAULT),
|
|
635
|
+
// Primer Checkout's primer-js SDK (its request gives up after 30 s) and a preferredNetwork that is not the
|
|
636
|
+
// card's own, and writes only the card fields. Staging and dev hosts are deliberately absent, and the
|
|
637
|
+
// sandbox host is pinned (S7): a sandbox row sends only documented test cards there, a live row never
|
|
638
|
+
// points at it. The request names no amount: the token is charged later.
|
|
639
|
+
// Ships dark: served only to a client that declares `primer_payment_instruments`, gated off for every
|
|
640
|
+
// org until an operator allowlists one, and never replayed by autopilot (EXCLUDED_OPERATIONS). A client
|
|
641
|
+
// session can save the card with no sign in the request, so the API also refuses every live row at
|
|
642
|
+
// create until the cardholder can consent to that save; only a test row pays.
|
|
643
|
+
capability: "primer_payment_instruments",
|
|
644
|
+
match: "sdk\\.api(?:\\.sandbox)?\\.primer\\.io/payment-instruments(?![\\w/.-])",
|
|
645
|
+
hosts: ["^sdk\\.api\\.primer\\.io$", "^sdk\\.api\\.sandbox\\.primer\\.io$"],
|
|
646
|
+
sandboxHosts: ["^sdk\\.api\\.sandbox\\.primer\\.io$"],
|
|
647
|
+
hostEnvironmentPinned: true,
|
|
648
|
+
encoding: "json",
|
|
649
|
+
// What Primer's controller sends beside the body; primer.js checks their shapes before any replay.
|
|
650
|
+
passthroughHeaders: [
|
|
651
|
+
"^primer-client-token$",
|
|
652
|
+
"^primer-sdk-client$",
|
|
653
|
+
"^primer-sdk-version$",
|
|
654
|
+
"^primer-sdk-checkout-session-id$",
|
|
655
|
+
"^x-api-version$",
|
|
656
|
+
"^x-request-id$"
|
|
657
|
+
],
|
|
658
|
+
jsonCardFields: [["paymentInstrument", "number"]],
|
|
659
|
+
passWithoutCard: "sdk\\.api(?:\\.sandbox)?\\.primer\\.io/payment-instruments"
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
psp: "amadeus_checkout",
|
|
663
|
+
// Outpayce (Amadeus Payment Platform): Air France and KLM, one shared release.
|
|
664
|
+
// PAN@ data.mopdata.pan (JSON, plaintext inside TLS). Two card-bearing XHRs on one host:
|
|
665
|
+
// 1. Checkout Web SDK: the SDK hands {PPID, data, action} to its tunnel iframe
|
|
666
|
+
// (prd.payment.amadeus.com/checkout/sdk/<v>/form-fields/tunnel.html), which swaps the pan and
|
|
667
|
+
// CVV iframes' ids for the typed digits and posts it to ARIAPP/pay: text/plain, no cookies, a
|
|
668
|
+
// 30 s timeout, HTTP 200 only.
|
|
669
|
+
// 2. Data Collection Page (DCP): the page at /1ASIATP/ATPDCP/land/?DCPID= posts
|
|
670
|
+
// {DCPID, action, data} to ATPDCP/collect, same-origin JSON, the whole card in one body.
|
|
671
|
+
// ONE URL, MANY ACTIONS. Only an add carrying a card mopid's pan, or a store carrying a pan, is a
|
|
672
|
+
// card request (amadeus-body.js, which card-fields.js asks for this psp); load, bin, prepare,
|
|
673
|
+
// obfees, installments, tdsinit, verify, fetch, cancel, the wallet actions and DCP bin_check,
|
|
674
|
+
// expired and back carry at most the agent's dummy and continue untouched (passWithoutCard).
|
|
675
|
+
// amadeus-checkout.js holds the exact-URL rule, the whole-request check, both fills and the answer
|
|
676
|
+
// judge (sources there). Hosts are the two literal paypages hosts, never a wildcard label:
|
|
677
|
+
// paypages.dev (1ASIATPD), the airline intranet hosts, the playground, paypages.*.payment.outpayce.com
|
|
678
|
+
// (resolves, but no shipped SDK allowlists it) and the hosted page's own origin are absent, and the
|
|
679
|
+
// test host takes no DCP store until one is observed. The test host is pinned (S7): a create
|
|
680
|
+
// refuses it on a live row, and the device sends it only documented test cards.
|
|
681
|
+
// Ships dark: served only to a client that declares amadeus_checkout_actions.v1 (one that judges
|
|
682
|
+
// these bodies and prepares before the page's first request), gated off for every org until an
|
|
683
|
+
// operator allowlists one, prepared before Pay (S4: the tunnel abandons the add after 30 s), and
|
|
684
|
+
// never replayed by autopilot (EXCLUDED_OPERATIONS).
|
|
685
|
+
capability: "amadeus_checkout_actions.v1",
|
|
686
|
+
match: "(?:paypages\\.payment\\.amadeus\\.com/1ASIATP/(?:ARIAPP/pay|ATPDCP/collect)|paypages\\.test\\.payment\\.amadeus\\.com/1ASIATP[UMK]?/ARIAPP/pay)(?![\\w/.-])",
|
|
687
|
+
hosts: ["^paypages\\.payment\\.amadeus\\.com$", "^paypages\\.test\\.payment\\.amadeus\\.com$"],
|
|
688
|
+
sandboxHosts: ["^paypages\\.test\\.payment\\.amadeus\\.com$"],
|
|
689
|
+
hostEnvironmentPinned: true,
|
|
690
|
+
preparationRequired: true,
|
|
691
|
+
encoding: "json",
|
|
692
|
+
passthroughHeaders: ["^amadeus-checkout-sdk-version$", "^amadeus-checkout-sdk-host$", "^amadeus-checkout-sdk-flavor$"],
|
|
693
|
+
jsonCardFields: [["data", "mopdata", "pan"]],
|
|
694
|
+
passWithoutCard: "(?:paypages\\.payment\\.amadeus\\.com/1ASIATP/(?:ARIAPP/pay|ATPDCP/collect)|paypages\\.test\\.payment\\.amadeus\\.com/1ASIATP[UMK]?/ARIAPP/pay)"
|
|
695
|
+
},
|
|
520
696
|
// ── Encrypted on the device under a pinned key ────────────────────────────
|
|
521
697
|
{
|
|
522
698
|
psp: "fiserv",
|
|
@@ -573,6 +749,38 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
573
749
|
fields: ["keyId", "encryptedKey", "encryptionBlock", "aesIv"]
|
|
574
750
|
}
|
|
575
751
|
},
|
|
752
|
+
{
|
|
753
|
+
psp: "verifone",
|
|
754
|
+
// Verifone eCommerce Secure Card Capture (verifone.js), The Container Store's card path. The
|
|
755
|
+
// merchant's page encrypts the card with OpenPGP under the merchant's own Verifone key and
|
|
756
|
+
// posts the blob to the MERCHANT's server, which calls Verifone: nothing card-bearing goes
|
|
757
|
+
// from the browser to a Verifone host. So this entry recognizes no URL and names no host: a
|
|
758
|
+
// Verifone card request is found only through a reviewed merchant profile
|
|
759
|
+
// (verifone-profiles.js), whose endpoint, body rules and pinned key (verifone-keys.js) the
|
|
760
|
+
// backend, the SDK and the Vault page read by the profile's id (verifone.js). `hosts` is empty
|
|
761
|
+
// and `match` never matches, so the registry, the enclave's destinations and the SDK's card
|
|
762
|
+
// patterns gain nothing, and resolveRecognizerForUrl never resolves a URL to verifone. The
|
|
763
|
+
// blob is a 15-minute bearer at the merchant and a 3-D Secure challenge needs the cardholder,
|
|
764
|
+
// so the cardholder approves every payment: dark until an org is allowlisted, and autopilot
|
|
765
|
+
// refuses verifone at all three gates.
|
|
766
|
+
capability: "verifone_card_capture",
|
|
767
|
+
// A Verifone card is encrypted only for a request the cardholder already approved through a
|
|
768
|
+
// prepare() for the same reviewed profile: the backend refuses an unprepared create (409
|
|
769
|
+
// preparation_required) and the SDK refuses locally before it prompts, as for Fiserv.
|
|
770
|
+
preparationRequired: true,
|
|
771
|
+
match: "(?!)",
|
|
772
|
+
hosts: [],
|
|
773
|
+
encoding: "json",
|
|
774
|
+
// The browser continues the merchant's own request with its own headers; none is stored.
|
|
775
|
+
passthroughHeaders: [],
|
|
776
|
+
clientSideEncrypted: true,
|
|
777
|
+
mode: "cse",
|
|
778
|
+
cse: {
|
|
779
|
+
// Where the blob sits is each profile's leg (holder and field), never one path for the psp.
|
|
780
|
+
at: "merchant_profile",
|
|
781
|
+
fields: ["encryptedCard"]
|
|
782
|
+
}
|
|
783
|
+
},
|
|
576
784
|
{
|
|
577
785
|
psp: "gravy",
|
|
578
786
|
// Gravy (Gr4vy) payment orchestration, Secure Fields. PAN@ payment_method.number,
|
|
@@ -632,9 +840,395 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
632
840
|
hostEnvironmentPinned: true,
|
|
633
841
|
encoding: "json",
|
|
634
842
|
passthroughHeaders: ["^x-mp-client-type$"]
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
psp: "cybersource_flex",
|
|
846
|
+
// CyberSource Flex Microform v2. ONE card-bearing request: a POST from a Microform field
|
|
847
|
+
// iframe (the loader picks the number or the securityCode iframe at random) to the capture
|
|
848
|
+
// context's flx.origin + flx.path, /flex/v2/tokens, sent as `application/jwt; charset=utf-8`
|
|
849
|
+
// with a 30 s XHR timeout. The body is a compact JWE the iframe seals under the context's own
|
|
850
|
+
// key, so it is opaque: no injector exists (injectCard and prepareDeviceReplay refuse this
|
|
851
|
+
// psp), and the device verifies the context, rebuilds the iframe's plaintext with the real
|
|
852
|
+
// card and seals it itself (cybersource-flex-replay.js). The same URL also carries Microform
|
|
853
|
+
// v0.11 and Flex API v2 direct traffic, so recognition is not coverage: the SDK creates only
|
|
854
|
+
// for a POST from a reviewed v2 field iframe whose fragment record it holds.
|
|
855
|
+
// Excluded on purpose: api/apitest.cybersource.com (server APIs, never a browser card),
|
|
856
|
+
// /flex/v1/tokens, /flex/v2/public-keys/*, /microform/bundle/* and flex.in.cybersource.com
|
|
857
|
+
// (it resolves but serves neither keys nor bundles). No other entry shares these hosts.
|
|
858
|
+
// `capability` names the capture-context sidecar a client must send on create (the reviewed
|
|
859
|
+
// "sidecar" negotiation term): the entry stays out of BUILTIN_REGISTRY, is served only to a
|
|
860
|
+
// client that declares it, and is off for every org until one is opted in. testflex is the
|
|
861
|
+
// sandbox host and the environment is pinned (S7): test kids and testflex only on sandbox rows.
|
|
862
|
+
capability: "capture_context",
|
|
863
|
+
match: "(?:test)?flex\\.cybersource\\.com/flex/v2/tokens(?![\\w/-])",
|
|
864
|
+
hosts: ["^flex\\.cybersource\\.com$", "^testflex\\.cybersource\\.com$"],
|
|
865
|
+
sandboxHosts: ["^testflex\\.cybersource\\.com$"],
|
|
866
|
+
hostEnvironmentPinned: true,
|
|
867
|
+
encoding: "jwe",
|
|
868
|
+
passthroughHeaders: []
|
|
869
|
+
},
|
|
870
|
+
{
|
|
871
|
+
psp: "juspay",
|
|
872
|
+
// Juspay Express Checkout, the merchant-page card flow Swiggy web ships (reviewed bundle
|
|
873
|
+
// web-payments.7cf02545077d488.js, SHA-256 08336f74599b7f756e4b17ed8747af8caa5d248879f7c0dd3d89f0abd8347504).
|
|
874
|
+
// The page tokenizes the card at /card/tokenize and pays at /txns with the token; juspay.js
|
|
875
|
+
// holds the whole protocol and says why only /txns is taken over.
|
|
876
|
+
// - Paused: the POST /txns that carries a synthetic token the SDK answered the placeholder
|
|
877
|
+
// tokenize with (never the tokenize itself: a real ctkn_ needs no merchant secret and pays
|
|
878
|
+
// any order of that merchant for 15 minutes). The SDK answers the placeholder tokenize and
|
|
879
|
+
// refuses the /v2/card/fingerprint lookup, so the placeholder never reaches Juspay.
|
|
880
|
+
// - deviceSteps.tokenize: the one other request the cardholder's device sends, the real
|
|
881
|
+
// card's tokenize, on the paused request's own host (request-policy.js
|
|
882
|
+
// assertAllowedDeviceStep). Definitions-only: the served row does not carry it.
|
|
883
|
+
// - NOT here, on purpose: api.juspay.io and api-ns1.juspay.in. Juspay operates both and
|
|
884
|
+
// serves the same API there, but no reviewed page was seen sending a card to either; the
|
|
885
|
+
// SDK refuses a card-bearing request to them instead of pausing it.
|
|
886
|
+
// - Headers: x-merchantid and x-routing-id only. client_auth_token can be scoped to a
|
|
887
|
+
// customer and Swiggy's card legs never send it; the merchant's API key must never reach
|
|
888
|
+
// a browser, so authorization is never passed.
|
|
889
|
+
// - Dark: served only to a client that declares juspay_txns.v1, and off for every org
|
|
890
|
+
// until one is allowlisted. The sandbox host takes only documented test cards (S7).
|
|
891
|
+
// - Autopilot never replays it: the enclave sends one request and Juspay needs two.
|
|
892
|
+
capability: "juspay_txns.v1",
|
|
893
|
+
match: "(api|sandbox)\\.juspay\\.in/txns(?![\\w/-])",
|
|
894
|
+
hosts: ["^api\\.juspay\\.in$", "^sandbox\\.juspay\\.in$"],
|
|
895
|
+
sandboxHosts: ["^sandbox\\.juspay\\.in$"],
|
|
896
|
+
hostEnvironmentPinned: true,
|
|
897
|
+
encoding: "form",
|
|
898
|
+
passthroughHeaders: ["^x-merchantid$", "^x-routing-id$"],
|
|
899
|
+
deviceSteps: { tokenize: "(api|sandbox)\\.juspay\\.in/card/tokenize" }
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
psp: "datatrans",
|
|
903
|
+
// Datatrans / PCI Proxy Secure Fields 2.0.0 in TOKENIZE mode (field.js 3.24.602):
|
|
904
|
+
// British Airways's Nexus checkout (merchantId 3000024893) and legacy ba-sell (3000025858). PAN@
|
|
905
|
+
// cardNumber (form). Datatrans's own card-number iframe document on pay.datatrans.com sends the
|
|
906
|
+
// whole card as one jQuery XHR to its relative URL `paymentField`: form-encoded, with the CVV read
|
|
907
|
+
// from its same-origin CVV frame and the expiry (expm, expy) from the merchant page, plus mode,
|
|
908
|
+
// formId, paymentMethod, merchantId and usage; no amount, key, cookie or signature. The server keys
|
|
909
|
+
// the form by formId in the body, and the replay gate (PCI Proxy's public sandbox merchant) showed
|
|
910
|
+
// it accepts that body from another client with no cookie, origin or referer.
|
|
911
|
+
// paymentField/cardInfo is a 12-digit BIN lookup on the same host and must never match: the
|
|
912
|
+
// right-edge boundary and the exact-URL rule in resolveRecognizerForUrl keep it (and every query,
|
|
913
|
+
// port and case variant) out. Wallet, bank-account and CVV-only posts share the URL and carry no
|
|
914
|
+
// cardNumber: cardFields and passWithoutCard let them continue untouched. The GET that loads the
|
|
915
|
+
// iframe document shares the path, and the POST gate keeps it out. datatrans.js judges the whole
|
|
916
|
+
// request, refuses usage=REGISTRATION (card on file) until that decision is made and a
|
|
917
|
+
// paymentMethod that is not the card's own, and writes only cardNumber, cvv, expm and expy.
|
|
918
|
+
// Hosts are the two literal labels (never *.datatrans.com: api., 3d. and admin. are other
|
|
919
|
+
// services, and PCI Proxy's custom domains are not recognized); the sandbox host is pinned (S7):
|
|
920
|
+
// it takes only documented test cards, and a live row never points at it.
|
|
921
|
+
// Ships dark: served only to a client that declares `datatrans_secure_fields_tokenize`, gated off
|
|
922
|
+
// for every org until an operator allowlists one, and never replayed by autopilot
|
|
923
|
+
// (EXCLUDED_OPERATIONS).
|
|
924
|
+
capability: "datatrans_secure_fields_tokenize",
|
|
925
|
+
match: "pay(?:\\.sandbox)?\\.datatrans\\.com/upp/payment/SecureFields/paymentField(?:[?#]|$)",
|
|
926
|
+
hosts: ["^pay\\.datatrans\\.com$", "^pay\\.sandbox\\.datatrans\\.com$"],
|
|
927
|
+
sandboxHosts: ["^pay\\.sandbox\\.datatrans\\.com$"],
|
|
928
|
+
hostEnvironmentPinned: true,
|
|
929
|
+
encoding: "form",
|
|
930
|
+
passthroughHeaders: [],
|
|
931
|
+
// the replay gate needed none: no x-requested-with, cookie, origin or referer
|
|
932
|
+
cardFields: ["cardNumber"],
|
|
933
|
+
passWithoutCard: "pay(?:\\.sandbox)?\\.datatrans\\.com/upp/payment/SecureFields/paymentField"
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
psp: "pelecard",
|
|
937
|
+
// Pelecard Iframe/Redirect 2.0, the hosted payment page Uman tourist tax (aumantax.com)
|
|
938
|
+
// loads in an iframe. PAN@ root CreditCardNumber, expiry MMYY @ CreditCardDate, CVV @ CvvNumber.
|
|
939
|
+
// Pelecard's own page (/PaymentGW?transactionId=<guid>) posts the flat SubmitModel JSON with one
|
|
940
|
+
// jQuery XHR (Payment.js sendAjax, sha256 75c37541...a669caea) to generalParameters.urlTransaction,
|
|
941
|
+
// the same host's /PaymentGW/Transaction: no cookie, no auth header, no client-side encryption.
|
|
942
|
+
// The amount, currency, action type (J4 charge, J2 registration, J5 hold) and CreateToken are bound
|
|
943
|
+
// to the TransactionId at the merchant's server-side init and never ride in the request.
|
|
944
|
+
// The same URL also serves the wallet, Bit, PIN pad and bank tabs with no card: jsonCardFields and
|
|
945
|
+
// passWithoutCard let those continue untouched. pelecard.js checks the exact URL (also in
|
|
946
|
+
// resolveRecognizerForUrl), validates the whole body, writes only the card fields, and refuses a
|
|
947
|
+
// saved token, a track, installments, a buyer-typed total and a body that asks to keep the card.
|
|
948
|
+
// NOT here: /PaymentGW/TimeOutTransaction (the dwell timer posts the same card fields there),
|
|
949
|
+
// /PaymentGW/CheckCreditCard, EndOfProcess, init and the other PaymentGW routes; gateway20qa
|
|
950
|
+
// (Pelecard QA); the legacy 1.0 page on gateway.pelecard.biz (/PayProcess/Transaction, a top-level
|
|
951
|
+
// form). Hosts are the two literal labels, never a wildcard. No sandboxHosts: Pelecard's public test
|
|
952
|
+
// terminals run on the same gateway21 host as live ones (the terminal bound to the TransactionId
|
|
953
|
+
// decides, and neither the request nor the page names it), so the S7 host rule has no test-only
|
|
954
|
+
// host to pin, and the device's test-card rule cannot tell a test payment from a live one here.
|
|
955
|
+
// A live row can therefore send a real card to a payment page created on a public test terminal,
|
|
956
|
+
// whose transactions anyone holding Pelecard's published demo credentials can read back.
|
|
957
|
+
// Ships dark: served only to a client that declares `pelecard_transaction`, gated off for every org
|
|
958
|
+
// until an operator allowlists one, and never replayed by autopilot (EXCLUDED_OPERATIONS).
|
|
959
|
+
capability: "pelecard_transaction",
|
|
960
|
+
match: "(?:gateway21|gateway20)\\.pelecard\\.biz/PaymentGW/Transaction(?![\\w/.-])",
|
|
961
|
+
hosts: ["^gateway21\\.pelecard\\.biz$", "^gateway20\\.pelecard\\.biz$"],
|
|
962
|
+
encoding: "json",
|
|
963
|
+
// jQuery's own same-origin marker, pinned to `XMLHttpRequest` by pelecard.js; nothing else rides.
|
|
964
|
+
passthroughHeaders: ["^x-requested-with$"],
|
|
965
|
+
jsonCardFields: [["CreditCardNumber"]],
|
|
966
|
+
passWithoutCard: "(?:gateway21|gateway20)\\.pelecard\\.biz/PaymentGW/Transaction"
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
psp: "aci",
|
|
970
|
+
// ACI Worldwide Open Payment Platform, COPYandPAY widget (Halfords). PAN@ card.number (form, dot keys).
|
|
971
|
+
// Each PCI iframe (/v1/pciIframe.html) posts the one field it holds, as a jQuery form XHR, to
|
|
972
|
+
// POST /v1/checkouts/{id} (no suffix); ACI merges them on the checkout. aci.js holds the leg
|
|
973
|
+
// rules, the fill and the answer judge (sources there). The id segment is the documented
|
|
974
|
+
// <32 hex>.<cluster>-vm-tx<nn>; (?![\w/.-]) is the right edge for the SDK's unanchored test and
|
|
975
|
+
// keeps /payment, /bins and /registration out of `match`. Hosts are the four literal hosts ACI
|
|
976
|
+
// serves the widget from, never a wildcard label; white-label OPP hosts need their own evidence.
|
|
977
|
+
// Ships dark: served only to a client that declares aci_split_card.v1 (one that holds the
|
|
978
|
+
// sibling legs below), gated off for every org until an operator allowlists one, and never
|
|
979
|
+
// replayed by autopilot (EXCLUDED_OPERATIONS).
|
|
980
|
+
capability: "aci_split_card.v1",
|
|
981
|
+
match: "(?:eu-prod\\.oppwa\\.com|oppwa\\.com|eu-test\\.oppwa\\.com|test\\.oppwa\\.com)/v1/checkouts/[0-9A-F]{32}\\.[a-z0-9]{1,16}-vm-tx[0-9]{1,3}(?![\\w/.-])",
|
|
982
|
+
hosts: ["^eu-prod\\.oppwa\\.com$", "^oppwa\\.com$", "^eu-test\\.oppwa\\.com$", "^test\\.oppwa\\.com$"],
|
|
983
|
+
// eu-test and test.oppwa.com are ACI's INTEGRATOR_TEST hosts. Pinned (S7): a create refuses a
|
|
984
|
+
// test host on a live row and a live host on a test row, and the device sends only documented
|
|
985
|
+
// test cards (ACI's own included, aci.js ACI_TEST_PANS) to a test host.
|
|
986
|
+
sandboxHosts: ["^eu-test\\.oppwa\\.com$", "^test\\.oppwa\\.com$"],
|
|
987
|
+
hostEnvironmentPinned: true,
|
|
988
|
+
// ACI's widget abandons Pay after its 60 s channel timeout, so the cardholder unlocks first (S4).
|
|
989
|
+
preparationRequired: true,
|
|
990
|
+
encoding: "form",
|
|
991
|
+
passthroughHeaders: [],
|
|
992
|
+
// no auth header; X-Requested-With is not replayed (it would force a CORS preflight)
|
|
993
|
+
cardFields: ["card.number"],
|
|
994
|
+
// One card, several legs on one checkout id. `absorb` legs (the page's CVC and expiry, dummy
|
|
995
|
+
// values) are held and answered with the approved leg's answer, never forwarded; `pass` legs
|
|
996
|
+
// (the holder) continue untouched; `siblingKeys` may ride any leg. `continuation` is the merchant
|
|
997
|
+
// form's /payment submission, which continues with `remove` taken out after `brandField` is
|
|
998
|
+
// checked against the approved card's network and every other key against the ones the widget
|
|
999
|
+
// sends (aci.js prepareAciContinuation).
|
|
1000
|
+
splitCard: {
|
|
1001
|
+
absorb: ["card.cvv", "card.expiryMonth", "card.expiryYear"],
|
|
1002
|
+
pass: ["card.holder"],
|
|
1003
|
+
siblingKeys: ["customParameters[SHOPPER_EndToEndIdentity]"],
|
|
1004
|
+
continuation: {
|
|
1005
|
+
match: "(?:eu-prod\\.oppwa\\.com|oppwa\\.com|eu-test\\.oppwa\\.com|test\\.oppwa\\.com)/v1/checkouts/[0-9A-F]{32}\\.[a-z0-9]{1,16}-vm-tx[0-9]{1,3}/payment(?![\\w/.-])",
|
|
1006
|
+
remove: ["card.expiryMonth", "card.expiryYear"],
|
|
1007
|
+
brandField: "paymentBrand"
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
psp: "creditguard",
|
|
1013
|
+
// Hyp CreditGuard PPS, the hosted page merchants frame at https://pps.creditguard.co.il/?txId=<uuid>
|
|
1014
|
+
// (SeboCalm). Its Angular transaction service posts the card to /services/v1/txn/<txId>/process as
|
|
1015
|
+
// same-origin JSON, no auth header, no cookie: the txId is the only credential and the submit is the
|
|
1016
|
+
// sale itself. PAN@ root `cardNumber` (expMonth MM, expYear YY, cvv, personalId) in plaintext, or one
|
|
1017
|
+
// js-jose JWE in root `jwePayload` when the transaction carries a jwePublicKey (creditguard.js keeps
|
|
1018
|
+
// that variant behind a flag). Sources: templates/cgt-basic/main.js on pps and ppsuat, reviewed
|
|
1019
|
+
// 2026-09-25. /card/details, /card/details/dcc, /cc/ddc/init, /cg3ds/*, /otp/request and
|
|
1020
|
+
// /applepay|paybox|pcp/process share the prefix, carry the agent's placeholder or no card, and fall
|
|
1021
|
+
// out at the exact path; (?![\w/-]) is the right edge for the SDK's unanchored test. pps2 is a
|
|
1022
|
+
// production host (cg-safecharge-3ds envConfig: pps, pps2, cgmpi = prod). The legacy MPI page
|
|
1023
|
+
// (cgmpi.creditguard.co.il), pps-dev, ppsqa, pps-qa1 and cguat2 are deliberately absent.
|
|
1024
|
+
// creditguard.js judges the whole request before a card is written and fills only the card fields.
|
|
1025
|
+
// Ships dark: served only to a client that declares `creditguard_pps_process`, gated off for every
|
|
1026
|
+
// org until an operator allowlists one, never replayed by autopilot (EXCLUDED_OPERATIONS).
|
|
1027
|
+
capability: "creditguard_pps_process",
|
|
1028
|
+
match: "(?:pps|pps2|ppsuat)\\.creditguard\\.co\\.il/services/v1/txn/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/process(?![\\w/-])",
|
|
1029
|
+
hosts: ["^pps\\.creditguard\\.co\\.il$", "^pps2\\.creditguard\\.co\\.il$", "^ppsuat\\.creditguard\\.co\\.il$"],
|
|
1030
|
+
// ppsuat is CreditGuard's UAT page. Pinned (S7): a create refuses it on a live row and pps or pps2
|
|
1031
|
+
// on a test row, and the device sends only documented test cards to it.
|
|
1032
|
+
sandboxHosts: ["^ppsuat\\.creditguard\\.co\\.il$"],
|
|
1033
|
+
hostEnvironmentPinned: true,
|
|
1034
|
+
// S4: the submit names no amount, so a card is sent only after the cardholder approved a
|
|
1035
|
+
// prepare() that read the transaction (GET /services/v1/txn/<txId>, creditguard.js).
|
|
1036
|
+
preparationRequired: true,
|
|
1037
|
+
encoding: "json",
|
|
1038
|
+
// The device sends Content-Type (and Accept) JSON itself; nothing the page sent is replayed.
|
|
1039
|
+
passthroughHeaders: [],
|
|
1040
|
+
// A /process body without either (Google Pay, a saved cardId, a js-jose object fallback) is not a
|
|
1041
|
+
// new card, and with no passWithoutCard it is refused instead of paused.
|
|
1042
|
+
jsonCardFields: [["cardNumber"], ["jwePayload"]]
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
psp: "payrails",
|
|
1046
|
+
// Payrails web SDK v6 (assets.payrails.io/web-sdk/v6/payrails.js 6.5.0), Blacklane's consumer
|
|
1047
|
+
// booking checkout: cardForm.tokenize() POSTs vaultConfiguration.links.saveInstrument.href. Body
|
|
1048
|
+
// (JSON.stringify, sent as text/plain): {holderReference, paymentMethod:'card', storeInstrument,
|
|
1049
|
+
// futureUsage, data:{encryptedData, vaultProviderConfigId}}. encryptedData is a compact JWE
|
|
1050
|
+
// (RSA-OAEP-256 + A256CBC-HS512, no kid) of {holderName, cardNumber, expiryMonth, expiryYear,
|
|
1051
|
+
// securityCode, holderReference}, built in the assets.payrails.io secure frame under the
|
|
1052
|
+
// session's vaultConfiguration.encryptionPublicKey. That key is per session, reaches us only
|
|
1053
|
+
// through the agent's page and cannot be pinned, so the mode is device_encrypt: the cardholder's
|
|
1054
|
+
// device encrypts the real card and sends this request itself (payrails-replay.js), and the
|
|
1055
|
+
// ciphertext never returns to the page. Dynamic payment-method forms save non-card instruments
|
|
1056
|
+
// on the same URL with no data.encryptedData: jsonCardFields claims only a card save and
|
|
1057
|
+
// passWithoutCard lets the rest continue untouched. payrails.js holds the request guard, the
|
|
1058
|
+
// card-on-file policy, the session-key and workspace checks and the answer rules. NOT here:
|
|
1059
|
+
// /public/payment/instruments/tokenize (web-cse used directly), api.payrails.io and the
|
|
1060
|
+
// execution authorize links (card-form payments, stored-card CVC), and assets.payrails.io.
|
|
1061
|
+
// `capability` keeps the entry out of BUILTIN_REGISTRY and every org until one opts in; the API
|
|
1062
|
+
// serves it only to a client that also asks for modes=device_encrypt. The two staging hosts are
|
|
1063
|
+
// pinned to sandbox rows (S7). Autopilot refuses it by operation (payrails.device_encrypted_card).
|
|
1064
|
+
capability: "payrails_device_encrypt",
|
|
1065
|
+
match: "(?:api-pub|api-pub\\.staging|sandbox-api-pub\\.staging)\\.payrails\\.io/public/payment/instruments(?![\\w/.-])",
|
|
1066
|
+
hosts: ["^api-pub\\.payrails\\.io$", "^api-pub\\.staging\\.payrails\\.io$", "^sandbox-api-pub\\.staging\\.payrails\\.io$"],
|
|
1067
|
+
sandboxHosts: ["^api-pub\\.staging\\.payrails\\.io$", "^sandbox-api-pub\\.staging\\.payrails\\.io$"],
|
|
1068
|
+
hostEnvironmentPinned: true,
|
|
1069
|
+
encoding: "json",
|
|
1070
|
+
// body shape; the SDK sends text/plain, replayed verbatim
|
|
1071
|
+
passthroughHeaders: ["^authorization$", "^x-idempotency-key$", "^x-client-version$", "^x-client-type$"],
|
|
1072
|
+
jsonCardFields: [["data", "encryptedData"]],
|
|
1073
|
+
passWithoutCard: "(?:api-pub|api-pub\\.staging|sandbox-api-pub\\.staging)\\.payrails\\.io/public/payment/instruments",
|
|
1074
|
+
clientSideEncrypted: true,
|
|
1075
|
+
// older SDKs read this and refuse locally
|
|
1076
|
+
mode: "device_encrypt",
|
|
1077
|
+
deviceEncrypt: {
|
|
1078
|
+
scheme: "payrails-jwe",
|
|
1079
|
+
// RSA-OAEP-256 + A256CBC-HS512, compact
|
|
1080
|
+
key: "session",
|
|
1081
|
+
// from the init payload the runtime captured, never pinned
|
|
1082
|
+
at: ["data", "encryptedData"],
|
|
1083
|
+
keyBits: [2048, 3072, 4096],
|
|
1084
|
+
// e = 65537; the wrapped key's length must equal the modulus length
|
|
1085
|
+
futureUsage: ["CardOnFile", "UnscheduledCardOnFile"],
|
|
1086
|
+
expiryYear: "YY"
|
|
1087
|
+
// Blacklane's single MM/YY field
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
psp: "elavon_converge",
|
|
1092
|
+
// Elavon Converge Hosted Payment Page (redirect, pageType hpp), NY DMV. Converge's
|
|
1093
|
+
// own AngularJS page posts the card as same-origin JSON to /hosted-payments/service/payment/hpp/process.
|
|
1094
|
+
// PAN@ paymentData.ssl_card_number (digits), expiry@ paymentData.ssl_exp_date (MMYY), CVC@
|
|
1095
|
+
// paymentData.ssl_cvv2cvc2. No client-side encryption; the session rides in the body (`context`).
|
|
1096
|
+
// Sources: assets/hpp-2.505.07.js, byte-identical on both hosts, reviewed 2026-09-25. The same URL
|
|
1097
|
+
// carries wallet, ACH and loan payments and the follow-ups after 3DS2, Pay Defense or a surcharge
|
|
1098
|
+
// quote: the Converge body gate decides (elavon-converge.js convergeBodyVerdict, which card-fields.js
|
|
1099
|
+
// asks first, so the SDK's generated copy carries it). The lightbox (hpm/process), Checkout.js
|
|
1100
|
+
// (hpe/process) and every other hpp/ call fall out at the exact path; (?![\w/.%-]) is the right edge
|
|
1101
|
+
// for the SDK's unanchored test. Hosts are two literal labels, never *.convergepay.com (www and demo
|
|
1102
|
+
// are the merchant web UI).
|
|
1103
|
+
// Ships dark: served only to a client that declares `converge_hpp_process`, gated off for every org
|
|
1104
|
+
// until an operator allowlists one, never replayed by autopilot (EXCLUDED_OPERATIONS).
|
|
1105
|
+
capability: "converge_hpp_process",
|
|
1106
|
+
match: "api(?:\\.demo)?\\.convergepay\\.com/hosted-payments/service/payment/hpp/process(?![\\w/.%-])",
|
|
1107
|
+
hosts: ["^api\\.convergepay\\.com$", "^api\\.demo\\.convergepay\\.com$"],
|
|
1108
|
+
// api.demo is Converge's demo environment. Pinned (S7): a create refuses it on a live row and the
|
|
1109
|
+
// production host on a test row, and the device sends only documented test cards to it.
|
|
1110
|
+
sandboxHosts: ["^api\\.demo\\.convergepay\\.com$"],
|
|
1111
|
+
hostEnvironmentPinned: true,
|
|
1112
|
+
encoding: "json",
|
|
1113
|
+
// The device sends Content-Type JSON itself; no Origin, Cookie, Referer or XSRF header is replayed.
|
|
1114
|
+
passthroughHeaders: [],
|
|
1115
|
+
jsonCardFields: [["paymentData", "ssl_card_number"]],
|
|
1116
|
+
// An electronic check or financing payment on the same URL carries no card and continues untouched.
|
|
1117
|
+
passWithoutCard: "api(?:\\.demo)?\\.convergepay\\.com/hosted-payments/service/payment/hpp/process"
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
psp: "wspay",
|
|
1121
|
+
// WSPay Components (WSPay's build of Monri Components 1.6.0), Valamar's booking payment.
|
|
1122
|
+
// PAN@ payment_method.data.pan, expiry YYMM @ .expiration_date, cvv @ .cvv. The processor
|
|
1123
|
+
// iframe (/v2/js/payment-method-component-dynamic.html) XHRs POST /v2/payment/{client_secret}/confirm
|
|
1124
|
+
// with `Authorization: WP3-v2-Client <authenticity token>` (proxy /dist/monri.js sha256 33fb5b45...).
|
|
1125
|
+
// /confirm is the only card route the proxy serves: /v2/payment/{cs}/token and /v2/temp-tokenize
|
|
1126
|
+
// answer 404 exactly like bogus control paths (card-free probes, 2026-09-23). The same URL also
|
|
1127
|
+
// carries saved_card and temp_card_id bodies with no new card, so wspay.js validates the whole
|
|
1128
|
+
// body, writes only the three card fields and never uses the generic walk; there is no `compose`
|
|
1129
|
+
// on purpose (it widens what the generic walk would call a card). The client_secret segment is a
|
|
1130
|
+
// per-payment bearer secret. (?![\w/-]) is the right edge for the SDK's unanchored test.
|
|
1131
|
+
// NOT here: ipg.monri.com / ipgtest.monri.com (Monri direct: no CORS headers, behind Cloudflare,
|
|
1132
|
+
// needs the relay; a separate `monri` entry), ipgdev.monri.com, the ipg[test].webteh.hr hosts in
|
|
1133
|
+
// the bundle's whitelist (they do not resolve) and form[test].wspay.biz (WSPay Form, another product).
|
|
1134
|
+
// Ships dark: the recognizer is served only to a client that declares `wspay_confirm` for an
|
|
1135
|
+
// org an operator allowlisted, the processor is gated off for every other org, and autopilot
|
|
1136
|
+
// never replays it (EXCLUDED_OPERATIONS). GET /coverage and POST /coverage/assess describe it
|
|
1137
|
+
// on the same rule; only the preflight rules, which identify its scripts and frames, name
|
|
1138
|
+
// WSPay to every client. A confirm that asks WSPay to keep the card on file is refused unless
|
|
1139
|
+
// the caller carries the cardholder's consent (wspay.js).
|
|
1140
|
+
capability: "wspay_confirm",
|
|
1141
|
+
match: "proxy(?:-test)?\\.wspay\\.biz/v2/payment/[A-Za-z0-9_-]{1,128}/confirm(?![\\w/-])",
|
|
1142
|
+
hosts: ["^proxy\\.wspay\\.biz$", "^proxy-test\\.wspay\\.biz$"],
|
|
1143
|
+
// proxy-test is WSPay's test platform. Pinned (S7): a create refuses it on a live row and
|
|
1144
|
+
// proxy.wspay.biz on a test row, and the device sends it only the shared public network test
|
|
1145
|
+
// cards (test-pans.js), never a real card. WSPay's own test card list is unverified.
|
|
1146
|
+
sandboxHosts: ["^proxy-test\\.wspay\\.biz$"],
|
|
1147
|
+
hostEnvironmentPinned: true,
|
|
1148
|
+
encoding: "json",
|
|
1149
|
+
// The iframe's own Accept is load-bearing (Worldpay precedent); cookie/origin/referer never ride.
|
|
1150
|
+
passthroughHeaders: ["^authorization$", "^accept$"]
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
psp: "shiji_sts",
|
|
1154
|
+
// Shiji Payment Solutions STS, the card leg of the MyCheck Wallet V3 (Shiji Group) that La Quinta
|
|
1155
|
+
// by Wyndham loads in its booking page. sts.proxy.v2.1.js encrypts the PAN digits and the "MM/YY"
|
|
1156
|
+
// expiry, each on its own, with JSEncrypt (RSAES-PKCS1-v1_5) under the RSA-1024 key it hardcodes,
|
|
1157
|
+
// and fetch-POSTs application/json {accessToken, pan, expires, keySequence?} to /v1/token/getTokenId;
|
|
1158
|
+
// after MyCheck's payment-methods call it posts {accessToken, cvv, keySequence?} to
|
|
1159
|
+
// /v1/token/getCvvId. ONE entry covers both paths: they share the host, and resolveRecognizerForUrl
|
|
1160
|
+
// takes the first definition by host, so a second entry would never be reached. shiji-sts.js judges
|
|
1161
|
+
// which a request is: getTokenId is the one prompt, getCvvId a companion that never prompts and is
|
|
1162
|
+
// continued only when bound to the getTokenId the runtime continued. The device encrypts under the
|
|
1163
|
+
// key shiji-sts.js pins (SPKI SHA-256 c7846a0f...5a469ff7), never one from a row, a request or a
|
|
1164
|
+
// page, and the runtime swaps the ciphertexts at the body root: cse.at '' is the root, which the
|
|
1165
|
+
// Adyen substitution refuses, so only substituteShijiSts writes this body. No auth header: the
|
|
1166
|
+
// accessToken rides in the body. NOT allowlisted: iframe.vault.cn.{prod,uat}.shijipayment.cn (in the
|
|
1167
|
+
// proxy's table, never chosen by the wallet) and api.vault.eu.prod.shijipayment.com (not the
|
|
1168
|
+
// browser's host). `capability` keeps the entry out of BUILTIN_REGISTRY, serves it only to a client
|
|
1169
|
+
// that declares shiji_sts_pinned_key, and leaves it off for every org until one is opted in. The UAT
|
|
1170
|
+
// host is the sandbox host and the environment is pinned (S7): UAT only on sandbox rows, with
|
|
1171
|
+
// documented test cards. Every getTokenId is refused as card on file (a hotel guarantee) until the
|
|
1172
|
+
// consent decision is made (shiji-sts.js SHIJI_STS_KEEP_ON_FILE). `(?![\w/-])` ends the path as
|
|
1173
|
+
// on mercado_pago and paysafe: a consumer that tests `match` unanchored never takes
|
|
1174
|
+
// /v1/token/getTokenIdX or /v1/token/getTokenId/x for a card request.
|
|
1175
|
+
capability: "shiji_sts_pinned_key",
|
|
1176
|
+
encryptedCardFields: { number: "pan", expiry: "expires", cvc: "cvv" },
|
|
1177
|
+
match: "iframe\\.vault\\.eu\\.(?:prod|uat)\\.shijipayment\\.com/v1/token/(?:getTokenId|getCvvId)(?![\\w/-])",
|
|
1178
|
+
hosts: ["^iframe\\.vault\\.eu\\.prod\\.shijipayment\\.com$", "^iframe\\.vault\\.eu\\.uat\\.shijipayment\\.com$"],
|
|
1179
|
+
sandboxHosts: ["^iframe\\.vault\\.eu\\.uat\\.shijipayment\\.com$"],
|
|
1180
|
+
hostEnvironmentPinned: true,
|
|
1181
|
+
encoding: "json",
|
|
1182
|
+
passthroughHeaders: [],
|
|
1183
|
+
clientSideEncrypted: true,
|
|
1184
|
+
mode: "cse",
|
|
1185
|
+
cse: { scheme: "rsa-pkcs1v15", at: "", fields: ["pan", "expires", "cvv"] }
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
psp: "worldline_mycheckout",
|
|
1189
|
+
// Worldline Connect MyCheckout, the hosted payment page DHL Express's MyDHL+ sends its card
|
|
1190
|
+
// payments to. The page submits the card as a top-level form POST to /checkout on its own host
|
|
1191
|
+
// (a Document navigation, like Tranzila's), so the cardholder's device rebuilds that form with
|
|
1192
|
+
// the real card and submits it itself (mode hosted_form) and the paused navigation is
|
|
1193
|
+
// answered with the submission notice. The same URL takes the page's cancel and every non-card
|
|
1194
|
+
// payment product; only a body with cardNumber is a card request, and the rest continue
|
|
1195
|
+
// untouched (cardFields, passWithoutCard). A card body is taken over only in the one plain
|
|
1196
|
+
// shape worldline-mycheckout.js admits (worldlineMyCheckoutRequestRefusal): no card kept for
|
|
1197
|
+
// later, no wallet, a covered card product. The form names no amount (the merchant fixed it
|
|
1198
|
+
// when it created the hosted checkout), so the agent's amount is the price the cardholder
|
|
1199
|
+
// approves. `payment.` is the subdomain Worldline says always works, on pay1 (Europe) and pay2
|
|
1200
|
+
// (US) and their pre-production twins; a merchant's own MyCheckout subdomain is not admitted.
|
|
1201
|
+
// resolveRecognizerForUrl takes only the four endpoints written exactly. `capability` keeps
|
|
1202
|
+
// the entry out of BUILTIN_REGISTRY, serves it only to a client that declares
|
|
1203
|
+
// worldline_mycheckout_form, and leaves it off for every org until one is opted in; the
|
|
1204
|
+
// pre-production hosts take only test rows and documented test cards (hostEnvironmentPinned).
|
|
1205
|
+
capability: "worldline_mycheckout_form",
|
|
1206
|
+
match: "payment\\.pay[12](?:\\.preprod)?\\.checkout\\.worldline-solutions\\.com/checkout(?![\\w/.-])",
|
|
1207
|
+
hosts: [
|
|
1208
|
+
"^payment\\.pay1\\.checkout\\.worldline-solutions\\.com$",
|
|
1209
|
+
"^payment\\.pay2\\.checkout\\.worldline-solutions\\.com$",
|
|
1210
|
+
"^payment\\.pay1\\.preprod\\.checkout\\.worldline-solutions\\.com$",
|
|
1211
|
+
"^payment\\.pay2\\.preprod\\.checkout\\.worldline-solutions\\.com$"
|
|
1212
|
+
],
|
|
1213
|
+
sandboxHosts: ["^payment\\.pay1\\.preprod\\.checkout\\.worldline-solutions\\.com$", "^payment\\.pay2\\.preprod\\.checkout\\.worldline-solutions\\.com$"],
|
|
1214
|
+
hostEnvironmentPinned: true,
|
|
1215
|
+
encoding: "form",
|
|
1216
|
+
passthroughHeaders: [],
|
|
1217
|
+
cardFields: ["cardNumber"],
|
|
1218
|
+
passWithoutCard: "payment\\.pay[12](?:\\.preprod)?\\.checkout\\.worldline-solutions\\.com/checkout",
|
|
1219
|
+
mode: "hosted_form",
|
|
1220
|
+
hostedForm: {
|
|
1221
|
+
required: ["publicMerchantId", "token", "requestToken", "idempotenceKey", "doPayment"],
|
|
1222
|
+
// expiryDate is one MM/YY field; the device writes it in the page's own delimiter.
|
|
1223
|
+
card: { number: "cardNumber", expiry: "expiryDate", cvc: "cvv" },
|
|
1224
|
+
// The merchant and the hosted checkout: one prompt per hosted checkout.
|
|
1225
|
+
dedupe: ["publicMerchantId", "token"],
|
|
1226
|
+
// A checked "remember" asks Worldline to keep the card for later purchases.
|
|
1227
|
+
token: "remember"
|
|
1228
|
+
}
|
|
635
1229
|
}
|
|
636
1230
|
]);
|
|
637
|
-
var PSP_RECOGNIZERS = deepFreeze(PROCESSOR_DEFINITIONS.map(({ compose, encryptedCardFields, ...definition }) => definition));
|
|
1231
|
+
var PSP_RECOGNIZERS = deepFreeze(PROCESSOR_DEFINITIONS.map(({ compose, encryptedCardFields, deviceSteps, deviceEncrypt, ...definition }) => definition));
|
|
638
1232
|
var PSP_CLIENT_TABLE = deepFreeze(PROCESSOR_DEFINITIONS.map((definition) => ({
|
|
639
1233
|
psp: definition.psp,
|
|
640
1234
|
match: new RegExp(definition.match, "i"),
|
|
@@ -643,21 +1237,30 @@ var PSP_CLIENT_TABLE = deepFreeze(PROCESSOR_DEFINITIONS.map((definition) => ({
|
|
|
643
1237
|
headers: definition.passthroughHeaders.map((source) => new RegExp(source, "i")),
|
|
644
1238
|
...definition.sandboxHosts ? { sandboxHosts: definition.sandboxHosts.map((source) => new RegExp(source, "i")) } : {},
|
|
645
1239
|
...definition.hostEnvironmentPinned ? { hostEnvironmentPinned: true } : {},
|
|
1240
|
+
...definition.request ? { request: definition.request } : {},
|
|
646
1241
|
...definition.mode ? { mode: definition.mode } : {},
|
|
647
1242
|
...definition.clientSideEncrypted ? { clientSideEncrypted: true } : {},
|
|
648
1243
|
...definition.compose ? { compose: definition.compose } : {},
|
|
649
1244
|
...definition.encryptedCardFields ? { cse: { fields: definition.encryptedCardFields } } : {},
|
|
650
|
-
...definition.
|
|
1245
|
+
...definition.caseInsensitiveFormKeys ? { caseInsensitiveFormKeys: true } : {},
|
|
1246
|
+
// The device's copy of the form's card keys (forms.js hostedFormPairs), with the card roles a
|
|
1247
|
+
// template may lack (`optional`), so the vault fills exactly what the definition names.
|
|
1248
|
+
...definition.hostedForm ? { form: {
|
|
1249
|
+
...definition.hostedForm.card,
|
|
1250
|
+
...definition.hostedForm.optional ? { optional: definition.hostedForm.optional } : {}
|
|
1251
|
+
} } : {},
|
|
1252
|
+
...definition.deviceSteps ? { deviceSteps: Object.fromEntries(Object.entries(definition.deviceSteps).map(([step, source]) => [step, new RegExp(source, "i")])) } : {},
|
|
1253
|
+
...definition.deviceEncrypt ? { deviceEncrypt: definition.deviceEncrypt } : {}
|
|
651
1254
|
})));
|
|
652
1255
|
function buildBuiltinRegistry(recognizers) {
|
|
653
|
-
return recognizers.filter((definition) => !definition.capability).map(({ cse, hostedForm, ...definition }) => ({
|
|
1256
|
+
return recognizers.filter((definition) => !definition.capability).map(({ cse, hostedForm, deviceEncrypt, ...definition }) => ({
|
|
654
1257
|
...definition,
|
|
655
1258
|
match: new RegExp(definition.match, "i"),
|
|
656
1259
|
passthroughHeaders: definition.passthroughHeaders.map((source) => new RegExp(source, "i"))
|
|
657
1260
|
}));
|
|
658
1261
|
}
|
|
659
1262
|
var BUILTIN_REGISTRY = deepFreeze(buildBuiltinRegistry(PSP_RECOGNIZERS));
|
|
660
|
-
var CHECKOUT_MODES = deepFreeze(["token", "cse", "hosted_form"]);
|
|
1263
|
+
var CHECKOUT_MODES = deepFreeze(["token", "cse", "hosted_form", "card_endpoint", "device_encrypt"]);
|
|
661
1264
|
function recognizerByPsp(psp) {
|
|
662
1265
|
return typeof psp === "string" ? PSP_CLIENT_TABLE.find((entry) => entry.psp === psp) ?? null : null;
|
|
663
1266
|
}
|
|
@@ -668,6 +1271,116 @@ function trustedClientRecognizer(pspOrEntry) {
|
|
|
668
1271
|
throw new Error("Refusing to pay: unknown payment processor.");
|
|
669
1272
|
return definition;
|
|
670
1273
|
}
|
|
1274
|
+
// src/datatrans.js
|
|
1275
|
+
var DATATRANS_HOSTS = Object.freeze(["pay.datatrans.com", "pay.sandbox.datatrans.com"]);
|
|
1276
|
+
var DATATRANS_REFUSAL_REASONS = Object.freeze(["unsupported", "card_on_file", "brand_mismatch", "unregistered_merchant"]);
|
|
1277
|
+
var DATATRANS_REGISTRATION_POLICIES = Object.freeze(["refuse", "disclose", "agentcard_single_use"]);
|
|
1278
|
+
var DATATRANS_REVIEWED_MERCHANT_IDS = Object.freeze({
|
|
1279
|
+
"pay.datatrans.com": Object.freeze([]),
|
|
1280
|
+
"pay.sandbox.datatrans.com": Object.freeze(["1110022968", "1100007006"])
|
|
1281
|
+
});
|
|
1282
|
+
var DATATRANS_PAYMENT_METHODS = Object.freeze(["VIS", "ECA", "AMX", "DIN", "DIS", "JCB", "CUP", "MAU", "UAP", "DNK"]);
|
|
1283
|
+
var DATATRANS_TEST_PANS = Object.freeze([
|
|
1284
|
+
"4242424242424242",
|
|
1285
|
+
"4900000000000086",
|
|
1286
|
+
"4900000000000003",
|
|
1287
|
+
"5404000000000001",
|
|
1288
|
+
"5200000000000007",
|
|
1289
|
+
"5200000000000080",
|
|
1290
|
+
"375811111111115",
|
|
1291
|
+
"375000000000007",
|
|
1292
|
+
"375811111111123",
|
|
1293
|
+
"36168002586009",
|
|
1294
|
+
"36167719110012",
|
|
1295
|
+
"6011000000000004",
|
|
1296
|
+
"3569990010030442",
|
|
1297
|
+
"3569990010030400",
|
|
1298
|
+
"6362970000457013",
|
|
1299
|
+
"3841000000000007",
|
|
1300
|
+
"6200104444444447",
|
|
1301
|
+
"6210946888060008",
|
|
1302
|
+
"6759000000000018",
|
|
1303
|
+
"6759000000000026",
|
|
1304
|
+
"4000001000000034",
|
|
1305
|
+
"4000001000000018",
|
|
1306
|
+
"4000001000000042",
|
|
1307
|
+
"4000001000000026",
|
|
1308
|
+
"5100001000000022",
|
|
1309
|
+
"5100001000000048",
|
|
1310
|
+
"5100001000000014",
|
|
1311
|
+
"5100001000000030",
|
|
1312
|
+
"340000100000024",
|
|
1313
|
+
"340000100000040",
|
|
1314
|
+
"340000100000016",
|
|
1315
|
+
"340000100000032",
|
|
1316
|
+
"36000010000022",
|
|
1317
|
+
"3550998599961037"
|
|
1318
|
+
]);
|
|
1319
|
+
// src/amadeus-checkout.js
|
|
1320
|
+
var AMADEUS_CARD_URLS = Object.freeze({
|
|
1321
|
+
production: Object.freeze({
|
|
1322
|
+
sdk: Object.freeze(["https://paypages.payment.amadeus.com/1ASIATP/ARIAPP/pay"]),
|
|
1323
|
+
dcp: Object.freeze(["https://paypages.payment.amadeus.com/1ASIATP/ATPDCP/collect"])
|
|
1324
|
+
}),
|
|
1325
|
+
// pdt, uat, mig and skl. DCP was seen on the production path only, so the test host takes no store.
|
|
1326
|
+
sandbox: Object.freeze({
|
|
1327
|
+
sdk: Object.freeze([
|
|
1328
|
+
"https://paypages.test.payment.amadeus.com/1ASIATP/ARIAPP/pay",
|
|
1329
|
+
"https://paypages.test.payment.amadeus.com/1ASIATPU/ARIAPP/pay",
|
|
1330
|
+
"https://paypages.test.payment.amadeus.com/1ASIATPM/ARIAPP/pay",
|
|
1331
|
+
"https://paypages.test.payment.amadeus.com/1ASIATPK/ARIAPP/pay"
|
|
1332
|
+
]),
|
|
1333
|
+
dcp: Object.freeze([])
|
|
1334
|
+
})
|
|
1335
|
+
});
|
|
1336
|
+
var AMADEUS_MERCHANT_EXPIRY_POLICIES = Object.freeze(["refuse", "fill"]);
|
|
1337
|
+
var AMADEUS_REFUSAL_REASONS = Object.freeze([
|
|
1338
|
+
"unsupported",
|
|
1339
|
+
"card_on_file",
|
|
1340
|
+
"split_tender",
|
|
1341
|
+
"installments",
|
|
1342
|
+
"currency_conversion",
|
|
1343
|
+
"amadeus_3ds",
|
|
1344
|
+
"saved_card",
|
|
1345
|
+
"vendor_mismatch",
|
|
1346
|
+
"header_binding",
|
|
1347
|
+
"merchant_held_expiry",
|
|
1348
|
+
"dcp_field_config_unreviewed"
|
|
1349
|
+
]);
|
|
1350
|
+
var MESSAGES = Object.freeze({
|
|
1351
|
+
unsupported: "Refusing to pay: unsupported Amadeus card request.",
|
|
1352
|
+
card_on_file: "Refusing to pay: this Amadeus payment would let the merchant keep your card on file, which needs your consent first. Nothing was sent.",
|
|
1353
|
+
split_tender: "Refusing to pay: this Amadeus payment splits the total across more than one payment method. Nothing was sent.",
|
|
1354
|
+
installments: "Refusing to pay: this Amadeus payment asks to pay in installments. Nothing was sent.",
|
|
1355
|
+
currency_conversion: "Refusing to pay: this Amadeus payment converts the total into another currency. Nothing was sent.",
|
|
1356
|
+
amadeus_3ds: "Refusing to pay: this Amadeus payment set up its card check for a different card. Nothing was sent.",
|
|
1357
|
+
saved_card: "Refusing to pay: this Amadeus payment uses a card saved with the merchant, not your Vault card. Nothing was sent.",
|
|
1358
|
+
vendor_mismatch: "Refusing to pay: this Amadeus payment names a card network that is not your card's. Nothing was sent.",
|
|
1359
|
+
header_binding: "Refusing to pay: this Amadeus card form does not belong to the merchant you approved. Nothing was sent.",
|
|
1360
|
+
merchant_held_expiry: "Refusing to pay: this merchant sends your card's expiry date separately, which Agentcard cannot fill yet. Nothing was sent.",
|
|
1361
|
+
dcp_field_config_unreviewed: "Refusing to pay: Agentcard has not reviewed this merchant's Amadeus card form yet. Nothing was sent."
|
|
1362
|
+
});
|
|
1363
|
+
var SDK_FLAVORS = Object.freeze(["Core-Sdk", "Angular-Web-Sdk"]);
|
|
1364
|
+
var LABEL = "[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?";
|
|
1365
|
+
var SDK_HOST = new RegExp(`^${LABEL}(?:\\.${LABEL})+(?::[0-9]{1,5})?$`, "i");
|
|
1366
|
+
var SDK_HEADERS = Object.freeze(["amadeus-checkout-sdk-version", "amadeus-checkout-sdk-host", "amadeus-checkout-sdk-flavor"]);
|
|
1367
|
+
var SDK_DATA_KEYS = Object.freeze(["mopid", "mopdata", "fingerprint"]);
|
|
1368
|
+
var SDK_MOPDATA_KEYS = Object.freeze(["pan", "CVV", "holdername", "expmonth", "expyear", "vendor", "address", "contact"]);
|
|
1369
|
+
var SDK_MOPDATA_REFUSALS = Object.freeze({
|
|
1370
|
+
prefill_index: "saved_card",
|
|
1371
|
+
installmentPlansID: "installments",
|
|
1372
|
+
selectedInstallmentPlan: "installments",
|
|
1373
|
+
options: "currency_conversion",
|
|
1374
|
+
tdsSessionId: "amadeus_3ds",
|
|
1375
|
+
tdsDeviceInformation: "amadeus_3ds"
|
|
1376
|
+
});
|
|
1377
|
+
var AMADEUS_DCP_REVIEWED_KEYS = Object.freeze(["vendor", "pan", "expdate", "owner", "cvv", "address", "city", "zipCode", "country", "state"]);
|
|
1378
|
+
var DCP_TEXT_KEYS = Object.freeze(["address", "city", "zipCode", "country", "state"]);
|
|
1379
|
+
var NETWORKS = Object.freeze(["visa", "mastercard", "amex"]);
|
|
1380
|
+
var DECLINE_LABELS = Object.freeze(["label_error_payment", "label_error_bin", "label_error_bin_vendor", "label_error_bin_type"]);
|
|
1381
|
+
var EXPIRED_LABELS = Object.freeze(["session_timeout", "ppid_expired"]);
|
|
1382
|
+
var REF_KEYS = Object.freeze(["recloc", "orderId", "mopId", "pri", "approvalcode", "externalId", "paymentMerchantReference", "prr"]);
|
|
1383
|
+
var PAYMENT_INFORMATION_KEYS = Object.freeze(["approvalcode", "pri", "externalId", "mopId"]);
|
|
671
1384
|
// src/recognition.js
|
|
672
1385
|
var PATTERN_WITHOUT_CARD_FIELDS = Object.freeze({
|
|
673
1386
|
stripe: "api\\.stripe\\.com/v1/(payment_methods|tokens|setup_intents/seti_\\w+/confirm|payment_intents/pi_\\w+/confirm)"
|
|
@@ -678,14 +1391,24 @@ var WITHOUT_CHECKOUT_SESSIONS = Object.freeze({
|
|
|
678
1391
|
passWithoutCard: "api\\.stripe\\.com/v1/(sources|confirmation_tokens)"
|
|
679
1392
|
})
|
|
680
1393
|
});
|
|
1394
|
+
var ONLY_WITH_CARD_FIELDS = Object.freeze(["amadeus_checkout"]);
|
|
681
1395
|
// src/request-policy.js
|
|
682
1396
|
var HEADER_NEVER_FORWARD = /^(cookie|set-cookie|authorization2|proxy-authorization|host|content-length|origin|referer)$/i;
|
|
683
1397
|
var ALLOWED_MEDIA_TYPES = {
|
|
684
1398
|
json: ["application/json", "text/plain"],
|
|
685
|
-
form: ["application/x-www-form-urlencoded"]
|
|
1399
|
+
form: ["application/x-www-form-urlencoded"],
|
|
1400
|
+
jwe: ["application/jwt"]
|
|
686
1401
|
};
|
|
1402
|
+
var JWE_CONTENT_TYPE = "application/jwt; charset=utf-8";
|
|
687
1403
|
function contentTypeFor(pspOrEntry, headers) {
|
|
688
1404
|
const rec = trustedClientRecognizer(pspOrEntry);
|
|
1405
|
+
if (rec.encoding === "jwe") {
|
|
1406
|
+
const captured = Object.entries(headers || {}).find(([k]) => /^content-type$/i.test(k));
|
|
1407
|
+
const base2 = captured && typeof captured[1] === "string" ? captured[1].split(";")[0].trim().toLowerCase() : "";
|
|
1408
|
+
if (!ALLOWED_MEDIA_TYPES.jwe.includes(base2))
|
|
1409
|
+
throw new Error("Refusing to pay: this processor takes its sealed card only as application/jwt.");
|
|
1410
|
+
return JWE_CONTENT_TYPE;
|
|
1411
|
+
}
|
|
689
1412
|
const encoding = rec && rec.encoding === "form" ? "form" : "json";
|
|
690
1413
|
const allowed = ALLOWED_MEDIA_TYPES[encoding];
|
|
691
1414
|
const fallback = allowed[0];
|
|
@@ -703,6 +1426,8 @@ function contentTypeFor(pspOrEntry, headers) {
|
|
|
703
1426
|
function replayHeaders(pspOrEntry, captured = {}) {
|
|
704
1427
|
const rec = trustedClientRecognizer(pspOrEntry);
|
|
705
1428
|
const headers = { "content-type": contentTypeFor(rec, captured) };
|
|
1429
|
+
if (rec.psp === "creditguard")
|
|
1430
|
+
headers.accept = "application/json";
|
|
706
1431
|
for (const [name, value] of Object.entries(captured)) {
|
|
707
1432
|
if (rec.headers.some((pattern) => pattern.test(name)) && !HEADER_NEVER_FORWARD.test(name))
|
|
708
1433
|
headers[name] = value;
|