@agent-cards/sdk 0.23.28 → 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 +84 -0
- package/PREFLIGHT.md +7 -1
- package/README.md +197 -102
- package/dist/aci.d.ts +52 -22
- package/dist/aci.js +79 -15
- package/dist/adyen-merchant-hosted.generated.d.ts +2 -2
- package/dist/adyen-merchant-hosted.generated.js +586 -55
- package/dist/agent-amount.generated.js +1 -1
- package/dist/agentcard.d.ts +4 -5
- package/dist/agentcard.js +4 -5
- package/dist/amadeus.d.ts +9 -3
- package/dist/amadeus.js +33 -4
- package/dist/api-module.d.ts +1 -7
- package/dist/api-module.js +3 -5
- package/dist/{voice-retry.js → api-retry.js} +1 -1
- package/dist/api-types.d.ts +53 -0
- package/dist/{voice-types.js → api-types.js} +7 -2
- package/dist/approvals.d.ts +166 -0
- package/dist/approvals.js +213 -0
- package/dist/aurus.d.ts +33 -0
- package/dist/aurus.js +75 -0
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/buy.d.ts +20 -101
- package/dist/buy.js +19 -74
- package/dist/capabilities.generated.js +1 -1
- package/dist/card-fields.generated.js +2864 -249
- package/dist/cardlink-vpos.d.ts +43 -0
- package/dist/cardlink-vpos.js +90 -0
- package/dist/cdp.d.ts +3 -13
- package/dist/cdp.js +244 -175
- package/dist/checkout-com.generated.js +5 -1
- package/dist/client.d.ts +170 -22
- package/dist/client.js +281 -40
- package/dist/creditguard.generated.d.ts +4 -4
- package/dist/cybersource-flex.generated.d.ts +39 -1
- package/dist/cybersource-flex.generated.js +100 -11
- package/dist/datatrans.generated.js +22 -1
- package/dist/eghl.d.ts +40 -0
- package/dist/eghl.js +72 -0
- package/dist/elavon-converge.generated.js +5 -3
- package/dist/gmo.generated.js +7 -2
- package/dist/hold.d.ts +8 -0
- package/dist/hold.js +43 -2
- package/dist/hosted-entry.js +4 -0
- package/dist/index.d.ts +9 -15
- package/dist/index.js +6 -10
- package/dist/lifecycle.d.ts +9 -61
- package/dist/lifecycle.js +24 -10
- package/dist/merchant-card-endpoints.generated.d.ts +6 -1
- package/dist/merchant-card-endpoints.generated.js +344 -19
- package/dist/merchant-hosted.d.ts +8 -1
- package/dist/nike-order.d.ts +51 -0
- package/dist/nike-order.js +81 -0
- package/dist/oceanpayment.d.ts +38 -0
- package/dist/oceanpayment.js +70 -0
- package/dist/paddle-tokenex.generated.js +111 -11
- package/dist/payplug.d.ts +41 -0
- package/dist/payplug.js +71 -0
- package/dist/payrails.generated.js +33 -8
- package/dist/pre-claim.d.ts +11 -0
- package/dist/pre-claim.js +130 -7
- package/dist/preflight-capabilities.generated.d.ts +0 -4
- package/dist/preflight-capabilities.generated.js +0 -5
- package/dist/preflight-catalog.json +200 -6
- package/dist/preflight-playwright.d.ts +2 -2
- package/dist/preflight-playwright.js +63 -14
- package/dist/preflight-schemas.json +18 -0
- package/dist/preflight.generated.d.ts +5 -4
- package/dist/preflight.generated.js +63 -3
- package/dist/preparation.d.ts +7 -0
- package/dist/preparation.js +21 -0
- package/dist/prepared-processor.d.ts +18 -5
- package/dist/prepared-processor.js +48 -8
- package/dist/primer.generated.js +2889 -268
- package/dist/processout.generated.d.ts +61 -0
- package/dist/processout.generated.js +577 -0
- package/dist/requests.js +1 -1
- package/dist/shiji-sts.generated.js +111 -11
- package/dist/stripe-checkout.generated.js +2761 -319
- package/dist/substitutions.generated.js +553 -26
- package/dist/tap-payments.generated.js +111 -11
- package/dist/twoc2p.generated.js +111 -11
- package/dist/url-masks/bluesnap.d.ts +2 -0
- package/dist/url-masks/bluesnap.js +15 -0
- package/dist/url-masks/oceanpayment.d.ts +2 -0
- package/dist/url-masks/oceanpayment.js +13 -0
- package/dist/url-masks/payplug.d.ts +2 -0
- package/dist/url-masks/payplug.js +13 -0
- package/dist/url-masks/vtex_payments.d.ts +2 -0
- package/dist/url-masks/vtex_payments.js +12 -0
- package/dist/url-masks.generated.d.ts +1 -1
- package/dist/url-masks.generated.js +6 -2
- package/dist/verifone.generated.js +42 -2
- package/dist/vtex-payments.generated.d.ts +127 -0
- package/dist/vtex-payments.generated.js +544 -0
- package/dist/webhooks.d.ts +2 -2
- package/dist/webhooks.js +2 -2
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +6 -8
- package/dist/languages.d.ts +0 -23
- package/dist/languages.js +0 -76
- package/dist/voice-pkce.d.ts +0 -49
- package/dist/voice-pkce.js +0 -147
- package/dist/voice-stream.generated.d.ts +0 -118
- package/dist/voice-stream.generated.js +0 -170
- package/dist/voice-types.d.ts +0 -735
- package/dist/voice.d.ts +0 -373
- package/dist/voice.js +0 -815
- package/readme.test.mjs +0 -53
- /package/dist/{voice-retry.d.ts → api-retry.d.ts} +0 -0
package/dist/primer.generated.js
CHANGED
|
@@ -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: 6c0e945e1d49960ab9a1af9cdcfc73ca013e927dda8e75bed8f1a19d39e81d3f
|
|
4
4
|
// src/card-number-key.js
|
|
5
5
|
var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
|
|
6
6
|
// src/json-path.js
|
|
@@ -109,8 +109,8 @@ function parseConvergeBody(body) {
|
|
|
109
109
|
return parsed;
|
|
110
110
|
}
|
|
111
111
|
function convergeAmountCents(value) {
|
|
112
|
-
const
|
|
113
|
-
const m = typeof
|
|
112
|
+
const text11 = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
|
|
113
|
+
const m = typeof text11 === "string" ? AMOUNT.exec(text11) : null;
|
|
114
114
|
if (!m)
|
|
115
115
|
return null;
|
|
116
116
|
const cents2 = Number(m[1]) * 100 + Number(((m[2] ?? "") + "00").slice(0, 2));
|
|
@@ -365,8 +365,8 @@ var CONTROL = /[\u0000-\u001f\u007f]/;
|
|
|
365
365
|
var cardLikeName = (name) => (name.match(/[0-9]/g) ?? []).length >= 12;
|
|
366
366
|
var record3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
367
367
|
var sameKeys = (value, keys) => {
|
|
368
|
-
const
|
|
369
|
-
return
|
|
368
|
+
const own23 = Object.keys(value);
|
|
369
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
370
370
|
};
|
|
371
371
|
var refuse4 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
372
372
|
var CARD4 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
@@ -590,9 +590,9 @@ var K = /* @__PURE__ */ new Uint32Array([
|
|
|
590
590
|
3329325298
|
|
591
591
|
]);
|
|
592
592
|
var rotr = (x, n) => x >>> n | x << 32 - n;
|
|
593
|
-
function utf8(
|
|
593
|
+
function utf8(text11) {
|
|
594
594
|
const out = [];
|
|
595
|
-
for (const char of
|
|
595
|
+
for (const char of text11) {
|
|
596
596
|
let cp = char.codePointAt(0);
|
|
597
597
|
if (cp >= 55296 && cp <= 57343)
|
|
598
598
|
cp = 65533;
|
|
@@ -667,6 +667,7 @@ var BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
|
667
667
|
var SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
668
668
|
var RSA_ALGORITHM = [48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0];
|
|
669
669
|
var MODULUS_BYTES = [128, 256, 384, 512];
|
|
670
|
+
var SMALL_MODULUS_BYTES = 64;
|
|
670
671
|
var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
|
|
671
672
|
var typedArrayName = Object.getOwnPropertyDescriptor(TYPED_ARRAY, Symbol.toStringTag).get;
|
|
672
673
|
function parseRsaPublicKey(key) {
|
|
@@ -675,6 +676,9 @@ function parseRsaPublicKey(key) {
|
|
|
675
676
|
const named = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "exponent") ? key.exponent : void 0;
|
|
676
677
|
if (named !== void 0 && named !== 17)
|
|
677
678
|
throw refuse6("key");
|
|
679
|
+
const sized = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "bits") ? key.bits : void 0;
|
|
680
|
+
if (sized !== void 0 && sized !== 512)
|
|
681
|
+
throw refuse6("key");
|
|
678
682
|
if (typeof spki !== "string" || spki.length > 1024 || spki.length % 4 !== 0 || !BASE64.test(spki))
|
|
679
683
|
throw refuse6("key");
|
|
680
684
|
if (typeof pin10 !== "string" || !SHA256_HEX.test(pin10))
|
|
@@ -707,7 +711,8 @@ function parseRsaPublicKey(key) {
|
|
|
707
711
|
if (exponent.end !== rsa.end)
|
|
708
712
|
throw refuse6("key");
|
|
709
713
|
const n = modulus.bytes;
|
|
710
|
-
|
|
714
|
+
const sizes = sized === 512 ? [SMALL_MODULUS_BYTES] : MODULUS_BYTES;
|
|
715
|
+
if (!sizes.includes(n.length) || !(n[0] & 128) || !(n[n.length - 1] & 1))
|
|
711
716
|
throw refuse6("key");
|
|
712
717
|
const e = exponent.bytes;
|
|
713
718
|
const expected = named === 17 ? [17] : [1, 0, 1];
|
|
@@ -721,13 +726,13 @@ function readElement(der, at, tag) {
|
|
|
721
726
|
let length = der[at + 1];
|
|
722
727
|
let start = at + 2;
|
|
723
728
|
if (length & 128) {
|
|
724
|
-
const
|
|
725
|
-
if (
|
|
729
|
+
const count2 = length & 127;
|
|
730
|
+
if (count2 === 0 || count2 > 2 || start + count2 > der.length || der[start] === 0)
|
|
726
731
|
throw refuse6("key");
|
|
727
|
-
length =
|
|
732
|
+
length = count2 === 1 ? der[start] : der[start] * 256 + der[start + 1];
|
|
728
733
|
if (length < 128)
|
|
729
734
|
throw refuse6("key");
|
|
730
|
-
start +=
|
|
735
|
+
start += count2;
|
|
731
736
|
}
|
|
732
737
|
if (start + length > der.length)
|
|
733
738
|
throw refuse6("key");
|
|
@@ -779,8 +784,8 @@ var PADDLE_TOKENEX_PSP = "paddle_tokenex";
|
|
|
779
784
|
var PADDLE_TOKENEX_FACT_KEYS = /* @__PURE__ */ Object.freeze(["card_first_six", "card_last_four", "expiry_month", "expiry_year", "card_brand"]);
|
|
780
785
|
var record4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
781
786
|
var sameKeys2 = (value, keys) => {
|
|
782
|
-
const
|
|
783
|
-
return
|
|
787
|
+
const own23 = Object.keys(value);
|
|
788
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
784
789
|
};
|
|
785
790
|
var refuse7 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
786
791
|
var CARD6 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
@@ -850,8 +855,8 @@ function readPay(body, line, environment2) {
|
|
|
850
855
|
const card = record4(method) && sameKeys2(method, ["card"]) ? method.card : null;
|
|
851
856
|
if (!record4(card) || !(sameKeys2(card, PAY_CARD_KEYS) || sameKeys2(card, [...PAY_CARD_KEYS, "session_tracking"])))
|
|
852
857
|
return null;
|
|
853
|
-
const
|
|
854
|
-
if (!record4(
|
|
858
|
+
const metadata2 = card.metadata;
|
|
859
|
+
if (!record4(metadata2) || !sameKeys2(metadata2, METADATA_KEYS2) || typeof metadata2.cardholder_name !== "string" || metadata2.cardholder_name.length > NAME_LIMIT2 || CONTROL2.test(metadata2.cardholder_name) || cardLikeName2(metadata2.cardholder_name) || typeof metadata2.card_first_six !== "string" || !FIRST_SIX.test(metadata2.card_first_six) || typeof metadata2.card_last_four !== "string" || !LAST_FOUR.test(metadata2.card_last_four) || !expiryMonth(metadata2.expiry_month) || !expiryYear(metadata2.expiry_year) || !FRAME_BRANDS.includes(metadata2.card_brand))
|
|
855
860
|
return null;
|
|
856
861
|
const details = card.three_d_s;
|
|
857
862
|
if (!record4(details) || !sameKeys2(details, ["browser_info"]) || typeof details.browser_info !== "string" || !BROWSER_INFO.test(details.browser_info))
|
|
@@ -1269,8 +1274,8 @@ var TEXT_LIMIT = 256;
|
|
|
1269
1274
|
var CONTROL4 = /[\u0000-\u001f\u007f]/;
|
|
1270
1275
|
var record6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1271
1276
|
var sameKeys3 = (value, keys) => {
|
|
1272
|
-
const
|
|
1273
|
-
return
|
|
1277
|
+
const own23 = Object.keys(value);
|
|
1278
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
1274
1279
|
};
|
|
1275
1280
|
var plainText = (value) => typeof value === "string" && value.length <= TEXT_LIMIT && !CONTROL4.test(value) && (value.match(/[0-9]/g) ?? []).length < 12;
|
|
1276
1281
|
var refuse9 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
@@ -1300,13 +1305,13 @@ function billingFields(value) {
|
|
|
1300
1305
|
if (names.length > MAX_FIELDS)
|
|
1301
1306
|
return false;
|
|
1302
1307
|
return names.every((name) => {
|
|
1303
|
-
const
|
|
1308
|
+
const field5 = value[name];
|
|
1304
1309
|
if (!FIELD_NAME.test(name))
|
|
1305
1310
|
return false;
|
|
1306
|
-
if (!record6(
|
|
1307
|
-
return billingText(
|
|
1308
|
-
const nested = Object.keys(
|
|
1309
|
-
return nested.length <= MAX_NESTED_FIELDS && nested.every((key) => FIELD_NAME.test(key) && billingText(
|
|
1311
|
+
if (!record6(field5))
|
|
1312
|
+
return billingText(field5);
|
|
1313
|
+
const nested = Object.keys(field5);
|
|
1314
|
+
return nested.length <= MAX_NESTED_FIELDS && nested.every((key) => FIELD_NAME.test(key) && billingText(field5[key]));
|
|
1310
1315
|
});
|
|
1311
1316
|
}
|
|
1312
1317
|
function wixPaymentsBodyVerdict(body) {
|
|
@@ -1380,14 +1385,14 @@ function readJson2(body) {
|
|
|
1380
1385
|
catch {
|
|
1381
1386
|
return { parsed: null, exact: false };
|
|
1382
1387
|
}
|
|
1383
|
-
let
|
|
1388
|
+
let exact6 = false;
|
|
1384
1389
|
try {
|
|
1385
|
-
|
|
1390
|
+
exact6 = body.length <= BODY_LIMIT6 && JSON.stringify(parsed) === body;
|
|
1386
1391
|
}
|
|
1387
1392
|
catch {
|
|
1388
|
-
|
|
1393
|
+
exact6 = false;
|
|
1389
1394
|
}
|
|
1390
|
-
return { parsed, exact:
|
|
1395
|
+
return { parsed, exact: exact6 };
|
|
1391
1396
|
}
|
|
1392
1397
|
function billingValue(value) {
|
|
1393
1398
|
if (value === UNDEFINED)
|
|
@@ -1401,15 +1406,15 @@ function judgeCardAttach(args, session) {
|
|
|
1401
1406
|
return "paymongo_body_unsupported";
|
|
1402
1407
|
}
|
|
1403
1408
|
const id = args[0].slice(3);
|
|
1404
|
-
const
|
|
1405
|
-
const details =
|
|
1409
|
+
const attributes2 = args[1].data.attributes;
|
|
1410
|
+
const details = attributes2.details;
|
|
1406
1411
|
if (record7(details) && CLICK_TO_PAY_KEYS.some((key) => own(details, key)))
|
|
1407
1412
|
return "paymongo_click_to_pay";
|
|
1408
|
-
if (!keysAre(args[1], ["data"]) || !keysAre(args[1].data, ["attributes"]) || !keysAre(
|
|
1413
|
+
if (!keysAre(args[1], ["data"]) || !keysAre(args[1].data, ["attributes"]) || !keysAre(attributes2, PAYMONGO_ATTRIBUTE_KEYS) || !record7(details) || !keysAre(details, PAYMONGO_CARD_KEYS))
|
|
1409
1414
|
return "paymongo_body_unsupported";
|
|
1410
1415
|
if (typeof details.card_number !== "string" || !NUMBER.test(details.card_number) || !Number.isSafeInteger(details.exp_month) || details.exp_month < 1 || details.exp_month > 12 || !Number.isSafeInteger(details.exp_year) || details.exp_year < 0 || details.exp_year > 99 || typeof details.cvc !== "string" || !SECURITY_CODE6.test(details.cvc))
|
|
1411
1416
|
return "paymongo_body_unsupported";
|
|
1412
|
-
const billing =
|
|
1417
|
+
const billing = attributes2.billing;
|
|
1413
1418
|
if (!record7(billing) || !keysAre(billing, PAYMONGO_BILLING_KEYS) || !record7(billing.address) || !keysAre(billing.address, PAYMONGO_ADDRESS_KEYS))
|
|
1414
1419
|
return "paymongo_body_unsupported";
|
|
1415
1420
|
if (billing.name === UNDEFINED || !billingValue(billing.name) || !billingValue(billing.email) || !billingValue(billing.phone) || !PAYMONGO_ADDRESS_KEYS.every((key) => billingValue(billing.address[key])))
|
|
@@ -1417,7 +1422,7 @@ function judgeCardAttach(args, session) {
|
|
|
1417
1422
|
const third = args[2];
|
|
1418
1423
|
if (!record7(third) || !keysAre(third, ["viewerAccept"]) || !billingValue(third.viewerAccept))
|
|
1419
1424
|
return "paymongo_body_unsupported";
|
|
1420
|
-
if (
|
|
1425
|
+
if (attributes2.return_url !== `${ORIGIN}${id}` || session !== void 0 && session !== id)
|
|
1421
1426
|
return "paymongo_session_mismatch";
|
|
1422
1427
|
return null;
|
|
1423
1428
|
}
|
|
@@ -1442,14 +1447,14 @@ function attachType(parsed) {
|
|
|
1442
1447
|
return typeof type === "string" ? type : null;
|
|
1443
1448
|
}
|
|
1444
1449
|
function paymongoBodyVerdict(body, session) {
|
|
1445
|
-
const { parsed, exact:
|
|
1450
|
+
const { parsed, exact: exact6 } = readJson2(body);
|
|
1446
1451
|
const type = parsed === null ? null : attachType(parsed);
|
|
1447
1452
|
if (type !== "card") {
|
|
1448
1453
|
if (parsed === null)
|
|
1449
1454
|
return body === void 0 || body === null || body === "" ? CONTINUE4 : refuse10("paymongo_body_unsupported");
|
|
1450
1455
|
return namesCardValue(parsed) ? refuse10("paymongo_body_unsupported") : CONTINUE4;
|
|
1451
1456
|
}
|
|
1452
|
-
if (!
|
|
1457
|
+
if (!exact6)
|
|
1453
1458
|
return refuse10("paymongo_body_unsupported");
|
|
1454
1459
|
const code = judgeCardAttach(parsed, session);
|
|
1455
1460
|
return code === null ? CARD9 : refuse10(code);
|
|
@@ -1472,8 +1477,8 @@ var EXPIRATION = /^[0-9]{2}(?:0[1-9]|1[0-2])$/;
|
|
|
1472
1477
|
var CARD_PAYMENT = "PAYMENT_CARD";
|
|
1473
1478
|
var record8 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1474
1479
|
var sameKeys4 = (value, keys) => {
|
|
1475
|
-
const
|
|
1476
|
-
return
|
|
1480
|
+
const own23 = Object.keys(value);
|
|
1481
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
1477
1482
|
};
|
|
1478
1483
|
var refuse11 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
1479
1484
|
var CARD10 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
@@ -1703,8 +1708,8 @@ var LOCALE = /^[a-z]{2}(?:-[A-Za-z]{2,4})?$/;
|
|
|
1703
1708
|
var PAN_LIKE3 = /(?:[0-9][ _.:-]*){12,}/;
|
|
1704
1709
|
var record9 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1705
1710
|
var sameKeys5 = (value, keys) => {
|
|
1706
|
-
const
|
|
1707
|
-
return
|
|
1711
|
+
const own23 = Object.keys(value);
|
|
1712
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
1708
1713
|
};
|
|
1709
1714
|
var refuse13 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
1710
1715
|
var CARD12 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
@@ -1956,10 +1961,10 @@ function judge(body, contentType, rule) {
|
|
|
1956
1961
|
if (read.parts.some((part) => !listed(rule.parts, part.name)))
|
|
1957
1962
|
return refusal("multipart_unknown_part");
|
|
1958
1963
|
for (const name of rule.card) {
|
|
1959
|
-
const
|
|
1960
|
-
if (
|
|
1964
|
+
const count2 = read.parts.filter((part) => part.name === name).length;
|
|
1965
|
+
if (count2 === 0)
|
|
1961
1966
|
return refusal("multipart_missing_card_part");
|
|
1962
|
-
if (
|
|
1967
|
+
if (count2 > 1)
|
|
1963
1968
|
return refusal("multipart_duplicate_card_part");
|
|
1964
1969
|
}
|
|
1965
1970
|
return read;
|
|
@@ -1968,6 +1973,25 @@ function multipartFormRefusal(body, contentType, rule) {
|
|
|
1968
1973
|
const read = judge(body, contentType, rule);
|
|
1969
1974
|
return read.refusal ?? null;
|
|
1970
1975
|
}
|
|
1976
|
+
// src/answer-card-leak.js
|
|
1977
|
+
var DECIMAL = /\p{Nd}/u;
|
|
1978
|
+
function digitValue(char) {
|
|
1979
|
+
const point = char.codePointAt(0);
|
|
1980
|
+
let first = point;
|
|
1981
|
+
while (DECIMAL.test(String.fromCodePoint(first - 1)))
|
|
1982
|
+
first -= 1;
|
|
1983
|
+
return String((point - first) % 10);
|
|
1984
|
+
}
|
|
1985
|
+
var ENCLOSED = /* @__PURE__ */ Object.freeze([[9451, 10, 11], [9461, 10, 1], [9471, 1, 0], [10102, 30, 1], [127243, 2, 0]]);
|
|
1986
|
+
var ENCLOSED_CHAR = /[\u24eb-\u24ff\u2776-\u2793\u{1f10b}\u{1f10c}]/gu;
|
|
1987
|
+
function enclosedValue(char) {
|
|
1988
|
+
const point = char.codePointAt(0);
|
|
1989
|
+
const [first, , start] = ENCLOSED.find(([from, size]) => point >= from && point < from + size);
|
|
1990
|
+
return String(first === 127243 ? 0 : first === 10102 ? (point - first) % 10 + 1 : start + point - first);
|
|
1991
|
+
}
|
|
1992
|
+
var asciiDigits = (text11) => (typeof text11.normalize === "function" ? text11.normalize("NFKC") : text11).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
|
|
1993
|
+
var digitCount = (text11) => (asciiDigits(String(text11)).match(/\p{N}/gu) ?? []).length;
|
|
1994
|
+
var NAME_DIGITS = 3;
|
|
1971
1995
|
// src/pay-nl.js
|
|
1972
1996
|
var PAY_NL_PSP = "pay_nl";
|
|
1973
1997
|
var PAY_NL_TOKEN_URL = "https://payment.pay.nl/v1/Payment/getCardToken/json";
|
|
@@ -2120,7 +2144,7 @@ var luhn2 = (digits4) => {
|
|
|
2120
2144
|
return sum % 10 === 0;
|
|
2121
2145
|
};
|
|
2122
2146
|
var ANY_NETWORK = /^[2-6][0-9]{12,18}$/;
|
|
2123
|
-
var holdsCardShape = (
|
|
2147
|
+
var holdsCardShape = (text11, shape = NETWORK) => (text11.match(/[0-9]{13,}/g) ?? []).some((run) => run.length > 19 || shape.test(run) && luhn2(run));
|
|
2124
2148
|
var phone = (value) => typeof value === "string" && PHONE.test(value) && (value.match(/[0-9]/g) ?? []).length >= 6 && (value.match(/[0-9]/g) ?? []).length <= 15;
|
|
2125
2149
|
var refuse16 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
2126
2150
|
var CARD15 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
@@ -2348,13 +2372,13 @@ var printable = (value) => [...value].every((ch) => ch.charCodeAt(0) >= 32 && ch
|
|
|
2348
2372
|
function typed(value, limit = 256) {
|
|
2349
2373
|
return typeof value === "string" && value.length >= 1 && value.length <= limit && !PAN_LIKE4.test(value) && printable(value);
|
|
2350
2374
|
}
|
|
2351
|
-
function decodeBase64(
|
|
2352
|
-
if (typeof
|
|
2375
|
+
function decodeBase64(text11) {
|
|
2376
|
+
if (typeof text11 !== "string" || !BASE643.test(text11) || text11.length % 4 !== 0)
|
|
2353
2377
|
return null;
|
|
2354
2378
|
let bits = 0;
|
|
2355
2379
|
let value = 0;
|
|
2356
2380
|
let out = "";
|
|
2357
|
-
for (const ch of
|
|
2381
|
+
for (const ch of text11.replace(/=+$/, "")) {
|
|
2358
2382
|
value = (value << 6 | BASE64_ALPHABET.indexOf(ch)) & 16777215;
|
|
2359
2383
|
bits += 6;
|
|
2360
2384
|
if (bits >= 8) {
|
|
@@ -2364,8 +2388,8 @@ function decodeBase64(text10) {
|
|
|
2364
2388
|
}
|
|
2365
2389
|
return out;
|
|
2366
2390
|
}
|
|
2367
|
-
function soundDevice(
|
|
2368
|
-
const json = decodeBase64(
|
|
2391
|
+
function soundDevice(text11) {
|
|
2392
|
+
const json = decodeBase64(text11);
|
|
2369
2393
|
if (json === null)
|
|
2370
2394
|
return false;
|
|
2371
2395
|
let value;
|
|
@@ -2483,17 +2507,17 @@ function sumupBodyVerdict(body, url) {
|
|
|
2483
2507
|
var SALTED = /* @__PURE__ */ Object.freeze([83, 97, 108, 116, 101, 100, 95, 95]);
|
|
2484
2508
|
var B64 = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
2485
2509
|
var FIELD_LIMIT = 1024;
|
|
2486
|
-
function decodeCanonical(
|
|
2487
|
-
if (typeof
|
|
2510
|
+
function decodeCanonical(text11) {
|
|
2511
|
+
if (typeof text11 !== "string" || text11.length === 0 || text11.length % 4 !== 0 || !B64.test(text11))
|
|
2488
2512
|
return null;
|
|
2489
2513
|
let binary;
|
|
2490
2514
|
try {
|
|
2491
|
-
binary = atob(
|
|
2515
|
+
binary = atob(text11);
|
|
2492
2516
|
}
|
|
2493
2517
|
catch {
|
|
2494
2518
|
return null;
|
|
2495
2519
|
}
|
|
2496
|
-
if (btoa(binary) !==
|
|
2520
|
+
if (btoa(binary) !== text11)
|
|
2497
2521
|
return null;
|
|
2498
2522
|
return Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
2499
2523
|
}
|
|
@@ -2735,8 +2759,8 @@ var TEXT_LIMIT3 = 256;
|
|
|
2735
2759
|
var CONTROL7 = /[\u0000-\u001f\u007f]/;
|
|
2736
2760
|
var record13 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2737
2761
|
var sameKeys7 = (value, keys) => {
|
|
2738
|
-
const
|
|
2739
|
-
return
|
|
2762
|
+
const own23 = Object.keys(value);
|
|
2763
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
2740
2764
|
};
|
|
2741
2765
|
var plainText3 = (value) => typeof value === "string" && value.length <= TEXT_LIMIT3 && !CONTROL7.test(value) && (value.match(/[0-9]/g) ?? []).length < 12;
|
|
2742
2766
|
var refuse19 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
@@ -3013,10 +3037,10 @@ function paypalBodyVerdict(body) {
|
|
|
3013
3037
|
if (number === void 0 || number === null || number === "")
|
|
3014
3038
|
return CONTINUE9;
|
|
3015
3039
|
const context = value.application_context;
|
|
3016
|
-
const
|
|
3017
|
-
if (record14(context) && context.vault === true || own3(card, "stored_credential") ||
|
|
3040
|
+
const attributes2 = record14(card.attributes) ? card.attributes : null;
|
|
3041
|
+
if (record14(context) && context.vault === true || own3(card, "stored_credential") || attributes2 && (own3(attributes2, "vault") || own3(attributes2, "customer")))
|
|
3018
3042
|
return refuse20("paypal_card_on_file");
|
|
3019
|
-
if (
|
|
3043
|
+
if (attributes2 && record14(attributes2.verification) && attributes2.verification.method === "SCA_ALWAYS")
|
|
3020
3044
|
return refuse20("paypal_three_ds");
|
|
3021
3045
|
if (!keysWithin2(value, ["payment_source"]) || !keysWithin2(source, ["card"]) || !keysWithin2(card, CARD_KEYS8) || !typedNumber(card.number) || typeof card.expiry !== "string" || !/^[0-9]{4}-(?:0[1-9]|1[0-2])$/.test(card.expiry))
|
|
3022
3046
|
return refuse20("paypal_body_unsupported");
|
|
@@ -3030,7 +3054,7 @@ function paypalBodyVerdict(body) {
|
|
|
3030
3054
|
if (own3(card, "billing_address") && !(keysWithin2(card.billing_address, ADDRESS_KEYS3) && Object.values(card.billing_address).every(text3))) {
|
|
3031
3055
|
return refuse20("paypal_body_unsupported");
|
|
3032
3056
|
}
|
|
3033
|
-
if (own3(card, "attributes") && !(keysWithin2(
|
|
3057
|
+
if (own3(card, "attributes") && !(keysWithin2(attributes2, ["installments"]) && installmentsOk(attributes2.installments))) {
|
|
3034
3058
|
return refuse20("paypal_body_unsupported");
|
|
3035
3059
|
}
|
|
3036
3060
|
return CARD19;
|
|
@@ -3432,7 +3456,7 @@ var YEAR11 = /^[0-9]{2}$/;
|
|
|
3432
3456
|
var CODE4 = /^[0-9]{3}$/;
|
|
3433
3457
|
var NAME_LIMIT3 = 100;
|
|
3434
3458
|
var NAME_WORD = /[a-z]+/gi;
|
|
3435
|
-
var printable2 = (
|
|
3459
|
+
var printable2 = (text11) => [...text11].every((character) => {
|
|
3436
3460
|
const point = character.codePointAt(0);
|
|
3437
3461
|
return point >= 32 && !(point >= 127 && point <= 159) && point !== 8232 && point !== 8233;
|
|
3438
3462
|
});
|
|
@@ -3441,8 +3465,8 @@ var HOSTNAME = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](
|
|
|
3441
3465
|
var PUBLISHABLE_KEY = /^[A-Za-z0-9]{16,64}$/;
|
|
3442
3466
|
var record18 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3443
3467
|
var sameKeys8 = (value, keys) => {
|
|
3444
|
-
const
|
|
3445
|
-
return
|
|
3468
|
+
const own23 = Object.keys(value);
|
|
3469
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
3446
3470
|
};
|
|
3447
3471
|
var refuse24 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
3448
3472
|
var CARD23 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
@@ -3812,7 +3836,7 @@ var POSTAL_CODE3 = /^[A-Za-z0-9_]{0,16}$/;
|
|
|
3812
3836
|
var COUNTRY4 = /^[A-Z]{2}$/;
|
|
3813
3837
|
var TEXT_LIMIT7 = 256;
|
|
3814
3838
|
var CONTROL10 = /[\u0000-\u001f\u007f]/;
|
|
3815
|
-
var cardLike2 = (
|
|
3839
|
+
var cardLike2 = (text11) => (text11.match(/[0-9]/g) ?? []).length >= 12;
|
|
3816
3840
|
var text5 = (value) => typeof value === "string" && value.length <= TEXT_LIMIT7 && !CONTROL10.test(value) && !cardLike2(value);
|
|
3817
3841
|
var record21 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3818
3842
|
var own5 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
@@ -4133,11 +4157,11 @@ var LONG_TEXT_LIMIT = BODY_LIMIT25;
|
|
|
4133
4157
|
var record22 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4134
4158
|
var owns6 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
4135
4159
|
var sameKeys9 = (value, keys) => {
|
|
4136
|
-
const
|
|
4137
|
-
return
|
|
4160
|
+
const own23 = Object.keys(value);
|
|
4161
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
4138
4162
|
};
|
|
4139
4163
|
var exact3 = (pattern, value) => typeof value === "string" && pattern.test(value);
|
|
4140
|
-
var printable3 = (
|
|
4164
|
+
var printable3 = (text11) => [...text11].every((character) => {
|
|
4141
4165
|
const point = character.codePointAt(0);
|
|
4142
4166
|
return point >= 32 && !(point >= 127 && point <= 159) && point !== 8232 && point !== 8233;
|
|
4143
4167
|
});
|
|
@@ -4210,7 +4234,7 @@ function companyStore(value) {
|
|
|
4210
4234
|
return record22(value) && sameKeys9(value, COMPANY_KEYS) && whole(value.CompanyNumber, 1) && COMPANY_KEYS.slice(1).every((key) => key.startsWith("Show") ? flag(value[key]) : pageText(value[key]));
|
|
4211
4235
|
}
|
|
4212
4236
|
var SUM_TEXT = /^(?:0*[1-9][0-9]*(?:\.[0-9]+)?|0+\.[0-9]*[1-9][0-9]*)$/;
|
|
4213
|
-
var sumText = (
|
|
4237
|
+
var sumText = (text11, sum) => text11 === null || typeof text11 === "string" && SUM_TEXT.test(text11) && Number.parseFloat(text11) === sum;
|
|
4214
4238
|
function chosenProduct(value) {
|
|
4215
4239
|
return record22(value) && sameKeys9(value, PRODUCT_KEYS) && whole(value.MinQuantity) && whole(value.MaxQuantity) && whole(value.JumpsInQuantity) && value.SelectedBuyQuantity === 1 && Array.isArray(value.QuantityOptions) && value.QuantityOptions.length === 0 && pageText(value.Comments) && flag(value.IsManualSum) && Array.isArray(value.PaymentsOptions) && flag(value.IsCouponActive) && typeof value.ManualPrice === "number" && sumText(value.ManualPriceTxt, value.ManualPrice) && flag(value.IsVatFree) && Array.isArray(value.SpecialPrices) && (value.PreConfiguredPrice === null || typeof value.PreConfiguredPrice === "number") && flag(value.IsPreSelected) && typeof value.CurrentInventory === "number" && flag(value.CheckInventory) && exact3(PRODUCT_ID, value.uid) && pageText(value.imageUrl) && typeof value.name === "string" && pageText(value.name) && pageText(value.description) && typeof value.BasePrice === "number" && typeof value.PriceBeforeDiscount === "number" && whole(value.BaseISOCurrency) && typeof value.PriceToShow === "number" && typeof value.PriceBeforeDiscountToShow === "number" && flag(value.IsCurrent);
|
|
4216
4240
|
}
|
|
@@ -4441,7 +4465,7 @@ var sameKeys10 = (value, keys) => {
|
|
|
4441
4465
|
};
|
|
4442
4466
|
var refuse28 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
4443
4467
|
var CARD27 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
4444
|
-
var printable4 = (
|
|
4468
|
+
var printable4 = (text11) => [...text11].every((character) => {
|
|
4445
4469
|
const point = character.codePointAt(0);
|
|
4446
4470
|
return point >= 32 && !(point >= 127 && point <= 159) && point !== 8232 && point !== 8233;
|
|
4447
4471
|
});
|
|
@@ -4533,8 +4557,8 @@ var POSTAL_CODE4 = /^[A-Za-z0-9 -]{0,16}$/;
|
|
|
4533
4557
|
var CIPHERTEXT_B64 = /^[A-Za-z0-9+/]{341}[AQgw]==$/;
|
|
4534
4558
|
var record24 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4535
4559
|
var sameKeys11 = (value, keys) => {
|
|
4536
|
-
const
|
|
4537
|
-
return
|
|
4560
|
+
const own23 = Object.keys(value);
|
|
4561
|
+
return own23.length === keys.length && own23.every((key, at) => key === keys[at]);
|
|
4538
4562
|
};
|
|
4539
4563
|
var refuse29 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
4540
4564
|
var failed = (code) => (
|
|
@@ -4685,14 +4709,14 @@ function readJson7(body) {
|
|
|
4685
4709
|
catch {
|
|
4686
4710
|
return { parsed: null, exact: false };
|
|
4687
4711
|
}
|
|
4688
|
-
let
|
|
4712
|
+
let exact6 = false;
|
|
4689
4713
|
try {
|
|
4690
|
-
|
|
4714
|
+
exact6 = JSON.stringify(parsed) === body;
|
|
4691
4715
|
}
|
|
4692
4716
|
catch {
|
|
4693
|
-
|
|
4717
|
+
exact6 = false;
|
|
4694
4718
|
}
|
|
4695
|
-
return { parsed, exact:
|
|
4719
|
+
return { parsed, exact: exact6 };
|
|
4696
4720
|
}
|
|
4697
4721
|
function numberDigits(number) {
|
|
4698
4722
|
if (typeof number !== "string")
|
|
@@ -4769,7 +4793,7 @@ function judgeCard2(parsed) {
|
|
|
4769
4793
|
return null;
|
|
4770
4794
|
}
|
|
4771
4795
|
function fastspringBodyVerdict(body) {
|
|
4772
|
-
const { parsed, exact:
|
|
4796
|
+
const { parsed, exact: exact6 } = readJson7(body);
|
|
4773
4797
|
if (!record25(parsed))
|
|
4774
4798
|
return body === void 0 || body === null || body === "" ? CONTINUE11 : refuse30("fastspring_body_unsupported");
|
|
4775
4799
|
if (parsed.paymentType !== "card") {
|
|
@@ -4777,7 +4801,7 @@ function fastspringBodyVerdict(body) {
|
|
|
4777
4801
|
return refuse30("fastspring_body_unsupported");
|
|
4778
4802
|
return typeof parsed.paymentType === "string" && parsed.paymentType !== "" ? CONTINUE11 : refuse30("fastspring_body_unsupported");
|
|
4779
4803
|
}
|
|
4780
|
-
if (!
|
|
4804
|
+
if (!exact6)
|
|
4781
4805
|
return refuse30("fastspring_body_unsupported");
|
|
4782
4806
|
const code = judgeCard2(parsed);
|
|
4783
4807
|
return code === null ? CARD29 : refuse30(code);
|
|
@@ -5003,20 +5027,20 @@ function readBody18(body) {
|
|
|
5003
5027
|
function amountValue(value) {
|
|
5004
5028
|
if (typeof value === "number" && !Number.isFinite(value))
|
|
5005
5029
|
return false;
|
|
5006
|
-
const
|
|
5007
|
-
if (typeof
|
|
5030
|
+
const text11 = typeof value === "number" ? String(value) : value;
|
|
5031
|
+
if (typeof text11 !== "string" || !AMOUNT_TEXT.test(text11))
|
|
5008
5032
|
return false;
|
|
5009
|
-
const amount2 = Number(
|
|
5033
|
+
const amount2 = Number(text11);
|
|
5010
5034
|
return amount2 > 0 && amount2 <= AMOUNT_LIMIT3;
|
|
5011
5035
|
}
|
|
5012
5036
|
function billingDetails(value) {
|
|
5013
5037
|
if (!record27(value) || !inOrder5(value, BILLING_KEYS))
|
|
5014
5038
|
return false;
|
|
5015
5039
|
return Object.keys(value).every((key) => {
|
|
5016
|
-
const
|
|
5040
|
+
const field5 = value[key];
|
|
5017
5041
|
if (key !== "address")
|
|
5018
|
-
return key === "mobile_number" || key === "phone_number" ? typeof
|
|
5019
|
-
return record27(
|
|
5042
|
+
return key === "mobile_number" || key === "phone_number" ? typeof field5 === "string" && PHONE4.test(field5) : plainText6(field5);
|
|
5043
|
+
return record27(field5) && inOrder5(field5, ADDRESS_KEYS5) && Object.keys(field5).every((name) => plainText6(field5[name]));
|
|
5020
5044
|
});
|
|
5021
5045
|
}
|
|
5022
5046
|
function cardData(value) {
|
|
@@ -5046,8 +5070,8 @@ function xenditBodyVerdict(body) {
|
|
|
5046
5070
|
if (own9(value, "fp_session_id") && (typeof value.fp_session_id !== "string" || !FP_SESSION.test(value.fp_session_id)))
|
|
5047
5071
|
return refuse32("xendit_body_unsupported");
|
|
5048
5072
|
if (own9(value, "metadata")) {
|
|
5049
|
-
const
|
|
5050
|
-
if (!record27(
|
|
5073
|
+
const metadata2 = value.metadata;
|
|
5074
|
+
if (!record27(metadata2) || Object.keys(metadata2).length !== 1 || !record27(metadata2._forter) || Object.keys(metadata2._forter).length !== 1 || typeof metadata2._forter.token !== "string" || !FORTER_TOKEN.test(metadata2._forter.token))
|
|
5051
5075
|
return refuse32("xendit_body_unsupported");
|
|
5052
5076
|
}
|
|
5053
5077
|
if (own9(value, "mid_label") && (typeof value.mid_label !== "string" || !MID_LABEL.test(value.mid_label)))
|
|
@@ -5204,10 +5228,10 @@ function isPaymobPayUrl(url) {
|
|
|
5204
5228
|
var BASE645 = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
5205
5229
|
var BASE64URL = /^[A-Za-z0-9_-]+$/;
|
|
5206
5230
|
var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
5207
|
-
function decodeBase642(
|
|
5208
|
-
if (typeof
|
|
5231
|
+
function decodeBase642(text11, url) {
|
|
5232
|
+
if (typeof text11 !== "string" || text11 === "")
|
|
5209
5233
|
return null;
|
|
5210
|
-
let body =
|
|
5234
|
+
let body = text11;
|
|
5211
5235
|
if (url) {
|
|
5212
5236
|
if (!BASE64URL.test(body) || body.length % 4 === 1)
|
|
5213
5237
|
return null;
|
|
@@ -5240,15 +5264,15 @@ function decodeBase642(text10, url) {
|
|
|
5240
5264
|
function jsonOf(bytes) {
|
|
5241
5265
|
if (!bytes)
|
|
5242
5266
|
return null;
|
|
5243
|
-
let
|
|
5267
|
+
let text11;
|
|
5244
5268
|
try {
|
|
5245
|
-
|
|
5269
|
+
text11 = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
5246
5270
|
}
|
|
5247
5271
|
catch {
|
|
5248
5272
|
return null;
|
|
5249
5273
|
}
|
|
5250
5274
|
try {
|
|
5251
|
-
const value = JSON.parse(
|
|
5275
|
+
const value = JSON.parse(text11);
|
|
5252
5276
|
return record29(value) ? value : null;
|
|
5253
5277
|
}
|
|
5254
5278
|
catch {
|
|
@@ -5325,14 +5349,14 @@ function readJson8(body) {
|
|
|
5325
5349
|
catch {
|
|
5326
5350
|
return { parsed: null, exact: false };
|
|
5327
5351
|
}
|
|
5328
|
-
let
|
|
5352
|
+
let exact6 = false;
|
|
5329
5353
|
try {
|
|
5330
|
-
|
|
5354
|
+
exact6 = body.length <= BODY_LIMIT32 && JSON.stringify(parsed) === body;
|
|
5331
5355
|
}
|
|
5332
5356
|
catch {
|
|
5333
|
-
|
|
5357
|
+
exact6 = false;
|
|
5334
5358
|
}
|
|
5335
|
-
return { parsed, exact:
|
|
5359
|
+
return { parsed, exact: exact6 };
|
|
5336
5360
|
}
|
|
5337
5361
|
function namesCardValue3(parsed) {
|
|
5338
5362
|
const pending = parsed !== null && typeof parsed === "object" ? [parsed] : [];
|
|
@@ -5349,7 +5373,7 @@ function namesCardValue3(parsed) {
|
|
|
5349
5373
|
return false;
|
|
5350
5374
|
}
|
|
5351
5375
|
function addressBlock(value) {
|
|
5352
|
-
return record29(value) && Object.keys(value).length <= 32 && Object.entries(value).every(([key,
|
|
5376
|
+
return record29(value) && Object.keys(value).length <= 32 && Object.entries(value).every(([key, text11]) => FIELD.test(key) && !CARD_MEMBER4.test(key) && (text11 === null || typeof text11 === "string" && TEXT3.test(text11)));
|
|
5353
5377
|
}
|
|
5354
5378
|
function judgeCardPayment(parsed) {
|
|
5355
5379
|
const source = parsed.source;
|
|
@@ -5393,8 +5417,8 @@ function judgeCardPayment(parsed) {
|
|
|
5393
5417
|
function paymobBodyVerdict(body) {
|
|
5394
5418
|
if (body === void 0 || body === null || body === "")
|
|
5395
5419
|
return CONTINUE12;
|
|
5396
|
-
const { parsed, exact:
|
|
5397
|
-
if (!
|
|
5420
|
+
const { parsed, exact: exact6 } = readJson8(body);
|
|
5421
|
+
if (!exact6 || !record29(parsed) || !record29(parsed.source) || typeof parsed.source.subtype !== "string")
|
|
5398
5422
|
return refuse34("paymob_body_unsupported");
|
|
5399
5423
|
const subtype = parsed.source.subtype;
|
|
5400
5424
|
if (subtype === "CARD") {
|
|
@@ -5847,8 +5871,8 @@ function cardNamed2(key) {
|
|
|
5847
5871
|
const phrase = words.join(" ");
|
|
5848
5872
|
return words.some((word) => CARD_WORDS.includes(word)) || ["security code", "codigo seguridad", "codigo verificacion"].some((said) => phrase.includes(said));
|
|
5849
5873
|
}
|
|
5850
|
-
function carriesCardNumber(
|
|
5851
|
-
for (const [run] of
|
|
5874
|
+
function carriesCardNumber(text11) {
|
|
5875
|
+
for (const [run] of text11.matchAll(/[0-9]+(?:[ ._/,-][0-9]+)*/g)) {
|
|
5852
5876
|
const groups = run.split(/[ ._/,-]/);
|
|
5853
5877
|
for (let first = 0; first < groups.length; first += 1) {
|
|
5854
5878
|
let digits4 = "";
|
|
@@ -5861,17 +5885,17 @@ function carriesCardNumber(text10) {
|
|
|
5861
5885
|
}
|
|
5862
5886
|
return false;
|
|
5863
5887
|
}
|
|
5864
|
-
var wholeCardNumber = (
|
|
5888
|
+
var wholeCardNumber = (text11) => /^[2-6][0-9]{12,18}$/.test(text11) && luhn7(text11);
|
|
5865
5889
|
function membersRefusal(root) {
|
|
5866
5890
|
const pending = [[root, ""]];
|
|
5867
5891
|
while (pending.length > 0) {
|
|
5868
5892
|
const [node, path] = pending.pop();
|
|
5869
|
-
const
|
|
5893
|
+
const own23 = path === "" ? TRANSACTION_MEMBERS : owns7(RECORD_MEMBERS, path) ? RECORD_MEMBERS[path] : null;
|
|
5870
5894
|
for (const [key, child] of Object.entries(node)) {
|
|
5871
5895
|
const at = Array.isArray(node) ? path : path === "" ? key : `${path}.${key}`;
|
|
5872
5896
|
if (at === "checkoutCreditCard")
|
|
5873
5897
|
continue;
|
|
5874
|
-
if (
|
|
5898
|
+
if (own23 !== null && !own23.includes(key))
|
|
5875
5899
|
return true;
|
|
5876
5900
|
if (TEXT_RECORDS.includes(path) && child !== null && typeof child !== "string")
|
|
5877
5901
|
return true;
|
|
@@ -6092,7 +6116,17 @@ var TOKEN_FACTS = /* @__PURE__ */ Object.freeze([
|
|
|
6092
6116
|
"primary"
|
|
6093
6117
|
]);
|
|
6094
6118
|
// src/registration.js
|
|
6095
|
-
var PARTS = {
|
|
6119
|
+
var PARTS = {
|
|
6120
|
+
psp: "id",
|
|
6121
|
+
definitions: "list",
|
|
6122
|
+
refusedOperations: "list",
|
|
6123
|
+
settlementReadback: "any",
|
|
6124
|
+
exactUrl: "rule",
|
|
6125
|
+
bodyGate: "rule",
|
|
6126
|
+
amount: "rule",
|
|
6127
|
+
hostedEntry: "rule",
|
|
6128
|
+
limitations: "sentences"
|
|
6129
|
+
};
|
|
6096
6130
|
var PSP_ID = /^[a-z][a-z0-9_]*$/;
|
|
6097
6131
|
var registrationProblems = (spec) => problemsOf(spec, PARTS);
|
|
6098
6132
|
function problemsOf(spec, parts) {
|
|
@@ -6108,9 +6142,14 @@ function problemsOf(spec, parts) {
|
|
|
6108
6142
|
continue;
|
|
6109
6143
|
if (kind === "rule" && typeof value !== "function")
|
|
6110
6144
|
problems2.push(`${psp}: ${key} is not a function`);
|
|
6145
|
+
if (kind === "flag" && value !== true)
|
|
6146
|
+
problems2.push(`${psp}: ${key} is not true`);
|
|
6111
6147
|
if (kind === "numbers" && !((Array.isArray(value) || value instanceof Set) && [...value].every((n) => typeof n === "string" && /^\d{12,19}$/.test(n)))) {
|
|
6112
6148
|
problems2.push(`${psp}: ${key} is not a list of card numbers`);
|
|
6113
6149
|
}
|
|
6150
|
+
if (kind === "sentences" && !(Array.isArray(value) && value.length > 0 && value.every((s) => typeof s === "string" && s.trim() !== ""))) {
|
|
6151
|
+
problems2.push(`${psp}: ${key} is not a list of sentences`);
|
|
6152
|
+
}
|
|
6114
6153
|
}
|
|
6115
6154
|
if ("definitions" in parts) {
|
|
6116
6155
|
if (!Array.isArray(spec.definitions) || spec.definitions.length === 0)
|
|
@@ -6121,6 +6160,10 @@ function problemsOf(spec, parts) {
|
|
|
6121
6160
|
if (typeof id !== "string" || !id.startsWith(`${psp}.`))
|
|
6122
6161
|
problems2.push(`${psp}: ${JSON.stringify(id)} is not one of its operations`);
|
|
6123
6162
|
}
|
|
6163
|
+
const pages = Array.isArray(spec.definitions) ? spec.definitions.filter((d) => d?.hostedForm?.cardIn === "processor_page") : [];
|
|
6164
|
+
if (spec.hostedEntry !== void 0 && (pages.length === 0 || pages.some((d) => d.hostedForm.policy !== void 0))) {
|
|
6165
|
+
problems2.push(`${psp}: hostedEntry needs a definition whose hosted form takes the card on the processor's page and names no policy`);
|
|
6166
|
+
}
|
|
6124
6167
|
}
|
|
6125
6168
|
return problems2;
|
|
6126
6169
|
}
|
|
@@ -6133,178 +6176,2754 @@ function registered(spec, parts) {
|
|
|
6133
6176
|
function registerProcessor(spec) {
|
|
6134
6177
|
return registered(spec, PARTS);
|
|
6135
6178
|
}
|
|
6136
|
-
// src/processors/
|
|
6137
|
-
var
|
|
6138
|
-
var
|
|
6139
|
-
var
|
|
6140
|
-
var
|
|
6141
|
-
var
|
|
6142
|
-
var
|
|
6143
|
-
var
|
|
6144
|
-
var
|
|
6145
|
-
var
|
|
6146
|
-
var
|
|
6147
|
-
var
|
|
6148
|
-
var
|
|
6149
|
-
var own12 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
6150
|
-
var inOrder6 = (value, keys) => {
|
|
6151
|
-
let at = 0;
|
|
6152
|
-
for (const name of Object.keys(value)) {
|
|
6153
|
-
while (at < keys.length && keys[at] !== name)
|
|
6154
|
-
at += 1;
|
|
6155
|
-
if (at === keys.length)
|
|
6156
|
-
return false;
|
|
6157
|
-
at += 1;
|
|
6158
|
-
}
|
|
6159
|
-
return true;
|
|
6160
|
-
};
|
|
6179
|
+
// src/processors/aurus.js
|
|
6180
|
+
var AURUS_PSP = "aurus";
|
|
6181
|
+
var AURUS_OPERATION = "aurus.card_request";
|
|
6182
|
+
var AURUS_FRAME_HOST = /^pecst[0-9]{2}\.aurusepay\.com$/;
|
|
6183
|
+
var AURUS_TOKEN_PATH = "/storeservices/ecom/oneTimeToken";
|
|
6184
|
+
var AURUS_PARTS = /* @__PURE__ */ Object.freeze(["Param", "formFactorId", "txnDateTime", "encryptionFlag", "sha256Flag", "hmacAuthData", "payload"]);
|
|
6185
|
+
var URL_LIMIT14 = 256;
|
|
6186
|
+
var BODY_LIMIT35 = 32768;
|
|
6187
|
+
var SERVER = /^es[0-9]{2}\.auruspay\.com$/;
|
|
6188
|
+
var HEX = /^[0-9A-Fa-f]{2,8192}$/;
|
|
6189
|
+
var FORM_FACTOR = /^[0-9]{1,16}$/;
|
|
6190
|
+
var DATE_TIME = /^[0-9]{14}$/;
|
|
6191
|
+
var FRAMED = /^STX[0-9]{1,6}\[FS\][0-9A-Fa-f]{2,16384}\[FS\]7[Bb][0-9A-Fa-f]{0,24576}7[Dd]ETX$/;
|
|
6161
6192
|
var refuse37 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
6162
6193
|
var CARD36 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
6163
|
-
function
|
|
6164
|
-
|
|
6194
|
+
function aurusTokenUrl(url) {
|
|
6195
|
+
if (typeof url !== "string" || url.length > URL_LIMIT14 || url.includes("#"))
|
|
6196
|
+
return null;
|
|
6197
|
+
let parsed;
|
|
6198
|
+
try {
|
|
6199
|
+
parsed = new URL(url);
|
|
6200
|
+
}
|
|
6201
|
+
catch {
|
|
6202
|
+
return null;
|
|
6203
|
+
}
|
|
6204
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !AURUS_FRAME_HOST.test(parsed.hostname) || parsed.pathname !== AURUS_TOKEN_PATH)
|
|
6205
|
+
return null;
|
|
6206
|
+
const query = parsed.search.startsWith("?") ? parsed.search.slice(1).split("&") : [];
|
|
6207
|
+
if (query.length !== 2)
|
|
6208
|
+
return null;
|
|
6209
|
+
const [d1, d2] = query.map((pair) => pair.split("="));
|
|
6210
|
+
if (d1.length !== 2 || d2.length !== 2 || d1[0] !== "d1" || d2[0] !== "d2" || !SERVER.test(d1[1]) || !SERVER.test(d2[1]))
|
|
6211
|
+
return null;
|
|
6212
|
+
return Object.freeze({ host: parsed.hostname });
|
|
6165
6213
|
}
|
|
6214
|
+
var isAurusTokenUrl = (url) => aurusTokenUrl(url) !== null;
|
|
6166
6215
|
function readBody21(body) {
|
|
6167
6216
|
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT35)
|
|
6168
6217
|
return null;
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6218
|
+
const pairs = body.split("&");
|
|
6219
|
+
if (pairs.length !== AURUS_PARTS.length)
|
|
6220
|
+
return null;
|
|
6221
|
+
const value = {};
|
|
6222
|
+
for (const [at, pair] of pairs.entries()) {
|
|
6223
|
+
const cut = pair.indexOf("=");
|
|
6224
|
+
if (cut < 0 || pair.slice(0, cut) !== AURUS_PARTS[at])
|
|
6173
6225
|
return null;
|
|
6226
|
+
value[AURUS_PARTS[at]] = pair.slice(cut + 1);
|
|
6174
6227
|
}
|
|
6175
|
-
|
|
6228
|
+
if (!HEX.test(value.Param) || !FORM_FACTOR.test(value.formFactorId) || !DATE_TIME.test(value.txnDateTime) || value.encryptionFlag !== "00" || value.sha256Flag !== "1" || !FRAMED.test(value.hmacAuthData) || !FRAMED.test(value.payload))
|
|
6176
6229
|
return null;
|
|
6177
|
-
}
|
|
6178
6230
|
return value;
|
|
6179
6231
|
}
|
|
6180
|
-
function
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6232
|
+
function aurusBodyVerdict(body) {
|
|
6233
|
+
return readBody21(body) === null ? refuse37("aurus_body_unsupported") : CARD36;
|
|
6234
|
+
}
|
|
6235
|
+
var aurus_default = /* @__PURE__ */ registerProcessor({
|
|
6236
|
+
psp: AURUS_PSP,
|
|
6237
|
+
definitions: [
|
|
6238
|
+
{
|
|
6239
|
+
psp: "aurus",
|
|
6240
|
+
// The frame's card request, as the header above reads it. No sandbox host is known: Aurus's test instances were
|
|
6241
|
+
// not read, so none is listed and no environment is pinned.
|
|
6242
|
+
// Ships dark: served only to a client that declares `aurus_one_time_token`, and only for a company the backend's
|
|
6243
|
+
// processor gate turns Aurus on for. `(?![\w/.%-])` ends the path for a consumer that tests `match` unanchored.
|
|
6244
|
+
capability: "aurus_one_time_token",
|
|
6245
|
+
match: "pecst[0-9]{2}\\.aurusepay\\.com/storeservices/ecom/oneTimeToken(?![\\w/.%-])",
|
|
6246
|
+
hosts: ["^pecst[0-9]{2}\\.aurusepay\\.com$"],
|
|
6247
|
+
encoding: "form",
|
|
6248
|
+
// The frame's XHR marker. Origin, Referer and cookies never ride.
|
|
6249
|
+
passthroughHeaders: ["^x-requested-with$"]
|
|
6250
|
+
}
|
|
6251
|
+
],
|
|
6252
|
+
// Only the cardholder's device would send this card, after a person approves; no reviewed list names aurus.
|
|
6253
|
+
refusedOperations: [AURUS_OPERATION],
|
|
6254
|
+
// The frame mints a one-time token and reads nothing: the store's server charges it with its own credentials.
|
|
6255
|
+
settlementReadback: {
|
|
6256
|
+
answer: "none",
|
|
6257
|
+
reason: "tokenization_credential_cannot_read_charges",
|
|
6258
|
+
note: "The tokenization credential cannot read a charge; the shop charges the token later with its own credentials.",
|
|
6259
|
+
source: "https://www.oreillyauto.com/checkout (Aurus's ecom iframe, read 2026-10-31)"
|
|
6260
|
+
},
|
|
6261
|
+
exactUrl: isAurusTokenUrl,
|
|
6262
|
+
bodyGate: (url, body) => url !== void 0 && !isAurusTokenUrl(url) ? refuse37("aurus_url_refused") : aurusBodyVerdict(body),
|
|
6263
|
+
limitations: ["The card frame seals the card in the page under a public key its own script carries; the cardholder's device does not seal for Aurus yet, so a held request opens no approval that pays."]
|
|
6264
|
+
});
|
|
6265
|
+
// src/processors/bluesnap.js
|
|
6266
|
+
var BLUESNAP_PSP = "bluesnap";
|
|
6267
|
+
var BLUESNAP_OPERATION = "bluesnap.card_request";
|
|
6268
|
+
var BLUESNAP_HOSTS = /* @__PURE__ */ Object.freeze({ 1: "ws1.bluesnap.com", 2: "ws2.bluesnap.com", _: "sandpay.bluesnap.com" });
|
|
6269
|
+
var BLUESNAP_SANDBOX_HOST = "sandpay.bluesnap.com";
|
|
6270
|
+
var BLUESNAP_CARD_KEYS = /* @__PURE__ */ Object.freeze(["cvv", "ccNumber", "expDate"]);
|
|
6271
|
+
var BLUESNAP_LEG_KEYS = /* @__PURE__ */ Object.freeze(["cvv", "expDate"]);
|
|
6272
|
+
var BODY_LIMIT36 = 1024;
|
|
6273
|
+
var TOKEN_URL2 = /^https:\/\/(ws1|ws2|sandpay)\.bluesnap\.com\/services\/2\/payment-fields-tokens\/([0-9a-f]{64}_[12]?)$/;
|
|
6274
|
+
var CARD_NUMBER18 = /^[0-9]{12,19}$/;
|
|
6275
|
+
var SECURITY_CODE22 = /^[0-9]{3,4}$/;
|
|
6276
|
+
var EXPIRY3 = /^(?:0[1-9]|1[0-2])\/20[0-9]{2}$/;
|
|
6277
|
+
var SAVED_CARD_KEYS2 = ["last4Digits", "lastFourDigits", "ccType"];
|
|
6278
|
+
var record32 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6279
|
+
var own12 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
6280
|
+
var refuse38 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
6281
|
+
var CARD37 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
6282
|
+
var LEG = /* @__PURE__ */ Object.freeze({ verdict: "continue" });
|
|
6283
|
+
function bluesnapTokenUrl(url) {
|
|
6284
|
+
const match = typeof url === "string" ? TOKEN_URL2.exec(url) : null;
|
|
6285
|
+
if (!match || BLUESNAP_HOSTS[match[2].slice(-1)] !== `${match[1]}.bluesnap.com`)
|
|
6286
|
+
return null;
|
|
6287
|
+
const host = `${match[1]}.bluesnap.com`;
|
|
6288
|
+
return Object.freeze({ host, token: match[2], environment: host === BLUESNAP_SANDBOX_HOST ? "sandbox" : "production" });
|
|
6289
|
+
}
|
|
6290
|
+
function isBluesnapTokenUrl(url) {
|
|
6291
|
+
return bluesnapTokenUrl(url) !== null;
|
|
6292
|
+
}
|
|
6293
|
+
function readBody22(body) {
|
|
6294
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT36)
|
|
6295
|
+
return null;
|
|
6296
|
+
try {
|
|
6297
|
+
const value = JSON.parse(body);
|
|
6298
|
+
return record32(value) && JSON.stringify(value) === body ? value : null;
|
|
6186
6299
|
}
|
|
6187
|
-
|
|
6188
|
-
return
|
|
6300
|
+
catch {
|
|
6301
|
+
return null;
|
|
6189
6302
|
}
|
|
6190
|
-
if (typeof value.card_cvv !== "string" || !SECURITY_CODE22.test(value.card_cvv) || typeof value.card_number !== "string" || !CARD_NUMBER18.test(value.card_number) || typeof value.card_exp_month !== "string" || !MONTH19.test(value.card_exp_month) || typeof value.card_exp_year !== "string" || !YEAR20.test(value.card_exp_year))
|
|
6191
|
-
return refuse37("midtrans_body_unsupported");
|
|
6192
|
-
if (own12(value, "installment_term") && (typeof value.installment_term !== "string" || !TERM.test(value.installment_term)))
|
|
6193
|
-
return refuse37("midtrans_body_unsupported");
|
|
6194
|
-
return CARD36;
|
|
6195
6303
|
}
|
|
6196
|
-
|
|
6197
|
-
|
|
6304
|
+
function bluesnapBodyVerdict(body) {
|
|
6305
|
+
const value = readBody22(body);
|
|
6306
|
+
if (value === null)
|
|
6307
|
+
return refuse38("bluesnap_body_unsupported");
|
|
6308
|
+
const keys = Object.keys(value);
|
|
6309
|
+
if (keys.some((key) => SAVED_CARD_KEYS2.includes(key)))
|
|
6310
|
+
return refuse38(own12(value, "ccNumber") ? "bluesnap_body_unsupported" : "bluesnap_saved_card");
|
|
6311
|
+
if (keys.length === 0 || keys.some((key, i) => !BLUESNAP_CARD_KEYS.includes(key) || i > 0 && BLUESNAP_CARD_KEYS.indexOf(keys[i - 1]) >= BLUESNAP_CARD_KEYS.indexOf(key))) {
|
|
6312
|
+
return refuse38("bluesnap_body_unsupported");
|
|
6313
|
+
}
|
|
6314
|
+
if (own12(value, "ccNumber") && !(typeof value.ccNumber === "string" && CARD_NUMBER18.test(value.ccNumber)) || own12(value, "cvv") && !(typeof value.cvv === "string" && SECURITY_CODE22.test(value.cvv)) || own12(value, "expDate") && !(typeof value.expDate === "string" && EXPIRY3.test(value.expDate)))
|
|
6315
|
+
return refuse38("bluesnap_body_unsupported");
|
|
6316
|
+
return own12(value, "ccNumber") ? CARD37 : LEG;
|
|
6317
|
+
}
|
|
6318
|
+
var bluesnap_default = /* @__PURE__ */ registerProcessor({
|
|
6319
|
+
psp: BLUESNAP_PSP,
|
|
6198
6320
|
definitions: [
|
|
6199
6321
|
{
|
|
6200
|
-
psp: "
|
|
6201
|
-
//
|
|
6202
|
-
// test-mode request only
|
|
6203
|
-
//
|
|
6204
|
-
//
|
|
6205
|
-
//
|
|
6206
|
-
capability: "
|
|
6207
|
-
match: "
|
|
6208
|
-
hosts: ["^
|
|
6209
|
-
sandboxHosts: ["^
|
|
6322
|
+
psp: "bluesnap",
|
|
6323
|
+
// The card fields' PUTs, as the header above reads them. The sandbox has its own server, so the device sends a
|
|
6324
|
+
// test-mode request only documented test cards (hostEnvironmentPinned, device-replay.js S7). `(?![\w/.%-])`
|
|
6325
|
+
// ends the token for a consumer that tests `match` unanchored; the exact-URL rule pins each server to its suffix.
|
|
6326
|
+
// Ships dark: served only to a client that declares `bluesnap_hosted_payment_fields`, and the backend's gate turns
|
|
6327
|
+
// it on for Agentcard's own company alone, in code.
|
|
6328
|
+
capability: "bluesnap_hosted_payment_fields",
|
|
6329
|
+
match: "(?:ws1|ws2|sandpay)\\.bluesnap\\.com/services/2/payment-fields-tokens/[0-9a-f]{64}_[12]?(?![\\w/.%-])",
|
|
6330
|
+
hosts: ["^ws1\\.bluesnap\\.com$", "^ws2\\.bluesnap\\.com$", "^sandpay\\.bluesnap\\.com$"],
|
|
6331
|
+
sandboxHosts: ["^sandpay\\.bluesnap\\.com$"],
|
|
6210
6332
|
hostEnvironmentPinned: true,
|
|
6211
6333
|
encoding: "json",
|
|
6212
|
-
//
|
|
6213
|
-
//
|
|
6214
|
-
passthroughHeaders: ["^authorization$", "^
|
|
6215
|
-
jsonCardFields: [["
|
|
6334
|
+
// The frames' own headers, each held to its shape by bluesnapRequestRefusal. Origin, Referer and cookies never
|
|
6335
|
+
// ride (the frames send no cookie).
|
|
6336
|
+
passthroughHeaders: ["^authorization$", "^bluesnap_version_header$", "^bluesnap_origin_version_header$", "^bluesnap_origin_header$"],
|
|
6337
|
+
jsonCardFields: [["ccNumber"]],
|
|
6338
|
+
// The expiry and code frames' PUTs: held by the checkout SDK and answered with the card request's answer.
|
|
6339
|
+
splitCard: { absorb: [...BLUESNAP_LEG_KEYS], pass: [], siblingKeys: [] },
|
|
6340
|
+
request: { method: "PUT", cardIn: "body", response: "json" }
|
|
6216
6341
|
}
|
|
6217
6342
|
],
|
|
6218
|
-
// Only the cardholder's device sends
|
|
6219
|
-
refusedOperations: [
|
|
6220
|
-
// Not surveyed: the
|
|
6343
|
+
// Only the cardholder's device sends the card, after a person approves; no reviewed list names bluesnap.
|
|
6344
|
+
refusedOperations: [BLUESNAP_OPERATION],
|
|
6345
|
+
// Not surveyed: the PUT moves no money, and the merchant's own charge is a server call Agentcard never sees.
|
|
6221
6346
|
settlementReadback: "not_surveyed",
|
|
6222
|
-
exactUrl:
|
|
6223
|
-
bodyGate: (url, body) => url !== void 0 && !
|
|
6347
|
+
exactUrl: isBluesnapTokenUrl,
|
|
6348
|
+
bodyGate: (url, body) => url !== void 0 && !isBluesnapTokenUrl(url) ? { verdict: "refuse", code: "bluesnap_url_refused" } : bluesnapBodyVerdict(body)
|
|
6224
6349
|
});
|
|
6225
|
-
// src/processors/
|
|
6226
|
-
var
|
|
6227
|
-
|
|
6350
|
+
// src/processors/ekashu.js
|
|
6351
|
+
var EKASHU_HOSTS = Object.freeze(["live.ekashu.com", "test.ekashu.com"]);
|
|
6352
|
+
var EKASHU_TEST_PANS = Object.freeze(["4100000000000100", "5100000000000107"]);
|
|
6353
|
+
var EKASHU_SIGNED_FIELDS = Object.freeze([
|
|
6354
|
+
"ekashu_3d_secure_verify",
|
|
6355
|
+
"ekashu_amount",
|
|
6356
|
+
"ekashu_amount_format",
|
|
6357
|
+
"ekashu_auto_confirm",
|
|
6358
|
+
"ekashu_callback_failure_url",
|
|
6359
|
+
"ekashu_callback_include_post",
|
|
6360
|
+
"ekashu_callback_success_url",
|
|
6361
|
+
"ekashu_card_address_editable",
|
|
6362
|
+
"ekashu_card_address_required",
|
|
6363
|
+
"ekashu_card_address_verify",
|
|
6364
|
+
"ekashu_card_email_address_mandatory",
|
|
6365
|
+
"ekashu_card_phone_number_mandatory",
|
|
6366
|
+
"ekashu_card_title_mandatory",
|
|
6367
|
+
"ekashu_card_zip_code_verify",
|
|
6368
|
+
"ekashu_currency",
|
|
6369
|
+
"ekashu_delivery_address_editable",
|
|
6370
|
+
"ekashu_delivery_address_required",
|
|
6371
|
+
"ekashu_delivery_email_address_mandatory",
|
|
6372
|
+
"ekashu_delivery_phone_number_mandatory",
|
|
6373
|
+
"ekashu_delivery_title_mandatory",
|
|
6374
|
+
"ekashu_description",
|
|
6375
|
+
"ekashu_device",
|
|
6376
|
+
"ekashu_duplicate_check",
|
|
6377
|
+
"ekashu_duplicate_minutes",
|
|
6378
|
+
"ekashu_failure_return_text",
|
|
6379
|
+
"ekashu_failure_url",
|
|
6380
|
+
"ekashu_hash_code_format",
|
|
6381
|
+
"ekashu_hash_code_type",
|
|
6382
|
+
"ekashu_hash_code_version",
|
|
6383
|
+
"ekashu_include_post",
|
|
6384
|
+
"ekashu_invoice_address_editable",
|
|
6385
|
+
"ekashu_invoice_address_required",
|
|
6386
|
+
"ekashu_invoice_email_address_mandatory",
|
|
6387
|
+
"ekashu_invoice_phone_number_mandatory",
|
|
6388
|
+
"ekashu_invoice_title_mandatory",
|
|
6389
|
+
"ekashu_locale",
|
|
6390
|
+
"ekashu_payment_methods",
|
|
6391
|
+
"ekashu_reference",
|
|
6392
|
+
"ekashu_request_type",
|
|
6393
|
+
"ekashu_return_text",
|
|
6394
|
+
"ekashu_seller_address",
|
|
6395
|
+
"ekashu_seller_email_address",
|
|
6396
|
+
"ekashu_seller_id",
|
|
6397
|
+
"ekashu_seller_key",
|
|
6398
|
+
"ekashu_seller_name",
|
|
6399
|
+
"ekashu_shortcut_icon",
|
|
6400
|
+
"ekashu_style_sheet",
|
|
6401
|
+
"ekashu_success_url",
|
|
6402
|
+
"ekashu_title",
|
|
6403
|
+
"ekashu_verification_value_mask",
|
|
6404
|
+
"ekashu_verification_value_verify",
|
|
6405
|
+
"ekashu_viewport"
|
|
6406
|
+
]);
|
|
6407
|
+
var REQUIRED = Object.freeze([
|
|
6408
|
+
"ekashu_seller_id",
|
|
6409
|
+
"ekashu_seller_key",
|
|
6410
|
+
"ekashu_amount",
|
|
6411
|
+
"ekashu_currency",
|
|
6412
|
+
"ekashu_reference",
|
|
6413
|
+
"ekashu_hash_code",
|
|
6414
|
+
"ekashu_hash_code_type",
|
|
6415
|
+
"ekashu_hash_code_version",
|
|
6416
|
+
"ekashu_success_url",
|
|
6417
|
+
"ekashu_failure_url",
|
|
6418
|
+
"ekashu_callback_success_url"
|
|
6419
|
+
]);
|
|
6420
|
+
var CARD_KEYS16 = Object.freeze([
|
|
6421
|
+
"ekashu_card_number",
|
|
6422
|
+
"ekashu_expires_end_month",
|
|
6423
|
+
"ekashu_expires_end_year",
|
|
6424
|
+
"ekashu_verification_value",
|
|
6425
|
+
"ekashu_valid_from_month",
|
|
6426
|
+
"ekashu_valid_from_year",
|
|
6427
|
+
"ekashu_issue_number"
|
|
6428
|
+
]);
|
|
6429
|
+
var PAGE_KEYS = Object.freeze(["ekashu_stage", "ekashu_context", "ekashu_submission_id"]);
|
|
6430
|
+
var STORED_KEYS = Object.freeze(["ekashu_card_hash", "ekashu_card_reference", "ekashu_cof_initiated_by", "ekashu_cof_reason", "ekashu_cof_id"]);
|
|
6431
|
+
var REDIRECT_KEYS = Object.freeze(["ekashu_success_url", "ekashu_failure_url", "ekashu_return_url"]);
|
|
6432
|
+
var CALLBACK_KEYS = Object.freeze(["ekashu_callback_success_url", "ekashu_callback_failure_url"]);
|
|
6433
|
+
var MAX_ENTRY = 16 * 1024;
|
|
6434
|
+
var MAX_PAGE = 256 * 1024;
|
|
6435
|
+
var EKASHU_SELLERS = Object.freeze([
|
|
6436
|
+
Object.freeze({ sellerId: "25060100", merchant: "Heathrow Drop-off", entryHost: "heathrowdropoff.apcoa.com", callbackHost: "incomingapi.apcoa.co.uk" })
|
|
6437
|
+
]);
|
|
6438
|
+
var CARD_FIELDS = Object.freeze({
|
|
6439
|
+
number: "ekashu_card_number",
|
|
6440
|
+
month: "ekashu_expires_end_month",
|
|
6441
|
+
year: "ekashu_expires_end_year",
|
|
6442
|
+
cvc: "ekashu_verification_value"
|
|
6228
6443
|
});
|
|
6229
|
-
|
|
6230
|
-
var
|
|
6231
|
-
var
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6444
|
+
var NAME_FIELDS = Object.freeze({ first: "ekashu_card_first_name", last: "ekashu_card_last_name" });
|
|
6445
|
+
var LEFT_EMPTY = Object.freeze(["ekashu_card_title", "ekashu_valid_from_month", "ekashu_valid_from_year", "ekashu_issue_number"]);
|
|
6446
|
+
var VISIBLE = /* @__PURE__ */ new Set([...Object.values(CARD_FIELDS), ...Object.values(NAME_FIELDS), ...LEFT_EMPTY]);
|
|
6447
|
+
// src/processors/redsys.js
|
|
6448
|
+
var REDSYS_HOSTS = Object.freeze(["sis.redsys.es"]);
|
|
6449
|
+
var REDSYS_ENTRY_PATHS = Object.freeze(["/sis/realizarPago", "/sis/realizarPago/utf-8"]);
|
|
6450
|
+
var REDSYS_MERCHANTS = Object.freeze([]);
|
|
6451
|
+
var MAX_ENTRY2 = 16 * 1024;
|
|
6452
|
+
var MAX_PARAMETERS = 8 * 1024;
|
|
6453
|
+
var FORM_KEY = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
6454
|
+
var ENTRY_KEYS = Object.freeze(["Ds_SignatureVersion", "Ds_MerchantParameters", "Ds_Signature"]);
|
|
6455
|
+
var REQUIRED2 = Object.freeze([
|
|
6456
|
+
"DS_MERCHANT_AMOUNT",
|
|
6457
|
+
"DS_MERCHANT_CURRENCY",
|
|
6458
|
+
"DS_MERCHANT_MERCHANTCODE",
|
|
6459
|
+
"DS_MERCHANT_ORDER",
|
|
6460
|
+
"DS_MERCHANT_TERMINAL",
|
|
6461
|
+
"DS_MERCHANT_TRANSACTIONTYPE",
|
|
6462
|
+
"DS_MERCHANT_MERCHANTURL",
|
|
6463
|
+
"DS_MERCHANT_URLOK",
|
|
6464
|
+
"DS_MERCHANT_URLKO"
|
|
6465
|
+
]);
|
|
6466
|
+
var STORED = Object.freeze([
|
|
6467
|
+
"DS_MERCHANT_IDENTIFIER",
|
|
6468
|
+
"DS_MERCHANT_GROUP",
|
|
6469
|
+
"DS_MERCHANT_COF_INI",
|
|
6470
|
+
"DS_MERCHANT_COF_TYPE",
|
|
6471
|
+
"DS_MERCHANT_COF_TXNID"
|
|
6472
|
+
]);
|
|
6473
|
+
var SPECIAL = Object.freeze([
|
|
6474
|
+
"DS_MERCHANT_DIRECTPAYMENT",
|
|
6475
|
+
"DS_MERCHANT_SUMTOTAL",
|
|
6476
|
+
"DS_MERCHANT_DATEFRECUENCY",
|
|
6477
|
+
"DS_MERCHANT_CHARGEEXPIRYDATE",
|
|
6478
|
+
"DS_MERCHANT_IDOPER"
|
|
6479
|
+
]);
|
|
6480
|
+
var CARD_PARAMETERS = Object.freeze(["DS_MERCHANT_PAN", "DS_MERCHANT_EXPIRYDATE", "DS_MERCHANT_CVV2"]);
|
|
6481
|
+
var CURRENCIES = Object.freeze({ 978: "eur", 840: "usd", 826: "gbp", 756: "chf" });
|
|
6482
|
+
function decode(text11) {
|
|
6483
|
+
return decodeURIComponent(text11.replace(/\+/g, " "));
|
|
6248
6484
|
}
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6485
|
+
function parseRedsysForm(body) {
|
|
6486
|
+
if (typeof body !== "string" || body.length === 0 || body.length > MAX_ENTRY2 || /[^\x21-\x7e]/.test(body))
|
|
6487
|
+
return null;
|
|
6488
|
+
const pairs = [];
|
|
6489
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6490
|
+
for (const chunk of body.split("&")) {
|
|
6491
|
+
const eq = chunk.indexOf("=");
|
|
6492
|
+
if (eq < 1)
|
|
6493
|
+
return null;
|
|
6494
|
+
let key;
|
|
6495
|
+
let value;
|
|
6496
|
+
try {
|
|
6497
|
+
key = decode(chunk.slice(0, eq));
|
|
6498
|
+
value = decode(chunk.slice(eq + 1));
|
|
6499
|
+
}
|
|
6500
|
+
catch {
|
|
6501
|
+
return null;
|
|
6502
|
+
}
|
|
6503
|
+
if (!FORM_KEY.test(key) || value.length > MAX_PARAMETERS || /[\u0000-\u001f\u007f]/.test(value))
|
|
6504
|
+
return null;
|
|
6505
|
+
const folded = key.toLowerCase();
|
|
6506
|
+
if (seen.has(folded))
|
|
6507
|
+
return null;
|
|
6508
|
+
seen.add(folded);
|
|
6509
|
+
pairs.push({ key, value });
|
|
6257
6510
|
}
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6511
|
+
return pairs;
|
|
6512
|
+
}
|
|
6513
|
+
var MAX_PAGE2 = 256 * 1024;
|
|
6514
|
+
var CARD_FIELDS2 = Object.freeze({
|
|
6515
|
+
shown: "Sis_card-number",
|
|
6516
|
+
expiry: "SIS_card-expiration",
|
|
6517
|
+
cvc: "Sis_Tarjeta_CVV2",
|
|
6518
|
+
holder: "cardholderName",
|
|
6519
|
+
number: "Sis_Numero_Tarjeta",
|
|
6520
|
+
month: "Sis_Caducidad_Tarjeta_Mes",
|
|
6521
|
+
year: "Sis_Caducidad_Tarjeta_Anno"
|
|
6522
|
+
});
|
|
6523
|
+
var BROWSER_FIELDS = Object.freeze([
|
|
6524
|
+
"browserJavaEnabled",
|
|
6525
|
+
"browserJavascriptEnabled",
|
|
6526
|
+
"browserLanguage",
|
|
6527
|
+
"browserColorDepth",
|
|
6528
|
+
"browserScreenHeight",
|
|
6529
|
+
"browserScreenWidth",
|
|
6530
|
+
"browserTZ",
|
|
6531
|
+
"browserUserAgent"
|
|
6532
|
+
]);
|
|
6533
|
+
var AS_SERVED = Object.freeze(["cvvObligatorio", "threeDSCompInd", "fuc", "terminal", "merchantOrder", "bcancel"]);
|
|
6534
|
+
var CARD_PAGE = /* @__PURE__ */ new Set([...Object.values(CARD_FIELDS2), ...BROWSER_FIELDS, ...AS_SERVED]);
|
|
6535
|
+
var VISIBLE2 = /* @__PURE__ */ new Set([CARD_FIELDS2.shown, CARD_FIELDS2.expiry, CARD_FIELDS2.cvc, CARD_FIELDS2.holder]);
|
|
6536
|
+
var METHOD_PAGE = /* @__PURE__ */ new Set(["resultadoMethod", ...BROWSER_FIELDS, "threeDSCompInd"]);
|
|
6537
|
+
var REDSYS_REFUSALS = Object.freeze(["redsys_card_page", "redsys_3ds_challenge", "redsys_declined"]);
|
|
6538
|
+
// src/processors/cardlink_vpos.js
|
|
6539
|
+
var CARDLINK_VPOS_PSP = "cardlink_vpos";
|
|
6540
|
+
var CARDLINK_VPOS_HOSTS = Object.freeze({
|
|
6541
|
+
"vpos.eurocommerce.gr": "worldline",
|
|
6542
|
+
"ecommerce.cardlink.gr": "cardlink",
|
|
6543
|
+
"www.alphaecommerce.gr": "nexi"
|
|
6544
|
+
});
|
|
6545
|
+
var CARDLINK_VPOS_TEST_HOSTS = Object.freeze([
|
|
6546
|
+
"eurocommerce-test.cardlink.gr",
|
|
6547
|
+
"ecommerce-test.cardlink.gr",
|
|
6548
|
+
"alphaecommerce-test.cardlink.gr"
|
|
6549
|
+
]);
|
|
6550
|
+
var CARDLINK_VPOS_ENTRY_PATH = "/vpos/shophandlermpi";
|
|
6551
|
+
var CARDLINK_VPOS_MERCHANTS = Object.freeze([
|
|
6552
|
+
Object.freeze({ merchant: "Holy Great Monastery of Vatopedi", mid: "0021713862", vposHost: "vpos.eurocommerce.gr", host: "www.vatopedi.gr" })
|
|
6553
|
+
]);
|
|
6554
|
+
var CARDLINK_VPOS_ENTRY_FIELDS = Object.freeze([
|
|
6555
|
+
"version",
|
|
6556
|
+
"mid",
|
|
6557
|
+
"lang",
|
|
6558
|
+
"deviceCategory",
|
|
6559
|
+
"orderid",
|
|
6560
|
+
"orderDesc",
|
|
6561
|
+
"orderAmount",
|
|
6562
|
+
"currency",
|
|
6563
|
+
"payerEmail",
|
|
6564
|
+
"payerPhone",
|
|
6565
|
+
"billCountry",
|
|
6566
|
+
"billState",
|
|
6567
|
+
"billZip",
|
|
6568
|
+
"billCity",
|
|
6569
|
+
"billAddress",
|
|
6570
|
+
"weight",
|
|
6571
|
+
"dimensions",
|
|
6572
|
+
"shipCountry",
|
|
6573
|
+
"shipState",
|
|
6574
|
+
"shipZip",
|
|
6575
|
+
"shipCity",
|
|
6576
|
+
"shipAddress",
|
|
6577
|
+
"addFraudScore",
|
|
6578
|
+
"maxPayRetries",
|
|
6579
|
+
"reject3dsU",
|
|
6580
|
+
"payMethod",
|
|
6581
|
+
"trType",
|
|
6582
|
+
"extInstallmentoffset",
|
|
6583
|
+
"extInstallmentperiod",
|
|
6584
|
+
"extRecurringfrequency",
|
|
6585
|
+
"extRecurringenddate",
|
|
6586
|
+
"blockScore",
|
|
6587
|
+
"cssUrl",
|
|
6588
|
+
"confirmUrl",
|
|
6589
|
+
"cancelUrl",
|
|
6590
|
+
"extTokenOptions",
|
|
6591
|
+
"extToken",
|
|
6592
|
+
"var1",
|
|
6593
|
+
"var2",
|
|
6594
|
+
"var3",
|
|
6595
|
+
"var4",
|
|
6596
|
+
"var5",
|
|
6597
|
+
"var6",
|
|
6598
|
+
"var7",
|
|
6599
|
+
"var8",
|
|
6600
|
+
"var9",
|
|
6601
|
+
"digest"
|
|
6602
|
+
]);
|
|
6603
|
+
var KNOWN = new Set(CARDLINK_VPOS_ENTRY_FIELDS);
|
|
6604
|
+
var REQUIRED3 = Object.freeze([
|
|
6605
|
+
"version",
|
|
6606
|
+
"mid",
|
|
6607
|
+
"orderid",
|
|
6608
|
+
"orderDesc",
|
|
6609
|
+
"orderAmount",
|
|
6610
|
+
"currency",
|
|
6611
|
+
"payerEmail",
|
|
6612
|
+
"confirmUrl",
|
|
6613
|
+
"cancelUrl",
|
|
6614
|
+
"digest"
|
|
6615
|
+
]);
|
|
6616
|
+
var STORED2 = Object.freeze(["extTokenOptions", "extToken"]);
|
|
6617
|
+
var SPECIAL2 = Object.freeze(["extInstallmentoffset", "extInstallmentperiod", "extRecurringfrequency", "extRecurringenddate"]);
|
|
6618
|
+
var CURRENCIES2 = Object.freeze({ EUR: "eur" });
|
|
6619
|
+
var MAX_URL = 512;
|
|
6620
|
+
var MAX_ENTRY3 = 8 * 1024;
|
|
6621
|
+
var MAX_VALUE = 256;
|
|
6622
|
+
var own13 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
6623
|
+
var field2 = (name, reason) => ({ ok: false, code: "hosted_form_field_refused", field: name, reason });
|
|
6624
|
+
function cardlinkVposEntryHost(raw) {
|
|
6625
|
+
if (typeof raw !== "string" || raw.length > MAX_URL || raw.includes("?") || raw.includes("#"))
|
|
6626
|
+
return null;
|
|
6627
|
+
let url;
|
|
6628
|
+
try {
|
|
6629
|
+
url = new URL(raw);
|
|
6264
6630
|
}
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
return { verdict: "refuse", code: "paypal_url_refused" };
|
|
6268
|
-
return paypalBodyVerdict(body);
|
|
6631
|
+
catch {
|
|
6632
|
+
return null;
|
|
6269
6633
|
}
|
|
6270
|
-
if (
|
|
6271
|
-
return
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6634
|
+
if (url.href !== raw || url.protocol !== "https:" || url.port || url.username || url.password || !own13(CARDLINK_VPOS_HOSTS, url.hostname) || url.pathname !== CARDLINK_VPOS_ENTRY_PATH)
|
|
6635
|
+
return null;
|
|
6636
|
+
return url.hostname;
|
|
6637
|
+
}
|
|
6638
|
+
function isCardlinkVposEntryUrl(raw) {
|
|
6639
|
+
return cardlinkVposEntryHost(raw) !== null;
|
|
6640
|
+
}
|
|
6641
|
+
function parseCardlinkVposForm(body) {
|
|
6642
|
+
if (typeof body !== "string" || body.length === 0 || body.length > MAX_ENTRY3 || /[^\x21-\x7e]/.test(body))
|
|
6643
|
+
return null;
|
|
6644
|
+
const pairs = [];
|
|
6645
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6646
|
+
for (const chunk of body.split("&")) {
|
|
6647
|
+
const eq = chunk.indexOf("=");
|
|
6648
|
+
if (eq < 1)
|
|
6649
|
+
return null;
|
|
6650
|
+
let key;
|
|
6651
|
+
let value;
|
|
6652
|
+
try {
|
|
6653
|
+
key = decodeURIComponent(chunk.slice(0, eq).replace(/\+/g, " "));
|
|
6654
|
+
value = decodeURIComponent(chunk.slice(eq + 1).replace(/\+/g, " "));
|
|
6655
|
+
}
|
|
6656
|
+
catch {
|
|
6657
|
+
return null;
|
|
6658
|
+
}
|
|
6659
|
+
if (!/^[A-Za-z_.][A-Za-z0-9_.-]{0,63}$/.test(key) || value.length > MAX_VALUE || /[\u0000-\u001f\u007f]/.test(value))
|
|
6660
|
+
return null;
|
|
6661
|
+
if (seen.has(key))
|
|
6662
|
+
return null;
|
|
6663
|
+
seen.add(key);
|
|
6664
|
+
pairs.push({ key, value });
|
|
6278
6665
|
}
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6666
|
+
return pairs;
|
|
6667
|
+
}
|
|
6668
|
+
function cardlinkVposMerchant(mid, vposHost, merchants = CARDLINK_VPOS_MERCHANTS) {
|
|
6669
|
+
if (typeof mid !== "string" || typeof vposHost !== "string" || !Array.isArray(merchants))
|
|
6670
|
+
return null;
|
|
6671
|
+
const found = merchants.filter((row) => !!row && typeof row.merchant === "string" && row.merchant.trim() !== "" && row.mid === mid && row.vposHost === vposHost && typeof row.host === "string" && row.host !== "");
|
|
6672
|
+
return found.length === 1 ? found[0] : null;
|
|
6673
|
+
}
|
|
6674
|
+
function entryAmount(values) {
|
|
6675
|
+
const amount2 = values.get("orderAmount");
|
|
6676
|
+
const code = values.get("currency");
|
|
6677
|
+
const currency = typeof code === "string" && own13(CURRENCIES2, code) ? CURRENCIES2[code] : null;
|
|
6678
|
+
if (!currency || typeof amount2 !== "string" || !/^(?:0|[1-9]\d{0,11})(?:\.\d{1,2})?$/.test(amount2))
|
|
6679
|
+
return null;
|
|
6680
|
+
const [whole2, fraction = ""] = amount2.split(".");
|
|
6681
|
+
const cents2 = Number(whole2) * 100 + Number(fraction.padEnd(2, "0"));
|
|
6682
|
+
return Number.isSafeInteger(cents2) && cents2 > 0 ? { amountCents: cents2, currency } : null;
|
|
6683
|
+
}
|
|
6684
|
+
function httpsUrl(value) {
|
|
6685
|
+
let url;
|
|
6686
|
+
try {
|
|
6687
|
+
url = new URL(value);
|
|
6285
6688
|
}
|
|
6286
|
-
|
|
6287
|
-
return
|
|
6288
|
-
if (recognizer && recognizer.psp === PADDLE_VGS_PSP) {
|
|
6289
|
-
if (url !== void 0 && !isPaddleVgsCardsUrl(url))
|
|
6290
|
-
return { verdict: "refuse", code: "paddle_vgs_url_refused" };
|
|
6291
|
-
return paddleVgsBodyVerdict(body);
|
|
6689
|
+
catch {
|
|
6690
|
+
return null;
|
|
6292
6691
|
}
|
|
6293
|
-
if (
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6692
|
+
if (url.protocol !== "https:" || url.username || url.password || url.port || url.hash)
|
|
6693
|
+
return null;
|
|
6694
|
+
return url;
|
|
6695
|
+
}
|
|
6696
|
+
function checkCardlinkVposEntry(body, { url = null, merchants = CARDLINK_VPOS_MERCHANTS } = {}) {
|
|
6697
|
+
const vposHost = cardlinkVposEntryHost(url);
|
|
6698
|
+
if (!vposHost)
|
|
6699
|
+
return field2("(url)", "malformed_field");
|
|
6700
|
+
const pairs = parseCardlinkVposForm(body);
|
|
6701
|
+
if (!pairs)
|
|
6702
|
+
return field2("(body)", "malformed");
|
|
6703
|
+
const values = new Map(pairs.map(({ key, value }) => [key, value]));
|
|
6704
|
+
for (const { key } of pairs) {
|
|
6705
|
+
if (KNOWN.has(key))
|
|
6706
|
+
continue;
|
|
6707
|
+
return field2(key, /^(?:card[._]|cvv|cmd$|trid$|st$|paystep$|paymentmethod$)/i.test(key) ? "card_in_entry" : "not_an_entry");
|
|
6708
|
+
}
|
|
6709
|
+
const missing = REQUIRED3.filter((name) => !values.get(name));
|
|
6710
|
+
if (missing.length)
|
|
6711
|
+
return { ok: false, code: "hosted_form_template_incomplete", missing };
|
|
6712
|
+
if (values.get("version") !== "2")
|
|
6713
|
+
return field2("version", "malformed");
|
|
6714
|
+
if (!/^[A-Za-z0-9+/]{43}=$/.test(values.get("digest")))
|
|
6715
|
+
return field2("digest", "unsigned");
|
|
6716
|
+
for (const name of STORED2)
|
|
6717
|
+
if (values.has(name))
|
|
6718
|
+
return field2(name, "stored_credential");
|
|
6719
|
+
for (const name of SPECIAL2)
|
|
6720
|
+
if (values.get(name))
|
|
6721
|
+
return field2(name, "special_flow");
|
|
6722
|
+
for (let i = 1; i <= 9; i += 1)
|
|
6723
|
+
if (/moto\s*=\s*true/i.test(values.get(`var${i}`) ?? ""))
|
|
6724
|
+
return field2(`var${i}`, "moto");
|
|
6725
|
+
if (values.has("trType") && values.get("trType") !== "1")
|
|
6726
|
+
return field2("trType", "not_a_sale");
|
|
6727
|
+
const method = values.get("payMethod");
|
|
6728
|
+
if (method)
|
|
6729
|
+
return field2("payMethod", /^iris$/i.test(method) ? "not_a_card_payment" : "special_flow");
|
|
6730
|
+
const amount2 = entryAmount(values);
|
|
6731
|
+
if (!amount2)
|
|
6732
|
+
return field2(own13(CURRENCIES2, values.get("currency")) ? "orderAmount" : "currency", "malformed");
|
|
6733
|
+
if (!/^\d{1,30}$/.test(values.get("mid")))
|
|
6734
|
+
return field2("mid", "malformed");
|
|
6735
|
+
if (!/^[A-Za-z0-9]{1,50}$/.test(values.get("orderid")))
|
|
6736
|
+
return field2("orderid", "malformed");
|
|
6737
|
+
const seller = cardlinkVposMerchant(values.get("mid"), vposHost, merchants);
|
|
6738
|
+
if (!seller)
|
|
6739
|
+
return field2("mid", "seller_unreviewed");
|
|
6740
|
+
for (const name of ["confirmUrl", "cancelUrl"]) {
|
|
6741
|
+
const target = httpsUrl(values.get(name));
|
|
6742
|
+
if (!target || target.hostname !== seller.host)
|
|
6743
|
+
return field2(name, "callback_host");
|
|
6297
6744
|
}
|
|
6298
|
-
|
|
6299
|
-
|
|
6745
|
+
return {
|
|
6746
|
+
ok: true,
|
|
6747
|
+
pairs,
|
|
6748
|
+
gated: false,
|
|
6749
|
+
dedupe: [vposHost, values.get("mid"), values.get("orderid"), values.get("orderAmount"), values.get("currency")],
|
|
6750
|
+
seller
|
|
6751
|
+
};
|
|
6752
|
+
}
|
|
6753
|
+
function cardlinkVposEntryAmount(body) {
|
|
6754
|
+
const pairs = parseCardlinkVposForm(body);
|
|
6755
|
+
return pairs ? entryAmount(new Map(pairs.map(({ key, value }) => [key, value]))) : null;
|
|
6756
|
+
}
|
|
6757
|
+
var CARDLINK_VPOS_TDS2_FIELDS = Object.freeze([
|
|
6758
|
+
"TDS2_Navigator_language",
|
|
6759
|
+
"TDS2_Navigator_jsEnabled",
|
|
6760
|
+
"TDS2_Navigator_javaEnabled",
|
|
6761
|
+
"TDS2_Screen_colorDepth",
|
|
6762
|
+
"TDS2_Screen_height",
|
|
6763
|
+
"TDS2_Screen_width",
|
|
6764
|
+
"TDS2_screen_pixelDepth",
|
|
6765
|
+
"TDS2_TimezoneOffset"
|
|
6766
|
+
]);
|
|
6767
|
+
var PAGE_FIELDS = Object.freeze(["trid", "st", "payStep", "cmd", "startbonus", "bonusdata"]);
|
|
6768
|
+
var WALLET_FIELDS2 = Object.freeze(["walletId", "applePayResponse"]);
|
|
6769
|
+
var CARD38 = Object.freeze({ number: "card.pan", holder: "card.holderName", month: "card.expiryMonth", year: "card.expiryYear", cvc: "card.cvv" });
|
|
6770
|
+
var TEXT_CONTROLS = /* @__PURE__ */ new Set([CARD38.number, CARD38.holder, CARD38.cvc]);
|
|
6771
|
+
var SELECT_CONTROLS = /* @__PURE__ */ new Set([CARD38.month, CARD38.year]);
|
|
6772
|
+
var MAX_PAGE3 = 256 * 1024;
|
|
6773
|
+
var COOKIE_DOMAINS = Object.freeze({
|
|
6774
|
+
"vpos.eurocommerce.gr": "eurocommerce.gr",
|
|
6775
|
+
"ecommerce.cardlink.gr": "cardlink.gr",
|
|
6776
|
+
"www.alphaecommerce.gr": "alphaecommerce.gr"
|
|
6777
|
+
});
|
|
6778
|
+
var POST_REQUIRED = Object.freeze(["trid", "st", "cmd", CARD38.number, CARD38.holder, CARD38.month, CARD38.year, CARD38.cvc, "makepayment"]);
|
|
6779
|
+
var POST_EMPTY = Object.freeze(["payStep", "startbonus", "bonusdata", ...WALLET_FIELDS2]);
|
|
6780
|
+
var POST_ALLOWED = /* @__PURE__ */ new Set([...POST_REQUIRED, ...POST_EMPTY, "paymentMethod", ...CARDLINK_VPOS_TDS2_FIELDS]);
|
|
6781
|
+
var CARDLINK_VPOS_REFUSALS = Object.freeze([
|
|
6782
|
+
"cardlink_vpos_card_refused",
|
|
6783
|
+
"cardlink_vpos_card_page",
|
|
6784
|
+
"cardlink_vpos_3ds_challenge",
|
|
6785
|
+
"cardlink_vpos_declined"
|
|
6786
|
+
]);
|
|
6787
|
+
var REFUSAL_FOR = Object.freeze({
|
|
6788
|
+
card_refused: "cardlink_vpos_card_refused",
|
|
6789
|
+
card_page: "cardlink_vpos_card_page",
|
|
6790
|
+
challenge: "cardlink_vpos_3ds_challenge",
|
|
6791
|
+
declined: "cardlink_vpos_declined"
|
|
6792
|
+
});
|
|
6793
|
+
var CARDLINK_VPOS_CAPABILITY = "cardlink_vpos_hosted_payment_page";
|
|
6794
|
+
var CARDLINK_VPOS_OPERATION = "cardlink_vpos.hosted_sale";
|
|
6795
|
+
var cardlink_vpos_default = /* @__PURE__ */ registerProcessor({
|
|
6796
|
+
psp: CARDLINK_VPOS_PSP,
|
|
6797
|
+
definitions: [
|
|
6798
|
+
{
|
|
6799
|
+
psp: "cardlink_vpos",
|
|
6800
|
+
// The merchant's signed entry, as the header above reads it: a Document navigation that carries no card. The
|
|
6801
|
+
// cardholder's device repeats it over the end-to-end TLS relay, fills the card into the page the VPOS returns
|
|
6802
|
+
// and posts it in that same session, and the runtime resolves the paused navigation with the hosted_form notice.
|
|
6803
|
+
// Only the entry path on the three live hosts is matched (isCardlinkVposEntryUrl). The card page posts to the same
|
|
6804
|
+
// path, so the SDK fails every other post to these hosts in the agent's browser, and no placeholder card reaches
|
|
6805
|
+
// the VPOS. The test hosts are listed so a live host classifies as live and the create refuses a test row there;
|
|
6806
|
+
// no entry on them is paused. Ships dark: served only to a client that declares
|
|
6807
|
+
// `cardlink_vpos_hosted_payment_page`, and gated off for every company the operator has not turned it on for.
|
|
6808
|
+
capability: CARDLINK_VPOS_CAPABILITY,
|
|
6809
|
+
match: "(?:vpos\\.eurocommerce\\.gr|ecommerce\\.cardlink\\.gr|www\\.alphaecommerce\\.gr)/vpos/shophandlermpi(?![\\w/.%;=!-])",
|
|
6810
|
+
hosts: [
|
|
6811
|
+
"^vpos\\.eurocommerce\\.gr$",
|
|
6812
|
+
"^ecommerce\\.cardlink\\.gr$",
|
|
6813
|
+
"^www\\.alphaecommerce\\.gr$",
|
|
6814
|
+
"^eurocommerce-test\\.cardlink\\.gr$",
|
|
6815
|
+
"^ecommerce-test\\.cardlink\\.gr$",
|
|
6816
|
+
"^alphaecommerce-test\\.cardlink\\.gr$"
|
|
6817
|
+
],
|
|
6818
|
+
sandboxHosts: ["^eurocommerce-test\\.cardlink\\.gr$", "^ecommerce-test\\.cardlink\\.gr$", "^alphaecommerce-test\\.cardlink\\.gr$"],
|
|
6819
|
+
hostEnvironmentPinned: true,
|
|
6820
|
+
encoding: "form",
|
|
6821
|
+
// A form navigation: no captured header is ever replayed.
|
|
6822
|
+
passthroughHeaders: [],
|
|
6823
|
+
mode: "hosted_form",
|
|
6824
|
+
hostedForm: {
|
|
6825
|
+
// The card goes into the VPOS's own page on the device, never into the entry, which must carry none
|
|
6826
|
+
// (checkCardlinkVposEntry). The entry's rules come with this registration (hostedEntry below), so no policy is
|
|
6827
|
+
// named here.
|
|
6828
|
+
cardIn: "processor_page",
|
|
6829
|
+
required: [...REQUIRED3],
|
|
6830
|
+
// The card page's own fields, which the device fills on that page.
|
|
6831
|
+
card: { number: "card.pan", month: "card.expiryMonth", year: "card.expiryYear", cvc: "card.cvv" },
|
|
6832
|
+
// The host, the mid, the order id and the amount name one payment; the entry's rules read the host from its URL.
|
|
6833
|
+
dedupe: ["(vposHost)", "mid", "orderid", "orderAmount", "currency"]
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
],
|
|
6837
|
+
// Only the cardholder's device repeats an entry, after a person approves; no reviewed list names cardlink_vpos.
|
|
6838
|
+
refusedOperations: [CARDLINK_VPOS_OPERATION],
|
|
6839
|
+
// Not surveyed: the VPOS tells the merchant the result through the browser's return and a copy to its server, both
|
|
6840
|
+
// signed under the merchant's secret, which Agentcard never holds.
|
|
6841
|
+
settlementReadback: "not_surveyed",
|
|
6842
|
+
exactUrl: isCardlinkVposEntryUrl,
|
|
6843
|
+
hostedEntry: (body, { url }) => checkCardlinkVposEntry(body, { url }),
|
|
6844
|
+
amount: (template) => template && isCardlinkVposEntryUrl(template.url) ? cardlinkVposEntryAmount(template.body) : null,
|
|
6845
|
+
limitations: [
|
|
6846
|
+
"The paused request is the merchant's signed entry form, which carries no card; the cardholder's device sends it to Cardlink's VPOS over the end-to-end TLS relay and fills the card into the page the VPOS returns.",
|
|
6847
|
+
"Agentcard takes only a reviewed merchant's entry: its mid and the host it posts to name the merchant the cardholder is shown, and its confirm and cancel URLs must sit on that merchant's own host.",
|
|
6848
|
+
"Agentcard takes one plain payment only and refuses an entry that asks for a stored card, installments, a recurring schedule, a pre-authorization, MOTO or a preselected payment method.",
|
|
6849
|
+
"The VPOS runs EMV 3-D Secure on the card. A frictionless answer pays; a challenge ends the payment on the device with nothing charged.",
|
|
6850
|
+
"The browser receives a submission notice, not the processor result."
|
|
6851
|
+
]
|
|
6852
|
+
});
|
|
6853
|
+
// src/processors/eghl.js
|
|
6854
|
+
var EGHL_PSP = "eghl";
|
|
6855
|
+
var EGHL_OPERATION = "eghl.hosted_sale";
|
|
6856
|
+
var EGHL_HOST = "securepay.e-ghl.com";
|
|
6857
|
+
var EGHL_SANDBOX_HOST = "test2pay.ghl.com";
|
|
6858
|
+
var LIVE_PATH = "/ipg/payment.aspx";
|
|
6859
|
+
var SANDBOX_PATH = "/ipgsg/payment.aspx";
|
|
6860
|
+
var MAX_URL2 = 8192;
|
|
6861
|
+
var field3 = (name, reason) => ({ ok: false, code: "hosted_form_field_refused", field: name, reason });
|
|
6862
|
+
function eghlEntry(raw) {
|
|
6863
|
+
if (typeof raw !== "string" || raw.length > MAX_URL2 || raw.includes("#"))
|
|
6864
|
+
return null;
|
|
6865
|
+
let url;
|
|
6866
|
+
try {
|
|
6867
|
+
url = new URL(raw);
|
|
6300
6868
|
}
|
|
6301
|
-
|
|
6302
|
-
return
|
|
6869
|
+
catch {
|
|
6870
|
+
return null;
|
|
6303
6871
|
}
|
|
6304
|
-
if (
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6872
|
+
if (url.href !== raw || url.protocol !== "https:" || url.port || url.username || url.password || url.search.length < 2)
|
|
6873
|
+
return null;
|
|
6874
|
+
const path = url.pathname.toLowerCase();
|
|
6875
|
+
const query = url.search.slice(1);
|
|
6876
|
+
if (url.hostname === EGHL_HOST && path === LIVE_PATH)
|
|
6877
|
+
return Object.freeze({ test: false, query });
|
|
6878
|
+
if (url.hostname === EGHL_SANDBOX_HOST && path === SANDBOX_PATH)
|
|
6879
|
+
return Object.freeze({ test: true, query });
|
|
6880
|
+
return null;
|
|
6881
|
+
}
|
|
6882
|
+
function isEghlEntryUrl(raw) {
|
|
6883
|
+
return eghlEntry(raw) !== null;
|
|
6884
|
+
}
|
|
6885
|
+
var EGHL_MERCHANTS = Object.freeze([
|
|
6886
|
+
Object.freeze({ merchant: "BookXcess", serviceId: "BXS", payee: "BookXcess Sdn Bhd", returnHosts: Object.freeze(["shopify.ghl.com:11443"]), test: false })
|
|
6887
|
+
]);
|
|
6888
|
+
var SERVICE_ID2 = /^[A-Za-z0-9]{3}$/;
|
|
6889
|
+
var HOST = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+(?::[1-9]\d{0,4})?$/;
|
|
6890
|
+
function eghlMerchant(serviceId, { test = false, merchants = EGHL_MERCHANTS } = {}) {
|
|
6891
|
+
if (typeof serviceId !== "string" || !SERVICE_ID2.test(serviceId) || !Array.isArray(merchants))
|
|
6892
|
+
return null;
|
|
6893
|
+
const found = merchants.filter((row) => !!row && typeof row.merchant === "string" && row.merchant.trim() !== "" && typeof row.payee === "string" && row.payee.trim() !== "" && row.serviceId === serviceId && row.test === test && Array.isArray(row.returnHosts) && row.returnHosts.length > 0 && row.returnHosts.every((host) => typeof host === "string" && HOST.test(host)));
|
|
6894
|
+
return found.length === 1 ? found[0] : null;
|
|
6895
|
+
}
|
|
6896
|
+
var REQUIRED4 = Object.freeze([
|
|
6897
|
+
"TransactionType",
|
|
6898
|
+
"PymtMethod",
|
|
6899
|
+
"ServiceID",
|
|
6900
|
+
"PaymentID",
|
|
6901
|
+
"OrderNumber",
|
|
6902
|
+
"MerchantReturnURL",
|
|
6903
|
+
"MerchantCallBackURL",
|
|
6904
|
+
"Amount",
|
|
6905
|
+
"CurrencyCode",
|
|
6906
|
+
"HashValue"
|
|
6907
|
+
]);
|
|
6908
|
+
var CARD_KEYS17 = /* @__PURE__ */ new Set(["cardno", "cardexp", "cardcvv2", "cardholder", "param2", "param4", "cvv2", "epmonth2", "epyear2", "custocp"]);
|
|
6909
|
+
var SECRET_KEYS = /* @__PURE__ */ new Set(["password"]);
|
|
6910
|
+
var STORED_KEYS2 = /* @__PURE__ */ new Set([
|
|
6911
|
+
"tokentype",
|
|
6912
|
+
"token",
|
|
6913
|
+
"cardid",
|
|
6914
|
+
"precheckoutid",
|
|
6915
|
+
"reqtoken",
|
|
6916
|
+
"pairingtoken",
|
|
6917
|
+
"reqverifier",
|
|
6918
|
+
"pairingverifier",
|
|
6919
|
+
"checkoutresourceurl"
|
|
6920
|
+
]);
|
|
6921
|
+
var SPECIAL_KEYS = /* @__PURE__ */ new Set(["eppmonth", "promocode"]);
|
|
6922
|
+
var RESULT_KEYS = Object.freeze(["MerchantReturnURL", "MerchantCallBackURL", "MerchantApprovalURL", "MerchantUnApprovalURL"]);
|
|
6923
|
+
var CURRENCIES3 = /* @__PURE__ */ new Set(["MYR", "SGD", "USD", "PHP", "THB"]);
|
|
6924
|
+
var AMOUNT3 = /^(0|[1-9]\d{0,8})\.(\d{2})$/;
|
|
6925
|
+
function httpsUrl2(value) {
|
|
6926
|
+
let url;
|
|
6927
|
+
try {
|
|
6928
|
+
url = new URL(value);
|
|
6929
|
+
}
|
|
6930
|
+
catch {
|
|
6931
|
+
return null;
|
|
6932
|
+
}
|
|
6933
|
+
if (url.protocol !== "https:" || url.username || url.password || url.hash)
|
|
6934
|
+
return null;
|
|
6935
|
+
return url;
|
|
6936
|
+
}
|
|
6937
|
+
function entryFields(text11) {
|
|
6938
|
+
const pairs = parseRedsysForm(text11);
|
|
6939
|
+
if (!pairs)
|
|
6940
|
+
return null;
|
|
6941
|
+
return { pairs, values: new Map(pairs.map(({ key, value }) => [key.toLowerCase(), value])) };
|
|
6942
|
+
}
|
|
6943
|
+
function entryAmount2(values) {
|
|
6944
|
+
const currency = values.get("currencycode");
|
|
6945
|
+
const amount2 = AMOUNT3.exec(values.get("amount") ?? "");
|
|
6946
|
+
if (!amount2 || typeof currency !== "string" || !CURRENCIES3.has(currency))
|
|
6947
|
+
return null;
|
|
6948
|
+
const cents2 = Number(amount2[1]) * 100 + Number(amount2[2]);
|
|
6949
|
+
return cents2 > 0 && Number.isSafeInteger(cents2) ? { amountCents: cents2, currency: currency.toLowerCase() } : null;
|
|
6950
|
+
}
|
|
6951
|
+
function checkEghlEntry(body, { url = null, merchants = EGHL_MERCHANTS } = {}) {
|
|
6952
|
+
if (body !== void 0 && body !== null && body !== "")
|
|
6953
|
+
return field3("(body)", "not_an_entry");
|
|
6954
|
+
const entry = eghlEntry(url);
|
|
6955
|
+
if (!entry)
|
|
6956
|
+
return field3("(url)", "malformed_field");
|
|
6957
|
+
const fields = entryFields(entry.query);
|
|
6958
|
+
if (!fields)
|
|
6959
|
+
return field3("(query)", "malformed");
|
|
6960
|
+
const { pairs, values } = fields;
|
|
6961
|
+
for (const { key, value } of pairs) {
|
|
6962
|
+
if (value === "")
|
|
6963
|
+
continue;
|
|
6964
|
+
const folded = key.toLowerCase();
|
|
6965
|
+
if (CARD_KEYS17.has(folded))
|
|
6966
|
+
return field3(key, "card_in_entry");
|
|
6967
|
+
if (SECRET_KEYS.has(folded))
|
|
6968
|
+
return field3(key, "not_an_entry");
|
|
6969
|
+
if (STORED_KEYS2.has(folded))
|
|
6970
|
+
return field3(key, "stored_credential");
|
|
6971
|
+
if (SPECIAL_KEYS.has(folded))
|
|
6972
|
+
return field3(key, "special_flow");
|
|
6973
|
+
}
|
|
6974
|
+
const missing = REQUIRED4.filter((name) => !values.get(name.toLowerCase()));
|
|
6975
|
+
if (missing.length)
|
|
6976
|
+
return { ok: false, code: "hosted_form_template_incomplete", missing };
|
|
6977
|
+
if (values.get("transactiontype") !== "SALE")
|
|
6978
|
+
return field3("TransactionType", "not_a_sale");
|
|
6979
|
+
if (!["ANY", "CC"].includes(values.get("pymtmethod")))
|
|
6980
|
+
return field3("PymtMethod", "special_flow");
|
|
6981
|
+
if (!/^[0-9A-Fa-f]{64}$/.test(values.get("hashvalue")))
|
|
6982
|
+
return field3("HashValue", "unsigned");
|
|
6983
|
+
if (!entryAmount2(values))
|
|
6984
|
+
return field3(CURRENCIES3.has(values.get("currencycode")) ? "Amount" : "CurrencyCode", "malformed");
|
|
6985
|
+
if (!SERVICE_ID2.test(values.get("serviceid")))
|
|
6986
|
+
return field3("ServiceID", "malformed");
|
|
6987
|
+
if (!/^[A-Za-z0-9._-]{1,20}$/.test(values.get("paymentid")))
|
|
6988
|
+
return field3("PaymentID", "malformed");
|
|
6989
|
+
if (values.get("ordernumber").length > 20)
|
|
6990
|
+
return field3("OrderNumber", "malformed");
|
|
6991
|
+
const pageTimeout = values.get("pagetimeout");
|
|
6992
|
+
if (pageTimeout !== void 0 && !/^[1-9]\d{1,4}$/.test(pageTimeout))
|
|
6993
|
+
return field3("PageTimeout", "malformed");
|
|
6994
|
+
const seller = eghlMerchant(values.get("serviceid"), { test: entry.test, merchants });
|
|
6995
|
+
if (!seller)
|
|
6996
|
+
return field3("ServiceID", "seller_unreviewed");
|
|
6997
|
+
for (const name of RESULT_KEYS) {
|
|
6998
|
+
const value = values.get(name.toLowerCase());
|
|
6999
|
+
if (!value)
|
|
7000
|
+
continue;
|
|
7001
|
+
const target = httpsUrl2(value);
|
|
7002
|
+
if (!target || !seller.returnHosts.includes(target.host) || [EGHL_HOST, EGHL_SANDBOX_HOST].includes(target.hostname))
|
|
7003
|
+
return field3(name, "callback_host");
|
|
7004
|
+
}
|
|
7005
|
+
return { ok: true, pairs, gated: false, dedupe: [values.get("serviceid"), values.get("paymentid")], sandbox: entry.test, seller };
|
|
7006
|
+
}
|
|
7007
|
+
function eghlEntryAmount(body, url) {
|
|
7008
|
+
if (body !== void 0 && body !== null && body !== "")
|
|
7009
|
+
return null;
|
|
7010
|
+
const entry = eghlEntry(url);
|
|
7011
|
+
const fields = entry ? entryFields(entry.query) : null;
|
|
7012
|
+
return fields ? entryAmount2(fields.values) : null;
|
|
7013
|
+
}
|
|
7014
|
+
var MAX_PAGE4 = 1024 * 1024;
|
|
7015
|
+
var NEVER_SENT = new Set(["expressCheckoutType", "c2pRememberMeBrowser", "CustOCP", "CustRecurr", "CustAddress"].map((name) => name.toLowerCase()));
|
|
7016
|
+
var PAGE_REQUIRED = Object.freeze([
|
|
7017
|
+
"TransactionType",
|
|
7018
|
+
"ServiceID",
|
|
7019
|
+
"MerchantName",
|
|
7020
|
+
"PaymentID",
|
|
7021
|
+
"Amount",
|
|
7022
|
+
"BaseTxnAmount",
|
|
7023
|
+
"CurrencyCode",
|
|
7024
|
+
"BaseCurrencyCode",
|
|
7025
|
+
"HashValue",
|
|
7026
|
+
"Param2",
|
|
7027
|
+
"Param4",
|
|
7028
|
+
"CardExp",
|
|
7029
|
+
"CVV2",
|
|
7030
|
+
"PymtMethod"
|
|
7031
|
+
]);
|
|
7032
|
+
var EGHL_REFUSALS = Object.freeze(["eghl_failed", "eghl_cancelled"]);
|
|
7033
|
+
var MAX_ANSWER = 256 * 1024;
|
|
7034
|
+
var RESULT_FIELDS = Object.freeze(["TxnStatus", "ServiceID", "PaymentID", "Amount", "CurrencyCode"]);
|
|
7035
|
+
var eghl_default = /* @__PURE__ */ registerProcessor({
|
|
7036
|
+
psp: EGHL_PSP,
|
|
7037
|
+
definitions: [
|
|
7038
|
+
{
|
|
7039
|
+
psp: "eghl",
|
|
7040
|
+
// The merchant's entry to eGHL's payment page, as the header above reads it: a GET Document navigation whose
|
|
7041
|
+
// query names the payment and which carries no card. The cardholder's device repeats it over the end-to-end TLS
|
|
7042
|
+
// relay and pays on the page eGHL returns to it, and the runtime resolves the paused navigation with the
|
|
7043
|
+
// hosted_form notice. Only the entry is matched (isEghlEntryUrl): the card page's own card post goes to the same
|
|
7044
|
+
// path as a POST. The path is matched in any letter case, as IIS reads it; `(?![\\w/.%-])` ends it for a consumer
|
|
7045
|
+
// that tests `match` unanchored. Ships dark: served only to a client that declares `eghl_hosted_payment_page`, and
|
|
7046
|
+
// gated off for every company the operator has not allowlisted.
|
|
7047
|
+
capability: "eghl_hosted_payment_page",
|
|
7048
|
+
match: "securepay\\.e-ghl\\.com/[Ii][Pp][Gg]/[Pp][Aa][Yy][Mm][Ee][Nn][Tt]\\.[Aa][Ss][Pp][Xx](?![\\w/.%-])|test2pay\\.ghl\\.com/[Ii][Pp][Gg][Ss][Gg]/[Pp][Aa][Yy][Mm][Ee][Nn][Tt]\\.[Aa][Ss][Pp][Xx](?![\\w/.%-])",
|
|
7049
|
+
hosts: ["^securepay\\.e-ghl\\.com$", "^test2pay\\.ghl\\.com$"],
|
|
7050
|
+
sandboxHosts: ["^test2pay\\.ghl\\.com$"],
|
|
7051
|
+
hostEnvironmentPinned: true,
|
|
7052
|
+
// `encoding` describes the card page's own card post, which the device makes as the page does, since the entry
|
|
7053
|
+
// has no body. No captured header is ever replayed.
|
|
7054
|
+
encoding: "form",
|
|
7055
|
+
passthroughHeaders: [],
|
|
7056
|
+
// The paused request is the navigation itself, a GET with the payment in its query.
|
|
7057
|
+
request: { method: "GET", cardIn: "processor_page", response: "document" },
|
|
7058
|
+
mode: "hosted_form",
|
|
7059
|
+
hostedForm: {
|
|
7060
|
+
// The card goes into eGHL's page on the device, never into the entry (checkEghlEntry refuses one there). The
|
|
7061
|
+
// entry's own rules come with this registration (hostedEntry below), so no policy is named here.
|
|
7062
|
+
cardIn: "processor_page",
|
|
7063
|
+
required: ["TransactionType", "PymtMethod", "ServiceID", "PaymentID", "OrderNumber", "MerchantReturnURL", "MerchantCallBackURL", "Amount", "CurrencyCode", "HashValue"],
|
|
7064
|
+
// The card page's own inputs in its card form (frmProcessPayment, read card free on 2026-11-05): the number in
|
|
7065
|
+
// Param2, the expiry in CardExp as YYYYMM, which the page builds from its month and year selects, the code in
|
|
7066
|
+
// CVV2. The cardholder's name goes in Param4.
|
|
7067
|
+
card: { number: "Param2", expiry: "CardExp", cvc: "CVV2" },
|
|
7068
|
+
// eGHL takes one PaymentID once per merchant.
|
|
7069
|
+
dedupe: ["ServiceID", "PaymentID"]
|
|
7070
|
+
}
|
|
7071
|
+
}
|
|
7072
|
+
],
|
|
7073
|
+
// Only the cardholder's device repeats an entry, after a person approves; no reviewed list names eghl.
|
|
7074
|
+
refusedOperations: [EGHL_OPERATION],
|
|
7075
|
+
// Not surveyed: eGHL tells the merchant's server the result (MerchantCallBackURL), and its return carries a hash only
|
|
7076
|
+
// the merchant can check.
|
|
7077
|
+
settlementReadback: "not_surveyed",
|
|
7078
|
+
exactUrl: isEghlEntryUrl,
|
|
7079
|
+
amount: (template) => template && typeof template === "object" ? eghlEntryAmount(template.body, template.url) : null,
|
|
7080
|
+
hostedEntry: (body, { url = null } = {}) => checkEghlEntry(body, { url }),
|
|
7081
|
+
limitations: [
|
|
7082
|
+
"The paused request is the merchant's redirect to eGHL's payment page, a GET whose query names the payment and carries no card; the cardholder's device repeats it over the end-to-end TLS relay and pays on the page eGHL returns.",
|
|
7083
|
+
"Agentcard takes an entry only for a merchant it reviewed, by the ServiceID inside the merchant's signed entry, and the approval names that merchant and the amount the entry names.",
|
|
7084
|
+
"eGHL runs 3-D Secure on the card. A challenge ends the payment on the device with nothing charged.",
|
|
7085
|
+
"eGHL sends the buyer to the merchant's return page with a result only the merchant can verify, so the browser receives a submission notice, not the processor result."
|
|
7086
|
+
]
|
|
7087
|
+
});
|
|
7088
|
+
// src/processors/frisbii.js
|
|
7089
|
+
var FRISBII_PSP = "frisbii";
|
|
7090
|
+
var FRISBII_OPERATION = "frisbii.card_request";
|
|
7091
|
+
var FRISBII_HOSTS = /* @__PURE__ */ Object.freeze({ "card.reepay.com": "reepay", "card.frisbii.com": "frisbii" });
|
|
7092
|
+
var FRISBII_TOKEN_PATH = "/v1/token/";
|
|
7093
|
+
var FRISBII_REFUSED_PATHS = /* @__PURE__ */ Object.freeze({
|
|
7094
|
+
"/v1/token/cof/": "frisbii_stored_card_unsupported",
|
|
7095
|
+
"/v1/token/create_click_to_pay": "frisbii_click_to_pay_unsupported"
|
|
7096
|
+
});
|
|
7097
|
+
var BODY_LIMIT37 = 8192;
|
|
7098
|
+
var URL_LIMIT15 = 256;
|
|
7099
|
+
var CARD_NUMBER19 = /^[0-9]{12,19}$/;
|
|
7100
|
+
var MONTH19 = /^(?:0[1-9]|1[0-2])$/;
|
|
7101
|
+
var YEAR20 = /^[0-9]{2}$/;
|
|
7102
|
+
var SECURITY_CODE23 = /^(?:[0-9]{3,4})?$/;
|
|
7103
|
+
var IDENTIFIER2 = /^[A-Za-z0-9_-]{8,128}$/;
|
|
7104
|
+
var SCA_RULES = /* @__PURE__ */ Object.freeze([
|
|
7105
|
+
"DO_NOT_USE_SCA",
|
|
7106
|
+
"MUST_USE_SCA_AUTH",
|
|
7107
|
+
"MUST_USE_SCA_PREAUTH",
|
|
7108
|
+
"USE_SCA_IF_AVAILABLE_AUTH",
|
|
7109
|
+
"USE_SCA_IF_AVAILABLE_PREAUTH"
|
|
7110
|
+
]);
|
|
7111
|
+
var BODY_ORDER = /* @__PURE__ */ Object.freeze([
|
|
7112
|
+
"number",
|
|
7113
|
+
"month",
|
|
7114
|
+
"year",
|
|
7115
|
+
"cvv",
|
|
7116
|
+
"cardTypeOverride",
|
|
7117
|
+
"click_to_pay_encrypt",
|
|
7118
|
+
"billing_address",
|
|
7119
|
+
"pkey",
|
|
7120
|
+
"recurring",
|
|
7121
|
+
"cardholder_name",
|
|
7122
|
+
"intent",
|
|
7123
|
+
"recurringAverageAmount",
|
|
7124
|
+
"agreementFilter",
|
|
7125
|
+
"strongAuthenticationRule",
|
|
7126
|
+
"tokenStrongAuthenticationRequest"
|
|
7127
|
+
]);
|
|
7128
|
+
var BODY_REQUIRED = /* @__PURE__ */ Object.freeze(["number", "month", "year", "cvv", "pkey", "recurring", "strongAuthenticationRule"]);
|
|
7129
|
+
var BODY_REFUSED = /* @__PURE__ */ Object.freeze(["cardTypeOverride", "click_to_pay_encrypt", "billing_address"]);
|
|
7130
|
+
var SCA_ORDER = /* @__PURE__ */ Object.freeze(["amount", "currency", "orderId", "orderText", "merchantScaData", "returnUrl", "tokenBrowserInfo"]);
|
|
7131
|
+
var BROWSER_ORDER = /* @__PURE__ */ Object.freeze([
|
|
7132
|
+
"javascriptEnabled",
|
|
7133
|
+
"challengeWindowSize",
|
|
7134
|
+
"colorDepth",
|
|
7135
|
+
"javaEnabled",
|
|
7136
|
+
"screenHeight",
|
|
7137
|
+
"screenWidth",
|
|
7138
|
+
"tz"
|
|
7139
|
+
]);
|
|
7140
|
+
var LABEL = /^[A-Za-z0-9_-]{1,64}$/;
|
|
7141
|
+
var record33 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7142
|
+
var own14 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
7143
|
+
var refuse39 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
7144
|
+
var CARD39 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
7145
|
+
var text9 = (value, max) => typeof value === "string" && value.length <= max;
|
|
7146
|
+
var absentOrNull = (value) => value === void 0 || value === null;
|
|
7147
|
+
var inOrder6 = (value, order) => Object.keys(value).every((key) => order.includes(key)) && Object.keys(value).join() === order.filter((key) => own14(value, key)).join();
|
|
7148
|
+
function frisbiiTokenUrl(url) {
|
|
7149
|
+
if (typeof url !== "string" || url.length > URL_LIMIT15 || url.includes("#"))
|
|
7150
|
+
return null;
|
|
7151
|
+
let parsed;
|
|
7152
|
+
try {
|
|
7153
|
+
parsed = new URL(url);
|
|
7154
|
+
}
|
|
7155
|
+
catch {
|
|
7156
|
+
return null;
|
|
7157
|
+
}
|
|
7158
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own14(FRISBII_HOSTS, parsed.hostname) || parsed.pathname !== FRISBII_TOKEN_PATH)
|
|
7159
|
+
return null;
|
|
7160
|
+
const match = /^\?session=([A-Za-z0-9_-]{8,128})$/.exec(parsed.search);
|
|
7161
|
+
return match ? Object.freeze({ host: parsed.hostname, brand: FRISBII_HOSTS[parsed.hostname], session: match[1] }) : null;
|
|
7162
|
+
}
|
|
7163
|
+
var isFrisbiiTokenUrl = (url) => frisbiiTokenUrl(url) !== null;
|
|
7164
|
+
function frisbiiRefusedFlowUrl(url) {
|
|
7165
|
+
if (typeof url !== "string" || url.length > URL_LIMIT15 || url.includes("#"))
|
|
7166
|
+
return null;
|
|
7167
|
+
let parsed;
|
|
7168
|
+
try {
|
|
7169
|
+
parsed = new URL(url);
|
|
7170
|
+
}
|
|
7171
|
+
catch {
|
|
7172
|
+
return null;
|
|
7173
|
+
}
|
|
7174
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own14(FRISBII_HOSTS, parsed.hostname) || !own14(FRISBII_REFUSED_PATHS, parsed.pathname))
|
|
7175
|
+
return null;
|
|
7176
|
+
return FRISBII_REFUSED_PATHS[parsed.pathname];
|
|
7177
|
+
}
|
|
7178
|
+
function luhn9(digits4) {
|
|
7179
|
+
let sum = 0;
|
|
7180
|
+
for (let at = digits4.length - 1, double = false; at >= 0; at -= 1, double = !double) {
|
|
7181
|
+
let digit = digits4.charCodeAt(at) - 48;
|
|
7182
|
+
if (double)
|
|
7183
|
+
digit = digit * 2 > 9 ? digit * 2 - 9 : digit * 2;
|
|
7184
|
+
sum += digit;
|
|
7185
|
+
}
|
|
7186
|
+
return sum % 10 === 0;
|
|
7187
|
+
}
|
|
7188
|
+
function readBody23(body) {
|
|
7189
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT37)
|
|
7190
|
+
return null;
|
|
7191
|
+
try {
|
|
7192
|
+
const value = JSON.parse(body);
|
|
7193
|
+
return record33(value) && JSON.stringify(value) === body ? value : null;
|
|
7194
|
+
}
|
|
7195
|
+
catch {
|
|
7196
|
+
return null;
|
|
7197
|
+
}
|
|
7198
|
+
}
|
|
7199
|
+
function browserInfo(info) {
|
|
7200
|
+
return record33(info) && Object.keys(info).join() === BROWSER_ORDER.join() && info.javascriptEnabled === true && typeof info.javaEnabled === "boolean" && /^size_[0-9]{3}x[0-9]{3}$/.test(info.challengeWindowSize) && [info.colorDepth, info.screenHeight, info.screenWidth].every((n) => Number.isSafeInteger(n) && n >= 0 && n <= 1e5) && Number.isSafeInteger(info.tz) && Math.abs(info.tz) <= 1440;
|
|
7201
|
+
}
|
|
7202
|
+
function scaBlock(block, target) {
|
|
7203
|
+
if (!record33(block) || !inOrder6(block, SCA_ORDER) || !own14(block, "returnUrl") || !own14(block, "tokenBrowserInfo"))
|
|
7204
|
+
return false;
|
|
7205
|
+
if (!Number.isSafeInteger(block.amount) || block.amount < 0 || typeof block.currency !== "string" || !/^[A-Z]{3}$/.test(block.currency))
|
|
7206
|
+
return false;
|
|
7207
|
+
if (!(absentOrNull(block.orderId) || text9(block.orderId, 128)) || !(absentOrNull(block.orderText) || text9(block.orderText, 512)))
|
|
7208
|
+
return false;
|
|
7209
|
+
if (!(absentOrNull(block.merchantScaData) || record33(block.merchantScaData)))
|
|
7210
|
+
return false;
|
|
7211
|
+
if (!text9(block.returnUrl, 2048) || !browserInfo(block.tokenBrowserInfo))
|
|
7212
|
+
return false;
|
|
7213
|
+
const back = /^https:\/\/checkout\.(reepay|frisbii)\.com\/return\.001\.html\?id=([A-Za-z0-9_-]{8,128})(?:&[A-Za-z0-9_.~%=+/-]*)*$/.exec(block.returnUrl);
|
|
7214
|
+
return back !== null && (target === null || back[1] === target.brand && back[2] === target.session);
|
|
7215
|
+
}
|
|
7216
|
+
function frisbiiBodyVerdict(body, url) {
|
|
7217
|
+
const value = readBody23(body);
|
|
7218
|
+
if (value === null || !inOrder6(value, BODY_ORDER) || !BODY_REQUIRED.every((key) => own14(value, key)) || BODY_REFUSED.some((key) => own14(value, key)))
|
|
7219
|
+
return refuse39("frisbii_body_unsupported");
|
|
7220
|
+
if (value.recurring === true || value.intent === "CHARGE_AND_STORE")
|
|
7221
|
+
return refuse39("frisbii_card_on_file");
|
|
7222
|
+
const target = url === void 0 ? null : frisbiiTokenUrl(url);
|
|
7223
|
+
if (url !== void 0 && target === null)
|
|
7224
|
+
return refuse39("frisbii_body_unsupported");
|
|
7225
|
+
const sound = typeof value.number === "string" && CARD_NUMBER19.test(value.number) && luhn9(value.number) && typeof value.month === "string" && MONTH19.test(value.month) && typeof value.year === "string" && YEAR20.test(value.year) && typeof value.cvv === "string" && SECURITY_CODE23.test(value.cvv) && typeof value.pkey === "string" && IDENTIFIER2.test(value.pkey) && value.recurring === false && (value.cardholder_name === void 0 || text9(value.cardholder_name, 64)) && (value.intent === void 0 || value.intent === "CHARGE") && (absentOrNull(value.recurringAverageAmount) || Number.isSafeInteger(value.recurringAverageAmount) && value.recurringAverageAmount >= 0) && (absentOrNull(value.agreementFilter) || typeof value.agreementFilter === "string" && LABEL.test(value.agreementFilter) || Array.isArray(value.agreementFilter) && value.agreementFilter.length <= 16 && value.agreementFilter.every((entry) => typeof entry === "string" && LABEL.test(entry))) && SCA_RULES.includes(value.strongAuthenticationRule) && (value.tokenStrongAuthenticationRequest === void 0 || scaBlock(value.tokenStrongAuthenticationRequest, target));
|
|
7226
|
+
return sound ? CARD39 : refuse39("frisbii_body_unsupported");
|
|
7227
|
+
}
|
|
7228
|
+
var frisbii_default = /* @__PURE__ */ registerProcessor({
|
|
7229
|
+
psp: FRISBII_PSP,
|
|
7230
|
+
definitions: [
|
|
7231
|
+
{
|
|
7232
|
+
psp: "frisbii",
|
|
7233
|
+
// The hosted page's card request, as the header above reads it, on both brands' card hosts. A test account
|
|
7234
|
+
// shares the live hosts, so no sandbox host is marked. The match reads the host and the path and ends with it. It
|
|
7235
|
+
// also takes the page's two other card paths, /v1/token/cof/ and /v1/token/create_click_to_pay, so the pause
|
|
7236
|
+
// decision holds them, and the body gate refuses every body there; the exact-URL rule below holds the session
|
|
7237
|
+
// query of the card request. Ships dark: served only to a client that declares `frisbii_card_token`, and only for a company
|
|
7238
|
+
// the backend's processor gate turns Frisbii on for.
|
|
7239
|
+
capability: "frisbii_card_token",
|
|
7240
|
+
match: "card\\.(?:reepay|frisbii)\\.com/v1/token/(?:cof/|create_click_to_pay)?",
|
|
7241
|
+
hosts: ["^card\\.reepay\\.com$", "^card\\.frisbii\\.com$"],
|
|
7242
|
+
encoding: "json",
|
|
7243
|
+
// The page sends no header but its content type. Origin, Referer and cookies never ride.
|
|
7244
|
+
passthroughHeaders: [],
|
|
7245
|
+
jsonCardFields: [["number"]]
|
|
7246
|
+
}
|
|
7247
|
+
],
|
|
7248
|
+
// Only the cardholder's device would send this card, after a person approves; no reviewed list names frisbii.
|
|
7249
|
+
refusedOperations: [FRISBII_OPERATION],
|
|
7250
|
+
// Not surveyed: the card request mints a token and moves no money, and the page then charges the session with it
|
|
7251
|
+
// in a card-free request. Whether the session's own read (checkout-api /v1/checkout/<session>) can confirm that
|
|
7252
|
+
// charge was not read.
|
|
7253
|
+
settlementReadback: "not_surveyed",
|
|
7254
|
+
exactUrl: (url) => isFrisbiiTokenUrl(url) || frisbiiRefusedFlowUrl(url) !== null,
|
|
7255
|
+
// A stored card's token and Click to Pay are refused whatever their body; the card request is judged by its body.
|
|
7256
|
+
bodyGate: (url, body) => {
|
|
7257
|
+
if (url === void 0)
|
|
7258
|
+
return frisbiiBodyVerdict(body);
|
|
7259
|
+
const flow = frisbiiRefusedFlowUrl(url);
|
|
7260
|
+
if (flow !== null)
|
|
7261
|
+
return refuse39(flow);
|
|
7262
|
+
return isFrisbiiTokenUrl(url) ? frisbiiBodyVerdict(body, url) : refuse39("frisbii_url_refused");
|
|
7263
|
+
},
|
|
7264
|
+
limitations: ["A live Frisbii card goes only to a merchant account a reviewed pin lists, and none is pinned yet."]
|
|
7265
|
+
});
|
|
7266
|
+
// src/processors/iyzico.js
|
|
7267
|
+
var IYZICO_PSP = "iyzico";
|
|
7268
|
+
var IYZICO_OPERATION = "iyzico.card_request";
|
|
7269
|
+
var PATHS = ["/payment/iyzipos/checkoutform/auth/ecom", "/payment/iyzipos/checkoutform/initialize3ds/ecom"];
|
|
7270
|
+
var IYZICO_CARD_URLS = /* @__PURE__ */ Object.freeze(["https://api.iyzipay.com", "https://sandbox-api.iyzipay.com"].flatMap((origin) => PATHS.map((path) => `${origin}${path}`)));
|
|
7271
|
+
var IYZICO_BODY_KEYS = /* @__PURE__ */ Object.freeze([
|
|
7272
|
+
"installment",
|
|
7273
|
+
"paidPrice",
|
|
7274
|
+
"paymentChannel",
|
|
7275
|
+
"paymentCard",
|
|
7276
|
+
"buyerProtected",
|
|
7277
|
+
"gsmNumber",
|
|
7278
|
+
"dccPayment",
|
|
7279
|
+
"dccQueryRrn",
|
|
7280
|
+
"pwiMetadata"
|
|
7281
|
+
]);
|
|
7282
|
+
var IYZICO_CARD_KEYS = /* @__PURE__ */ Object.freeze([
|
|
7283
|
+
"cardNumber",
|
|
7284
|
+
"cardHolderName",
|
|
7285
|
+
"expireYear",
|
|
7286
|
+
"expireMonth",
|
|
7287
|
+
"cvc",
|
|
7288
|
+
"registerConsumerCard",
|
|
7289
|
+
"registerCard"
|
|
7290
|
+
]);
|
|
7291
|
+
var BODY_LIMIT38 = 4096;
|
|
7292
|
+
var CARD_NUMBER20 = /^[0-9]{12,19}$/;
|
|
7293
|
+
var SECURITY_CODE24 = /^[0-9]{3,4}$/;
|
|
7294
|
+
var MONTH20 = /^(?:0?[1-9]|1[0-2])$/;
|
|
7295
|
+
var YEAR21 = /^(?:[0-9]{2}|20[0-9]{2})$/;
|
|
7296
|
+
var PRICE = /^([1-9][0-9]{0,8}|0)(?:\.([0-9]{1,2}))?$/;
|
|
7297
|
+
var CHANNELS = /* @__PURE__ */ Object.freeze(["WEB", "MOBILE_WEB", "MOBILE_IOS", "MOBILE_ANDROID", "MOBILE_WINDOWS"]);
|
|
7298
|
+
var METADATA_KEYS3 = /* @__PURE__ */ Object.freeze(["lightRedesign", "pwiGrowthActionDisabled"]);
|
|
7299
|
+
var FLAG = /^[A-Za-z_]{1,16}$/;
|
|
7300
|
+
var HOLDER5 = /^[^\x00-\x1f\x7f0-9]{3,100}$/u;
|
|
7301
|
+
var record34 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7302
|
+
var own15 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
7303
|
+
var inOrder7 = (value, keys) => {
|
|
7304
|
+
let at = 0;
|
|
7305
|
+
for (const name of Object.keys(value)) {
|
|
7306
|
+
while (at < keys.length && keys[at] !== name)
|
|
7307
|
+
at += 1;
|
|
7308
|
+
if (at === keys.length)
|
|
7309
|
+
return false;
|
|
7310
|
+
at += 1;
|
|
7311
|
+
}
|
|
7312
|
+
return true;
|
|
7313
|
+
};
|
|
7314
|
+
var refuse40 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
7315
|
+
var CARD40 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
7316
|
+
function isIyzicoCardUrl(url) {
|
|
7317
|
+
return typeof url === "string" && IYZICO_CARD_URLS.includes(url);
|
|
7318
|
+
}
|
|
7319
|
+
function readBody24(body) {
|
|
7320
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT38)
|
|
7321
|
+
return null;
|
|
7322
|
+
try {
|
|
7323
|
+
const value = JSON.parse(body);
|
|
7324
|
+
return record34(value) && JSON.stringify(value) === body ? value : null;
|
|
7325
|
+
}
|
|
7326
|
+
catch {
|
|
7327
|
+
return null;
|
|
7328
|
+
}
|
|
7329
|
+
}
|
|
7330
|
+
function hundredths(price) {
|
|
7331
|
+
const match = typeof price === "number" && Number.isFinite(price) ? PRICE.exec(String(price)) : null;
|
|
7332
|
+
const value = match ? Number(match[1]) * 100 + Number((match[2] ?? "").padEnd(2, "0")) : 0;
|
|
7333
|
+
return value > 0 ? value : null;
|
|
7334
|
+
}
|
|
7335
|
+
var holderName2 = (name) => typeof name === "string" && HOLDER5.test(name) && name.trim().split(/\s+/).filter((word) => word.length > 1).length > 1;
|
|
7336
|
+
var metadata = (value) => record34(value) && inOrder7(value, METADATA_KEYS3) && Object.values(value).every((flag3) => Array.isArray(flag3) && flag3.length === 1 && typeof flag3[0] === "string" && FLAG.test(flag3[0]));
|
|
7337
|
+
function iyzicoBodyVerdict(body) {
|
|
7338
|
+
const value = readBody24(body);
|
|
7339
|
+
if (value === null)
|
|
7340
|
+
return refuse40("iyzico_body_unsupported");
|
|
7341
|
+
const card = value.paymentCard;
|
|
7342
|
+
if (record34(card) && (own15(card, "cardToken") || own15(card, "ucsToken") || own15(card, "consumerToken")) && !own15(card, "cardNumber"))
|
|
7343
|
+
return refuse40("iyzico_saved_card");
|
|
7344
|
+
if (own15(value, "dccPayment") || own15(value, "dccQueryRrn"))
|
|
7345
|
+
return refuse40("iyzico_dcc_refused");
|
|
7346
|
+
if (own15(value, "gsmNumber") || own15(value, "buyerProtected") && value.buyerProtected !== false || record34(card) && (own15(card, "registerCard") && card.registerCard !== 0 || own15(card, "registerConsumerCard") && card.registerConsumerCard !== false)) {
|
|
7347
|
+
return refuse40("iyzico_keeps_card");
|
|
7348
|
+
}
|
|
7349
|
+
if (Number.isSafeInteger(value.installment) && value.installment > 1)
|
|
7350
|
+
return refuse40("iyzico_installments_refused");
|
|
7351
|
+
if (!inOrder7(value, IYZICO_BODY_KEYS) || !["installment", "paidPrice", "paymentChannel", "paymentCard"].every((key) => own15(value, key)) || value.installment !== 1 || hundredths(value.paidPrice) === null || !CHANNELS.includes(value.paymentChannel) || own15(value, "pwiMetadata") && !metadata(value.pwiMetadata))
|
|
7352
|
+
return refuse40("iyzico_body_unsupported");
|
|
7353
|
+
if (!record34(card) || Object.keys(card).join() !== IYZICO_CARD_KEYS.join() || typeof card.cardNumber !== "string" || !CARD_NUMBER20.test(card.cardNumber) || !holderName2(card.cardHolderName) || typeof card.expireYear !== "string" || !YEAR21.test(card.expireYear) || typeof card.expireMonth !== "string" || !MONTH20.test(card.expireMonth) || typeof card.cvc !== "string" || !SECURITY_CODE24.test(card.cvc))
|
|
7354
|
+
return refuse40("iyzico_body_unsupported");
|
|
7355
|
+
return CARD40;
|
|
7356
|
+
}
|
|
7357
|
+
var iyzico_default = /* @__PURE__ */ registerProcessor({
|
|
7358
|
+
psp: IYZICO_PSP,
|
|
7359
|
+
definitions: [
|
|
7360
|
+
{
|
|
7361
|
+
psp: "iyzico",
|
|
7362
|
+
// The Checkout Form's card payment, as the header above reads it. Sandbox has its own host, so the device sends
|
|
7363
|
+
// a test-mode payment only iyzico's documented test cards (hostEnvironmentPinned, device-replay.js S7). Ships dark:
|
|
7364
|
+
// served only to a client that declares `iyzico_checkout_form`, for a company the backend's gate turns iyzico on
|
|
7365
|
+
// for, and autopilot never sends it.
|
|
7366
|
+
capability: "iyzico_checkout_form",
|
|
7367
|
+
match: "(?:sandbox-)?api\\.iyzipay\\.com/payment/iyzipos/checkoutform/(?:auth|initialize3ds)/ecom",
|
|
7368
|
+
hosts: ["^api\\.iyzipay\\.com$", "^sandbox-api\\.iyzipay\\.com$"],
|
|
7369
|
+
sandboxHosts: ["^sandbox-api\\.iyzipay\\.com$"],
|
|
7370
|
+
hostEnvironmentPinned: true,
|
|
7371
|
+
encoding: "json",
|
|
7372
|
+
// The form's session token and its Accept. Origin, Referer and cookies never ride, and neither does IYZI_LC,
|
|
7373
|
+
// which iyzico's preflight does not allow.
|
|
7374
|
+
passthroughHeaders: ["^x-iyzi-token$", "^accept$"],
|
|
7375
|
+
jsonCardFields: [["paymentCard", "cardNumber"]]
|
|
7376
|
+
}
|
|
7377
|
+
],
|
|
7378
|
+
// Only the cardholder's device sends it, after a person approves; 3-D Secure needs that person at the browser.
|
|
7379
|
+
refusedOperations: [IYZICO_OPERATION],
|
|
7380
|
+
// iyzico answers the form's result (CF retrieve) only to the merchant's API key and secret.
|
|
7381
|
+
settlementReadback: {
|
|
7382
|
+
answer: "none",
|
|
7383
|
+
reason: "merchant_credential_required",
|
|
7384
|
+
note: "The processor answers a payment result only to the server credentials of the shop; the intercepted request carries a checkout reference and no credential.",
|
|
7385
|
+
source: "https://docs.iyzico.com/en/payment-methods/checkoutform/cf-implementation/cf-retrieve"
|
|
7386
|
+
},
|
|
7387
|
+
exactUrl: isIyzicoCardUrl,
|
|
7388
|
+
bodyGate: (url, body) => url !== void 0 && !isIyzicoCardUrl(url) ? refuse40("iyzico_url_refused") : iyzicoBodyVerdict(body)
|
|
7389
|
+
});
|
|
7390
|
+
// src/processors/midtrans.js
|
|
7391
|
+
var MIDTRANS_PSP = "midtrans";
|
|
7392
|
+
var MIDTRANS_OPERATION = "midtrans.card_request";
|
|
7393
|
+
var MIDTRANS_TOKEN_URL = "https://api.midtrans.com/v2/token";
|
|
7394
|
+
var MIDTRANS_SANDBOX_TOKEN_URL = "https://api.sandbox.midtrans.com/v2/token";
|
|
7395
|
+
var MIDTRANS_TOKEN_KEYS = /* @__PURE__ */ Object.freeze(["card_cvv", "card_number", "card_exp_month", "card_exp_year", "installment_term"]);
|
|
7396
|
+
var BODY_LIMIT39 = 4096;
|
|
7397
|
+
var CARD_NUMBER21 = /^[0-9]{12,19}$/;
|
|
7398
|
+
var SECURITY_CODE25 = /^[0-9]{3,4}$/;
|
|
7399
|
+
var MONTH21 = /^(?:0[1-9]|1[0-2])$/;
|
|
7400
|
+
var YEAR22 = /^20[0-9]{2}$/;
|
|
7401
|
+
var TERM = /^[0-9]{1,3}$/;
|
|
7402
|
+
var record35 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7403
|
+
var own16 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
7404
|
+
var inOrder8 = (value, keys) => {
|
|
7405
|
+
let at = 0;
|
|
7406
|
+
for (const name of Object.keys(value)) {
|
|
7407
|
+
while (at < keys.length && keys[at] !== name)
|
|
7408
|
+
at += 1;
|
|
7409
|
+
if (at === keys.length)
|
|
7410
|
+
return false;
|
|
7411
|
+
at += 1;
|
|
7412
|
+
}
|
|
7413
|
+
return true;
|
|
7414
|
+
};
|
|
7415
|
+
var refuse41 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
7416
|
+
var CARD41 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
7417
|
+
function isMidtransTokenUrl(url) {
|
|
7418
|
+
return url === MIDTRANS_TOKEN_URL || url === MIDTRANS_SANDBOX_TOKEN_URL;
|
|
7419
|
+
}
|
|
7420
|
+
function readBody25(body) {
|
|
7421
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT39)
|
|
7422
|
+
return null;
|
|
7423
|
+
let value;
|
|
7424
|
+
try {
|
|
7425
|
+
value = JSON.parse(body);
|
|
7426
|
+
if (!record35(value) || JSON.stringify(value) !== body)
|
|
7427
|
+
return null;
|
|
7428
|
+
}
|
|
7429
|
+
catch {
|
|
7430
|
+
return null;
|
|
7431
|
+
}
|
|
7432
|
+
return value;
|
|
7433
|
+
}
|
|
7434
|
+
function midtransBodyVerdict(body) {
|
|
7435
|
+
const value = readBody25(body);
|
|
7436
|
+
if (value === null || !inOrder8(value, MIDTRANS_TOKEN_KEYS)) {
|
|
7437
|
+
if (record35(value) && (own16(value, "token_id") || own16(value, "two_click")) && !own16(value, "card_number"))
|
|
7438
|
+
return refuse41("midtrans_saved_card");
|
|
7439
|
+
return refuse41("midtrans_body_unsupported");
|
|
7440
|
+
}
|
|
7441
|
+
if (!own16(value, "card_cvv") || !own16(value, "card_number") || !own16(value, "card_exp_month") || !own16(value, "card_exp_year")) {
|
|
7442
|
+
return refuse41("midtrans_body_unsupported");
|
|
7443
|
+
}
|
|
7444
|
+
if (typeof value.card_cvv !== "string" || !SECURITY_CODE25.test(value.card_cvv) || typeof value.card_number !== "string" || !CARD_NUMBER21.test(value.card_number) || typeof value.card_exp_month !== "string" || !MONTH21.test(value.card_exp_month) || typeof value.card_exp_year !== "string" || !YEAR22.test(value.card_exp_year))
|
|
7445
|
+
return refuse41("midtrans_body_unsupported");
|
|
7446
|
+
if (own16(value, "installment_term") && (typeof value.installment_term !== "string" || !TERM.test(value.installment_term)))
|
|
7447
|
+
return refuse41("midtrans_body_unsupported");
|
|
7448
|
+
return CARD41;
|
|
7449
|
+
}
|
|
7450
|
+
var midtrans_default = /* @__PURE__ */ registerProcessor({
|
|
7451
|
+
psp: MIDTRANS_PSP,
|
|
7452
|
+
definitions: [
|
|
7453
|
+
{
|
|
7454
|
+
psp: "midtrans",
|
|
7455
|
+
// Snap's token request, as the header above reads it. Sandbox has its own host, so the device sends a
|
|
7456
|
+
// test-mode request only Midtrans' documented test cards (hostEnvironmentPinned, device-replay.js S7).
|
|
7457
|
+
// Ships dark: served only to a client that declares `midtrans_card_token`, gated off for every org until an
|
|
7458
|
+
// operator lists one (`midtrans:<org>`), and the backend's gate serves only Agentcard's own company until the
|
|
7459
|
+
// token's publishable key is bound to the merchant (backend config.ts MIDTRANS_KEY_BOUND_TO_MERCHANT).
|
|
7460
|
+
capability: "midtrans_card_token",
|
|
7461
|
+
match: "api\\.(?:sandbox\\.)?midtrans\\.com/v2/token",
|
|
7462
|
+
hosts: ["^api\\.midtrans\\.com$", "^api\\.sandbox\\.midtrans\\.com$"],
|
|
7463
|
+
sandboxHosts: ["^api\\.sandbox\\.midtrans\\.com$"],
|
|
7464
|
+
hostEnvironmentPinned: true,
|
|
7465
|
+
encoding: "json",
|
|
7466
|
+
// Snap's own headers: the publishable client key (Authorization Basic) and X-Service. Origin, Referer and
|
|
7467
|
+
// cookies never ride.
|
|
7468
|
+
passthroughHeaders: ["^authorization$", "^x-service$"],
|
|
7469
|
+
jsonCardFields: [["card_number"]]
|
|
7470
|
+
}
|
|
7471
|
+
],
|
|
7472
|
+
// Only the cardholder's device sends a token, after a person approves; no reviewed list names midtrans.
|
|
7473
|
+
refusedOperations: [MIDTRANS_OPERATION],
|
|
7474
|
+
// Not surveyed: the token moves no money, and the merchant's own charge names its status by the order id alone.
|
|
7475
|
+
settlementReadback: "not_surveyed",
|
|
7476
|
+
exactUrl: isMidtransTokenUrl,
|
|
7477
|
+
bodyGate: (url, body) => url !== void 0 && !isMidtransTokenUrl(url) ? { verdict: "refuse", code: "midtrans_url_refused" } : midtransBodyVerdict(body)
|
|
7478
|
+
});
|
|
7479
|
+
// src/processors/monei.js
|
|
7480
|
+
var MONEI_PSP = "monei";
|
|
7481
|
+
var MONEI_OPERATION = "monei.card_request";
|
|
7482
|
+
var MONEI_TOKENS_URL = "https://api.monei.com/v1/tokens";
|
|
7483
|
+
var BODY_LIMIT40 = 1024;
|
|
7484
|
+
var PAYMENT_ID = /^(?:[0-9a-f]{32}|[0-9a-f]{40})$/;
|
|
7485
|
+
var MONEI_CARD_KEYS = /* @__PURE__ */ Object.freeze(["number", "expMonth", "expYear", "cvc"]);
|
|
7486
|
+
var NUMBER8 = /^[0-9]{12,19}$/;
|
|
7487
|
+
var MONTH22 = /^(?:0[1-9]|1[0-2])$/;
|
|
7488
|
+
var YEAR23 = /^[0-9]{2}$/;
|
|
7489
|
+
var CODE8 = /^[0-9]{3,4}$/;
|
|
7490
|
+
var record36 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7491
|
+
var keysAre2 = (value, keys) => {
|
|
7492
|
+
const found = Object.keys(value);
|
|
7493
|
+
return found.length === keys.length && found.every((key, at) => key === keys[at]);
|
|
7494
|
+
};
|
|
7495
|
+
var refuse42 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
7496
|
+
var CARD42 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
7497
|
+
function luhn10(digits4) {
|
|
7498
|
+
let sum = 0;
|
|
7499
|
+
for (let at = 0; at < digits4.length; at += 1) {
|
|
7500
|
+
let digit = Number(digits4[digits4.length - 1 - at]);
|
|
7501
|
+
if (at % 2 === 1) {
|
|
7502
|
+
digit *= 2;
|
|
7503
|
+
if (digit > 9)
|
|
7504
|
+
digit -= 9;
|
|
7505
|
+
}
|
|
7506
|
+
sum += digit;
|
|
7507
|
+
}
|
|
7508
|
+
return sum % 10 === 0;
|
|
7509
|
+
}
|
|
7510
|
+
function isMoneiTokensUrl(url) {
|
|
7511
|
+
return url === MONEI_TOKENS_URL;
|
|
7512
|
+
}
|
|
7513
|
+
function readBody26(body) {
|
|
7514
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT40)
|
|
7515
|
+
return null;
|
|
7516
|
+
try {
|
|
7517
|
+
const value = JSON.parse(body);
|
|
7518
|
+
return record36(value) && JSON.stringify(value) === body ? value : null;
|
|
7519
|
+
}
|
|
7520
|
+
catch {
|
|
7521
|
+
return null;
|
|
7522
|
+
}
|
|
7523
|
+
}
|
|
7524
|
+
function moneiBodyVerdict(body, url) {
|
|
7525
|
+
if (url !== void 0 && !isMoneiTokensUrl(url))
|
|
7526
|
+
return refuse42("monei_url_refused");
|
|
7527
|
+
const value = readBody26(body);
|
|
7528
|
+
if (value === null || !keysAre2(value, ["paymentId", "paymentMethod"]) || typeof value.paymentId !== "string" || !PAYMENT_ID.test(value.paymentId))
|
|
7529
|
+
return refuse42("monei_body_unsupported");
|
|
7530
|
+
const method = value.paymentMethod;
|
|
7531
|
+
if (!record36(method) || !keysAre2(method, ["card"]) || !record36(method.card) || !keysAre2(method.card, MONEI_CARD_KEYS))
|
|
7532
|
+
return refuse42("monei_body_unsupported");
|
|
7533
|
+
const { number, expMonth, expYear, cvc } = method.card;
|
|
7534
|
+
if (![number, expMonth, expYear, cvc].every((part) => typeof part === "string"))
|
|
7535
|
+
return refuse42("monei_body_unsupported");
|
|
7536
|
+
if (!NUMBER8.test(number) || !luhn10(number) || !MONTH22.test(expMonth) || !YEAR23.test(expYear) || !CODE8.test(cvc))
|
|
7537
|
+
return refuse42("monei_body_unsupported");
|
|
7538
|
+
return CARD42;
|
|
7539
|
+
}
|
|
7540
|
+
var MONEI_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
7541
|
+
Object.freeze({ merchant: "Genuins", accountIds: Object.freeze(["8d58ab4c-4ad0-4053-b18f-79d80e9ee158"]), merchantUrls: Object.freeze(["https://genuins.com/"]) })
|
|
7542
|
+
]);
|
|
7543
|
+
var monei_default = /* @__PURE__ */ registerProcessor({
|
|
7544
|
+
psp: MONEI_PSP,
|
|
7545
|
+
definitions: [
|
|
7546
|
+
{
|
|
7547
|
+
psp: "monei",
|
|
7548
|
+
// The card frame's token request, as the header above reads it. One host serves test and live payments alike,
|
|
7549
|
+
// so no sandbox host is marked: MONEI's record of the payment names its mode, and the device sends a test payment
|
|
7550
|
+
// only MONEI's documented test cards (moneiDeviceRefusal). The frame sets no deadline on the fetch, so the
|
|
7551
|
+
// cardholder approves at the shopper's Pay. `(?![\w/.%-])` ends the path for a consumer that tests `match`
|
|
7552
|
+
// unanchored, and the exact-URL rule below holds the rest. Ships dark: served only to a client that declares
|
|
7553
|
+
// `monei_card_token`, and gated off for every company until the backend's gate names one.
|
|
7554
|
+
capability: "monei_card_token",
|
|
7555
|
+
match: "api\\.monei\\.com/v1/tokens(?![\\w/.%-])",
|
|
7556
|
+
hosts: ["^api\\.monei\\.com$"],
|
|
7557
|
+
encoding: "json",
|
|
7558
|
+
// The frame's two device headers. Origin, Referer and cookies never ride.
|
|
7559
|
+
passthroughHeaders: ["^x-client-env$", "^x-client-fingerprint$"],
|
|
7560
|
+
jsonCardFields: [["paymentMethod", "card", "number"]]
|
|
7561
|
+
}
|
|
7562
|
+
],
|
|
7563
|
+
// Only the cardholder's device sends a card, after a person approves; no reviewed list names monei.
|
|
7564
|
+
refusedOperations: [MONEI_OPERATION],
|
|
7565
|
+
// Not surveyed: the card request mints a token and moves no money; MONEI's confirm, which the page sends, charges it.
|
|
7566
|
+
settlementReadback: "not_surveyed",
|
|
7567
|
+
exactUrl: isMoneiTokensUrl,
|
|
7568
|
+
bodyGate: (url, body) => moneiBodyVerdict(body, url)
|
|
7569
|
+
// No amount reader: the request names none. MONEI's record of the payment names it, and the device holds that record
|
|
7570
|
+
// to the approved amount before it writes any card.
|
|
7571
|
+
});
|
|
7572
|
+
// src/processors/oceanpayment.js
|
|
7573
|
+
var OCEANPAYMENT_PSP = "oceanpayment";
|
|
7574
|
+
var OCEANPAYMENT_OPERATION = "oceanpayment.card_request";
|
|
7575
|
+
var OCEANPAYMENT_HOSTS = /* @__PURE__ */ Object.freeze({ "secure.oceanpayment.com": "production", "test-secure.oceanpayment.com": "sandbox" });
|
|
7576
|
+
var OCEANPAYMENT_FORM_FIELDS = /* @__PURE__ */ Object.freeze([
|
|
7577
|
+
"card_number_three",
|
|
7578
|
+
"card_number_two",
|
|
7579
|
+
"card_number_temp",
|
|
7580
|
+
"card_number",
|
|
7581
|
+
"card_date",
|
|
7582
|
+
"card_year",
|
|
7583
|
+
"card_month",
|
|
7584
|
+
"card_secureCode",
|
|
7585
|
+
"copyCard",
|
|
7586
|
+
"closePage",
|
|
7587
|
+
"starttime",
|
|
7588
|
+
"endtime",
|
|
7589
|
+
"comloadpage",
|
|
7590
|
+
"timezone",
|
|
7591
|
+
"OSLang",
|
|
7592
|
+
"os",
|
|
7593
|
+
"brower",
|
|
7594
|
+
"BrowerLang",
|
|
7595
|
+
"resolution",
|
|
7596
|
+
"methods",
|
|
7597
|
+
"reference_id",
|
|
7598
|
+
"methods",
|
|
7599
|
+
"reference"
|
|
7600
|
+
]);
|
|
7601
|
+
var URL_LIMIT16 = 2048;
|
|
7602
|
+
var BODY_LIMIT41 = 8192;
|
|
7603
|
+
var SEND_PAY = /^\/gateway\/sendPay;jsessionid=[A-Za-z0-9._!-]{16,128}$/;
|
|
7604
|
+
var own17 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
7605
|
+
var exact4 = (pattern, value) => typeof value === "string" && pattern.test(value);
|
|
7606
|
+
var CARD_RUN = /[0-9]{12}/;
|
|
7607
|
+
var printable5 = (max) => (value) => typeof value === "string" && value.length <= max && /^[\x20-\x7e]*$/.test(value) && !CARD_RUN.test(value);
|
|
7608
|
+
var STAMP = /^(?:|20[0-9]{2}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01]) (?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\.[0-9]{3})$/;
|
|
7609
|
+
var LANGUAGE4 = /^(?:|[A-Za-z]{2,8}(?:[-_][A-Za-z0-9]{1,8}){0,3})$/;
|
|
7610
|
+
var SHAPES2 = /* @__PURE__ */ new Map([
|
|
7611
|
+
["customerCardType", (v) => v === ""],
|
|
7612
|
+
// The page's paste and typing markers: "0" until typed, the number's length when its key handler read it, or "N"
|
|
7613
|
+
// after a paste.
|
|
7614
|
+
["card_number_three", (v) => exact4(/^(?:0|N|[1-9]|1[0-9])$/, v)],
|
|
7615
|
+
["card_number_two", (v) => exact4(/^(?:0|[1-9]|1[0-9])$/, v)],
|
|
7616
|
+
["card_number_temp", (v) => exact4(/^[0-9]{4}(?: ?[0-9]{4}){3}$/, v)],
|
|
7617
|
+
["card_number", (v) => exact4(/^[0-9]{16}$/, v)],
|
|
7618
|
+
["card_date", (v) => exact4(/^(?:0[1-9]|1[0-2])\/[0-9]{2}$/, v)],
|
|
7619
|
+
["card_year", (v) => exact4(/^20[0-9]{2}$/, v)],
|
|
7620
|
+
["card_month", (v) => exact4(/^(?:0[1-9]|1[0-2])$/, v)],
|
|
7621
|
+
["card_secureCode", (v) => exact4(/^[0-9]{3,4}$/, v)],
|
|
7622
|
+
["copyCard", (v) => v === "" || v === "0" || v === "1"],
|
|
7623
|
+
// PAY NOW's handler sets it to 1 before the page submits.
|
|
7624
|
+
["closePage", (v) => v === "1"],
|
|
7625
|
+
["starttime", (v) => exact4(STAMP, v)],
|
|
7626
|
+
["endtime", (v) => exact4(STAMP, v)],
|
|
7627
|
+
["comloadpage", (v) => v === "0" || v === "1"],
|
|
7628
|
+
// getTimezoneOffset()/60*-1: whole or fractional hours.
|
|
7629
|
+
["timezone", (v) => exact4(/^(?:|-?(?:[0-9]|1[0-4])(?:\.[0-9]{1,2})?)$/, v)],
|
|
7630
|
+
["OSLang", (v) => exact4(LANGUAGE4, v)],
|
|
7631
|
+
["os", printable5(64)],
|
|
7632
|
+
["brower", printable5(128)],
|
|
7633
|
+
["BrowerLang", (v) => exact4(LANGUAGE4, v)],
|
|
7634
|
+
["resolution", printable5(32)],
|
|
7635
|
+
["methods", (v) => v === "1"],
|
|
7636
|
+
["reference_id", (v) => v === ""],
|
|
7637
|
+
// The page's own trade number.
|
|
7638
|
+
["reference", (v) => exact4(/^[0-9]{1,40}$/, v)],
|
|
7639
|
+
["button", (v) => v === ""]
|
|
7640
|
+
]);
|
|
7641
|
+
function oceanpaymentSendPayUrl(url) {
|
|
7642
|
+
if (typeof url !== "string" || url.length > URL_LIMIT16 || url.includes("?") || url.includes("#"))
|
|
7643
|
+
return null;
|
|
7644
|
+
let parsed;
|
|
7645
|
+
try {
|
|
7646
|
+
parsed = new URL(url);
|
|
7647
|
+
}
|
|
7648
|
+
catch {
|
|
7649
|
+
return null;
|
|
7650
|
+
}
|
|
7651
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own17(OCEANPAYMENT_HOSTS, parsed.hostname) || !SEND_PAY.test(parsed.pathname))
|
|
7652
|
+
return null;
|
|
7653
|
+
return Object.freeze({ host: parsed.hostname, environment: OCEANPAYMENT_HOSTS[parsed.hostname] });
|
|
7654
|
+
}
|
|
7655
|
+
var isOceanpaymentSendPayUrl = (url) => oceanpaymentSendPayUrl(url) !== null;
|
|
7656
|
+
function formEncode3(value) {
|
|
7657
|
+
let encoded;
|
|
7658
|
+
try {
|
|
7659
|
+
encoded = encodeURIComponent(value);
|
|
7660
|
+
}
|
|
7661
|
+
catch {
|
|
7662
|
+
return null;
|
|
7663
|
+
}
|
|
7664
|
+
return encoded.replace(/[!'()~]/g, (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase()}`).replace(/%20/g, "+");
|
|
7665
|
+
}
|
|
7666
|
+
function formDecode2(raw) {
|
|
7667
|
+
if (!/^(?:[A-Za-z0-9*._+-]|%[0-9A-F]{2})*$/.test(raw))
|
|
7668
|
+
return null;
|
|
7669
|
+
let value;
|
|
7670
|
+
try {
|
|
7671
|
+
value = decodeURIComponent(raw.replace(/\+/g, "%20"));
|
|
7672
|
+
}
|
|
7673
|
+
catch {
|
|
7674
|
+
return null;
|
|
7675
|
+
}
|
|
7676
|
+
return formEncode3(value) === raw ? value : null;
|
|
7677
|
+
}
|
|
7678
|
+
function readPairs2(body) {
|
|
7679
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT41)
|
|
7680
|
+
return null;
|
|
7681
|
+
const pairs = [];
|
|
7682
|
+
for (const chunk of body.split("&")) {
|
|
7683
|
+
const separator = chunk.indexOf("=");
|
|
7684
|
+
if (separator < 1)
|
|
7685
|
+
return null;
|
|
7686
|
+
const rawName = chunk.slice(0, separator), raw = chunk.slice(separator + 1);
|
|
7687
|
+
const name = formDecode2(rawName), value = formDecode2(raw);
|
|
7688
|
+
if (name === null || value === null)
|
|
7689
|
+
return null;
|
|
7690
|
+
pairs.push({ name, rawName, raw, value });
|
|
7691
|
+
}
|
|
7692
|
+
return pairs;
|
|
7693
|
+
}
|
|
7694
|
+
function formPairs(body) {
|
|
7695
|
+
const pairs = readPairs2(body);
|
|
7696
|
+
if (!pairs)
|
|
7697
|
+
return null;
|
|
7698
|
+
const start = pairs[0].name === "customerCardType" ? 1 : 0;
|
|
7699
|
+
const end = pairs[pairs.length - 1].name === "button" ? pairs.length - 1 : pairs.length;
|
|
7700
|
+
if (end - start !== OCEANPAYMENT_FORM_FIELDS.length || OCEANPAYMENT_FORM_FIELDS.some((name, i) => pairs[start + i].name !== name))
|
|
7701
|
+
return null;
|
|
7702
|
+
return pairs;
|
|
7703
|
+
}
|
|
7704
|
+
var valueOf = (pairs, name) => pairs.find((pair) => pair.name === name)?.value;
|
|
7705
|
+
function bodyRefusal(body) {
|
|
7706
|
+
const pairs = formPairs(body);
|
|
7707
|
+
if (!pairs)
|
|
7708
|
+
return "oceanpayment_body_unsupported";
|
|
7709
|
+
if (pairs[0].name === "customerCardType" && pairs[0].value !== "")
|
|
7710
|
+
return "oceanpayment_card_brand_refused";
|
|
7711
|
+
if (valueOf(pairs, "reference_id") !== "")
|
|
7712
|
+
return "oceanpayment_device_data_refused";
|
|
7713
|
+
if (pairs.some(({ name, value }) => !SHAPES2.get(name)(value)))
|
|
7714
|
+
return "oceanpayment_body_unsupported";
|
|
7715
|
+
const number = valueOf(pairs, "card_number");
|
|
7716
|
+
const temp = valueOf(pairs, "card_number_temp");
|
|
7717
|
+
const [month, year] = valueOf(pairs, "card_date").split("/");
|
|
7718
|
+
if (temp.replace(/ /g, "") !== number || temp !== number && temp !== spaced(number))
|
|
7719
|
+
return "oceanpayment_body_unsupported";
|
|
7720
|
+
if (valueOf(pairs, "card_month") !== month || valueOf(pairs, "card_year") !== `20${year}`)
|
|
7721
|
+
return "oceanpayment_body_unsupported";
|
|
7722
|
+
return null;
|
|
7723
|
+
}
|
|
7724
|
+
var spaced = (number) => number.replace(/([0-9]{4})(?=[0-9])/g, "$1 ");
|
|
7725
|
+
function oceanpaymentBodyVerdict(body) {
|
|
7726
|
+
const code = bodyRefusal(body);
|
|
7727
|
+
return code ? Object.freeze({ verdict: "refuse", code }) : Object.freeze({ verdict: "card" });
|
|
7728
|
+
}
|
|
7729
|
+
var oceanpayment_default = /* @__PURE__ */ registerProcessor({
|
|
7730
|
+
psp: OCEANPAYMENT_PSP,
|
|
7731
|
+
definitions: [
|
|
7732
|
+
{
|
|
7733
|
+
psp: "oceanpayment",
|
|
7734
|
+
// The hosted page's card post, as the header above reads it. The sandbox has its own host, so a test row's device
|
|
7735
|
+
// sends only Oceanpayment's documented test cards (hostEnvironmentPinned, device-replay.js S7).
|
|
7736
|
+
// Ships dark: served only to a client that declares `oceanpayment_hosted_payment_page`, and only for a company the
|
|
7737
|
+
// backend's processor gate turns Oceanpayment on for. `(?![\w/.%;=!-])` ends the path for a consumer that tests
|
|
7738
|
+
// `match` unanchored.
|
|
7739
|
+
capability: "oceanpayment_hosted_payment_page",
|
|
7740
|
+
match: "(?:test-)?secure\\.oceanpayment\\.com/gateway/sendPay;jsessionid=[A-Za-z0-9._!-]{16,128}(?![\\w/.%;=!-])",
|
|
7741
|
+
hosts: ["^secure\\.oceanpayment\\.com$", "^test-secure\\.oceanpayment\\.com$"],
|
|
7742
|
+
sandboxHosts: ["^test-secure\\.oceanpayment\\.com$"],
|
|
7743
|
+
hostEnvironmentPinned: true,
|
|
7744
|
+
encoding: "form",
|
|
7745
|
+
// A form navigation: nothing but its type is replayed. Origin, Referer and cookies never ride.
|
|
7746
|
+
passthroughHeaders: [],
|
|
7747
|
+
cardFields: ["card_number"]
|
|
7748
|
+
}
|
|
7749
|
+
],
|
|
7750
|
+
// Only the cardholder's device sends this card, after a person approves; no reviewed list names oceanpayment.
|
|
7751
|
+
refusedOperations: [OCEANPAYMENT_OPERATION],
|
|
7752
|
+
// Not surveyed: Oceanpayment tells the merchant's server the result (its noticeUrl), and reading a payment back takes the
|
|
7753
|
+
// merchant's own secure code, which Agentcard never holds.
|
|
7754
|
+
settlementReadback: "not_surveyed",
|
|
7755
|
+
exactUrl: isOceanpaymentSendPayUrl,
|
|
7756
|
+
bodyGate: (url, body) => url !== void 0 && !isOceanpaymentSendPayUrl(url) ? Object.freeze({ verdict: "refuse", code: "oceanpayment_url_refused" }) : oceanpaymentBodyVerdict(body)
|
|
7757
|
+
// No amount reader: the post names none, so the agent's pair is the figure the cardholder approves.
|
|
7758
|
+
});
|
|
7759
|
+
// src/processors/paymentwall.js
|
|
7760
|
+
var PAYMENTWALL_PSP = "paymentwall";
|
|
7761
|
+
var PAYMENTWALL_OPERATION = "paymentwall.card_request";
|
|
7762
|
+
var PAYMENTWALL_TOKEN_URL = "https://pwgateway.com/api/token";
|
|
7763
|
+
var PAYMENTWALL_SANDBOX_TOKEN_URL = "https://api.paymentwall.com/api/brick/token";
|
|
7764
|
+
var BODY_LIMIT42 = 2048;
|
|
7765
|
+
var KEY3 = "public_key";
|
|
7766
|
+
var PUBLIC_KEY2 = /^(?:t_)?[A-Za-z0-9]{16,64}$/;
|
|
7767
|
+
var SHAPES3 = /* @__PURE__ */ Object.freeze({
|
|
7768
|
+
[KEY3]: PUBLIC_KEY2,
|
|
7769
|
+
"card[number]": /^[0-9]{12,19}$/,
|
|
7770
|
+
"card[exp_month]": /^(?:0?[1-9]|1[0-2])$/,
|
|
7771
|
+
"card[exp_year]": /^(?:[0-9]{2}|20[0-9]{2})$/,
|
|
7772
|
+
"card[cvv]": /^[0-9]{3,4}$/
|
|
7773
|
+
});
|
|
7774
|
+
var refuse43 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
7775
|
+
var CARD43 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
7776
|
+
function luhn11(digits4) {
|
|
7777
|
+
let sum = 0;
|
|
7778
|
+
for (let at = 0; at < digits4.length; at += 1) {
|
|
7779
|
+
let digit = Number(digits4[digits4.length - 1 - at]);
|
|
7780
|
+
if (at % 2 === 1) {
|
|
7781
|
+
digit *= 2;
|
|
7782
|
+
if (digit > 9)
|
|
7783
|
+
digit -= 9;
|
|
7784
|
+
}
|
|
7785
|
+
sum += digit;
|
|
7786
|
+
}
|
|
7787
|
+
return sum % 10 === 0;
|
|
7788
|
+
}
|
|
7789
|
+
function paymentwallUrlEnvironment(url) {
|
|
7790
|
+
if (url === PAYMENTWALL_TOKEN_URL)
|
|
7791
|
+
return "production";
|
|
7792
|
+
return url === PAYMENTWALL_SANDBOX_TOKEN_URL ? "sandbox" : null;
|
|
7793
|
+
}
|
|
7794
|
+
function isPaymentwallTokenUrl(url) {
|
|
7795
|
+
return paymentwallUrlEnvironment(url) !== null;
|
|
7796
|
+
}
|
|
7797
|
+
function paymentwallKeyEnvironment(publicKey) {
|
|
7798
|
+
if (typeof publicKey !== "string" || !PUBLIC_KEY2.test(publicKey))
|
|
7799
|
+
return null;
|
|
7800
|
+
return publicKey.startsWith("t_") ? "sandbox" : "production";
|
|
7801
|
+
}
|
|
7802
|
+
function readPairs3(body) {
|
|
7803
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT42 || !/^[A-Za-z0-9_[\]=&]+$/.test(body))
|
|
7804
|
+
return null;
|
|
7805
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
7806
|
+
for (const chunk of body.split("&")) {
|
|
7807
|
+
const eq = chunk.indexOf("=");
|
|
7808
|
+
if (eq <= 0 || chunk.indexOf("=", eq + 1) !== -1)
|
|
7809
|
+
return null;
|
|
7810
|
+
const key = chunk.slice(0, eq);
|
|
7811
|
+
if (pairs.has(key))
|
|
7812
|
+
return null;
|
|
7813
|
+
pairs.set(key, chunk.slice(eq + 1));
|
|
7814
|
+
}
|
|
7815
|
+
return pairs;
|
|
7816
|
+
}
|
|
7817
|
+
function paymentwallBodyVerdict(body, url) {
|
|
7818
|
+
if (url !== void 0 && !isPaymentwallTokenUrl(url))
|
|
7819
|
+
return refuse43("paymentwall_url_refused");
|
|
7820
|
+
const pairs = readPairs3(body);
|
|
7821
|
+
if (pairs === null)
|
|
7822
|
+
return refuse43("paymentwall_body_unsupported");
|
|
7823
|
+
if (pairs.has("card[token]") && !pairs.has("card[number]"))
|
|
7824
|
+
return refuse43("paymentwall_saved_card");
|
|
7825
|
+
const keys = Object.keys(SHAPES3);
|
|
7826
|
+
if (pairs.size !== keys.length || !keys.every((key) => pairs.has(key) && SHAPES3[key].test(pairs.get(key)))) {
|
|
7827
|
+
return refuse43("paymentwall_body_unsupported");
|
|
7828
|
+
}
|
|
7829
|
+
if (!luhn11(pairs.get("card[number]")))
|
|
7830
|
+
return refuse43("paymentwall_body_unsupported");
|
|
7831
|
+
if (url !== void 0 && paymentwallKeyEnvironment(pairs.get(KEY3)) !== paymentwallUrlEnvironment(url))
|
|
7832
|
+
return refuse43("paymentwall_key_refused");
|
|
7833
|
+
return CARD43;
|
|
7834
|
+
}
|
|
7835
|
+
var paymentwall_default = /* @__PURE__ */ registerProcessor({
|
|
7836
|
+
psp: PAYMENTWALL_PSP,
|
|
7837
|
+
definitions: [
|
|
7838
|
+
{
|
|
7839
|
+
psp: "paymentwall",
|
|
7840
|
+
// Brick's token request, as the header above reads it. A test key's request has its own host, so the device sends
|
|
7841
|
+
// it only Paymentwall's documented test cards (hostEnvironmentPinned, device-replay.js S7). Ships dark: served only
|
|
7842
|
+
// to a client that declares `paymentwall_card_token`, for a company the backend's gate turns it on for
|
|
7843
|
+
// (checkout-processor-gate.ts), and the device sends a live card only under a key a reviewed pin names.
|
|
7844
|
+
capability: "paymentwall_card_token",
|
|
7845
|
+
match: "(?:pwgateway\\.com/api/token|api\\.paymentwall\\.com/api/brick/token)",
|
|
7846
|
+
hosts: ["^pwgateway\\.com$", "^api\\.paymentwall\\.com$"],
|
|
7847
|
+
sandboxHosts: ["^api\\.paymentwall\\.com$"],
|
|
7848
|
+
hostEnvironmentPinned: true,
|
|
7849
|
+
encoding: "form",
|
|
7850
|
+
// Brick's XHR sets the form Content-Type alone, and that always rides. Origin, Referer and cookies never do.
|
|
7851
|
+
passthroughHeaders: [],
|
|
7852
|
+
cardFields: ["card[number]"]
|
|
7853
|
+
}
|
|
7854
|
+
],
|
|
7855
|
+
// Only the cardholder's device sends a card request, after a person approves; no reviewed list names paymentwall.
|
|
7856
|
+
refusedOperations: [PAYMENTWALL_OPERATION],
|
|
7857
|
+
// Not surveyed: the token moves no money, and the charge that spends it happens out of this request.
|
|
7858
|
+
settlementReadback: "not_surveyed",
|
|
7859
|
+
exactUrl: isPaymentwallTokenUrl,
|
|
7860
|
+
bodyGate: (url, body) => paymentwallBodyVerdict(body, url)
|
|
7861
|
+
});
|
|
7862
|
+
// src/processors/payplug.js
|
|
7863
|
+
var PAYPLUG_PSP = "payplug";
|
|
7864
|
+
var PAYPLUG_OPERATION = "payplug.hosted_sale";
|
|
7865
|
+
var PAYPLUG_HOST = "secure.payplug.com";
|
|
7866
|
+
var ENTRY_PATH = /^\/pay\/(?:(test)\/)?([A-Za-z0-9]{22})$/;
|
|
7867
|
+
var MAX_URL3 = 256;
|
|
7868
|
+
var field4 = (name, reason) => ({ ok: false, code: "hosted_form_field_refused", field: name, reason });
|
|
7869
|
+
function payplugEntry(raw) {
|
|
7870
|
+
if (typeof raw !== "string" || raw.length > MAX_URL3 || raw.includes("?") || raw.includes("#"))
|
|
7871
|
+
return null;
|
|
7872
|
+
let url;
|
|
7873
|
+
try {
|
|
7874
|
+
url = new URL(raw);
|
|
7875
|
+
}
|
|
7876
|
+
catch {
|
|
7877
|
+
return null;
|
|
7878
|
+
}
|
|
7879
|
+
if (url.href !== raw || url.protocol !== "https:" || url.hostname !== PAYPLUG_HOST || url.port || url.username || url.password)
|
|
7880
|
+
return null;
|
|
7881
|
+
const match = ENTRY_PATH.exec(url.pathname);
|
|
7882
|
+
return match ? Object.freeze({ id: match[2], test: match[1] === "test" }) : null;
|
|
7883
|
+
}
|
|
7884
|
+
function isPayplugEntryUrl(raw) {
|
|
7885
|
+
return payplugEntry(raw) !== null;
|
|
7886
|
+
}
|
|
7887
|
+
var PAYPLUG_MERCHANTS = Object.freeze([
|
|
7888
|
+
Object.freeze({ merchant: "Lazartigue", origins: Object.freeze(["https://lazartigue.com"]), payee: null, account: null })
|
|
7889
|
+
]);
|
|
7890
|
+
var ACCOUNT_ID = /^[A-Za-z0-9-]{1,64}$/;
|
|
7891
|
+
function payplugMerchant(checkoutOrigin, merchants = PAYPLUG_MERCHANTS) {
|
|
7892
|
+
if (typeof checkoutOrigin !== "string" || checkoutOrigin.length > MAX_URL3 || !Array.isArray(merchants))
|
|
7893
|
+
return null;
|
|
7894
|
+
let url;
|
|
7895
|
+
try {
|
|
7896
|
+
url = new URL(checkoutOrigin);
|
|
7897
|
+
}
|
|
7898
|
+
catch {
|
|
7899
|
+
return null;
|
|
7900
|
+
}
|
|
7901
|
+
if (url.protocol !== "https:" || url.origin !== checkoutOrigin || url.port)
|
|
7902
|
+
return null;
|
|
7903
|
+
const found = merchants.filter((row) => !!row && typeof row.merchant === "string" && row.merchant.trim() !== "" && typeof row.payee === "string" && row.payee.trim() !== "" && typeof row.account === "string" && ACCOUNT_ID.test(row.account) && Array.isArray(row.origins) && row.origins.includes(checkoutOrigin));
|
|
7904
|
+
return found.length === 1 ? found[0] : null;
|
|
7905
|
+
}
|
|
7906
|
+
function checkPayplugEntry(body, { url = null, checkoutOrigin = null, merchants = PAYPLUG_MERCHANTS } = {}) {
|
|
7907
|
+
if (body !== void 0 && body !== null && body !== "")
|
|
7908
|
+
return field4("(body)", "not_an_entry");
|
|
7909
|
+
const entry = payplugEntry(url);
|
|
7910
|
+
if (!entry)
|
|
7911
|
+
return field4("(url)", "malformed_field");
|
|
7912
|
+
const seller = payplugMerchant(checkoutOrigin, merchants);
|
|
7913
|
+
if (!seller)
|
|
7914
|
+
return field4("(checkout_origin)", "seller_unreviewed");
|
|
7915
|
+
return { ok: true, pairs: [], gated: false, dedupe: [entry.id], paymentId: entry.id, sandbox: entry.test, seller };
|
|
7916
|
+
}
|
|
7917
|
+
var MAX_PAGE5 = 512 * 1024;
|
|
7918
|
+
var PAYPLUG_REFUSALS = Object.freeze(["payplug_failed", "payplug_expired", "payplug_cancelled"]);
|
|
7919
|
+
var payplug_default = /* @__PURE__ */ registerProcessor({
|
|
7920
|
+
psp: PAYPLUG_PSP,
|
|
7921
|
+
definitions: [
|
|
7922
|
+
{
|
|
7923
|
+
psp: "payplug",
|
|
7924
|
+
// The merchant's redirect to PayPlug's payment page, as the header above reads it: a Document navigation that
|
|
7925
|
+
// carries no card. The cardholder's device repeats it over the end-to-end TLS relay and pays on the page PayPlug
|
|
7926
|
+
// returns to it, and the runtime resolves the paused navigation with the hosted_form notice. Only the entry is
|
|
7927
|
+
// matched (isPayplugEntryUrl): the page's card post and its 3-D Secure steps share the host, and none of them is
|
|
7928
|
+
// the entry. Test and live payments share the host, and the entry's path says which it is. Ships dark: served
|
|
7929
|
+
// only to a client that declares `payplug_hosted_payment_page`, and the backend's gate serves only Agentcard's
|
|
7930
|
+
// own company until a reviewed merchant pays.
|
|
7931
|
+
capability: "payplug_hosted_payment_page",
|
|
7932
|
+
match: "secure\\.payplug\\.com/pay/(?:test/)?[A-Za-z0-9]{22}",
|
|
7933
|
+
hosts: ["^secure\\.payplug\\.com$"],
|
|
7934
|
+
// `encoding` describes the page's own card post, which the device makes as the page does, since the entry has no
|
|
7935
|
+
// body. No captured header is ever replayed.
|
|
7936
|
+
encoding: "form",
|
|
7937
|
+
passthroughHeaders: [],
|
|
7938
|
+
request: { method: "GET", cardIn: "none", response: "html_page" },
|
|
7939
|
+
mode: "hosted_form",
|
|
7940
|
+
hostedForm: {
|
|
7941
|
+
// The card goes into PayPlug's page on the device, never into the entry, which carries no body at all. The
|
|
7942
|
+
// entry's own rules come with this registration (hostedEntry below), so no policy is named here.
|
|
7943
|
+
cardIn: "processor_page",
|
|
7944
|
+
required: [],
|
|
7945
|
+
// The page's card inputs, by the data-payplug role its script reads them by: they carry no name, and the
|
|
7946
|
+
// script posts the card only as its ciphertext, encryptedCard.
|
|
7947
|
+
card: { number: "card_number", expiry: "card_month_year", cvc: "card_cvv" },
|
|
7948
|
+
// The payment's id in the entry's URL names the one payment the merchant created; the entry's rules read it
|
|
7949
|
+
// there (checkPayplugEntry's dedupe), since no form field holds it.
|
|
7950
|
+
dedupe: ["(paymentId)"]
|
|
7951
|
+
}
|
|
7952
|
+
}
|
|
7953
|
+
],
|
|
7954
|
+
// Only the cardholder's device repeats an entry, after a person approves; no reviewed list names payplug.
|
|
7955
|
+
refusedOperations: [PAYPLUG_OPERATION],
|
|
7956
|
+
// Not surveyed: PayPlug tells only the merchant's server the result, and the browser returns whatever it was.
|
|
7957
|
+
settlementReadback: "not_surveyed",
|
|
7958
|
+
exactUrl: isPayplugEntryUrl,
|
|
7959
|
+
hostedEntry: checkPayplugEntry,
|
|
7960
|
+
limitations: [
|
|
7961
|
+
"The paused request is the merchant's redirect to PayPlug's payment page, a GET that carries only the payment's id and no card; the cardholder's device opens that page over the end-to-end TLS relay.",
|
|
7962
|
+
"The redirect names no merchant and no amount, so Agentcard takes one only from the checkout page of a merchant it reviewed, the approval names that merchant and the amount you send, and the cardholder's device pays only a PayPlug page that names that merchant and that amount.",
|
|
7963
|
+
"PayPlug runs 3-D Secure on the card. A challenge ends the payment on the device with nothing charged.",
|
|
7964
|
+
"PayPlug sends the buyer to the merchant's return page whether the payment succeeded or not, so the browser receives a submission notice, not the processor result."
|
|
7965
|
+
]
|
|
7966
|
+
});
|
|
7967
|
+
// src/processors/paystack.js
|
|
7968
|
+
var PAYSTACK_PSP = "paystack";
|
|
7969
|
+
var PAYSTACK_OPERATION = "paystack.card_request";
|
|
7970
|
+
var PAYSTACK_CHARGE_URL = "https://standard.paystack.co/charge/";
|
|
7971
|
+
var PAYSTACK_BODY_KEYS = /* @__PURE__ */ Object.freeze([
|
|
7972
|
+
"clientdata",
|
|
7973
|
+
"last4",
|
|
7974
|
+
"trans",
|
|
7975
|
+
"access_code",
|
|
7976
|
+
"device",
|
|
7977
|
+
"offset",
|
|
7978
|
+
"remember_card",
|
|
7979
|
+
"card_holder_name",
|
|
7980
|
+
"transaction_type"
|
|
7981
|
+
]);
|
|
7982
|
+
var OPTIONAL = /* @__PURE__ */ new Set(["access_code", "card_holder_name", "transaction_type"]);
|
|
7983
|
+
var BODY_LIMIT43 = 4096;
|
|
7984
|
+
var CIPHERTEXT_BYTES2 = [62, 63, 64];
|
|
7985
|
+
var BASE646 = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
7986
|
+
var SHAPES4 = /* @__PURE__ */ Object.freeze({
|
|
7987
|
+
last4: /^[0-9]{4}$/,
|
|
7988
|
+
trans: /^[0-9]{1,20}$/,
|
|
7989
|
+
access_code: /^[A-Za-z0-9]{1,64}$/,
|
|
7990
|
+
device: /^[\x21-\x7e]{1,512}$/,
|
|
7991
|
+
offset: /^-?[0-9]{1,3}$/,
|
|
7992
|
+
remember_card: /^false$/,
|
|
7993
|
+
// A name carries no digit, so no card number can ride in it.
|
|
7994
|
+
card_holder_name: /^[^\x00-\x1f\x7f0-9]{1,128}$/u,
|
|
7995
|
+
transaction_type: /^[a-z_]{1,32}$/
|
|
7996
|
+
});
|
|
7997
|
+
var own18 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
7998
|
+
var refuse44 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
7999
|
+
function paystackFormValue(value) {
|
|
8000
|
+
return encodeURIComponent(String(value)).replace(/%20/g, "+").replace(/[!'()*~]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
8001
|
+
}
|
|
8002
|
+
function paystackFormBody(entries) {
|
|
8003
|
+
return entries.map(([key, value]) => `${paystackFormValue(key)}=${paystackFormValue(value)}`).join("&");
|
|
8004
|
+
}
|
|
8005
|
+
function isPaystackChargeUrl(url) {
|
|
8006
|
+
return url === PAYSTACK_CHARGE_URL;
|
|
8007
|
+
}
|
|
8008
|
+
function isCiphertext2(value) {
|
|
8009
|
+
if (value.length % 4 !== 0 || !BASE646.test(value))
|
|
8010
|
+
return false;
|
|
8011
|
+
let binary;
|
|
8012
|
+
try {
|
|
8013
|
+
binary = atob(value);
|
|
8014
|
+
}
|
|
8015
|
+
catch {
|
|
8016
|
+
return false;
|
|
8017
|
+
}
|
|
8018
|
+
return btoa(binary) === value && CIPHERTEXT_BYTES2.includes(binary.length);
|
|
8019
|
+
}
|
|
8020
|
+
function readForm3(body) {
|
|
8021
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT43)
|
|
8022
|
+
return null;
|
|
8023
|
+
const entries = [];
|
|
8024
|
+
for (const part of body.split("&")) {
|
|
8025
|
+
const at = part.indexOf("=");
|
|
8026
|
+
if (at <= 0)
|
|
8027
|
+
return null;
|
|
8028
|
+
try {
|
|
8029
|
+
entries.push([decodeURIComponent(part.slice(0, at).replace(/\+/g, " ")), decodeURIComponent(part.slice(at + 1).replace(/\+/g, " "))]);
|
|
8030
|
+
}
|
|
8031
|
+
catch {
|
|
8032
|
+
return null;
|
|
8033
|
+
}
|
|
8034
|
+
}
|
|
8035
|
+
return paystackFormBody(entries) === body ? entries : null;
|
|
8036
|
+
}
|
|
8037
|
+
function paystackBodyVerdict(body) {
|
|
8038
|
+
const entries = readForm3(body);
|
|
8039
|
+
if (entries === null)
|
|
8040
|
+
return refuse44("paystack_body_unsupported");
|
|
8041
|
+
const keys = entries.map(([key]) => key);
|
|
8042
|
+
if (keys.includes("subscription"))
|
|
8043
|
+
return refuse44("paystack_subscription");
|
|
8044
|
+
if (keys.includes("remember_card") && entries.find(([key]) => key === "remember_card")[1] !== "false")
|
|
8045
|
+
return refuse44("paystack_saved_card");
|
|
8046
|
+
const expected = PAYSTACK_BODY_KEYS.filter((key) => !OPTIONAL.has(key) || keys.includes(key));
|
|
8047
|
+
if (keys.length !== expected.length || keys.some((key, i) => key !== expected[i]))
|
|
8048
|
+
return refuse44("paystack_body_unsupported");
|
|
8049
|
+
const fields = Object.fromEntries(entries);
|
|
8050
|
+
if (!isCiphertext2(fields.clientdata))
|
|
8051
|
+
return refuse44("paystack_body_unsupported");
|
|
8052
|
+
for (const [key, shape] of Object.entries(SHAPES4)) {
|
|
8053
|
+
if (own18(fields, key) && !shape.test(fields[key]))
|
|
8054
|
+
return refuse44("paystack_body_unsupported");
|
|
8055
|
+
}
|
|
8056
|
+
return Object.freeze({ verdict: "card", fields: Object.freeze(fields) });
|
|
8057
|
+
}
|
|
8058
|
+
var paystack_default = /* @__PURE__ */ registerProcessor({
|
|
8059
|
+
psp: PAYSTACK_PSP,
|
|
8060
|
+
definitions: [
|
|
8061
|
+
{
|
|
8062
|
+
psp: "paystack",
|
|
8063
|
+
// The card page's charge, as the header above reads it. Live and test transactions share standard.paystack.co,
|
|
8064
|
+
// so no sandbox host is listed and no environment is pinned. Ships dark: served only to a client that declares
|
|
8065
|
+
// `paystack_pinned_key`, and only for a company the backend's processor gate turns Paystack on for.
|
|
8066
|
+
// `(?![\w/.%?#-])` ends the path for a consumer that tests `match` unanchored; the exact-URL rule takes no query.
|
|
8067
|
+
capability: "paystack_pinned_key",
|
|
8068
|
+
match: "standard\\.paystack\\.co/charge/(?![\\w/.%?#-])",
|
|
8069
|
+
hosts: ["^standard\\.paystack\\.co$"],
|
|
8070
|
+
encoding: "form",
|
|
8071
|
+
// The browser's language rides as the page sent it; Origin, Referer and cookies never do (the page sends no cookie).
|
|
8072
|
+
passthroughHeaders: ["^accept-language$"],
|
|
8073
|
+
cardFields: ["clientdata"]
|
|
8074
|
+
}
|
|
8075
|
+
],
|
|
8076
|
+
// Only the cardholder's device sends this charge, after a person approves; no reviewed list names paystack.
|
|
8077
|
+
refusedOperations: [PAYSTACK_OPERATION],
|
|
8078
|
+
// Not surveyed: reading a charge back takes the merchant's secret key, which Agentcard never holds.
|
|
8079
|
+
settlementReadback: "not_surveyed",
|
|
8080
|
+
exactUrl: isPaystackChargeUrl,
|
|
8081
|
+
bodyGate: (url, body) => url !== void 0 && !isPaystackChargeUrl(url) ? refuse44("paystack_url_refused") : paystackBodyVerdict(body),
|
|
8082
|
+
// No amount reader: the charge names none, so the agent's pair is the figure the cardholder approves.
|
|
8083
|
+
limitations: ["The charge names no merchant and no amount: Paystack's transaction binds both, so the cardholder approves the agent's figure for whichever Paystack merchant opened the checkout."]
|
|
8084
|
+
});
|
|
8085
|
+
// src/processors/processout.js
|
|
8086
|
+
var PROCESSOUT_PSP = "processout";
|
|
8087
|
+
var PROCESSOUT_OPERATION = "processout.card_request";
|
|
8088
|
+
var URL_LIMIT17 = 512;
|
|
8089
|
+
var BODY_LIMIT44 = 4096;
|
|
8090
|
+
var CARD_URL2 = /^https:\/\/api\.processout\.com\/cards\?legacyrequest=true&project_id=((?:test-)?proj_[A-Za-z0-9]{16,64})&x-Content-Type=application\/json&x-API-Version=1\.3\.0\.0&x-Authorization=Basic%20([A-Za-z0-9+/]{4,256}={0,2})$/;
|
|
8091
|
+
var PAGE_KEYS2 = /* @__PURE__ */ Object.freeze(["name", "contact", "preferred_scheme"]);
|
|
8092
|
+
var CONTACT_KEYS = /* @__PURE__ */ Object.freeze(["address1", "address2", "city", "state", "country_code", "zip"]);
|
|
8093
|
+
var DEVICE_KEYS4 = /* @__PURE__ */ Object.freeze([
|
|
8094
|
+
"request_origin",
|
|
8095
|
+
"app_color_depth",
|
|
8096
|
+
"app_language",
|
|
8097
|
+
"app_screen_height",
|
|
8098
|
+
"app_screen_width",
|
|
8099
|
+
"app_timezone_offset",
|
|
8100
|
+
"app_java_enabled"
|
|
8101
|
+
]);
|
|
8102
|
+
var PROCESSOUT_CARD_KEYS = /* @__PURE__ */ Object.freeze(["number", "exp_month", "exp_year", "cvc2"]);
|
|
8103
|
+
var BODY_KEYS3 = /* @__PURE__ */ new Set([...PAGE_KEYS2, "device", ...DEVICE_KEYS4, ...PROCESSOUT_CARD_KEYS]);
|
|
8104
|
+
var NUMBER9 = /^[0-9]{12,19}$/;
|
|
8105
|
+
var MONTH23 = /^(?:[1-9]|1[0-2])$/;
|
|
8106
|
+
var YEAR24 = /^20[0-9]{2}$/;
|
|
8107
|
+
var CODE9 = /^[0-9]{3,4}$/;
|
|
8108
|
+
var TEXT_LIMIT14 = 256;
|
|
8109
|
+
var SCHEME = /^[A-Za-z][A-Za-z0-9 _-]{0,31}$/;
|
|
8110
|
+
var LANGUAGE5 = /^[A-Za-z]{1,8}(?:-[A-Za-z0-9]{1,8}){0,4}$/;
|
|
8111
|
+
var PAN_LIKE7 = /(?:[0-9][^0-9A-Za-z]*){12,}/;
|
|
8112
|
+
var record37 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8113
|
+
var own19 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
8114
|
+
var refuse45 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
8115
|
+
var CARD44 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
8116
|
+
var BASE647 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
8117
|
+
function base64Of(text11) {
|
|
8118
|
+
let out = "";
|
|
8119
|
+
for (let at = 0; at < text11.length; at += 3) {
|
|
8120
|
+
const a = text11.charCodeAt(at);
|
|
8121
|
+
const b = at + 1 < text11.length ? text11.charCodeAt(at + 1) : NaN;
|
|
8122
|
+
const c = at + 2 < text11.length ? text11.charCodeAt(at + 2) : NaN;
|
|
8123
|
+
out += BASE647[a >> 2] + BASE647[(a & 3) << 4 | (Number.isNaN(b) ? 0 : b >> 4)] + (Number.isNaN(b) ? "=" : BASE647[(b & 15) << 2 | (Number.isNaN(c) ? 0 : c >> 6)]) + (Number.isNaN(c) ? "=" : BASE647[c & 63]);
|
|
8124
|
+
}
|
|
8125
|
+
return out;
|
|
8126
|
+
}
|
|
8127
|
+
var basicOf = (projectId) => base64Of(`${projectId}:`);
|
|
8128
|
+
function luhn12(digits4) {
|
|
8129
|
+
let sum = 0;
|
|
8130
|
+
for (let at = 0; at < digits4.length; at += 1) {
|
|
8131
|
+
let digit = Number(digits4[digits4.length - 1 - at]);
|
|
8132
|
+
if (at % 2 === 1) {
|
|
8133
|
+
digit *= 2;
|
|
8134
|
+
if (digit > 9)
|
|
8135
|
+
digit -= 9;
|
|
8136
|
+
}
|
|
8137
|
+
sum += digit;
|
|
8138
|
+
}
|
|
8139
|
+
return sum % 10 === 0;
|
|
8140
|
+
}
|
|
8141
|
+
function processoutCardTarget(url) {
|
|
8142
|
+
if (typeof url !== "string" || url.length > URL_LIMIT17)
|
|
8143
|
+
return null;
|
|
8144
|
+
const match = CARD_URL2.exec(url);
|
|
8145
|
+
if (!match || match[2] !== basicOf(match[1]))
|
|
8146
|
+
return null;
|
|
8147
|
+
return Object.freeze({ projectId: match[1], environment: match[1].startsWith("test-") ? "sandbox" : "production" });
|
|
8148
|
+
}
|
|
8149
|
+
function isProcessoutCardUrl(url) {
|
|
8150
|
+
return processoutCardTarget(url) !== null;
|
|
8151
|
+
}
|
|
8152
|
+
function readBody27(body) {
|
|
8153
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT44)
|
|
8154
|
+
return null;
|
|
8155
|
+
try {
|
|
8156
|
+
const value = JSON.parse(body);
|
|
8157
|
+
return record37(value) && JSON.stringify(value) === body ? value : null;
|
|
8158
|
+
}
|
|
8159
|
+
catch {
|
|
8160
|
+
return null;
|
|
8161
|
+
}
|
|
8162
|
+
}
|
|
8163
|
+
var pageText2 = (value) => value === null || typeof value === "string" && value.length <= TEXT_LIMIT14 && !PAN_LIKE7.test(value);
|
|
8164
|
+
var DEVICE_RULES = /* @__PURE__ */ Object.freeze({
|
|
8165
|
+
request_origin: (value) => value === "web",
|
|
8166
|
+
app_color_depth: (value) => Number.isSafeInteger(value) && value >= 1 && value <= 64,
|
|
8167
|
+
app_language: (value) => typeof value === "string" && value.length <= 64 && LANGUAGE5.test(value),
|
|
8168
|
+
app_screen_height: (value) => Number.isSafeInteger(value) && value >= 1 && value <= 1e5,
|
|
8169
|
+
app_screen_width: (value) => Number.isSafeInteger(value) && value >= 1 && value <= 1e5,
|
|
8170
|
+
app_timezone_offset: (value) => Number.isSafeInteger(value) && value >= -1440 && value <= 1440,
|
|
8171
|
+
app_java_enabled: (value) => typeof value === "boolean"
|
|
8172
|
+
});
|
|
8173
|
+
function soundDevice3(value) {
|
|
8174
|
+
const device = value.device;
|
|
8175
|
+
if (!record37(device) || !own19(device, "request_origin") || !own19(device, "app_timezone_offset"))
|
|
8176
|
+
return false;
|
|
8177
|
+
return DEVICE_KEYS4.every((key) => own19(device, key) ? DEVICE_RULES[key](device[key]) && own19(value, key) && value[key] === device[key] : !own19(value, key)) && Object.keys(device).every((key) => DEVICE_KEYS4.includes(key));
|
|
8178
|
+
}
|
|
8179
|
+
function soundPageData(value) {
|
|
8180
|
+
if (own19(value, "name") && !pageText2(value.name))
|
|
8181
|
+
return false;
|
|
8182
|
+
if (own19(value, "preferred_scheme") && !(value.preferred_scheme === null || typeof value.preferred_scheme === "string" && SCHEME.test(value.preferred_scheme)))
|
|
8183
|
+
return false;
|
|
8184
|
+
const contact = value.contact;
|
|
8185
|
+
return record37(contact) && Object.keys(contact).every((key) => CONTACT_KEYS.includes(key) && pageText2(contact[key]));
|
|
8186
|
+
}
|
|
8187
|
+
function processoutBodyVerdict(body, url) {
|
|
8188
|
+
if (url !== void 0 && processoutCardTarget(url) === null)
|
|
8189
|
+
return refuse45("processout_url_refused");
|
|
8190
|
+
const value = readBody27(body);
|
|
8191
|
+
if (value === null || !Object.keys(value).every((key) => BODY_KEYS3.has(key)))
|
|
8192
|
+
return refuse45("processout_body_unsupported");
|
|
8193
|
+
if (!PROCESSOUT_CARD_KEYS.every((key) => typeof value[key] === "string"))
|
|
8194
|
+
return refuse45("processout_body_unsupported");
|
|
8195
|
+
if (!NUMBER9.test(value.number) || !luhn12(value.number) || !MONTH23.test(value.exp_month) || !YEAR24.test(value.exp_year) || !CODE9.test(value.cvc2))
|
|
8196
|
+
return refuse45("processout_body_unsupported");
|
|
8197
|
+
if (!soundPageData(value) || !soundDevice3(value))
|
|
8198
|
+
return refuse45("processout_body_unsupported");
|
|
8199
|
+
return CARD44;
|
|
8200
|
+
}
|
|
8201
|
+
var processout_default = /* @__PURE__ */ registerProcessor({
|
|
8202
|
+
psp: PROCESSOUT_PSP,
|
|
8203
|
+
definitions: [
|
|
8204
|
+
{
|
|
8205
|
+
psp: "processout",
|
|
8206
|
+
// ProcessOut.js's card request, as the header above reads it. One host serves every project, live and sandbox
|
|
8207
|
+
// alike, so no sandbox host is marked: the project id names the environment, and the device sends a sandbox
|
|
8208
|
+
// project only ProcessOut's documented test cards (processoutDeviceRefusal). The page gives up 20 seconds after
|
|
8209
|
+
// its tokenize message, so the lane is prepared only (preparationRequired). The match reads the host and the path,
|
|
8210
|
+
// and ends where the path does, as Pin Payments' does: a card's own record under /cards/, where the code refresh
|
|
8211
|
+
// goes, is never paused. The exact-URL rule below holds the query, the project id and its Basic credential among it.
|
|
8212
|
+
// Ships dark: served only to a client that declares `processout_card_token`, and gated off for every org until
|
|
8213
|
+
// the backend's gate names one.
|
|
8214
|
+
capability: "processout_card_token",
|
|
8215
|
+
match: "api\\.processout\\.com/cards(?![\\w/.%-])",
|
|
8216
|
+
hosts: ["^api\\.processout\\.com$"],
|
|
8217
|
+
preparationRequired: true,
|
|
8218
|
+
encoding: "json",
|
|
8219
|
+
// ProcessOut.js's own headers: the project's Basic credential and the API version. Origin, Referer and cookies
|
|
8220
|
+
// never ride.
|
|
8221
|
+
passthroughHeaders: ["^authorization$", "^api-version$"],
|
|
8222
|
+
jsonCardFields: [["number"]]
|
|
8223
|
+
}
|
|
8224
|
+
],
|
|
8225
|
+
// Only the cardholder's device sends a card, after a person approves; no reviewed list names processout.
|
|
8226
|
+
refusedOperations: [PROCESSOUT_OPERATION],
|
|
8227
|
+
// Not surveyed: the card request mints a token and moves no money; the store's server charges it under its own
|
|
8228
|
+
// secret key, which Agentcard never holds.
|
|
8229
|
+
settlementReadback: "not_surveyed",
|
|
8230
|
+
exactUrl: isProcessoutCardUrl,
|
|
8231
|
+
bodyGate: (url, body) => processoutBodyVerdict(body, url)
|
|
8232
|
+
});
|
|
8233
|
+
// src/processors/usaepay.js
|
|
8234
|
+
var USAEPAY_PSP = "usaepay";
|
|
8235
|
+
var USAEPAY_OPERATION = "usaepay.card_request";
|
|
8236
|
+
var USAEPAY_HOSTS = /* @__PURE__ */ Object.freeze({
|
|
8237
|
+
"www.usaepay.com": "production",
|
|
8238
|
+
"secure.usaepay.com": "production",
|
|
8239
|
+
"sandbox.usaepay.com": "sandbox"
|
|
8240
|
+
});
|
|
8241
|
+
var USAEPAY_PAYMENT_KEYS_PATH = "/api/v2/pub/payment_keys";
|
|
8242
|
+
var BODY_LIMIT45 = 512;
|
|
8243
|
+
var URL_LIMIT18 = 256;
|
|
8244
|
+
var CARD_NUMBER22 = /^[0-9]{13,19}$/;
|
|
8245
|
+
var EXPIRATION2 = /^(?:0[1-9]|1[0-2])[0-9]{2}$/;
|
|
8246
|
+
var SECURITY_CODE26 = /^(?:[0-9]{3,4})?$/;
|
|
8247
|
+
var record38 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8248
|
+
var own20 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
8249
|
+
var refuse46 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
8250
|
+
var CARD45 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
8251
|
+
function usaepayPaymentKeysUrl(url) {
|
|
8252
|
+
if (typeof url !== "string" || url.length > URL_LIMIT18 || url.includes("?") || url.includes("#"))
|
|
8253
|
+
return null;
|
|
8254
|
+
let parsed;
|
|
8255
|
+
try {
|
|
8256
|
+
parsed = new URL(url);
|
|
8257
|
+
}
|
|
8258
|
+
catch {
|
|
8259
|
+
return null;
|
|
8260
|
+
}
|
|
8261
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own20(USAEPAY_HOSTS, parsed.hostname) || parsed.pathname !== USAEPAY_PAYMENT_KEYS_PATH)
|
|
8262
|
+
return null;
|
|
8263
|
+
return Object.freeze({ host: parsed.hostname, environment: USAEPAY_HOSTS[parsed.hostname] });
|
|
8264
|
+
}
|
|
8265
|
+
var isUsaepayPaymentKeysUrl = (url) => usaepayPaymentKeysUrl(url) !== null;
|
|
8266
|
+
function luhn13(digits4) {
|
|
8267
|
+
let sum = 0;
|
|
8268
|
+
for (let at = digits4.length - 1, double = false; at >= 0; at -= 1, double = !double) {
|
|
8269
|
+
let digit = digits4.charCodeAt(at) - 48;
|
|
8270
|
+
if (double)
|
|
8271
|
+
digit = digit * 2 > 9 ? digit * 2 - 9 : digit * 2;
|
|
8272
|
+
sum += digit;
|
|
8273
|
+
}
|
|
8274
|
+
return sum % 10 === 0;
|
|
8275
|
+
}
|
|
8276
|
+
function readBody28(body) {
|
|
8277
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT45)
|
|
8278
|
+
return null;
|
|
8279
|
+
try {
|
|
8280
|
+
const value = JSON.parse(body);
|
|
8281
|
+
return record38(value) && JSON.stringify(value) === body ? value : null;
|
|
8282
|
+
}
|
|
8283
|
+
catch {
|
|
8284
|
+
return null;
|
|
8285
|
+
}
|
|
8286
|
+
}
|
|
8287
|
+
function usaepayBodyVerdict(body) {
|
|
8288
|
+
const value = readBody28(body);
|
|
8289
|
+
const card = value === null ? null : value.creditcard;
|
|
8290
|
+
if (value === null || Object.keys(value).join() !== "creditcard" || !record38(card) || Object.keys(card).join() !== "number,expiration,cvc" || typeof card.number !== "string" || !CARD_NUMBER22.test(card.number) || !luhn13(card.number) || typeof card.expiration !== "string" || !EXPIRATION2.test(card.expiration) || typeof card.cvc !== "string" || !SECURITY_CODE26.test(card.cvc))
|
|
8291
|
+
return refuse46("usaepay_body_unsupported");
|
|
8292
|
+
return CARD45;
|
|
8293
|
+
}
|
|
8294
|
+
var usaepay_default = /* @__PURE__ */ registerProcessor({
|
|
8295
|
+
psp: USAEPAY_PSP,
|
|
8296
|
+
definitions: [
|
|
8297
|
+
{
|
|
8298
|
+
psp: "usaepay",
|
|
8299
|
+
// The frame's card request, as the header above reads it. sandbox.usaepay.com is USAePay's sandbox, pinned to test
|
|
8300
|
+
// rows, which send only USAePay's documented test cards (hostEnvironmentPinned, device-replay.js S7).
|
|
8301
|
+
// Ships dark: served only to a client that declares `usaepay_payment_key`, and only for a company the backend's
|
|
8302
|
+
// processor gate turns USAePay on for. `(?![\w/.%-])` ends the path for a consumer that tests `match` unanchored.
|
|
8303
|
+
capability: "usaepay_payment_key",
|
|
8304
|
+
match: "(?:www|secure|sandbox)\\.usaepay\\.com/api/v2/pub/payment_keys(?![\\w/.%-])",
|
|
8305
|
+
hosts: ["^www\\.usaepay\\.com$", "^secure\\.usaepay\\.com$", "^sandbox\\.usaepay\\.com$"],
|
|
8306
|
+
sandboxHosts: ["^sandbox\\.usaepay\\.com$"],
|
|
8307
|
+
hostEnvironmentPinned: true,
|
|
8308
|
+
encoding: "json",
|
|
8309
|
+
// The frame's Authorization, which carries the merchant's public key. Origin, Referer and cookies never ride.
|
|
8310
|
+
passthroughHeaders: ["^authorization$"],
|
|
8311
|
+
jsonCardFields: [["creditcard", "number"]]
|
|
8312
|
+
}
|
|
8313
|
+
],
|
|
8314
|
+
// Only the cardholder's device sends this card, after a person approves; no reviewed list names usaepay.
|
|
8315
|
+
refusedOperations: [USAEPAY_OPERATION],
|
|
8316
|
+
// The public key mints a payment key and reads nothing: the merchant's server runs the sale with its private key.
|
|
8317
|
+
settlementReadback: {
|
|
8318
|
+
answer: "none",
|
|
8319
|
+
reason: "tokenization_credential_cannot_read_charges",
|
|
8320
|
+
note: "The tokenization credential cannot read a charge; the shop charges the token later with its own credentials.",
|
|
8321
|
+
source: "https://help.usaepay.info/developer/payjs-v2/ , https://help.usaepay.info/api/rest/"
|
|
8322
|
+
},
|
|
8323
|
+
exactUrl: isUsaepayPaymentKeysUrl,
|
|
8324
|
+
bodyGate: (url, body) => url !== void 0 && !isUsaepayPaymentKeysUrl(url) ? refuse46("usaepay_url_refused") : usaepayBodyVerdict(body)
|
|
8325
|
+
// No amount reader: the request names none, so the agent's pair is the figure the cardholder approves.
|
|
8326
|
+
});
|
|
8327
|
+
// src/processors/viva_wallet.js
|
|
8328
|
+
var VIVA_WALLET_PSP = "viva_wallet";
|
|
8329
|
+
var VIVA_WALLET_OPERATION = "viva_wallet.card_request";
|
|
8330
|
+
var VIVA_WALLET_HOSTS = /* @__PURE__ */ Object.freeze({ "www.vivapayments.com": "production", "demo.vivapayments.com": "sandbox" });
|
|
8331
|
+
var VIVA_WALLET_CHARGE_TOKENS_PATH = "/web2/checkout/v2/chargetokens";
|
|
8332
|
+
var VIVA_WALLET_BODY_KEYS = /* @__PURE__ */ Object.freeze([
|
|
8333
|
+
"orderCode",
|
|
8334
|
+
"amount",
|
|
8335
|
+
"currencyCode",
|
|
8336
|
+
"holderName",
|
|
8337
|
+
"holderMail",
|
|
8338
|
+
"cvc",
|
|
8339
|
+
"number",
|
|
8340
|
+
"expirationMonth",
|
|
8341
|
+
"expirationYear",
|
|
8342
|
+
"installments",
|
|
8343
|
+
"customer",
|
|
8344
|
+
"rememberCard",
|
|
8345
|
+
"friendlyName",
|
|
8346
|
+
"maskedNumber",
|
|
8347
|
+
"bankId",
|
|
8348
|
+
"selectedBrand",
|
|
8349
|
+
"cardholderBrandSelection",
|
|
8350
|
+
"dccOptions",
|
|
8351
|
+
"dccAccepted",
|
|
8352
|
+
"offerCodes",
|
|
8353
|
+
"loyaltySupported",
|
|
8354
|
+
"redeemedAmount",
|
|
8355
|
+
"retrievalReferenceNumber",
|
|
8356
|
+
"scaRequestedTransactionId",
|
|
8357
|
+
"merchantTrns",
|
|
8358
|
+
"captchaToken"
|
|
8359
|
+
]);
|
|
8360
|
+
var BODY_LIMIT46 = 16384;
|
|
8361
|
+
var URL_LIMIT19 = 256;
|
|
8362
|
+
var ORDER_CODE = /^[0-9]{16}$/;
|
|
8363
|
+
var CARD_NUMBER23 = /^[0-9]{13,19}$/;
|
|
8364
|
+
var MONTH24 = /^(?:0[1-9]|1[0-2])$/;
|
|
8365
|
+
var YEAR25 = /^[0-9]{2}$/;
|
|
8366
|
+
var SECURITY_CODE27 = /^[0-9]{3,4}$/;
|
|
8367
|
+
var CAPTCHA_TOKEN = /^[A-Za-z0-9_.-]{20,8192}$/;
|
|
8368
|
+
var MEMBER_NAME = /^[A-Za-z][A-Za-z0-9]{0,31}$/;
|
|
8369
|
+
var SHORT_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
8370
|
+
var TEXT4 = /^[^\u0000-\u001f\u007f]{0,200}$/;
|
|
8371
|
+
var CARD_DIGITS2 = /[0-9]{12,}/;
|
|
8372
|
+
var record39 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8373
|
+
var own21 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
8374
|
+
var refuse47 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
8375
|
+
var CARD46 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
8376
|
+
var inOrder9 = (value, keys) => {
|
|
8377
|
+
let at = 0;
|
|
8378
|
+
for (const name of Object.keys(value)) {
|
|
8379
|
+
while (at < keys.length && keys[at] !== name)
|
|
8380
|
+
at += 1;
|
|
8381
|
+
if (at === keys.length)
|
|
8382
|
+
return false;
|
|
8383
|
+
at += 1;
|
|
8384
|
+
}
|
|
8385
|
+
return true;
|
|
8386
|
+
};
|
|
8387
|
+
var cardDigits2 = (text11) => CARD_DIGITS2.test(text11.replace(/[^0-9A-Za-z]/g, ""));
|
|
8388
|
+
var plainText8 = (value) => typeof value === "string" && TEXT4.test(value) && !cardDigits2(value);
|
|
8389
|
+
var scalar = (value) => value === null || typeof value === "boolean" || Number.isSafeInteger(value) && Math.abs(value) < 1e9 || plainText8(value);
|
|
8390
|
+
var flatRecord = (value, limit) => record39(value) && Object.keys(value).length <= limit && Object.entries(value).every(([key, item]) => MEMBER_NAME.test(key) && scalar(item));
|
|
8391
|
+
function vivaWalletChargeTokensUrl(url) {
|
|
8392
|
+
if (typeof url !== "string" || url.length > URL_LIMIT19 || url.includes("?") || url.includes("#"))
|
|
8393
|
+
return null;
|
|
8394
|
+
let parsed;
|
|
8395
|
+
try {
|
|
8396
|
+
parsed = new URL(url);
|
|
8397
|
+
}
|
|
8398
|
+
catch {
|
|
8399
|
+
return null;
|
|
8400
|
+
}
|
|
8401
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own21(VIVA_WALLET_HOSTS, parsed.hostname) || parsed.pathname !== VIVA_WALLET_CHARGE_TOKENS_PATH)
|
|
8402
|
+
return null;
|
|
8403
|
+
return Object.freeze({ host: parsed.hostname, environment: VIVA_WALLET_HOSTS[parsed.hostname] });
|
|
8404
|
+
}
|
|
8405
|
+
var isVivaWalletChargeTokensUrl = (url) => vivaWalletChargeTokensUrl(url) !== null;
|
|
8406
|
+
function luhn14(digits4) {
|
|
8407
|
+
let sum = 0;
|
|
8408
|
+
for (let at = digits4.length - 1, double = false; at >= 0; at -= 1, double = !double) {
|
|
8409
|
+
let digit = digits4.charCodeAt(at) - 48;
|
|
8410
|
+
if (double)
|
|
8411
|
+
digit = digit * 2 > 9 ? digit * 2 - 9 : digit * 2;
|
|
8412
|
+
sum += digit;
|
|
8413
|
+
}
|
|
8414
|
+
return sum % 10 === 0;
|
|
8415
|
+
}
|
|
8416
|
+
function vivaWalletMaskedNumber(number) {
|
|
8417
|
+
return `${number.slice(0, 6)}${"X".repeat(Math.max(0, number.length - 10))}${number.slice(-4)}`;
|
|
8418
|
+
}
|
|
8419
|
+
function readBody29(body) {
|
|
8420
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT46)
|
|
8421
|
+
return null;
|
|
8422
|
+
try {
|
|
8423
|
+
const value = JSON.parse(body);
|
|
8424
|
+
return record39(value) && JSON.stringify(value) === body ? value : null;
|
|
8425
|
+
}
|
|
8426
|
+
catch {
|
|
8427
|
+
return null;
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8430
|
+
function currencyNumber(value) {
|
|
8431
|
+
if (Number.isSafeInteger(value) && value > 0 && value < 1e3)
|
|
8432
|
+
return value;
|
|
8433
|
+
return typeof value === "string" && /^[0-9]{3}$/.test(value) ? Number(value) : null;
|
|
8434
|
+
}
|
|
8435
|
+
function vivaWalletBodyVerdict(body) {
|
|
8436
|
+
const value = readBody29(body);
|
|
8437
|
+
if (value === null || !Object.keys(value).every((key) => VIVA_WALLET_BODY_KEYS.includes(key))) {
|
|
8438
|
+
return value !== null && (own21(value, "creditCardId") || own21(value, "token")) ? refuse47("viva_wallet_stored_card") : refuse47("viva_wallet_body_unsupported");
|
|
8439
|
+
}
|
|
8440
|
+
if (value.rememberCard !== false)
|
|
8441
|
+
return refuse47(value.rememberCard === true ? "viva_wallet_keep_on_file" : "viva_wallet_body_unsupported");
|
|
8442
|
+
if (value.dccAccepted === true)
|
|
8443
|
+
return refuse47("viva_wallet_currency_conversion");
|
|
8444
|
+
if (own21(value, "dccAccepted") && value.dccAccepted !== false)
|
|
8445
|
+
return refuse47("viva_wallet_body_unsupported");
|
|
8446
|
+
if (own21(value, "scaRequestedTransactionId"))
|
|
8447
|
+
return refuse47("viva_wallet_retry_refused");
|
|
8448
|
+
if (!(value.installments === 0 || value.installments === 1)) {
|
|
8449
|
+
return refuse47(Number.isSafeInteger(value.installments) && value.installments > 1 ? "viva_wallet_installments" : "viva_wallet_body_unsupported");
|
|
8450
|
+
}
|
|
8451
|
+
if (!inOrder9(value, VIVA_WALLET_BODY_KEYS) || ["offerCodes", "loyaltySupported", "redeemedAmount", "retrievalReferenceNumber", "merchantTrns"].some((key) => own21(value, key)))
|
|
8452
|
+
return refuse47("viva_wallet_body_unsupported");
|
|
8453
|
+
const number = value.number;
|
|
8454
|
+
const sound = typeof value.orderCode === "string" && ORDER_CODE.test(value.orderCode) && Number.isSafeInteger(value.amount) && value.amount > 0 && currencyNumber(value.currencyCode) !== null && plainText8(value.holderName) && value.holderName.trim() !== "" && plainText8(value.holderMail) && (value.cvc === null || typeof value.cvc === "string" && SECURITY_CODE27.test(value.cvc)) && typeof number === "string" && CARD_NUMBER23.test(number) && luhn14(number) && typeof value.expirationMonth === "string" && MONTH24.test(value.expirationMonth) && typeof value.expirationYear === "string" && YEAR25.test(value.expirationYear) && flatRecord(value.customer, 12) && (!own21(value, "friendlyName") || plainText8(value.friendlyName)) && value.maskedNumber === vivaWalletMaskedNumber(number) && (!own21(value, "bankId") || typeof value.bankId === "string" && SHORT_ID.test(value.bankId) || Number.isSafeInteger(value.bankId) && value.bankId >= 0) && (!own21(value, "selectedBrand") || value.selectedBrand === null || flatRecord(value.selectedBrand, 16)) && (!own21(value, "cardholderBrandSelection") || typeof value.cardholderBrandSelection === "boolean") && (!own21(value, "dccOptions") || flatRecord(value.dccOptions, 16)) && (!own21(value, "captchaToken") || typeof value.captchaToken === "string" && CAPTCHA_TOKEN.test(value.captchaToken));
|
|
8455
|
+
return sound ? CARD46 : refuse47("viva_wallet_body_unsupported");
|
|
8456
|
+
}
|
|
8457
|
+
var VIVA_WALLET_CURRENCIES = /* @__PURE__ */ Object.freeze({
|
|
8458
|
+
978: "eur",
|
|
8459
|
+
826: "gbp",
|
|
8460
|
+
946: "ron",
|
|
8461
|
+
985: "pln",
|
|
8462
|
+
203: "czk",
|
|
8463
|
+
348: "huf",
|
|
8464
|
+
752: "sek",
|
|
8465
|
+
208: "dkk"
|
|
8466
|
+
});
|
|
8467
|
+
function vivaWalletAmount(body) {
|
|
8468
|
+
if (vivaWalletBodyVerdict(body).verdict !== "card")
|
|
8469
|
+
return null;
|
|
8470
|
+
const value = JSON.parse(body);
|
|
8471
|
+
const currency = VIVA_WALLET_CURRENCIES[currencyNumber(value.currencyCode)];
|
|
8472
|
+
return currency ? { amountCents: value.amount, currency } : null;
|
|
8473
|
+
}
|
|
8474
|
+
var VIVA_WALLET_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
8475
|
+
Object.freeze({
|
|
8476
|
+
id: "klimaka_donation",
|
|
8477
|
+
merchant: "Klimaka",
|
|
8478
|
+
tradeName: "ΚΛΙΜΑΚΑ ΑΜΚΕ",
|
|
8479
|
+
orderCodes: Object.freeze(["7871752880772607"]),
|
|
8480
|
+
origin: "https://www.vivapayments.com",
|
|
8481
|
+
currencyCode: 978
|
|
8482
|
+
}),
|
|
8483
|
+
Object.freeze({
|
|
8484
|
+
id: "desmos_donation",
|
|
8485
|
+
merchant: "Desmos",
|
|
8486
|
+
tradeName: "DESMOS",
|
|
8487
|
+
orderCodes: Object.freeze(["8156257435672606"]),
|
|
8488
|
+
origin: "https://www.vivapayments.com",
|
|
8489
|
+
currencyCode: 978
|
|
8490
|
+
})
|
|
8491
|
+
]);
|
|
8492
|
+
var CARD_MEMBERS = Object.freeze(["cvc", "number", "expirationMonth", "expirationYear", "maskedNumber"]);
|
|
8493
|
+
var viva_wallet_default = /* @__PURE__ */ registerProcessor({
|
|
8494
|
+
psp: VIVA_WALLET_PSP,
|
|
8495
|
+
definitions: [
|
|
8496
|
+
{
|
|
8497
|
+
psp: "viva_wallet",
|
|
8498
|
+
// The page's card request, as the header above reads it. demo.vivapayments.com is Viva's sandbox, pinned to test
|
|
8499
|
+
// rows, which send only Viva's documented test cards (hostEnvironmentPinned, device-replay.js S7).
|
|
8500
|
+
// Ships dark: served only to a client that declares `viva_smart_checkout_chargetoken`, and only for a company the
|
|
8501
|
+
// backend's processor gate turns Viva Wallet on for. `(?![\w/.%-])` ends the path for a consumer that tests `match`
|
|
8502
|
+
// unanchored.
|
|
8503
|
+
capability: "viva_smart_checkout_chargetoken",
|
|
8504
|
+
match: "(?:www|demo)\\.vivapayments\\.com/web2/checkout/v2/chargetokens(?![\\w/.%-])",
|
|
8505
|
+
hosts: ["^www\\.vivapayments\\.com$", "^demo\\.vivapayments\\.com$"],
|
|
8506
|
+
sandboxHosts: ["^demo\\.vivapayments\\.com$"],
|
|
8507
|
+
hostEnvironmentPinned: true,
|
|
8508
|
+
encoding: "json",
|
|
8509
|
+
// The page sends no Authorization; Origin, Referer, cookies and the reCAPTCHA state never ride.
|
|
8510
|
+
passthroughHeaders: [],
|
|
8511
|
+
jsonCardFields: [["number"]]
|
|
8512
|
+
}
|
|
8513
|
+
],
|
|
8514
|
+
// Only the cardholder's device sends this card, after a person approves; no reviewed list names viva_wallet.
|
|
8515
|
+
refusedOperations: [VIVA_WALLET_OPERATION],
|
|
8516
|
+
settlementReadback: "not_surveyed",
|
|
8517
|
+
exactUrl: isVivaWalletChargeTokensUrl,
|
|
8518
|
+
bodyGate: (url, body) => url !== void 0 && !isVivaWalletChargeTokensUrl(url) ? refuse47("viva_wallet_url_refused") : vivaWalletBodyVerdict(body),
|
|
8519
|
+
// The body names the order's amount in cents and its numeric currency, which the page's card-free charge repeats.
|
|
8520
|
+
amount: (template) => record39(template) && isVivaWalletChargeTokensUrl(template.url) ? vivaWalletAmount(template.body) : null
|
|
8521
|
+
});
|
|
8522
|
+
// src/processors/vtex_payments.js
|
|
8523
|
+
var VTEX_PAYMENTS_PSP = "vtex_payments";
|
|
8524
|
+
var VTEX_PAYMENTS_OPERATION = "vtex_payments.card_request";
|
|
8525
|
+
var VTEX_PAYMENTS_FALLBACK_HOST = "api.vtexvault.com";
|
|
8526
|
+
var VTEX_PAYMENTS_LINE_KEYS = /* @__PURE__ */ Object.freeze([
|
|
8527
|
+
"currencyCode",
|
|
8528
|
+
"paymentSystem",
|
|
8529
|
+
"accountId",
|
|
8530
|
+
"value",
|
|
8531
|
+
"referenceValue",
|
|
8532
|
+
"installments",
|
|
8533
|
+
"installmentsInterestRate",
|
|
8534
|
+
"installmentsValue",
|
|
8535
|
+
"groupName",
|
|
8536
|
+
"fields",
|
|
8537
|
+
"transaction",
|
|
8538
|
+
"id"
|
|
8539
|
+
]);
|
|
8540
|
+
var VTEX_PAYMENTS_FIELD_KEYS = /* @__PURE__ */ Object.freeze([
|
|
8541
|
+
"address",
|
|
8542
|
+
"accountId",
|
|
8543
|
+
"validationCode",
|
|
8544
|
+
"metadata",
|
|
8545
|
+
"document",
|
|
8546
|
+
"holderName",
|
|
8547
|
+
"cardNumber",
|
|
8548
|
+
"dueDate",
|
|
8549
|
+
"deviceFingerprint",
|
|
8550
|
+
"addressId"
|
|
8551
|
+
]);
|
|
8552
|
+
var VTEX_PAYMENTS_ADDRESS_KEYS = /* @__PURE__ */ Object.freeze([
|
|
8553
|
+
"street",
|
|
8554
|
+
"complement",
|
|
8555
|
+
"number",
|
|
8556
|
+
"city",
|
|
8557
|
+
"reference",
|
|
8558
|
+
"addressType",
|
|
8559
|
+
"neighborhood",
|
|
8560
|
+
"addressId",
|
|
8561
|
+
"state",
|
|
8562
|
+
"country",
|
|
8563
|
+
"postalCode"
|
|
8564
|
+
]);
|
|
8565
|
+
var VTEX_PAYMENTS_NETWORKS = /* @__PURE__ */ Object.freeze({ 1: "amex", 2: "visa", 4: "mastercard", 5: "discover" });
|
|
8566
|
+
var VTEX_PAYMENTS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
8567
|
+
Object.freeze({ account: "alssports", origin: "https://www.als.com", merchant: "Al's Sporting Goods", currency: "USD" }),
|
|
8568
|
+
Object.freeze({ account: "roadrunnersports", origin: "https://www.roadrunnersports.com", merchant: "Road Runner Sports", currency: "USD" })
|
|
8569
|
+
]);
|
|
8570
|
+
var BODY_LIMIT47 = 16384;
|
|
8571
|
+
var ACCOUNT_HOST = /^([a-z0-9]{1,63})\.vtexvault\.com$/;
|
|
8572
|
+
var PATH = /^\/api\/payments\/transactions\/([0-9A-Fa-f]{32})\/payments$/;
|
|
8573
|
+
var ORDER_GROUP = /^[0-9]{6,24}$/;
|
|
8574
|
+
var BASE648 = /^[A-Za-z0-9+/]{4,1020}={0,2}$/;
|
|
8575
|
+
var CARD_NUMBER24 = /^[0-9]{12,19}$/;
|
|
8576
|
+
var SECURITY_CODE28 = /^[0-9]{3,4}$/;
|
|
8577
|
+
var DUE_DATE = /^(?:0[1-9]|1[0-2])\/[0-9]{2}$/;
|
|
8578
|
+
var CURRENCY6 = /^[A-Z]{3}$/;
|
|
8579
|
+
var TRANSACTION_ID = /^[0-9A-Fa-f]{32}$/;
|
|
8580
|
+
var MERCHANT_NAME = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
8581
|
+
var SHORT_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
|
|
8582
|
+
var FINGERPRINT4 = /^[A-Za-z0-9_.:=+/-]{1,256}$/;
|
|
8583
|
+
var TEXT5 = /^[^\u0000-\u001f\u007f]{1,200}$/;
|
|
8584
|
+
var CARD_DIGITS3 = /[0-9]{12,}/;
|
|
8585
|
+
var DEVICE_INFO_KEYS = Object.freeze(["sw", "sh", "cd", "tz", "lang", "java", "sourceApplication"]);
|
|
8586
|
+
var record40 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8587
|
+
var own22 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
8588
|
+
var refuse48 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
8589
|
+
var CARD47 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
8590
|
+
var inOrder10 = (value, keys) => {
|
|
8591
|
+
let at = 0;
|
|
8592
|
+
for (const name of Object.keys(value)) {
|
|
8593
|
+
while (at < keys.length && keys[at] !== name)
|
|
8594
|
+
at += 1;
|
|
8595
|
+
if (at === keys.length)
|
|
8596
|
+
return false;
|
|
8597
|
+
at += 1;
|
|
8598
|
+
}
|
|
8599
|
+
return true;
|
|
8600
|
+
};
|
|
8601
|
+
var cardDigits3 = (text11) => CARD_DIGITS3.test(text11.replace(/[^0-9A-Za-z]/g, ""));
|
|
8602
|
+
var plainText9 = (value) => typeof value === "string" && TEXT5.test(value) && !cardDigits3(value);
|
|
8603
|
+
var count = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
8604
|
+
var BASE64_ALPHABET2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
8605
|
+
function base64Text2(input) {
|
|
8606
|
+
if (input.length % 4 !== 0)
|
|
8607
|
+
return null;
|
|
8608
|
+
const stripped = input.replace(/={1,2}$/, "");
|
|
8609
|
+
let out = "";
|
|
8610
|
+
let bits = 0;
|
|
8611
|
+
let value = 0;
|
|
8612
|
+
for (const character of stripped) {
|
|
8613
|
+
const sextet = BASE64_ALPHABET2.indexOf(character);
|
|
8614
|
+
if (sextet < 0)
|
|
8615
|
+
return null;
|
|
8616
|
+
value = value << 6 | sextet;
|
|
8617
|
+
bits += 6;
|
|
8618
|
+
if (bits >= 8) {
|
|
8619
|
+
bits -= 8;
|
|
8620
|
+
out += String.fromCharCode(value >> bits & 255);
|
|
8621
|
+
value &= (1 << bits) - 1;
|
|
8622
|
+
}
|
|
8623
|
+
}
|
|
8624
|
+
return out;
|
|
8625
|
+
}
|
|
8626
|
+
function deviceInfoSound(text11) {
|
|
8627
|
+
if (typeof text11 !== "string" || !BASE648.test(text11))
|
|
8628
|
+
return false;
|
|
8629
|
+
const decoded = base64Text2(text11);
|
|
8630
|
+
if (decoded === null)
|
|
8631
|
+
return false;
|
|
8632
|
+
let info;
|
|
8633
|
+
try {
|
|
8634
|
+
info = JSON.parse(decoded);
|
|
8635
|
+
}
|
|
8636
|
+
catch {
|
|
8637
|
+
return false;
|
|
8638
|
+
}
|
|
8639
|
+
if (!record40(info) || !Object.keys(info).every((key) => DEVICE_INFO_KEYS.includes(key)))
|
|
8640
|
+
return false;
|
|
8641
|
+
for (const key of ["sw", "sh", "cd"])
|
|
8642
|
+
if (own22(info, key) && !(count(info[key]) && info[key] <= 1e5))
|
|
8643
|
+
return false;
|
|
8644
|
+
if (own22(info, "tz") && !(Number.isSafeInteger(info.tz) && Math.abs(info.tz) <= 1440))
|
|
8645
|
+
return false;
|
|
8646
|
+
if (own22(info, "lang") && !(typeof info.lang === "string" && /^[A-Za-z]{0,8}$/.test(info.lang)))
|
|
8647
|
+
return false;
|
|
8648
|
+
if (own22(info, "java") && typeof info.java !== "boolean")
|
|
8649
|
+
return false;
|
|
8650
|
+
return !own22(info, "sourceApplication") || typeof info.sourceApplication === "string" && /^[A-Za-z0-9_.-]{1,32}$/.test(info.sourceApplication);
|
|
8651
|
+
}
|
|
8652
|
+
function vtexPaymentsCardTarget(url) {
|
|
8653
|
+
if (typeof url !== "string" || url.length > 8192)
|
|
8654
|
+
return null;
|
|
8655
|
+
let parsed;
|
|
8656
|
+
try {
|
|
8657
|
+
parsed = new URL(url);
|
|
8658
|
+
}
|
|
8659
|
+
catch {
|
|
8660
|
+
return null;
|
|
8661
|
+
}
|
|
8662
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || parsed.hash)
|
|
8663
|
+
return null;
|
|
8664
|
+
const path = PATH.exec(parsed.pathname);
|
|
8665
|
+
const host = ACCOUNT_HOST.exec(parsed.hostname);
|
|
8666
|
+
if (!path || !host)
|
|
8667
|
+
return null;
|
|
8668
|
+
const fallback = parsed.hostname === VTEX_PAYMENTS_FALLBACK_HOST;
|
|
8669
|
+
const names = [...parsed.searchParams.keys()];
|
|
8670
|
+
const expected = ["orderId", "deviceInfo", ...parsed.searchParams.has("callbackUrl") ? ["callbackUrl"] : [], ...fallback ? ["an"] : []];
|
|
8671
|
+
if (names.length !== expected.length || names.some((name, i) => name !== expected[i]))
|
|
8672
|
+
return null;
|
|
8673
|
+
const orderId = parsed.searchParams.get("orderId");
|
|
8674
|
+
if (!ORDER_GROUP.test(orderId) || !deviceInfoSound(parsed.searchParams.get("deviceInfo")))
|
|
8675
|
+
return null;
|
|
8676
|
+
if (parsed.searchParams.has("callbackUrl")) {
|
|
8677
|
+
let callback;
|
|
8678
|
+
try {
|
|
8679
|
+
callback = new URL(parsed.searchParams.get("callbackUrl"));
|
|
8680
|
+
}
|
|
8681
|
+
catch {
|
|
8682
|
+
return null;
|
|
8683
|
+
}
|
|
8684
|
+
if (callback.protocol !== "https:" || callback.username || callback.password || callback.searchParams.get("step") !== "payment" || callback.searchParams.get("og") !== orderId)
|
|
8685
|
+
return null;
|
|
8686
|
+
}
|
|
8687
|
+
const account = fallback ? parsed.searchParams.get("an") : host[1];
|
|
8688
|
+
if (!/^[a-z0-9]{1,63}$/.test(account) || account === "api")
|
|
8689
|
+
return null;
|
|
8690
|
+
return Object.freeze({ account, transactionId: path[1], orderId, fallback });
|
|
8691
|
+
}
|
|
8692
|
+
function isVtexPaymentsCardUrl(url) {
|
|
8693
|
+
const target = vtexPaymentsCardTarget(url);
|
|
8694
|
+
return target !== null && !target.fallback;
|
|
8695
|
+
}
|
|
8696
|
+
function readBody30(body) {
|
|
8697
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT47)
|
|
8698
|
+
return null;
|
|
8699
|
+
let value;
|
|
8700
|
+
try {
|
|
8701
|
+
value = JSON.parse(body);
|
|
8702
|
+
if (!Array.isArray(value) || JSON.stringify(value) !== body)
|
|
8703
|
+
return null;
|
|
8704
|
+
}
|
|
8705
|
+
catch {
|
|
8706
|
+
return null;
|
|
8707
|
+
}
|
|
8708
|
+
return value;
|
|
8709
|
+
}
|
|
8710
|
+
function cardLine(line) {
|
|
8711
|
+
if (!record40(line))
|
|
8712
|
+
return false;
|
|
8713
|
+
const fields = record40(line.fields) ? line.fields : {};
|
|
8714
|
+
return line.groupName === "creditCardPaymentGroup" || line.groupName === "debitCardPaymentGroup" || own22(line, "accountId") || own22(fields, "accountId") || own22(fields, "cardNumber") || own22(fields, "validationCode") || own22(fields, "dueDate");
|
|
8715
|
+
}
|
|
8716
|
+
function addressSound(address2) {
|
|
8717
|
+
if (!record40(address2) || !inOrder10(address2, VTEX_PAYMENTS_ADDRESS_KEYS))
|
|
8718
|
+
return false;
|
|
8719
|
+
for (const [key, value] of Object.entries(address2)) {
|
|
8720
|
+
if (key === "addressType") {
|
|
8721
|
+
if (value !== "billing")
|
|
8722
|
+
return false;
|
|
8723
|
+
continue;
|
|
8724
|
+
}
|
|
8725
|
+
if (key === "addressId") {
|
|
8726
|
+
if (!(typeof value === "string" && SHORT_ID2.test(value)))
|
|
8727
|
+
return false;
|
|
8728
|
+
continue;
|
|
8729
|
+
}
|
|
8730
|
+
if (value === null && (key === "complement" || key === "reference"))
|
|
8731
|
+
continue;
|
|
8732
|
+
if (!(value === "" || plainText9(value)))
|
|
8733
|
+
return false;
|
|
8734
|
+
}
|
|
8735
|
+
return true;
|
|
8736
|
+
}
|
|
8737
|
+
function fieldsSound(fields) {
|
|
8738
|
+
if (!record40(fields) || !inOrder10(fields, VTEX_PAYMENTS_FIELD_KEYS) || own22(fields, "metadata"))
|
|
8739
|
+
return false;
|
|
8740
|
+
if (!(typeof fields.cardNumber === "string" && CARD_NUMBER24.test(fields.cardNumber)))
|
|
8741
|
+
return false;
|
|
8742
|
+
if (!(typeof fields.validationCode === "string" && SECURITY_CODE28.test(fields.validationCode)))
|
|
8743
|
+
return false;
|
|
8744
|
+
if (!(typeof fields.dueDate === "string" && DUE_DATE.test(fields.dueDate)))
|
|
8745
|
+
return false;
|
|
8746
|
+
if (!plainText9(fields.holderName))
|
|
8747
|
+
return false;
|
|
8748
|
+
if (own22(fields, "document") && !(fields.document === "" || plainText9(fields.document) && fields.document.length <= 32))
|
|
8749
|
+
return false;
|
|
8750
|
+
if (own22(fields, "address") && !addressSound(fields.address))
|
|
8751
|
+
return false;
|
|
8752
|
+
if (own22(fields, "deviceFingerprint") && !(typeof fields.deviceFingerprint === "string" && FINGERPRINT4.test(fields.deviceFingerprint)))
|
|
8753
|
+
return false;
|
|
8754
|
+
return !own22(fields, "addressId") || typeof fields.addressId === "string" && SHORT_ID2.test(fields.addressId);
|
|
8755
|
+
}
|
|
8756
|
+
function vtexPaymentsBodyVerdict(body, target) {
|
|
8757
|
+
const lines = readBody30(body);
|
|
8758
|
+
if (lines === null || lines.length === 0 || !lines.every(record40))
|
|
8759
|
+
return refuse48("vtex_payments_body_unsupported");
|
|
8760
|
+
const cards = lines.filter(cardLine);
|
|
8761
|
+
if (cards.some((line2) => own22(line2, "accountId") || own22(line2.fields ?? {}, "accountId")))
|
|
8762
|
+
return refuse48("vtex_payments_saved_card");
|
|
8763
|
+
if (cards.length === 0)
|
|
8764
|
+
return refuse48("vtex_payments_body_unsupported");
|
|
8765
|
+
if (lines.length !== 1 || own22(lines[0], "id"))
|
|
8766
|
+
return refuse48("vtex_payments_split_payment");
|
|
8767
|
+
const line = lines[0];
|
|
8768
|
+
if (!inOrder10(line, VTEX_PAYMENTS_LINE_KEYS) || line.groupName !== "creditCardPaymentGroup")
|
|
8769
|
+
return refuse48("vtex_payments_body_unsupported");
|
|
8770
|
+
if (!(typeof line.currencyCode === "string" && CURRENCY6.test(line.currencyCode)) || !own22(VTEX_PAYMENTS_NETWORKS, line.paymentSystem) || !Number.isSafeInteger(line.paymentSystem) || !(count(line.value) && line.value > 0))
|
|
8771
|
+
return refuse48("vtex_payments_body_unsupported");
|
|
8772
|
+
if (line.installments !== 1 || line.referenceValue !== line.value || own22(line, "installmentsInterestRate") && line.installmentsInterestRate !== 0 || own22(line, "installmentsValue") && line.installmentsValue !== line.value)
|
|
8773
|
+
return refuse48("vtex_payments_installments");
|
|
8774
|
+
const transaction = line.transaction;
|
|
8775
|
+
if (!record40(transaction) || Object.keys(transaction).join() !== "id,merchantName" || !(typeof transaction.id === "string" && TRANSACTION_ID.test(transaction.id)) || !(typeof transaction.merchantName === "string" && MERCHANT_NAME.test(transaction.merchantName)))
|
|
8776
|
+
return refuse48("vtex_payments_body_unsupported");
|
|
8777
|
+
if (target && transaction.id.toUpperCase() !== target.transactionId.toUpperCase())
|
|
8778
|
+
return refuse48("vtex_payments_split_payment");
|
|
8779
|
+
return fieldsSound(line.fields) ? CARD47 : refuse48("vtex_payments_body_unsupported");
|
|
8780
|
+
}
|
|
8781
|
+
function vtexPaymentsAmount(body) {
|
|
8782
|
+
if (vtexPaymentsBodyVerdict(body).verdict !== "card")
|
|
8783
|
+
return null;
|
|
8784
|
+
const [line] = JSON.parse(body);
|
|
8785
|
+
return { amountCents: line.value, currency: line.currencyCode.toLowerCase() };
|
|
8786
|
+
}
|
|
8787
|
+
var NETWORK_OF = Object.freeze({
|
|
8788
|
+
visa: (number) => /^4[0-9]{12}(?:[0-9]{3}){0,2}$/.test(number),
|
|
8789
|
+
mastercard: (number) => /^(?:5[1-5][0-9]{14}|2(?:2(?:2[1-9]|[3-9][0-9])|[3-6][0-9]{2}|7(?:[01][0-9]|20))[0-9]{12})$/.test(number),
|
|
8790
|
+
amex: (number) => /^3[47][0-9]{13}$/.test(number),
|
|
8791
|
+
discover: (number) => /^(?:6011[0-9]{12}|64[4-9][0-9]{13}|65[0-9]{14})$/.test(number)
|
|
8792
|
+
});
|
|
8793
|
+
var NETWORK_NAME = Object.freeze({ visa: "Visa", mastercard: "Mastercard", amex: "American Express", discover: "Discover" });
|
|
8794
|
+
var vtex_payments_default = /* @__PURE__ */ registerProcessor({
|
|
8795
|
+
psp: VTEX_PAYMENTS_PSP,
|
|
8796
|
+
definitions: [
|
|
8797
|
+
{
|
|
8798
|
+
psp: "vtex_payments",
|
|
8799
|
+
// Ollie's card post to a VTEX account's own vault, as the header above reads it, and the fallback host, which
|
|
8800
|
+
// the gate recognizes only to refuse, so the agent's placeholder never reaches it either. VTEX has no test host:
|
|
8801
|
+
// every request is live. Prepared only: Ollie gives the post 12 seconds. Ships dark: served only to a client that
|
|
8802
|
+
// declares `vtex_payments_card_payment`, on for Agentcard's own company alone (backend
|
|
8803
|
+
// checkout-processor-gate.ts), and autopilot never sends it.
|
|
8804
|
+
capability: "vtex_payments_card_payment",
|
|
8805
|
+
match: "[a-z0-9-]{1,63}\\.vtexvault\\.com/api/payments/transactions/[A-Za-z0-9-]{1,64}/payments(?![\\w/.%-])",
|
|
8806
|
+
hosts: ["^[a-z0-9-]{1,63}\\.vtexvault\\.com$"],
|
|
8807
|
+
preparationRequired: true,
|
|
8808
|
+
encoding: "json",
|
|
8809
|
+
// Ollie's fetch sets the JSON content type alone. Origin, Referer and cookies never ride.
|
|
8810
|
+
passthroughHeaders: [],
|
|
8811
|
+
jsonCardFields: [[0, "fields", "cardNumber"]]
|
|
8812
|
+
}
|
|
8813
|
+
],
|
|
8814
|
+
// Only the cardholder's device sends it, after a person approves; no reviewed list names vtex_payments.
|
|
8815
|
+
refusedOperations: [VTEX_PAYMENTS_OPERATION],
|
|
8816
|
+
// Not surveyed: VTEX names a payment's end only to the store's own API keys and at the gatewayCallback that follows.
|
|
8817
|
+
settlementReadback: "not_surveyed",
|
|
8818
|
+
exactUrl: isVtexPaymentsCardUrl,
|
|
8819
|
+
bodyGate: (url, body) => {
|
|
8820
|
+
if (url === void 0)
|
|
8821
|
+
return vtexPaymentsBodyVerdict(body);
|
|
8822
|
+
const target = vtexPaymentsCardTarget(url);
|
|
8823
|
+
if (target === null)
|
|
8824
|
+
return refuse48("vtex_payments_url_refused");
|
|
8825
|
+
return target.fallback ? refuse48("vtex_payments_fallback_refused") : vtexPaymentsBodyVerdict(body, target);
|
|
8826
|
+
},
|
|
8827
|
+
amount: (template) => record40(template) && isVtexPaymentsCardUrl(template.url) ? vtexPaymentsAmount(template.body) : null
|
|
8828
|
+
});
|
|
8829
|
+
// src/processors/index.generated.js
|
|
8830
|
+
var REGISTERED_MODULES = Object.freeze({
|
|
8831
|
+
aurus: aurus_default,
|
|
8832
|
+
bluesnap: bluesnap_default,
|
|
8833
|
+
cardlink_vpos: cardlink_vpos_default,
|
|
8834
|
+
eghl: eghl_default,
|
|
8835
|
+
frisbii: frisbii_default,
|
|
8836
|
+
iyzico: iyzico_default,
|
|
8837
|
+
midtrans: midtrans_default,
|
|
8838
|
+
monei: monei_default,
|
|
8839
|
+
oceanpayment: oceanpayment_default,
|
|
8840
|
+
paymentwall: paymentwall_default,
|
|
8841
|
+
payplug: payplug_default,
|
|
8842
|
+
paystack: paystack_default,
|
|
8843
|
+
processout: processout_default,
|
|
8844
|
+
usaepay: usaepay_default,
|
|
8845
|
+
viva_wallet: viva_wallet_default,
|
|
8846
|
+
vtex_payments: vtex_payments_default
|
|
8847
|
+
});
|
|
8848
|
+
// src/registry.js
|
|
8849
|
+
var REGISTERED_PROCESSORS = Object.values(REGISTERED_MODULES);
|
|
8850
|
+
var ids = REGISTERED_PROCESSORS.map((processor) => processor.psp);
|
|
8851
|
+
var problems = REGISTERED_PROCESSORS.flatMap(registrationProblems);
|
|
8852
|
+
for (const [name, processor] of Object.entries(REGISTERED_MODULES)) {
|
|
8853
|
+
if (processor.psp !== name)
|
|
8854
|
+
problems.push(`processors/${name}.js registers ${JSON.stringify(processor.psp)}`);
|
|
8855
|
+
}
|
|
8856
|
+
if (ids.some((id, i) => i > 0 && ids[i - 1] >= id))
|
|
8857
|
+
problems.push(`registered processors out of id order: ${ids.join(", ")}`);
|
|
8858
|
+
if (problems.length)
|
|
8859
|
+
throw new Error(`payment-core registry refused: ${problems.join("; ")}`);
|
|
8860
|
+
var BY_PSP = new Map(REGISTERED_PROCESSORS.map((processor) => [processor.psp, processor]));
|
|
8861
|
+
var REGISTERED_IDS = Object.freeze(ids);
|
|
8862
|
+
var REGISTERED_DEFINITIONS = Object.freeze(REGISTERED_PROCESSORS.flatMap((processor) => processor.definitions));
|
|
8863
|
+
var REGISTERED_REFUSED_OPERATIONS = Object.freeze(REGISTERED_PROCESSORS.flatMap((processor) => processor.refusedOperations ?? []));
|
|
8864
|
+
var REGISTERED_SETTLEMENT_READBACK = Object.freeze(REGISTERED_PROCESSORS.filter((processor) => processor.settlementReadback !== void 0).map((processor) => [processor.psp, processor.settlementReadback]));
|
|
8865
|
+
function registeredRule(psp, name) {
|
|
8866
|
+
return typeof psp === "string" ? BY_PSP.get(psp)?.[name] : void 0;
|
|
8867
|
+
}
|
|
8868
|
+
// src/card-fields.js
|
|
8869
|
+
function processorGate(recognizer, url, body) {
|
|
8870
|
+
if (recognizer && recognizer.psp === LYRA_PSP)
|
|
8871
|
+
return lyraBodyVerdict(body, url);
|
|
8872
|
+
if (recognizer && recognizer.psp === WIX_PAYMENTS_PSP) {
|
|
8873
|
+
if (url !== void 0 && !isWixPaymentsTokenizeUrl(url))
|
|
8874
|
+
return { verdict: "refuse", code: "wix_payments_url_refused" };
|
|
8875
|
+
return wixPaymentsBodyVerdict(body);
|
|
8876
|
+
}
|
|
8877
|
+
if (recognizer && recognizer.psp === KOMOJU_PSP)
|
|
8878
|
+
return komojuBodyVerdict(body, url);
|
|
8879
|
+
if (recognizer && recognizer.psp === HIPAY_PSP) {
|
|
8880
|
+
if (url !== void 0 && !isHipayTokenUrl(url))
|
|
8881
|
+
return { verdict: "refuse", code: "hipay_url_refused" };
|
|
8882
|
+
return hipayBodyVerdict(body);
|
|
8883
|
+
}
|
|
8884
|
+
if (recognizer && recognizer.psp === PAYPAL_PSP) {
|
|
8885
|
+
if (url !== void 0 && !isPaypalConfirmUrl(url))
|
|
8886
|
+
return { verdict: "refuse", code: "paypal_url_refused" };
|
|
8887
|
+
return paypalBodyVerdict(body);
|
|
8888
|
+
}
|
|
8889
|
+
if (recognizer && recognizer.psp === MAKECOMMERCE_PSP)
|
|
8890
|
+
return makecommerceBodyVerdict(body, url);
|
|
8891
|
+
if (recognizer && recognizer.psp === OPENPAY_PSP)
|
|
8892
|
+
return openpayBodyVerdict(body, url);
|
|
8893
|
+
if (recognizer && recognizer.psp === POYNT_PSP) {
|
|
8894
|
+
if (url !== void 0 && !isPoyntNonceUrl(url))
|
|
8895
|
+
return { verdict: "refuse", code: "poynt_url_refused" };
|
|
8896
|
+
return poyntBodyVerdict(body);
|
|
8897
|
+
}
|
|
8898
|
+
if (recognizer && recognizer.psp === CARDCOM_PSP)
|
|
8899
|
+
return cardcomBodyVerdict(body, url);
|
|
8900
|
+
if (recognizer && recognizer.psp === TOAST_PSP) {
|
|
8901
|
+
if (url !== void 0 && !isToastPaymentMethodsUrl(url))
|
|
8902
|
+
return { verdict: "refuse", code: "toast_url_refused" };
|
|
8903
|
+
return toastBodyVerdict(body);
|
|
8904
|
+
}
|
|
8905
|
+
if (recognizer && recognizer.psp === PAYU_LATAM_PSP)
|
|
8906
|
+
return payuLatamBodyVerdict(body, url);
|
|
8907
|
+
if (recognizer && recognizer.psp === PADDLE_VGS_PSP) {
|
|
8908
|
+
if (url !== void 0 && !isPaddleVgsCardsUrl(url))
|
|
8909
|
+
return { verdict: "refuse", code: "paddle_vgs_url_refused" };
|
|
8910
|
+
return paddleVgsBodyVerdict(body);
|
|
8911
|
+
}
|
|
8912
|
+
if (recognizer && recognizer.psp === PAYFAST_PSP) {
|
|
8913
|
+
if (url !== void 0 && !isPayfastPayUrl(url))
|
|
8914
|
+
return { verdict: "refuse", code: "payfast_url_refused" };
|
|
8915
|
+
return payfastBodyVerdict(body);
|
|
8916
|
+
}
|
|
8917
|
+
if (recognizer && recognizer.psp === PAYREXX_PSP) {
|
|
8918
|
+
return url !== void 0 ? payrexxGateVerdict(url, body) : payrexxBodyVerdict(body);
|
|
8919
|
+
}
|
|
8920
|
+
if (recognizer && recognizer.psp === PAYGENT_PSP) {
|
|
8921
|
+
return url !== void 0 ? paygentRequestVerdict(url, body) : paygentBodyVerdict(body);
|
|
8922
|
+
}
|
|
8923
|
+
if (recognizer && recognizer.psp === PAY_NL_PSP) {
|
|
8924
|
+
if (url !== void 0 && !isPayNlTokenUrl(url))
|
|
8925
|
+
return { verdict: "refuse", code: "pay_nl_url_refused" };
|
|
8926
|
+
return payNlBodyVerdict(body);
|
|
6308
8927
|
}
|
|
6309
8928
|
if (recognizer && recognizer.psp === TWOC2P_PSP) {
|
|
6310
8929
|
if (url === void 0)
|
|
@@ -6412,7 +9031,7 @@ function carriesCardFields(recognizer, body) {
|
|
|
6412
9031
|
if (typeof body !== "string" || body === "")
|
|
6413
9032
|
return false;
|
|
6414
9033
|
const anyCase = recognizer.caseInsensitiveFormKeys === true;
|
|
6415
|
-
const wanted = anyCase ? fields.map((
|
|
9034
|
+
const wanted = anyCase ? fields.map((field5) => String(field5).toLowerCase()) : fields;
|
|
6416
9035
|
for (const chunk of body.split("&")) {
|
|
6417
9036
|
const eq = chunk.indexOf("=");
|
|
6418
9037
|
if (eq <= 0 || eq === chunk.length - 1)
|
|
@@ -6503,20 +9122,20 @@ var KEEP_ON_FILE_REFUSAL = "Refusing to pay: this Primer payment would keep the
|
|
|
6503
9122
|
var UNSUPPORTED_SDK_REFUSAL = "Refusing to pay: this checkout uses a Primer SDK Agentcard does not support yet. Nothing was sent.";
|
|
6504
9123
|
var NETWORK_MISMATCH_REFUSAL = "Refusing to pay: this Primer payment names a card network that is not your card's. Nothing was sent.";
|
|
6505
9124
|
var FILL_REFUSAL = "Could not fill the card fields for Primer. Nothing was sent.";
|
|
6506
|
-
var
|
|
9125
|
+
var BODY_LIMIT48 = 16384;
|
|
6507
9126
|
var RESPONSE_LIMIT = 32768;
|
|
6508
9127
|
var ROOT_KEYS10 = ["paymentInstrument", "userDescription", "tokenType", "paymentFlow"];
|
|
6509
9128
|
var INSTRUMENT_KEYS = ["number", "cvv", "expirationMonth", "expirationYear", "cardholderName", "preferredNetwork"];
|
|
6510
9129
|
var REQUIRED_INSTRUMENT_KEYS = ["number", "cvv", "expirationMonth", "expirationYear"];
|
|
6511
|
-
var
|
|
9130
|
+
var record41 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6512
9131
|
var owns8 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
6513
|
-
var
|
|
6514
|
-
var
|
|
9132
|
+
var exact5 = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
|
|
9133
|
+
var text10 = (value, max) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
|
|
6515
9134
|
var digits3 = (value, min, max) => typeof value === "string" && value.length >= min && value.length <= max && !/[^0-9]/.test(value);
|
|
6516
9135
|
var panLike2 = (value) => /(?:[0-9][ _.:-]*){12,}/.test(value);
|
|
6517
|
-
var plain2 = (value, max) =>
|
|
6518
|
-
var
|
|
6519
|
-
var
|
|
9136
|
+
var plain2 = (value, max) => text10(value, max) && !panLike2(value);
|
|
9137
|
+
var MONTH25 = /^(?:0[1-9]|1[0-2])$/;
|
|
9138
|
+
var YEAR26 = /^20[0-9]{2}$/;
|
|
6520
9139
|
var NETWORK3 = /^[A-Z][A-Z_]{1,31}$/;
|
|
6521
9140
|
function isPrimerTokenizeUrl(url, method = "POST") {
|
|
6522
9141
|
if (method !== "POST" || typeof url !== "string" || url.length > 256 || url.includes("?") || url.includes("#"))
|
|
@@ -6531,7 +9150,7 @@ function isPrimerTokenizeUrl(url, method = "POST") {
|
|
|
6531
9150
|
return parsed.href === url && parsed.protocol === "https:" && !parsed.port && !parsed.username && !parsed.password && !parsed.search && !parsed.hash && PRIMER_PCI_HOSTS.includes(parsed.hostname) && parsed.pathname === PRIMER_TOKENIZE_PATH;
|
|
6532
9151
|
}
|
|
6533
9152
|
function judgeBody6(body) {
|
|
6534
|
-
if (typeof body !== "string" || body === "" || body.length >
|
|
9153
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT48)
|
|
6535
9154
|
return null;
|
|
6536
9155
|
let value;
|
|
6537
9156
|
try {
|
|
@@ -6540,16 +9159,16 @@ function judgeBody6(body) {
|
|
|
6540
9159
|
catch {
|
|
6541
9160
|
return null;
|
|
6542
9161
|
}
|
|
6543
|
-
if (!
|
|
9162
|
+
if (!record41(value) || !roundTrips(value, body))
|
|
6544
9163
|
return null;
|
|
6545
9164
|
if (!Object.keys(value).every((key) => ROOT_KEYS10.includes(key)) || !owns8(value, "paymentInstrument"))
|
|
6546
9165
|
return null;
|
|
6547
9166
|
const instrument = value.paymentInstrument;
|
|
6548
|
-
if (!
|
|
9167
|
+
if (!record41(instrument) || !Object.keys(instrument).every((key) => INSTRUMENT_KEYS.includes(key)) || !REQUIRED_INSTRUMENT_KEYS.every((key) => owns8(instrument, key)))
|
|
6549
9168
|
return null;
|
|
6550
|
-
if (!digits3(instrument.number, 12, 19) || !digits3(instrument.cvv, 3, 4) || !
|
|
9169
|
+
if (!digits3(instrument.number, 12, 19) || !digits3(instrument.cvv, 3, 4) || !exact5(MONTH25, instrument.expirationMonth) || !exact5(YEAR26, instrument.expirationYear))
|
|
6551
9170
|
return null;
|
|
6552
|
-
if (owns8(instrument, "cardholderName") && instrument.cardholderName !== null && !plain2(instrument.cardholderName, 256) || owns8(instrument, "preferredNetwork") && instrument.preferredNetwork !== null && !
|
|
9171
|
+
if (owns8(instrument, "cardholderName") && instrument.cardholderName !== null && !plain2(instrument.cardholderName, 256) || owns8(instrument, "preferredNetwork") && instrument.preferredNetwork !== null && !exact5(NETWORK3, instrument.preferredNetwork) || owns8(value, "userDescription") && value.userDescription !== null && !plain2(value.userDescription, 256) || owns8(value, "tokenType") && value.tokenType !== "MULTI_USE" || owns8(value, "paymentFlow") && value.paymentFlow !== "VAULT")
|
|
6553
9172
|
return null;
|
|
6554
9173
|
return { value, keepOnFile: owns8(value, "tokenType") || owns8(value, "paymentFlow") };
|
|
6555
9174
|
}
|
|
@@ -6573,7 +9192,7 @@ var CLIENT_TOKEN = /^[A-Za-z0-9._~+/=-]{16,4096}$/;
|
|
|
6573
9192
|
var REQUEST_ID = /^[A-Za-z0-9-]{1,64}$/;
|
|
6574
9193
|
var API_VERSION = /^2\.[0-9]{1,2}$/;
|
|
6575
9194
|
function readHeaders(headers) {
|
|
6576
|
-
if (!
|
|
9195
|
+
if (!record41(headers))
|
|
6577
9196
|
return null;
|
|
6578
9197
|
const folded = /* @__PURE__ */ new Map();
|
|
6579
9198
|
for (const [name, value] of Object.entries(headers)) {
|
|
@@ -6591,9 +9210,9 @@ function headersRefusal(headers) {
|
|
|
6591
9210
|
const version = folded.get("primer-sdk-version");
|
|
6592
9211
|
if (typeof version !== "string")
|
|
6593
9212
|
return "unsupported";
|
|
6594
|
-
if (!
|
|
9213
|
+
if (!exact5(LEGACY_SDK_VERSION, version))
|
|
6595
9214
|
return "unsupported_sdk";
|
|
6596
|
-
if (!
|
|
9215
|
+
if (!exact5(CONTENT_TYPE2, folded.get("content-type")) || !exact5(CLIENT_TOKEN, folded.get("primer-client-token")) || folded.has("primer-sdk-client") && folded.get("primer-sdk-client") !== "WEB" || folded.has("x-api-version") && !exact5(API_VERSION, folded.get("x-api-version")) || folded.has("primer-sdk-checkout-session-id") && !exact5(REQUEST_ID, folded.get("primer-sdk-checkout-session-id")) || folded.has("x-request-id") && !exact5(REQUEST_ID, folded.get("x-request-id")))
|
|
6597
9216
|
return "unsupported";
|
|
6598
9217
|
return null;
|
|
6599
9218
|
}
|
|
@@ -6620,7 +9239,7 @@ function onTokenizePath(url) {
|
|
|
6620
9239
|
}
|
|
6621
9240
|
}
|
|
6622
9241
|
function primerTokenizeRefusal(request) {
|
|
6623
|
-
if (!
|
|
9242
|
+
if (!record41(request) || request.method !== "POST" || !isPrimerTokenizeUrl(request.url))
|
|
6624
9243
|
return "unsupported";
|
|
6625
9244
|
return headersRefusal(request.headers) ?? primerBodyRefusal(request.body);
|
|
6626
9245
|
}
|
|
@@ -6635,7 +9254,7 @@ function primerCardOnFileRefusal(url, options, policy = PRIMER_SESSION_CARD_ON_F
|
|
|
6635
9254
|
return "unsupported";
|
|
6636
9255
|
if (new URL(url).hostname !== LIVE_PCI_HOST)
|
|
6637
9256
|
return null;
|
|
6638
|
-
return primerCardOnFileDisclosure(url, policy) &&
|
|
9257
|
+
return primerCardOnFileDisclosure(url, policy) && record41(options) && options.keepOnFile === true ? null : "keep_on_file";
|
|
6639
9258
|
}
|
|
6640
9259
|
function primerRefusalMessage(reason) {
|
|
6641
9260
|
if (reason === "keep_on_file")
|
|
@@ -6696,8 +9315,8 @@ function injectPrimerCard(body, card) {
|
|
|
6696
9315
|
}
|
|
6697
9316
|
var TOKEN4 = /^[A-Za-z0-9_-]{8,256}$/;
|
|
6698
9317
|
var ERROR_ID = /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/;
|
|
6699
|
-
var
|
|
6700
|
-
var
|
|
9318
|
+
var CODE10 = /^[A-Z][A-Z0-9_]{0,63}$/;
|
|
9319
|
+
var NETWORK_NAME2 = /^[A-Za-z][A-Za-z0-9 _-]{0,31}$/;
|
|
6701
9320
|
var RESPONSE_MONTH = /^(?:0?[1-9]|1[0-2])$/;
|
|
6702
9321
|
var RESPONSE_YEAR = /^(?:[0-9]{2}|20[0-9]{2})$/;
|
|
6703
9322
|
var PROTOCOL2 = /^[0-9]{1,2}(?:\.[0-9]{1,2}){0,2}$/;
|
|
@@ -6719,25 +9338,25 @@ function readAnswer(body) {
|
|
|
6719
9338
|
return null;
|
|
6720
9339
|
try {
|
|
6721
9340
|
const value = JSON.parse(body);
|
|
6722
|
-
return
|
|
9341
|
+
return record41(value) ? value : null;
|
|
6723
9342
|
}
|
|
6724
9343
|
catch {
|
|
6725
9344
|
return null;
|
|
6726
9345
|
}
|
|
6727
9346
|
}
|
|
6728
|
-
var tokenValue = (value) =>
|
|
9347
|
+
var tokenValue = (value) => exact5(TOKEN4, value) && !panLike2(value);
|
|
6729
9348
|
var optional = (value, key, check) => !owns8(value, key) || value[key] === null || check(value[key]);
|
|
6730
9349
|
function cardDetails(data) {
|
|
6731
|
-
if (!
|
|
9350
|
+
if (!record41(data) || !exact5(/^[0-9]{4}$/, data.last4Digits))
|
|
6732
9351
|
return null;
|
|
6733
|
-
if (!optional(data, "first6Digits", (v) =>
|
|
9352
|
+
if (!optional(data, "first6Digits", (v) => exact5(/^[0-9]{6}$/, v)) || !optional(data, "expirationMonth", (v) => exact5(RESPONSE_MONTH, v)) || !optional(data, "expirationYear", (v) => exact5(RESPONSE_YEAR, v)) || !optional(data, "cardholderName", (v) => plain2(v, 256)) || !optional(data, "network", (v) => exact5(NETWORK_NAME2, v)) || !optional(data, "isNetworkTokenized", (v) => typeof v === "boolean") || !optional(data, "binData", record41))
|
|
6734
9353
|
return null;
|
|
6735
9354
|
const safe = { last4Digits: data.last4Digits };
|
|
6736
9355
|
for (const key of ["first6Digits", "expirationMonth", "expirationYear", "cardholderName", "network", "isNetworkTokenized"]) {
|
|
6737
9356
|
if (owns8(data, key) && data[key] !== null)
|
|
6738
9357
|
safe[key] = data[key];
|
|
6739
9358
|
}
|
|
6740
|
-
if (
|
|
9359
|
+
if (record41(data.binData)) {
|
|
6741
9360
|
const bin = {};
|
|
6742
9361
|
for (const key of BIN_KEYS) {
|
|
6743
9362
|
if (!owns8(data.binData, key) || data.binData[key] === null)
|
|
@@ -6748,12 +9367,14 @@ function cardDetails(data) {
|
|
|
6748
9367
|
}
|
|
6749
9368
|
safe.binData = bin;
|
|
6750
9369
|
}
|
|
9370
|
+
if ([safe.network, ...Object.values(safe.binData ?? {})].reduce((sum, value) => sum + (typeof value === "string" ? digitCount(value) : 0), 0) > NAME_DIGITS)
|
|
9371
|
+
return null;
|
|
6751
9372
|
return safe;
|
|
6752
9373
|
}
|
|
6753
9374
|
function threeDsSummary(value) {
|
|
6754
9375
|
if (value === void 0 || value === null)
|
|
6755
9376
|
return null;
|
|
6756
|
-
if (!
|
|
9377
|
+
if (!record41(value) || !exact5(CODE10, value.responseCode) || !optional(value, "reasonCode", (v) => exact5(CODE10, v)) || !optional(value, "reasonText", (v) => plain2(v, 256)) || !optional(value, "protocolVersion", (v) => v === "" || exact5(PROTOCOL2, v)) || !optional(value, "challengeIssued", (v) => typeof v === "boolean"))
|
|
6757
9378
|
return void 0;
|
|
6758
9379
|
const safe = { responseCode: value.responseCode };
|
|
6759
9380
|
for (const key of ["reasonCode", "reasonText", "protocolVersion", "challengeIssued"]) {
|
|
@@ -6781,8 +9402,8 @@ function rebuildToken(value) {
|
|
|
6781
9402
|
}
|
|
6782
9403
|
function primerErrorId(body) {
|
|
6783
9404
|
const value = readAnswer(body);
|
|
6784
|
-
const id = value &&
|
|
6785
|
-
return
|
|
9405
|
+
const id = value && record41(value.error) ? value.error.errorId : null;
|
|
9406
|
+
return exact5(ERROR_ID, id) && !panLike2(id) ? id : null;
|
|
6786
9407
|
}
|
|
6787
9408
|
function matchesCard(details, card) {
|
|
6788
9409
|
const number = card && typeof card.number === "string" ? card.number : "";
|