@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
|
@@ -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: 13395ab9cfe5d3a197ccb1efe5cd2211ffa86ffdd727d65cfb175f967d52314d
|
|
4
4
|
// src/deep-freeze.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -11,7 +11,17 @@ function deepFreeze(value) {
|
|
|
11
11
|
return value;
|
|
12
12
|
}
|
|
13
13
|
// src/registration.js
|
|
14
|
-
var PARTS = {
|
|
14
|
+
var PARTS = {
|
|
15
|
+
psp: "id",
|
|
16
|
+
definitions: "list",
|
|
17
|
+
refusedOperations: "list",
|
|
18
|
+
settlementReadback: "any",
|
|
19
|
+
exactUrl: "rule",
|
|
20
|
+
bodyGate: "rule",
|
|
21
|
+
amount: "rule",
|
|
22
|
+
hostedEntry: "rule",
|
|
23
|
+
limitations: "sentences"
|
|
24
|
+
};
|
|
15
25
|
var PSP_ID = /^[a-z][a-z0-9_]*$/;
|
|
16
26
|
var registrationProblems = (spec) => problemsOf(spec, PARTS);
|
|
17
27
|
function problemsOf(spec, parts) {
|
|
@@ -27,9 +37,14 @@ function problemsOf(spec, parts) {
|
|
|
27
37
|
continue;
|
|
28
38
|
if (kind === "rule" && typeof value !== "function")
|
|
29
39
|
problems2.push(`${psp}: ${key} is not a function`);
|
|
40
|
+
if (kind === "flag" && value !== true)
|
|
41
|
+
problems2.push(`${psp}: ${key} is not true`);
|
|
30
42
|
if (kind === "numbers" && !((Array.isArray(value) || value instanceof Set) && [...value].every((n) => typeof n === "string" && /^\d{12,19}$/.test(n)))) {
|
|
31
43
|
problems2.push(`${psp}: ${key} is not a list of card numbers`);
|
|
32
44
|
}
|
|
45
|
+
if (kind === "sentences" && !(Array.isArray(value) && value.length > 0 && value.every((s) => typeof s === "string" && s.trim() !== ""))) {
|
|
46
|
+
problems2.push(`${psp}: ${key} is not a list of sentences`);
|
|
47
|
+
}
|
|
33
48
|
}
|
|
34
49
|
if ("definitions" in parts) {
|
|
35
50
|
if (!Array.isArray(spec.definitions) || spec.definitions.length === 0)
|
|
@@ -40,55 +55,2549 @@ function problemsOf(spec, parts) {
|
|
|
40
55
|
if (typeof id !== "string" || !id.startsWith(`${psp}.`))
|
|
41
56
|
problems2.push(`${psp}: ${JSON.stringify(id)} is not one of its operations`);
|
|
42
57
|
}
|
|
58
|
+
const pages = Array.isArray(spec.definitions) ? spec.definitions.filter((d) => d?.hostedForm?.cardIn === "processor_page") : [];
|
|
59
|
+
if (spec.hostedEntry !== void 0 && (pages.length === 0 || pages.some((d) => d.hostedForm.policy !== void 0))) {
|
|
60
|
+
problems2.push(`${psp}: hostedEntry needs a definition whose hosted form takes the card on the processor's page and names no policy`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return problems2;
|
|
64
|
+
}
|
|
65
|
+
function registered(spec, parts) {
|
|
66
|
+
const problems2 = problemsOf(spec, parts);
|
|
67
|
+
if (problems2.length)
|
|
68
|
+
throw new Error(`payment-core registration refused: ${problems2.join("; ")}`);
|
|
69
|
+
return deepFreeze({ ...spec });
|
|
70
|
+
}
|
|
71
|
+
function registerProcessor(spec) {
|
|
72
|
+
return registered(spec, PARTS);
|
|
73
|
+
}
|
|
74
|
+
// src/processors/aurus.js
|
|
75
|
+
var AURUS_PSP = "aurus";
|
|
76
|
+
var AURUS_OPERATION = "aurus.card_request";
|
|
77
|
+
var AURUS_FRAME_HOST = /^pecst[0-9]{2}\.aurusepay\.com$/;
|
|
78
|
+
var AURUS_TOKEN_PATH = "/storeservices/ecom/oneTimeToken";
|
|
79
|
+
var AURUS_PARTS = /* @__PURE__ */ Object.freeze(["Param", "formFactorId", "txnDateTime", "encryptionFlag", "sha256Flag", "hmacAuthData", "payload"]);
|
|
80
|
+
var URL_LIMIT = 256;
|
|
81
|
+
var BODY_LIMIT = 32768;
|
|
82
|
+
var SERVER = /^es[0-9]{2}\.auruspay\.com$/;
|
|
83
|
+
var HEX = /^[0-9A-Fa-f]{2,8192}$/;
|
|
84
|
+
var FORM_FACTOR = /^[0-9]{1,16}$/;
|
|
85
|
+
var DATE_TIME = /^[0-9]{14}$/;
|
|
86
|
+
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$/;
|
|
87
|
+
var refuse = (code) => Object.freeze({ verdict: "refuse", code });
|
|
88
|
+
var CARD = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
89
|
+
function aurusTokenUrl(url) {
|
|
90
|
+
if (typeof url !== "string" || url.length > URL_LIMIT || url.includes("#"))
|
|
91
|
+
return null;
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = new URL(url);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !AURUS_FRAME_HOST.test(parsed.hostname) || parsed.pathname !== AURUS_TOKEN_PATH)
|
|
100
|
+
return null;
|
|
101
|
+
const query = parsed.search.startsWith("?") ? parsed.search.slice(1).split("&") : [];
|
|
102
|
+
if (query.length !== 2)
|
|
103
|
+
return null;
|
|
104
|
+
const [d1, d2] = query.map((pair) => pair.split("="));
|
|
105
|
+
if (d1.length !== 2 || d2.length !== 2 || d1[0] !== "d1" || d2[0] !== "d2" || !SERVER.test(d1[1]) || !SERVER.test(d2[1]))
|
|
106
|
+
return null;
|
|
107
|
+
return Object.freeze({ host: parsed.hostname });
|
|
108
|
+
}
|
|
109
|
+
var isAurusTokenUrl = (url) => aurusTokenUrl(url) !== null;
|
|
110
|
+
function readBody(body) {
|
|
111
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT)
|
|
112
|
+
return null;
|
|
113
|
+
const pairs = body.split("&");
|
|
114
|
+
if (pairs.length !== AURUS_PARTS.length)
|
|
115
|
+
return null;
|
|
116
|
+
const value = {};
|
|
117
|
+
for (const [at, pair] of pairs.entries()) {
|
|
118
|
+
const cut = pair.indexOf("=");
|
|
119
|
+
if (cut < 0 || pair.slice(0, cut) !== AURUS_PARTS[at])
|
|
120
|
+
return null;
|
|
121
|
+
value[AURUS_PARTS[at]] = pair.slice(cut + 1);
|
|
122
|
+
}
|
|
123
|
+
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))
|
|
124
|
+
return null;
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
function aurusBodyVerdict(body) {
|
|
128
|
+
return readBody(body) === null ? refuse("aurus_body_unsupported") : CARD;
|
|
129
|
+
}
|
|
130
|
+
var aurus_default = /* @__PURE__ */ registerProcessor({
|
|
131
|
+
psp: AURUS_PSP,
|
|
132
|
+
definitions: [
|
|
133
|
+
{
|
|
134
|
+
psp: "aurus",
|
|
135
|
+
// The frame's card request, as the header above reads it. No sandbox host is known: Aurus's test instances were
|
|
136
|
+
// not read, so none is listed and no environment is pinned.
|
|
137
|
+
// Ships dark: served only to a client that declares `aurus_one_time_token`, and only for a company the backend's
|
|
138
|
+
// processor gate turns Aurus on for. `(?![\w/.%-])` ends the path for a consumer that tests `match` unanchored.
|
|
139
|
+
capability: "aurus_one_time_token",
|
|
140
|
+
match: "pecst[0-9]{2}\\.aurusepay\\.com/storeservices/ecom/oneTimeToken(?![\\w/.%-])",
|
|
141
|
+
hosts: ["^pecst[0-9]{2}\\.aurusepay\\.com$"],
|
|
142
|
+
encoding: "form",
|
|
143
|
+
// The frame's XHR marker. Origin, Referer and cookies never ride.
|
|
144
|
+
passthroughHeaders: ["^x-requested-with$"]
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
// Only the cardholder's device would send this card, after a person approves; no reviewed list names aurus.
|
|
148
|
+
refusedOperations: [AURUS_OPERATION],
|
|
149
|
+
// The frame mints a one-time token and reads nothing: the store's server charges it with its own credentials.
|
|
150
|
+
settlementReadback: {
|
|
151
|
+
answer: "none",
|
|
152
|
+
reason: "tokenization_credential_cannot_read_charges",
|
|
153
|
+
note: "The tokenization credential cannot read a charge; the shop charges the token later with its own credentials.",
|
|
154
|
+
source: "https://www.oreillyauto.com/checkout (Aurus's ecom iframe, read 2026-10-31)"
|
|
155
|
+
},
|
|
156
|
+
exactUrl: isAurusTokenUrl,
|
|
157
|
+
bodyGate: (url, body) => url !== void 0 && !isAurusTokenUrl(url) ? refuse("aurus_url_refused") : aurusBodyVerdict(body),
|
|
158
|
+
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."]
|
|
159
|
+
});
|
|
160
|
+
// src/processors/bluesnap.js
|
|
161
|
+
var BLUESNAP_PSP = "bluesnap";
|
|
162
|
+
var BLUESNAP_OPERATION = "bluesnap.card_request";
|
|
163
|
+
var BLUESNAP_HOSTS = /* @__PURE__ */ Object.freeze({ 1: "ws1.bluesnap.com", 2: "ws2.bluesnap.com", _: "sandpay.bluesnap.com" });
|
|
164
|
+
var BLUESNAP_SANDBOX_HOST = "sandpay.bluesnap.com";
|
|
165
|
+
var BLUESNAP_CARD_KEYS = /* @__PURE__ */ Object.freeze(["cvv", "ccNumber", "expDate"]);
|
|
166
|
+
var BLUESNAP_LEG_KEYS = /* @__PURE__ */ Object.freeze(["cvv", "expDate"]);
|
|
167
|
+
var BODY_LIMIT2 = 1024;
|
|
168
|
+
var TOKEN_URL = /^https:\/\/(ws1|ws2|sandpay)\.bluesnap\.com\/services\/2\/payment-fields-tokens\/([0-9a-f]{64}_[12]?)$/;
|
|
169
|
+
var CARD_NUMBER = /^[0-9]{12,19}$/;
|
|
170
|
+
var SECURITY_CODE = /^[0-9]{3,4}$/;
|
|
171
|
+
var EXPIRY = /^(?:0[1-9]|1[0-2])\/20[0-9]{2}$/;
|
|
172
|
+
var SAVED_CARD_KEYS = ["last4Digits", "lastFourDigits", "ccType"];
|
|
173
|
+
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
174
|
+
var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
175
|
+
var refuse2 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
176
|
+
var CARD2 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
177
|
+
var LEG = /* @__PURE__ */ Object.freeze({ verdict: "continue" });
|
|
178
|
+
function bluesnapTokenUrl(url) {
|
|
179
|
+
const match = typeof url === "string" ? TOKEN_URL.exec(url) : null;
|
|
180
|
+
if (!match || BLUESNAP_HOSTS[match[2].slice(-1)] !== `${match[1]}.bluesnap.com`)
|
|
181
|
+
return null;
|
|
182
|
+
const host = `${match[1]}.bluesnap.com`;
|
|
183
|
+
return Object.freeze({ host, token: match[2], environment: host === BLUESNAP_SANDBOX_HOST ? "sandbox" : "production" });
|
|
184
|
+
}
|
|
185
|
+
function isBluesnapTokenUrl(url) {
|
|
186
|
+
return bluesnapTokenUrl(url) !== null;
|
|
187
|
+
}
|
|
188
|
+
function readBody2(body) {
|
|
189
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT2)
|
|
190
|
+
return null;
|
|
191
|
+
try {
|
|
192
|
+
const value = JSON.parse(body);
|
|
193
|
+
return record(value) && JSON.stringify(value) === body ? value : null;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function bluesnapBodyVerdict(body) {
|
|
200
|
+
const value = readBody2(body);
|
|
201
|
+
if (value === null)
|
|
202
|
+
return refuse2("bluesnap_body_unsupported");
|
|
203
|
+
const keys = Object.keys(value);
|
|
204
|
+
if (keys.some((key) => SAVED_CARD_KEYS.includes(key)))
|
|
205
|
+
return refuse2(own(value, "ccNumber") ? "bluesnap_body_unsupported" : "bluesnap_saved_card");
|
|
206
|
+
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))) {
|
|
207
|
+
return refuse2("bluesnap_body_unsupported");
|
|
208
|
+
}
|
|
209
|
+
if (own(value, "ccNumber") && !(typeof value.ccNumber === "string" && CARD_NUMBER.test(value.ccNumber)) || own(value, "cvv") && !(typeof value.cvv === "string" && SECURITY_CODE.test(value.cvv)) || own(value, "expDate") && !(typeof value.expDate === "string" && EXPIRY.test(value.expDate)))
|
|
210
|
+
return refuse2("bluesnap_body_unsupported");
|
|
211
|
+
return own(value, "ccNumber") ? CARD2 : LEG;
|
|
212
|
+
}
|
|
213
|
+
var bluesnap_default = /* @__PURE__ */ registerProcessor({
|
|
214
|
+
psp: BLUESNAP_PSP,
|
|
215
|
+
definitions: [
|
|
216
|
+
{
|
|
217
|
+
psp: "bluesnap",
|
|
218
|
+
// The card fields' PUTs, as the header above reads them. The sandbox has its own server, so the device sends a
|
|
219
|
+
// test-mode request only documented test cards (hostEnvironmentPinned, device-replay.js S7). `(?![\w/.%-])`
|
|
220
|
+
// ends the token for a consumer that tests `match` unanchored; the exact-URL rule pins each server to its suffix.
|
|
221
|
+
// Ships dark: served only to a client that declares `bluesnap_hosted_payment_fields`, and the backend's gate turns
|
|
222
|
+
// it on for Agentcard's own company alone, in code.
|
|
223
|
+
capability: "bluesnap_hosted_payment_fields",
|
|
224
|
+
match: "(?:ws1|ws2|sandpay)\\.bluesnap\\.com/services/2/payment-fields-tokens/[0-9a-f]{64}_[12]?(?![\\w/.%-])",
|
|
225
|
+
hosts: ["^ws1\\.bluesnap\\.com$", "^ws2\\.bluesnap\\.com$", "^sandpay\\.bluesnap\\.com$"],
|
|
226
|
+
sandboxHosts: ["^sandpay\\.bluesnap\\.com$"],
|
|
227
|
+
hostEnvironmentPinned: true,
|
|
228
|
+
encoding: "json",
|
|
229
|
+
// The frames' own headers, each held to its shape by bluesnapRequestRefusal. Origin, Referer and cookies never
|
|
230
|
+
// ride (the frames send no cookie).
|
|
231
|
+
passthroughHeaders: ["^authorization$", "^bluesnap_version_header$", "^bluesnap_origin_version_header$", "^bluesnap_origin_header$"],
|
|
232
|
+
jsonCardFields: [["ccNumber"]],
|
|
233
|
+
// The expiry and code frames' PUTs: held by the checkout SDK and answered with the card request's answer.
|
|
234
|
+
splitCard: { absorb: [...BLUESNAP_LEG_KEYS], pass: [], siblingKeys: [] },
|
|
235
|
+
request: { method: "PUT", cardIn: "body", response: "json" }
|
|
236
|
+
}
|
|
237
|
+
],
|
|
238
|
+
// Only the cardholder's device sends the card, after a person approves; no reviewed list names bluesnap.
|
|
239
|
+
refusedOperations: [BLUESNAP_OPERATION],
|
|
240
|
+
// Not surveyed: the PUT moves no money, and the merchant's own charge is a server call Agentcard never sees.
|
|
241
|
+
settlementReadback: "not_surveyed",
|
|
242
|
+
exactUrl: isBluesnapTokenUrl,
|
|
243
|
+
bodyGate: (url, body) => url !== void 0 && !isBluesnapTokenUrl(url) ? { verdict: "refuse", code: "bluesnap_url_refused" } : bluesnapBodyVerdict(body)
|
|
244
|
+
});
|
|
245
|
+
// src/processors/ekashu.js
|
|
246
|
+
var EKASHU_HOSTS = Object.freeze(["live.ekashu.com", "test.ekashu.com"]);
|
|
247
|
+
var EKASHU_TEST_PANS = Object.freeze(["4100000000000100", "5100000000000107"]);
|
|
248
|
+
var EKASHU_SIGNED_FIELDS = Object.freeze([
|
|
249
|
+
"ekashu_3d_secure_verify",
|
|
250
|
+
"ekashu_amount",
|
|
251
|
+
"ekashu_amount_format",
|
|
252
|
+
"ekashu_auto_confirm",
|
|
253
|
+
"ekashu_callback_failure_url",
|
|
254
|
+
"ekashu_callback_include_post",
|
|
255
|
+
"ekashu_callback_success_url",
|
|
256
|
+
"ekashu_card_address_editable",
|
|
257
|
+
"ekashu_card_address_required",
|
|
258
|
+
"ekashu_card_address_verify",
|
|
259
|
+
"ekashu_card_email_address_mandatory",
|
|
260
|
+
"ekashu_card_phone_number_mandatory",
|
|
261
|
+
"ekashu_card_title_mandatory",
|
|
262
|
+
"ekashu_card_zip_code_verify",
|
|
263
|
+
"ekashu_currency",
|
|
264
|
+
"ekashu_delivery_address_editable",
|
|
265
|
+
"ekashu_delivery_address_required",
|
|
266
|
+
"ekashu_delivery_email_address_mandatory",
|
|
267
|
+
"ekashu_delivery_phone_number_mandatory",
|
|
268
|
+
"ekashu_delivery_title_mandatory",
|
|
269
|
+
"ekashu_description",
|
|
270
|
+
"ekashu_device",
|
|
271
|
+
"ekashu_duplicate_check",
|
|
272
|
+
"ekashu_duplicate_minutes",
|
|
273
|
+
"ekashu_failure_return_text",
|
|
274
|
+
"ekashu_failure_url",
|
|
275
|
+
"ekashu_hash_code_format",
|
|
276
|
+
"ekashu_hash_code_type",
|
|
277
|
+
"ekashu_hash_code_version",
|
|
278
|
+
"ekashu_include_post",
|
|
279
|
+
"ekashu_invoice_address_editable",
|
|
280
|
+
"ekashu_invoice_address_required",
|
|
281
|
+
"ekashu_invoice_email_address_mandatory",
|
|
282
|
+
"ekashu_invoice_phone_number_mandatory",
|
|
283
|
+
"ekashu_invoice_title_mandatory",
|
|
284
|
+
"ekashu_locale",
|
|
285
|
+
"ekashu_payment_methods",
|
|
286
|
+
"ekashu_reference",
|
|
287
|
+
"ekashu_request_type",
|
|
288
|
+
"ekashu_return_text",
|
|
289
|
+
"ekashu_seller_address",
|
|
290
|
+
"ekashu_seller_email_address",
|
|
291
|
+
"ekashu_seller_id",
|
|
292
|
+
"ekashu_seller_key",
|
|
293
|
+
"ekashu_seller_name",
|
|
294
|
+
"ekashu_shortcut_icon",
|
|
295
|
+
"ekashu_style_sheet",
|
|
296
|
+
"ekashu_success_url",
|
|
297
|
+
"ekashu_title",
|
|
298
|
+
"ekashu_verification_value_mask",
|
|
299
|
+
"ekashu_verification_value_verify",
|
|
300
|
+
"ekashu_viewport"
|
|
301
|
+
]);
|
|
302
|
+
var REQUIRED = Object.freeze([
|
|
303
|
+
"ekashu_seller_id",
|
|
304
|
+
"ekashu_seller_key",
|
|
305
|
+
"ekashu_amount",
|
|
306
|
+
"ekashu_currency",
|
|
307
|
+
"ekashu_reference",
|
|
308
|
+
"ekashu_hash_code",
|
|
309
|
+
"ekashu_hash_code_type",
|
|
310
|
+
"ekashu_hash_code_version",
|
|
311
|
+
"ekashu_success_url",
|
|
312
|
+
"ekashu_failure_url",
|
|
313
|
+
"ekashu_callback_success_url"
|
|
314
|
+
]);
|
|
315
|
+
var CARD_KEYS = Object.freeze([
|
|
316
|
+
"ekashu_card_number",
|
|
317
|
+
"ekashu_expires_end_month",
|
|
318
|
+
"ekashu_expires_end_year",
|
|
319
|
+
"ekashu_verification_value",
|
|
320
|
+
"ekashu_valid_from_month",
|
|
321
|
+
"ekashu_valid_from_year",
|
|
322
|
+
"ekashu_issue_number"
|
|
323
|
+
]);
|
|
324
|
+
var PAGE_KEYS = Object.freeze(["ekashu_stage", "ekashu_context", "ekashu_submission_id"]);
|
|
325
|
+
var STORED_KEYS = Object.freeze(["ekashu_card_hash", "ekashu_card_reference", "ekashu_cof_initiated_by", "ekashu_cof_reason", "ekashu_cof_id"]);
|
|
326
|
+
var REDIRECT_KEYS = Object.freeze(["ekashu_success_url", "ekashu_failure_url", "ekashu_return_url"]);
|
|
327
|
+
var CALLBACK_KEYS = Object.freeze(["ekashu_callback_success_url", "ekashu_callback_failure_url"]);
|
|
328
|
+
var MAX_ENTRY = 16 * 1024;
|
|
329
|
+
var MAX_PAGE = 256 * 1024;
|
|
330
|
+
var EKASHU_SELLERS = Object.freeze([
|
|
331
|
+
Object.freeze({ sellerId: "25060100", merchant: "Heathrow Drop-off", entryHost: "heathrowdropoff.apcoa.com", callbackHost: "incomingapi.apcoa.co.uk" })
|
|
332
|
+
]);
|
|
333
|
+
var CARD_FIELDS = Object.freeze({
|
|
334
|
+
number: "ekashu_card_number",
|
|
335
|
+
month: "ekashu_expires_end_month",
|
|
336
|
+
year: "ekashu_expires_end_year",
|
|
337
|
+
cvc: "ekashu_verification_value"
|
|
338
|
+
});
|
|
339
|
+
var NAME_FIELDS = Object.freeze({ first: "ekashu_card_first_name", last: "ekashu_card_last_name" });
|
|
340
|
+
var LEFT_EMPTY = Object.freeze(["ekashu_card_title", "ekashu_valid_from_month", "ekashu_valid_from_year", "ekashu_issue_number"]);
|
|
341
|
+
var VISIBLE = /* @__PURE__ */ new Set([...Object.values(CARD_FIELDS), ...Object.values(NAME_FIELDS), ...LEFT_EMPTY]);
|
|
342
|
+
// src/processors/redsys.js
|
|
343
|
+
var REDSYS_HOSTS = Object.freeze(["sis.redsys.es"]);
|
|
344
|
+
var REDSYS_ENTRY_PATHS = Object.freeze(["/sis/realizarPago", "/sis/realizarPago/utf-8"]);
|
|
345
|
+
var REDSYS_MERCHANTS = Object.freeze([]);
|
|
346
|
+
var MAX_ENTRY2 = 16 * 1024;
|
|
347
|
+
var MAX_PARAMETERS = 8 * 1024;
|
|
348
|
+
var FORM_KEY = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
349
|
+
var ENTRY_KEYS = Object.freeze(["Ds_SignatureVersion", "Ds_MerchantParameters", "Ds_Signature"]);
|
|
350
|
+
var REQUIRED2 = Object.freeze([
|
|
351
|
+
"DS_MERCHANT_AMOUNT",
|
|
352
|
+
"DS_MERCHANT_CURRENCY",
|
|
353
|
+
"DS_MERCHANT_MERCHANTCODE",
|
|
354
|
+
"DS_MERCHANT_ORDER",
|
|
355
|
+
"DS_MERCHANT_TERMINAL",
|
|
356
|
+
"DS_MERCHANT_TRANSACTIONTYPE",
|
|
357
|
+
"DS_MERCHANT_MERCHANTURL",
|
|
358
|
+
"DS_MERCHANT_URLOK",
|
|
359
|
+
"DS_MERCHANT_URLKO"
|
|
360
|
+
]);
|
|
361
|
+
var STORED = Object.freeze([
|
|
362
|
+
"DS_MERCHANT_IDENTIFIER",
|
|
363
|
+
"DS_MERCHANT_GROUP",
|
|
364
|
+
"DS_MERCHANT_COF_INI",
|
|
365
|
+
"DS_MERCHANT_COF_TYPE",
|
|
366
|
+
"DS_MERCHANT_COF_TXNID"
|
|
367
|
+
]);
|
|
368
|
+
var SPECIAL = Object.freeze([
|
|
369
|
+
"DS_MERCHANT_DIRECTPAYMENT",
|
|
370
|
+
"DS_MERCHANT_SUMTOTAL",
|
|
371
|
+
"DS_MERCHANT_DATEFRECUENCY",
|
|
372
|
+
"DS_MERCHANT_CHARGEEXPIRYDATE",
|
|
373
|
+
"DS_MERCHANT_IDOPER"
|
|
374
|
+
]);
|
|
375
|
+
var CARD_PARAMETERS = Object.freeze(["DS_MERCHANT_PAN", "DS_MERCHANT_EXPIRYDATE", "DS_MERCHANT_CVV2"]);
|
|
376
|
+
var CURRENCIES = Object.freeze({ 978: "eur", 840: "usd", 826: "gbp", 756: "chf" });
|
|
377
|
+
function decode(text3) {
|
|
378
|
+
return decodeURIComponent(text3.replace(/\+/g, " "));
|
|
379
|
+
}
|
|
380
|
+
function parseRedsysForm(body) {
|
|
381
|
+
if (typeof body !== "string" || body.length === 0 || body.length > MAX_ENTRY2 || /[^\x21-\x7e]/.test(body))
|
|
382
|
+
return null;
|
|
383
|
+
const pairs = [];
|
|
384
|
+
const seen = /* @__PURE__ */ new Set();
|
|
385
|
+
for (const chunk of body.split("&")) {
|
|
386
|
+
const eq = chunk.indexOf("=");
|
|
387
|
+
if (eq < 1)
|
|
388
|
+
return null;
|
|
389
|
+
let key;
|
|
390
|
+
let value;
|
|
391
|
+
try {
|
|
392
|
+
key = decode(chunk.slice(0, eq));
|
|
393
|
+
value = decode(chunk.slice(eq + 1));
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
if (!FORM_KEY.test(key) || value.length > MAX_PARAMETERS || /[\u0000-\u001f\u007f]/.test(value))
|
|
399
|
+
return null;
|
|
400
|
+
const folded = key.toLowerCase();
|
|
401
|
+
if (seen.has(folded))
|
|
402
|
+
return null;
|
|
403
|
+
seen.add(folded);
|
|
404
|
+
pairs.push({ key, value });
|
|
405
|
+
}
|
|
406
|
+
return pairs;
|
|
407
|
+
}
|
|
408
|
+
var MAX_PAGE2 = 256 * 1024;
|
|
409
|
+
var CARD_FIELDS2 = Object.freeze({
|
|
410
|
+
shown: "Sis_card-number",
|
|
411
|
+
expiry: "SIS_card-expiration",
|
|
412
|
+
cvc: "Sis_Tarjeta_CVV2",
|
|
413
|
+
holder: "cardholderName",
|
|
414
|
+
number: "Sis_Numero_Tarjeta",
|
|
415
|
+
month: "Sis_Caducidad_Tarjeta_Mes",
|
|
416
|
+
year: "Sis_Caducidad_Tarjeta_Anno"
|
|
417
|
+
});
|
|
418
|
+
var BROWSER_FIELDS = Object.freeze([
|
|
419
|
+
"browserJavaEnabled",
|
|
420
|
+
"browserJavascriptEnabled",
|
|
421
|
+
"browserLanguage",
|
|
422
|
+
"browserColorDepth",
|
|
423
|
+
"browserScreenHeight",
|
|
424
|
+
"browserScreenWidth",
|
|
425
|
+
"browserTZ",
|
|
426
|
+
"browserUserAgent"
|
|
427
|
+
]);
|
|
428
|
+
var AS_SERVED = Object.freeze(["cvvObligatorio", "threeDSCompInd", "fuc", "terminal", "merchantOrder", "bcancel"]);
|
|
429
|
+
var CARD_PAGE = /* @__PURE__ */ new Set([...Object.values(CARD_FIELDS2), ...BROWSER_FIELDS, ...AS_SERVED]);
|
|
430
|
+
var VISIBLE2 = /* @__PURE__ */ new Set([CARD_FIELDS2.shown, CARD_FIELDS2.expiry, CARD_FIELDS2.cvc, CARD_FIELDS2.holder]);
|
|
431
|
+
var METHOD_PAGE = /* @__PURE__ */ new Set(["resultadoMethod", ...BROWSER_FIELDS, "threeDSCompInd"]);
|
|
432
|
+
var REDSYS_REFUSALS = Object.freeze(["redsys_card_page", "redsys_3ds_challenge", "redsys_declined"]);
|
|
433
|
+
// src/processors/cardlink_vpos.js
|
|
434
|
+
var CARDLINK_VPOS_PSP = "cardlink_vpos";
|
|
435
|
+
var CARDLINK_VPOS_HOSTS = Object.freeze({
|
|
436
|
+
"vpos.eurocommerce.gr": "worldline",
|
|
437
|
+
"ecommerce.cardlink.gr": "cardlink",
|
|
438
|
+
"www.alphaecommerce.gr": "nexi"
|
|
439
|
+
});
|
|
440
|
+
var CARDLINK_VPOS_TEST_HOSTS = Object.freeze([
|
|
441
|
+
"eurocommerce-test.cardlink.gr",
|
|
442
|
+
"ecommerce-test.cardlink.gr",
|
|
443
|
+
"alphaecommerce-test.cardlink.gr"
|
|
444
|
+
]);
|
|
445
|
+
var CARDLINK_VPOS_ENTRY_PATH = "/vpos/shophandlermpi";
|
|
446
|
+
var CARDLINK_VPOS_MERCHANTS = Object.freeze([
|
|
447
|
+
Object.freeze({ merchant: "Holy Great Monastery of Vatopedi", mid: "0021713862", vposHost: "vpos.eurocommerce.gr", host: "www.vatopedi.gr" })
|
|
448
|
+
]);
|
|
449
|
+
var CARDLINK_VPOS_ENTRY_FIELDS = Object.freeze([
|
|
450
|
+
"version",
|
|
451
|
+
"mid",
|
|
452
|
+
"lang",
|
|
453
|
+
"deviceCategory",
|
|
454
|
+
"orderid",
|
|
455
|
+
"orderDesc",
|
|
456
|
+
"orderAmount",
|
|
457
|
+
"currency",
|
|
458
|
+
"payerEmail",
|
|
459
|
+
"payerPhone",
|
|
460
|
+
"billCountry",
|
|
461
|
+
"billState",
|
|
462
|
+
"billZip",
|
|
463
|
+
"billCity",
|
|
464
|
+
"billAddress",
|
|
465
|
+
"weight",
|
|
466
|
+
"dimensions",
|
|
467
|
+
"shipCountry",
|
|
468
|
+
"shipState",
|
|
469
|
+
"shipZip",
|
|
470
|
+
"shipCity",
|
|
471
|
+
"shipAddress",
|
|
472
|
+
"addFraudScore",
|
|
473
|
+
"maxPayRetries",
|
|
474
|
+
"reject3dsU",
|
|
475
|
+
"payMethod",
|
|
476
|
+
"trType",
|
|
477
|
+
"extInstallmentoffset",
|
|
478
|
+
"extInstallmentperiod",
|
|
479
|
+
"extRecurringfrequency",
|
|
480
|
+
"extRecurringenddate",
|
|
481
|
+
"blockScore",
|
|
482
|
+
"cssUrl",
|
|
483
|
+
"confirmUrl",
|
|
484
|
+
"cancelUrl",
|
|
485
|
+
"extTokenOptions",
|
|
486
|
+
"extToken",
|
|
487
|
+
"var1",
|
|
488
|
+
"var2",
|
|
489
|
+
"var3",
|
|
490
|
+
"var4",
|
|
491
|
+
"var5",
|
|
492
|
+
"var6",
|
|
493
|
+
"var7",
|
|
494
|
+
"var8",
|
|
495
|
+
"var9",
|
|
496
|
+
"digest"
|
|
497
|
+
]);
|
|
498
|
+
var KNOWN = new Set(CARDLINK_VPOS_ENTRY_FIELDS);
|
|
499
|
+
var REQUIRED3 = Object.freeze([
|
|
500
|
+
"version",
|
|
501
|
+
"mid",
|
|
502
|
+
"orderid",
|
|
503
|
+
"orderDesc",
|
|
504
|
+
"orderAmount",
|
|
505
|
+
"currency",
|
|
506
|
+
"payerEmail",
|
|
507
|
+
"confirmUrl",
|
|
508
|
+
"cancelUrl",
|
|
509
|
+
"digest"
|
|
510
|
+
]);
|
|
511
|
+
var STORED2 = Object.freeze(["extTokenOptions", "extToken"]);
|
|
512
|
+
var SPECIAL2 = Object.freeze(["extInstallmentoffset", "extInstallmentperiod", "extRecurringfrequency", "extRecurringenddate"]);
|
|
513
|
+
var CURRENCIES2 = Object.freeze({ EUR: "eur" });
|
|
514
|
+
var MAX_URL = 512;
|
|
515
|
+
var MAX_ENTRY3 = 8 * 1024;
|
|
516
|
+
var MAX_VALUE = 256;
|
|
517
|
+
var own2 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
518
|
+
var field = (name, reason) => ({ ok: false, code: "hosted_form_field_refused", field: name, reason });
|
|
519
|
+
function cardlinkVposEntryHost(raw) {
|
|
520
|
+
if (typeof raw !== "string" || raw.length > MAX_URL || raw.includes("?") || raw.includes("#"))
|
|
521
|
+
return null;
|
|
522
|
+
let url;
|
|
523
|
+
try {
|
|
524
|
+
url = new URL(raw);
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
if (url.href !== raw || url.protocol !== "https:" || url.port || url.username || url.password || !own2(CARDLINK_VPOS_HOSTS, url.hostname) || url.pathname !== CARDLINK_VPOS_ENTRY_PATH)
|
|
530
|
+
return null;
|
|
531
|
+
return url.hostname;
|
|
532
|
+
}
|
|
533
|
+
function isCardlinkVposEntryUrl(raw) {
|
|
534
|
+
return cardlinkVposEntryHost(raw) !== null;
|
|
535
|
+
}
|
|
536
|
+
function parseCardlinkVposForm(body) {
|
|
537
|
+
if (typeof body !== "string" || body.length === 0 || body.length > MAX_ENTRY3 || /[^\x21-\x7e]/.test(body))
|
|
538
|
+
return null;
|
|
539
|
+
const pairs = [];
|
|
540
|
+
const seen = /* @__PURE__ */ new Set();
|
|
541
|
+
for (const chunk of body.split("&")) {
|
|
542
|
+
const eq = chunk.indexOf("=");
|
|
543
|
+
if (eq < 1)
|
|
544
|
+
return null;
|
|
545
|
+
let key;
|
|
546
|
+
let value;
|
|
547
|
+
try {
|
|
548
|
+
key = decodeURIComponent(chunk.slice(0, eq).replace(/\+/g, " "));
|
|
549
|
+
value = decodeURIComponent(chunk.slice(eq + 1).replace(/\+/g, " "));
|
|
550
|
+
}
|
|
551
|
+
catch {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
if (!/^[A-Za-z_.][A-Za-z0-9_.-]{0,63}$/.test(key) || value.length > MAX_VALUE || /[\u0000-\u001f\u007f]/.test(value))
|
|
555
|
+
return null;
|
|
556
|
+
if (seen.has(key))
|
|
557
|
+
return null;
|
|
558
|
+
seen.add(key);
|
|
559
|
+
pairs.push({ key, value });
|
|
560
|
+
}
|
|
561
|
+
return pairs;
|
|
562
|
+
}
|
|
563
|
+
function cardlinkVposMerchant(mid, vposHost, merchants = CARDLINK_VPOS_MERCHANTS) {
|
|
564
|
+
if (typeof mid !== "string" || typeof vposHost !== "string" || !Array.isArray(merchants))
|
|
565
|
+
return null;
|
|
566
|
+
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 !== "");
|
|
567
|
+
return found.length === 1 ? found[0] : null;
|
|
568
|
+
}
|
|
569
|
+
function entryAmount(values) {
|
|
570
|
+
const amount = values.get("orderAmount");
|
|
571
|
+
const code = values.get("currency");
|
|
572
|
+
const currency = typeof code === "string" && own2(CURRENCIES2, code) ? CURRENCIES2[code] : null;
|
|
573
|
+
if (!currency || typeof amount !== "string" || !/^(?:0|[1-9]\d{0,11})(?:\.\d{1,2})?$/.test(amount))
|
|
574
|
+
return null;
|
|
575
|
+
const [whole, fraction = ""] = amount.split(".");
|
|
576
|
+
const cents = Number(whole) * 100 + Number(fraction.padEnd(2, "0"));
|
|
577
|
+
return Number.isSafeInteger(cents) && cents > 0 ? { amountCents: cents, currency } : null;
|
|
578
|
+
}
|
|
579
|
+
function httpsUrl(value) {
|
|
580
|
+
let url;
|
|
581
|
+
try {
|
|
582
|
+
url = new URL(value);
|
|
583
|
+
}
|
|
584
|
+
catch {
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
if (url.protocol !== "https:" || url.username || url.password || url.port || url.hash)
|
|
588
|
+
return null;
|
|
589
|
+
return url;
|
|
590
|
+
}
|
|
591
|
+
function checkCardlinkVposEntry(body, { url = null, merchants = CARDLINK_VPOS_MERCHANTS } = {}) {
|
|
592
|
+
const vposHost = cardlinkVposEntryHost(url);
|
|
593
|
+
if (!vposHost)
|
|
594
|
+
return field("(url)", "malformed_field");
|
|
595
|
+
const pairs = parseCardlinkVposForm(body);
|
|
596
|
+
if (!pairs)
|
|
597
|
+
return field("(body)", "malformed");
|
|
598
|
+
const values = new Map(pairs.map(({ key, value }) => [key, value]));
|
|
599
|
+
for (const { key } of pairs) {
|
|
600
|
+
if (KNOWN.has(key))
|
|
601
|
+
continue;
|
|
602
|
+
return field(key, /^(?:card[._]|cvv|cmd$|trid$|st$|paystep$|paymentmethod$)/i.test(key) ? "card_in_entry" : "not_an_entry");
|
|
603
|
+
}
|
|
604
|
+
const missing = REQUIRED3.filter((name) => !values.get(name));
|
|
605
|
+
if (missing.length)
|
|
606
|
+
return { ok: false, code: "hosted_form_template_incomplete", missing };
|
|
607
|
+
if (values.get("version") !== "2")
|
|
608
|
+
return field("version", "malformed");
|
|
609
|
+
if (!/^[A-Za-z0-9+/]{43}=$/.test(values.get("digest")))
|
|
610
|
+
return field("digest", "unsigned");
|
|
611
|
+
for (const name of STORED2)
|
|
612
|
+
if (values.has(name))
|
|
613
|
+
return field(name, "stored_credential");
|
|
614
|
+
for (const name of SPECIAL2)
|
|
615
|
+
if (values.get(name))
|
|
616
|
+
return field(name, "special_flow");
|
|
617
|
+
for (let i = 1; i <= 9; i += 1)
|
|
618
|
+
if (/moto\s*=\s*true/i.test(values.get(`var${i}`) ?? ""))
|
|
619
|
+
return field(`var${i}`, "moto");
|
|
620
|
+
if (values.has("trType") && values.get("trType") !== "1")
|
|
621
|
+
return field("trType", "not_a_sale");
|
|
622
|
+
const method = values.get("payMethod");
|
|
623
|
+
if (method)
|
|
624
|
+
return field("payMethod", /^iris$/i.test(method) ? "not_a_card_payment" : "special_flow");
|
|
625
|
+
const amount = entryAmount(values);
|
|
626
|
+
if (!amount)
|
|
627
|
+
return field(own2(CURRENCIES2, values.get("currency")) ? "orderAmount" : "currency", "malformed");
|
|
628
|
+
if (!/^\d{1,30}$/.test(values.get("mid")))
|
|
629
|
+
return field("mid", "malformed");
|
|
630
|
+
if (!/^[A-Za-z0-9]{1,50}$/.test(values.get("orderid")))
|
|
631
|
+
return field("orderid", "malformed");
|
|
632
|
+
const seller = cardlinkVposMerchant(values.get("mid"), vposHost, merchants);
|
|
633
|
+
if (!seller)
|
|
634
|
+
return field("mid", "seller_unreviewed");
|
|
635
|
+
for (const name of ["confirmUrl", "cancelUrl"]) {
|
|
636
|
+
const target = httpsUrl(values.get(name));
|
|
637
|
+
if (!target || target.hostname !== seller.host)
|
|
638
|
+
return field(name, "callback_host");
|
|
639
|
+
}
|
|
640
|
+
return {
|
|
641
|
+
ok: true,
|
|
642
|
+
pairs,
|
|
643
|
+
gated: false,
|
|
644
|
+
dedupe: [vposHost, values.get("mid"), values.get("orderid"), values.get("orderAmount"), values.get("currency")],
|
|
645
|
+
seller
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
function cardlinkVposEntryAmount(body) {
|
|
649
|
+
const pairs = parseCardlinkVposForm(body);
|
|
650
|
+
return pairs ? entryAmount(new Map(pairs.map(({ key, value }) => [key, value]))) : null;
|
|
651
|
+
}
|
|
652
|
+
var CARDLINK_VPOS_TDS2_FIELDS = Object.freeze([
|
|
653
|
+
"TDS2_Navigator_language",
|
|
654
|
+
"TDS2_Navigator_jsEnabled",
|
|
655
|
+
"TDS2_Navigator_javaEnabled",
|
|
656
|
+
"TDS2_Screen_colorDepth",
|
|
657
|
+
"TDS2_Screen_height",
|
|
658
|
+
"TDS2_Screen_width",
|
|
659
|
+
"TDS2_screen_pixelDepth",
|
|
660
|
+
"TDS2_TimezoneOffset"
|
|
661
|
+
]);
|
|
662
|
+
var PAGE_FIELDS = Object.freeze(["trid", "st", "payStep", "cmd", "startbonus", "bonusdata"]);
|
|
663
|
+
var WALLET_FIELDS = Object.freeze(["walletId", "applePayResponse"]);
|
|
664
|
+
var CARD3 = Object.freeze({ number: "card.pan", holder: "card.holderName", month: "card.expiryMonth", year: "card.expiryYear", cvc: "card.cvv" });
|
|
665
|
+
var TEXT_CONTROLS = /* @__PURE__ */ new Set([CARD3.number, CARD3.holder, CARD3.cvc]);
|
|
666
|
+
var SELECT_CONTROLS = /* @__PURE__ */ new Set([CARD3.month, CARD3.year]);
|
|
667
|
+
var MAX_PAGE3 = 256 * 1024;
|
|
668
|
+
var COOKIE_DOMAINS = Object.freeze({
|
|
669
|
+
"vpos.eurocommerce.gr": "eurocommerce.gr",
|
|
670
|
+
"ecommerce.cardlink.gr": "cardlink.gr",
|
|
671
|
+
"www.alphaecommerce.gr": "alphaecommerce.gr"
|
|
672
|
+
});
|
|
673
|
+
var POST_REQUIRED = Object.freeze(["trid", "st", "cmd", CARD3.number, CARD3.holder, CARD3.month, CARD3.year, CARD3.cvc, "makepayment"]);
|
|
674
|
+
var POST_EMPTY = Object.freeze(["payStep", "startbonus", "bonusdata", ...WALLET_FIELDS]);
|
|
675
|
+
var POST_ALLOWED = /* @__PURE__ */ new Set([...POST_REQUIRED, ...POST_EMPTY, "paymentMethod", ...CARDLINK_VPOS_TDS2_FIELDS]);
|
|
676
|
+
var CARDLINK_VPOS_REFUSALS = Object.freeze([
|
|
677
|
+
"cardlink_vpos_card_refused",
|
|
678
|
+
"cardlink_vpos_card_page",
|
|
679
|
+
"cardlink_vpos_3ds_challenge",
|
|
680
|
+
"cardlink_vpos_declined"
|
|
681
|
+
]);
|
|
682
|
+
var REFUSAL_FOR = Object.freeze({
|
|
683
|
+
card_refused: "cardlink_vpos_card_refused",
|
|
684
|
+
card_page: "cardlink_vpos_card_page",
|
|
685
|
+
challenge: "cardlink_vpos_3ds_challenge",
|
|
686
|
+
declined: "cardlink_vpos_declined"
|
|
687
|
+
});
|
|
688
|
+
var CARDLINK_VPOS_CAPABILITY = "cardlink_vpos_hosted_payment_page";
|
|
689
|
+
var CARDLINK_VPOS_OPERATION = "cardlink_vpos.hosted_sale";
|
|
690
|
+
var cardlink_vpos_default = /* @__PURE__ */ registerProcessor({
|
|
691
|
+
psp: CARDLINK_VPOS_PSP,
|
|
692
|
+
definitions: [
|
|
693
|
+
{
|
|
694
|
+
psp: "cardlink_vpos",
|
|
695
|
+
// The merchant's signed entry, as the header above reads it: a Document navigation that carries no card. The
|
|
696
|
+
// cardholder's device repeats it over the end-to-end TLS relay, fills the card into the page the VPOS returns
|
|
697
|
+
// and posts it in that same session, and the runtime resolves the paused navigation with the hosted_form notice.
|
|
698
|
+
// Only the entry path on the three live hosts is matched (isCardlinkVposEntryUrl). The card page posts to the same
|
|
699
|
+
// path, so the SDK fails every other post to these hosts in the agent's browser, and no placeholder card reaches
|
|
700
|
+
// the VPOS. The test hosts are listed so a live host classifies as live and the create refuses a test row there;
|
|
701
|
+
// no entry on them is paused. Ships dark: served only to a client that declares
|
|
702
|
+
// `cardlink_vpos_hosted_payment_page`, and gated off for every company the operator has not turned it on for.
|
|
703
|
+
capability: CARDLINK_VPOS_CAPABILITY,
|
|
704
|
+
match: "(?:vpos\\.eurocommerce\\.gr|ecommerce\\.cardlink\\.gr|www\\.alphaecommerce\\.gr)/vpos/shophandlermpi(?![\\w/.%;=!-])",
|
|
705
|
+
hosts: [
|
|
706
|
+
"^vpos\\.eurocommerce\\.gr$",
|
|
707
|
+
"^ecommerce\\.cardlink\\.gr$",
|
|
708
|
+
"^www\\.alphaecommerce\\.gr$",
|
|
709
|
+
"^eurocommerce-test\\.cardlink\\.gr$",
|
|
710
|
+
"^ecommerce-test\\.cardlink\\.gr$",
|
|
711
|
+
"^alphaecommerce-test\\.cardlink\\.gr$"
|
|
712
|
+
],
|
|
713
|
+
sandboxHosts: ["^eurocommerce-test\\.cardlink\\.gr$", "^ecommerce-test\\.cardlink\\.gr$", "^alphaecommerce-test\\.cardlink\\.gr$"],
|
|
714
|
+
hostEnvironmentPinned: true,
|
|
715
|
+
encoding: "form",
|
|
716
|
+
// A form navigation: no captured header is ever replayed.
|
|
717
|
+
passthroughHeaders: [],
|
|
718
|
+
mode: "hosted_form",
|
|
719
|
+
hostedForm: {
|
|
720
|
+
// The card goes into the VPOS's own page on the device, never into the entry, which must carry none
|
|
721
|
+
// (checkCardlinkVposEntry). The entry's rules come with this registration (hostedEntry below), so no policy is
|
|
722
|
+
// named here.
|
|
723
|
+
cardIn: "processor_page",
|
|
724
|
+
required: [...REQUIRED3],
|
|
725
|
+
// The card page's own fields, which the device fills on that page.
|
|
726
|
+
card: { number: "card.pan", month: "card.expiryMonth", year: "card.expiryYear", cvc: "card.cvv" },
|
|
727
|
+
// The host, the mid, the order id and the amount name one payment; the entry's rules read the host from its URL.
|
|
728
|
+
dedupe: ["(vposHost)", "mid", "orderid", "orderAmount", "currency"]
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
],
|
|
732
|
+
// Only the cardholder's device repeats an entry, after a person approves; no reviewed list names cardlink_vpos.
|
|
733
|
+
refusedOperations: [CARDLINK_VPOS_OPERATION],
|
|
734
|
+
// Not surveyed: the VPOS tells the merchant the result through the browser's return and a copy to its server, both
|
|
735
|
+
// signed under the merchant's secret, which Agentcard never holds.
|
|
736
|
+
settlementReadback: "not_surveyed",
|
|
737
|
+
exactUrl: isCardlinkVposEntryUrl,
|
|
738
|
+
hostedEntry: (body, { url }) => checkCardlinkVposEntry(body, { url }),
|
|
739
|
+
amount: (template) => template && isCardlinkVposEntryUrl(template.url) ? cardlinkVposEntryAmount(template.body) : null,
|
|
740
|
+
limitations: [
|
|
741
|
+
"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.",
|
|
742
|
+
"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.",
|
|
743
|
+
"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.",
|
|
744
|
+
"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.",
|
|
745
|
+
"The browser receives a submission notice, not the processor result."
|
|
746
|
+
]
|
|
747
|
+
});
|
|
748
|
+
// src/processors/eghl.js
|
|
749
|
+
var EGHL_PSP = "eghl";
|
|
750
|
+
var EGHL_OPERATION = "eghl.hosted_sale";
|
|
751
|
+
var EGHL_HOST = "securepay.e-ghl.com";
|
|
752
|
+
var EGHL_SANDBOX_HOST = "test2pay.ghl.com";
|
|
753
|
+
var LIVE_PATH = "/ipg/payment.aspx";
|
|
754
|
+
var SANDBOX_PATH = "/ipgsg/payment.aspx";
|
|
755
|
+
var MAX_URL2 = 8192;
|
|
756
|
+
var field2 = (name, reason) => ({ ok: false, code: "hosted_form_field_refused", field: name, reason });
|
|
757
|
+
function eghlEntry(raw) {
|
|
758
|
+
if (typeof raw !== "string" || raw.length > MAX_URL2 || raw.includes("#"))
|
|
759
|
+
return null;
|
|
760
|
+
let url;
|
|
761
|
+
try {
|
|
762
|
+
url = new URL(raw);
|
|
763
|
+
}
|
|
764
|
+
catch {
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
if (url.href !== raw || url.protocol !== "https:" || url.port || url.username || url.password || url.search.length < 2)
|
|
768
|
+
return null;
|
|
769
|
+
const path = url.pathname.toLowerCase();
|
|
770
|
+
const query = url.search.slice(1);
|
|
771
|
+
if (url.hostname === EGHL_HOST && path === LIVE_PATH)
|
|
772
|
+
return Object.freeze({ test: false, query });
|
|
773
|
+
if (url.hostname === EGHL_SANDBOX_HOST && path === SANDBOX_PATH)
|
|
774
|
+
return Object.freeze({ test: true, query });
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
function isEghlEntryUrl(raw) {
|
|
778
|
+
return eghlEntry(raw) !== null;
|
|
779
|
+
}
|
|
780
|
+
var EGHL_MERCHANTS = Object.freeze([
|
|
781
|
+
Object.freeze({ merchant: "BookXcess", serviceId: "BXS", payee: "BookXcess Sdn Bhd", returnHosts: Object.freeze(["shopify.ghl.com:11443"]), test: false })
|
|
782
|
+
]);
|
|
783
|
+
var SERVICE_ID = /^[A-Za-z0-9]{3}$/;
|
|
784
|
+
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})?$/;
|
|
785
|
+
function eghlMerchant(serviceId, { test = false, merchants = EGHL_MERCHANTS } = {}) {
|
|
786
|
+
if (typeof serviceId !== "string" || !SERVICE_ID.test(serviceId) || !Array.isArray(merchants))
|
|
787
|
+
return null;
|
|
788
|
+
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)));
|
|
789
|
+
return found.length === 1 ? found[0] : null;
|
|
790
|
+
}
|
|
791
|
+
var REQUIRED4 = Object.freeze([
|
|
792
|
+
"TransactionType",
|
|
793
|
+
"PymtMethod",
|
|
794
|
+
"ServiceID",
|
|
795
|
+
"PaymentID",
|
|
796
|
+
"OrderNumber",
|
|
797
|
+
"MerchantReturnURL",
|
|
798
|
+
"MerchantCallBackURL",
|
|
799
|
+
"Amount",
|
|
800
|
+
"CurrencyCode",
|
|
801
|
+
"HashValue"
|
|
802
|
+
]);
|
|
803
|
+
var CARD_KEYS2 = /* @__PURE__ */ new Set(["cardno", "cardexp", "cardcvv2", "cardholder", "param2", "param4", "cvv2", "epmonth2", "epyear2", "custocp"]);
|
|
804
|
+
var SECRET_KEYS = /* @__PURE__ */ new Set(["password"]);
|
|
805
|
+
var STORED_KEYS2 = /* @__PURE__ */ new Set([
|
|
806
|
+
"tokentype",
|
|
807
|
+
"token",
|
|
808
|
+
"cardid",
|
|
809
|
+
"precheckoutid",
|
|
810
|
+
"reqtoken",
|
|
811
|
+
"pairingtoken",
|
|
812
|
+
"reqverifier",
|
|
813
|
+
"pairingverifier",
|
|
814
|
+
"checkoutresourceurl"
|
|
815
|
+
]);
|
|
816
|
+
var SPECIAL_KEYS = /* @__PURE__ */ new Set(["eppmonth", "promocode"]);
|
|
817
|
+
var RESULT_KEYS = Object.freeze(["MerchantReturnURL", "MerchantCallBackURL", "MerchantApprovalURL", "MerchantUnApprovalURL"]);
|
|
818
|
+
var CURRENCIES3 = /* @__PURE__ */ new Set(["MYR", "SGD", "USD", "PHP", "THB"]);
|
|
819
|
+
var AMOUNT = /^(0|[1-9]\d{0,8})\.(\d{2})$/;
|
|
820
|
+
function httpsUrl2(value) {
|
|
821
|
+
let url;
|
|
822
|
+
try {
|
|
823
|
+
url = new URL(value);
|
|
824
|
+
}
|
|
825
|
+
catch {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
if (url.protocol !== "https:" || url.username || url.password || url.hash)
|
|
829
|
+
return null;
|
|
830
|
+
return url;
|
|
831
|
+
}
|
|
832
|
+
function entryFields(text3) {
|
|
833
|
+
const pairs = parseRedsysForm(text3);
|
|
834
|
+
if (!pairs)
|
|
835
|
+
return null;
|
|
836
|
+
return { pairs, values: new Map(pairs.map(({ key, value }) => [key.toLowerCase(), value])) };
|
|
837
|
+
}
|
|
838
|
+
function entryAmount2(values) {
|
|
839
|
+
const currency = values.get("currencycode");
|
|
840
|
+
const amount = AMOUNT.exec(values.get("amount") ?? "");
|
|
841
|
+
if (!amount || typeof currency !== "string" || !CURRENCIES3.has(currency))
|
|
842
|
+
return null;
|
|
843
|
+
const cents = Number(amount[1]) * 100 + Number(amount[2]);
|
|
844
|
+
return cents > 0 && Number.isSafeInteger(cents) ? { amountCents: cents, currency: currency.toLowerCase() } : null;
|
|
845
|
+
}
|
|
846
|
+
function checkEghlEntry(body, { url = null, merchants = EGHL_MERCHANTS } = {}) {
|
|
847
|
+
if (body !== void 0 && body !== null && body !== "")
|
|
848
|
+
return field2("(body)", "not_an_entry");
|
|
849
|
+
const entry = eghlEntry(url);
|
|
850
|
+
if (!entry)
|
|
851
|
+
return field2("(url)", "malformed_field");
|
|
852
|
+
const fields = entryFields(entry.query);
|
|
853
|
+
if (!fields)
|
|
854
|
+
return field2("(query)", "malformed");
|
|
855
|
+
const { pairs, values } = fields;
|
|
856
|
+
for (const { key, value } of pairs) {
|
|
857
|
+
if (value === "")
|
|
858
|
+
continue;
|
|
859
|
+
const folded = key.toLowerCase();
|
|
860
|
+
if (CARD_KEYS2.has(folded))
|
|
861
|
+
return field2(key, "card_in_entry");
|
|
862
|
+
if (SECRET_KEYS.has(folded))
|
|
863
|
+
return field2(key, "not_an_entry");
|
|
864
|
+
if (STORED_KEYS2.has(folded))
|
|
865
|
+
return field2(key, "stored_credential");
|
|
866
|
+
if (SPECIAL_KEYS.has(folded))
|
|
867
|
+
return field2(key, "special_flow");
|
|
868
|
+
}
|
|
869
|
+
const missing = REQUIRED4.filter((name) => !values.get(name.toLowerCase()));
|
|
870
|
+
if (missing.length)
|
|
871
|
+
return { ok: false, code: "hosted_form_template_incomplete", missing };
|
|
872
|
+
if (values.get("transactiontype") !== "SALE")
|
|
873
|
+
return field2("TransactionType", "not_a_sale");
|
|
874
|
+
if (!["ANY", "CC"].includes(values.get("pymtmethod")))
|
|
875
|
+
return field2("PymtMethod", "special_flow");
|
|
876
|
+
if (!/^[0-9A-Fa-f]{64}$/.test(values.get("hashvalue")))
|
|
877
|
+
return field2("HashValue", "unsigned");
|
|
878
|
+
if (!entryAmount2(values))
|
|
879
|
+
return field2(CURRENCIES3.has(values.get("currencycode")) ? "Amount" : "CurrencyCode", "malformed");
|
|
880
|
+
if (!SERVICE_ID.test(values.get("serviceid")))
|
|
881
|
+
return field2("ServiceID", "malformed");
|
|
882
|
+
if (!/^[A-Za-z0-9._-]{1,20}$/.test(values.get("paymentid")))
|
|
883
|
+
return field2("PaymentID", "malformed");
|
|
884
|
+
if (values.get("ordernumber").length > 20)
|
|
885
|
+
return field2("OrderNumber", "malformed");
|
|
886
|
+
const pageTimeout = values.get("pagetimeout");
|
|
887
|
+
if (pageTimeout !== void 0 && !/^[1-9]\d{1,4}$/.test(pageTimeout))
|
|
888
|
+
return field2("PageTimeout", "malformed");
|
|
889
|
+
const seller = eghlMerchant(values.get("serviceid"), { test: entry.test, merchants });
|
|
890
|
+
if (!seller)
|
|
891
|
+
return field2("ServiceID", "seller_unreviewed");
|
|
892
|
+
for (const name of RESULT_KEYS) {
|
|
893
|
+
const value = values.get(name.toLowerCase());
|
|
894
|
+
if (!value)
|
|
895
|
+
continue;
|
|
896
|
+
const target = httpsUrl2(value);
|
|
897
|
+
if (!target || !seller.returnHosts.includes(target.host) || [EGHL_HOST, EGHL_SANDBOX_HOST].includes(target.hostname))
|
|
898
|
+
return field2(name, "callback_host");
|
|
899
|
+
}
|
|
900
|
+
return { ok: true, pairs, gated: false, dedupe: [values.get("serviceid"), values.get("paymentid")], sandbox: entry.test, seller };
|
|
901
|
+
}
|
|
902
|
+
function eghlEntryAmount(body, url) {
|
|
903
|
+
if (body !== void 0 && body !== null && body !== "")
|
|
904
|
+
return null;
|
|
905
|
+
const entry = eghlEntry(url);
|
|
906
|
+
const fields = entry ? entryFields(entry.query) : null;
|
|
907
|
+
return fields ? entryAmount2(fields.values) : null;
|
|
908
|
+
}
|
|
909
|
+
var MAX_PAGE4 = 1024 * 1024;
|
|
910
|
+
var NEVER_SENT = new Set(["expressCheckoutType", "c2pRememberMeBrowser", "CustOCP", "CustRecurr", "CustAddress"].map((name) => name.toLowerCase()));
|
|
911
|
+
var PAGE_REQUIRED = Object.freeze([
|
|
912
|
+
"TransactionType",
|
|
913
|
+
"ServiceID",
|
|
914
|
+
"MerchantName",
|
|
915
|
+
"PaymentID",
|
|
916
|
+
"Amount",
|
|
917
|
+
"BaseTxnAmount",
|
|
918
|
+
"CurrencyCode",
|
|
919
|
+
"BaseCurrencyCode",
|
|
920
|
+
"HashValue",
|
|
921
|
+
"Param2",
|
|
922
|
+
"Param4",
|
|
923
|
+
"CardExp",
|
|
924
|
+
"CVV2",
|
|
925
|
+
"PymtMethod"
|
|
926
|
+
]);
|
|
927
|
+
var EGHL_REFUSALS = Object.freeze(["eghl_failed", "eghl_cancelled"]);
|
|
928
|
+
var MAX_ANSWER = 256 * 1024;
|
|
929
|
+
var RESULT_FIELDS = Object.freeze(["TxnStatus", "ServiceID", "PaymentID", "Amount", "CurrencyCode"]);
|
|
930
|
+
var eghl_default = /* @__PURE__ */ registerProcessor({
|
|
931
|
+
psp: EGHL_PSP,
|
|
932
|
+
definitions: [
|
|
933
|
+
{
|
|
934
|
+
psp: "eghl",
|
|
935
|
+
// The merchant's entry to eGHL's payment page, as the header above reads it: a GET Document navigation whose
|
|
936
|
+
// query names the payment and which carries no card. The cardholder's device repeats it over the end-to-end TLS
|
|
937
|
+
// relay and pays on the page eGHL returns to it, and the runtime resolves the paused navigation with the
|
|
938
|
+
// hosted_form notice. Only the entry is matched (isEghlEntryUrl): the card page's own card post goes to the same
|
|
939
|
+
// path as a POST. The path is matched in any letter case, as IIS reads it; `(?![\\w/.%-])` ends it for a consumer
|
|
940
|
+
// that tests `match` unanchored. Ships dark: served only to a client that declares `eghl_hosted_payment_page`, and
|
|
941
|
+
// gated off for every company the operator has not allowlisted.
|
|
942
|
+
capability: "eghl_hosted_payment_page",
|
|
943
|
+
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/.%-])",
|
|
944
|
+
hosts: ["^securepay\\.e-ghl\\.com$", "^test2pay\\.ghl\\.com$"],
|
|
945
|
+
sandboxHosts: ["^test2pay\\.ghl\\.com$"],
|
|
946
|
+
hostEnvironmentPinned: true,
|
|
947
|
+
// `encoding` describes the card page's own card post, which the device makes as the page does, since the entry
|
|
948
|
+
// has no body. No captured header is ever replayed.
|
|
949
|
+
encoding: "form",
|
|
950
|
+
passthroughHeaders: [],
|
|
951
|
+
// The paused request is the navigation itself, a GET with the payment in its query.
|
|
952
|
+
request: { method: "GET", cardIn: "processor_page", response: "document" },
|
|
953
|
+
mode: "hosted_form",
|
|
954
|
+
hostedForm: {
|
|
955
|
+
// The card goes into eGHL's page on the device, never into the entry (checkEghlEntry refuses one there). The
|
|
956
|
+
// entry's own rules come with this registration (hostedEntry below), so no policy is named here.
|
|
957
|
+
cardIn: "processor_page",
|
|
958
|
+
required: ["TransactionType", "PymtMethod", "ServiceID", "PaymentID", "OrderNumber", "MerchantReturnURL", "MerchantCallBackURL", "Amount", "CurrencyCode", "HashValue"],
|
|
959
|
+
// The card page's own inputs in its card form (frmProcessPayment, read card free on 2026-11-05): the number in
|
|
960
|
+
// Param2, the expiry in CardExp as YYYYMM, which the page builds from its month and year selects, the code in
|
|
961
|
+
// CVV2. The cardholder's name goes in Param4.
|
|
962
|
+
card: { number: "Param2", expiry: "CardExp", cvc: "CVV2" },
|
|
963
|
+
// eGHL takes one PaymentID once per merchant.
|
|
964
|
+
dedupe: ["ServiceID", "PaymentID"]
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
],
|
|
968
|
+
// Only the cardholder's device repeats an entry, after a person approves; no reviewed list names eghl.
|
|
969
|
+
refusedOperations: [EGHL_OPERATION],
|
|
970
|
+
// Not surveyed: eGHL tells the merchant's server the result (MerchantCallBackURL), and its return carries a hash only
|
|
971
|
+
// the merchant can check.
|
|
972
|
+
settlementReadback: "not_surveyed",
|
|
973
|
+
exactUrl: isEghlEntryUrl,
|
|
974
|
+
amount: (template) => template && typeof template === "object" ? eghlEntryAmount(template.body, template.url) : null,
|
|
975
|
+
hostedEntry: (body, { url = null } = {}) => checkEghlEntry(body, { url }),
|
|
976
|
+
limitations: [
|
|
977
|
+
"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.",
|
|
978
|
+
"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.",
|
|
979
|
+
"eGHL runs 3-D Secure on the card. A challenge ends the payment on the device with nothing charged.",
|
|
980
|
+
"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."
|
|
981
|
+
]
|
|
982
|
+
});
|
|
983
|
+
// src/processors/frisbii.js
|
|
984
|
+
var FRISBII_PSP = "frisbii";
|
|
985
|
+
var FRISBII_OPERATION = "frisbii.card_request";
|
|
986
|
+
var FRISBII_HOSTS = /* @__PURE__ */ Object.freeze({ "card.reepay.com": "reepay", "card.frisbii.com": "frisbii" });
|
|
987
|
+
var FRISBII_TOKEN_PATH = "/v1/token/";
|
|
988
|
+
var FRISBII_REFUSED_PATHS = /* @__PURE__ */ Object.freeze({
|
|
989
|
+
"/v1/token/cof/": "frisbii_stored_card_unsupported",
|
|
990
|
+
"/v1/token/create_click_to_pay": "frisbii_click_to_pay_unsupported"
|
|
991
|
+
});
|
|
992
|
+
var BODY_LIMIT3 = 8192;
|
|
993
|
+
var URL_LIMIT2 = 256;
|
|
994
|
+
var CARD_NUMBER2 = /^[0-9]{12,19}$/;
|
|
995
|
+
var MONTH = /^(?:0[1-9]|1[0-2])$/;
|
|
996
|
+
var YEAR = /^[0-9]{2}$/;
|
|
997
|
+
var SECURITY_CODE2 = /^(?:[0-9]{3,4})?$/;
|
|
998
|
+
var IDENTIFIER = /^[A-Za-z0-9_-]{8,128}$/;
|
|
999
|
+
var SCA_RULES = /* @__PURE__ */ Object.freeze([
|
|
1000
|
+
"DO_NOT_USE_SCA",
|
|
1001
|
+
"MUST_USE_SCA_AUTH",
|
|
1002
|
+
"MUST_USE_SCA_PREAUTH",
|
|
1003
|
+
"USE_SCA_IF_AVAILABLE_AUTH",
|
|
1004
|
+
"USE_SCA_IF_AVAILABLE_PREAUTH"
|
|
1005
|
+
]);
|
|
1006
|
+
var BODY_ORDER = /* @__PURE__ */ Object.freeze([
|
|
1007
|
+
"number",
|
|
1008
|
+
"month",
|
|
1009
|
+
"year",
|
|
1010
|
+
"cvv",
|
|
1011
|
+
"cardTypeOverride",
|
|
1012
|
+
"click_to_pay_encrypt",
|
|
1013
|
+
"billing_address",
|
|
1014
|
+
"pkey",
|
|
1015
|
+
"recurring",
|
|
1016
|
+
"cardholder_name",
|
|
1017
|
+
"intent",
|
|
1018
|
+
"recurringAverageAmount",
|
|
1019
|
+
"agreementFilter",
|
|
1020
|
+
"strongAuthenticationRule",
|
|
1021
|
+
"tokenStrongAuthenticationRequest"
|
|
1022
|
+
]);
|
|
1023
|
+
var BODY_REQUIRED = /* @__PURE__ */ Object.freeze(["number", "month", "year", "cvv", "pkey", "recurring", "strongAuthenticationRule"]);
|
|
1024
|
+
var BODY_REFUSED = /* @__PURE__ */ Object.freeze(["cardTypeOverride", "click_to_pay_encrypt", "billing_address"]);
|
|
1025
|
+
var SCA_ORDER = /* @__PURE__ */ Object.freeze(["amount", "currency", "orderId", "orderText", "merchantScaData", "returnUrl", "tokenBrowserInfo"]);
|
|
1026
|
+
var BROWSER_ORDER = /* @__PURE__ */ Object.freeze([
|
|
1027
|
+
"javascriptEnabled",
|
|
1028
|
+
"challengeWindowSize",
|
|
1029
|
+
"colorDepth",
|
|
1030
|
+
"javaEnabled",
|
|
1031
|
+
"screenHeight",
|
|
1032
|
+
"screenWidth",
|
|
1033
|
+
"tz"
|
|
1034
|
+
]);
|
|
1035
|
+
var LABEL = /^[A-Za-z0-9_-]{1,64}$/;
|
|
1036
|
+
var record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1037
|
+
var own3 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1038
|
+
var refuse3 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
1039
|
+
var CARD4 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
1040
|
+
var text = (value, max) => typeof value === "string" && value.length <= max;
|
|
1041
|
+
var absentOrNull = (value) => value === void 0 || value === null;
|
|
1042
|
+
var inOrder = (value, order) => Object.keys(value).every((key) => order.includes(key)) && Object.keys(value).join() === order.filter((key) => own3(value, key)).join();
|
|
1043
|
+
function frisbiiTokenUrl(url) {
|
|
1044
|
+
if (typeof url !== "string" || url.length > URL_LIMIT2 || url.includes("#"))
|
|
1045
|
+
return null;
|
|
1046
|
+
let parsed;
|
|
1047
|
+
try {
|
|
1048
|
+
parsed = new URL(url);
|
|
1049
|
+
}
|
|
1050
|
+
catch {
|
|
1051
|
+
return null;
|
|
1052
|
+
}
|
|
1053
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own3(FRISBII_HOSTS, parsed.hostname) || parsed.pathname !== FRISBII_TOKEN_PATH)
|
|
1054
|
+
return null;
|
|
1055
|
+
const match = /^\?session=([A-Za-z0-9_-]{8,128})$/.exec(parsed.search);
|
|
1056
|
+
return match ? Object.freeze({ host: parsed.hostname, brand: FRISBII_HOSTS[parsed.hostname], session: match[1] }) : null;
|
|
1057
|
+
}
|
|
1058
|
+
var isFrisbiiTokenUrl = (url) => frisbiiTokenUrl(url) !== null;
|
|
1059
|
+
function frisbiiRefusedFlowUrl(url) {
|
|
1060
|
+
if (typeof url !== "string" || url.length > URL_LIMIT2 || url.includes("#"))
|
|
1061
|
+
return null;
|
|
1062
|
+
let parsed;
|
|
1063
|
+
try {
|
|
1064
|
+
parsed = new URL(url);
|
|
1065
|
+
}
|
|
1066
|
+
catch {
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own3(FRISBII_HOSTS, parsed.hostname) || !own3(FRISBII_REFUSED_PATHS, parsed.pathname))
|
|
1070
|
+
return null;
|
|
1071
|
+
return FRISBII_REFUSED_PATHS[parsed.pathname];
|
|
1072
|
+
}
|
|
1073
|
+
function luhn(digits2) {
|
|
1074
|
+
let sum = 0;
|
|
1075
|
+
for (let at = digits2.length - 1, double = false; at >= 0; at -= 1, double = !double) {
|
|
1076
|
+
let digit = digits2.charCodeAt(at) - 48;
|
|
1077
|
+
if (double)
|
|
1078
|
+
digit = digit * 2 > 9 ? digit * 2 - 9 : digit * 2;
|
|
1079
|
+
sum += digit;
|
|
1080
|
+
}
|
|
1081
|
+
return sum % 10 === 0;
|
|
1082
|
+
}
|
|
1083
|
+
function readBody3(body) {
|
|
1084
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT3)
|
|
1085
|
+
return null;
|
|
1086
|
+
try {
|
|
1087
|
+
const value = JSON.parse(body);
|
|
1088
|
+
return record2(value) && JSON.stringify(value) === body ? value : null;
|
|
1089
|
+
}
|
|
1090
|
+
catch {
|
|
1091
|
+
return null;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
function browserInfo(info) {
|
|
1095
|
+
return record2(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;
|
|
1096
|
+
}
|
|
1097
|
+
function scaBlock(block, target) {
|
|
1098
|
+
if (!record2(block) || !inOrder(block, SCA_ORDER) || !own3(block, "returnUrl") || !own3(block, "tokenBrowserInfo"))
|
|
1099
|
+
return false;
|
|
1100
|
+
if (!Number.isSafeInteger(block.amount) || block.amount < 0 || typeof block.currency !== "string" || !/^[A-Z]{3}$/.test(block.currency))
|
|
1101
|
+
return false;
|
|
1102
|
+
if (!(absentOrNull(block.orderId) || text(block.orderId, 128)) || !(absentOrNull(block.orderText) || text(block.orderText, 512)))
|
|
1103
|
+
return false;
|
|
1104
|
+
if (!(absentOrNull(block.merchantScaData) || record2(block.merchantScaData)))
|
|
1105
|
+
return false;
|
|
1106
|
+
if (!text(block.returnUrl, 2048) || !browserInfo(block.tokenBrowserInfo))
|
|
1107
|
+
return false;
|
|
1108
|
+
const back = /^https:\/\/checkout\.(reepay|frisbii)\.com\/return\.001\.html\?id=([A-Za-z0-9_-]{8,128})(?:&[A-Za-z0-9_.~%=+/-]*)*$/.exec(block.returnUrl);
|
|
1109
|
+
return back !== null && (target === null || back[1] === target.brand && back[2] === target.session);
|
|
1110
|
+
}
|
|
1111
|
+
function frisbiiBodyVerdict(body, url) {
|
|
1112
|
+
const value = readBody3(body);
|
|
1113
|
+
if (value === null || !inOrder(value, BODY_ORDER) || !BODY_REQUIRED.every((key) => own3(value, key)) || BODY_REFUSED.some((key) => own3(value, key)))
|
|
1114
|
+
return refuse3("frisbii_body_unsupported");
|
|
1115
|
+
if (value.recurring === true || value.intent === "CHARGE_AND_STORE")
|
|
1116
|
+
return refuse3("frisbii_card_on_file");
|
|
1117
|
+
const target = url === void 0 ? null : frisbiiTokenUrl(url);
|
|
1118
|
+
if (url !== void 0 && target === null)
|
|
1119
|
+
return refuse3("frisbii_body_unsupported");
|
|
1120
|
+
const sound = typeof value.number === "string" && CARD_NUMBER2.test(value.number) && luhn(value.number) && typeof value.month === "string" && MONTH.test(value.month) && typeof value.year === "string" && YEAR.test(value.year) && typeof value.cvv === "string" && SECURITY_CODE2.test(value.cvv) && typeof value.pkey === "string" && IDENTIFIER.test(value.pkey) && value.recurring === false && (value.cardholder_name === void 0 || text(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));
|
|
1121
|
+
return sound ? CARD4 : refuse3("frisbii_body_unsupported");
|
|
1122
|
+
}
|
|
1123
|
+
var frisbii_default = /* @__PURE__ */ registerProcessor({
|
|
1124
|
+
psp: FRISBII_PSP,
|
|
1125
|
+
definitions: [
|
|
1126
|
+
{
|
|
1127
|
+
psp: "frisbii",
|
|
1128
|
+
// The hosted page's card request, as the header above reads it, on both brands' card hosts. A test account
|
|
1129
|
+
// shares the live hosts, so no sandbox host is marked. The match reads the host and the path and ends with it. It
|
|
1130
|
+
// also takes the page's two other card paths, /v1/token/cof/ and /v1/token/create_click_to_pay, so the pause
|
|
1131
|
+
// decision holds them, and the body gate refuses every body there; the exact-URL rule below holds the session
|
|
1132
|
+
// query of the card request. Ships dark: served only to a client that declares `frisbii_card_token`, and only for a company
|
|
1133
|
+
// the backend's processor gate turns Frisbii on for.
|
|
1134
|
+
capability: "frisbii_card_token",
|
|
1135
|
+
match: "card\\.(?:reepay|frisbii)\\.com/v1/token/(?:cof/|create_click_to_pay)?",
|
|
1136
|
+
hosts: ["^card\\.reepay\\.com$", "^card\\.frisbii\\.com$"],
|
|
1137
|
+
encoding: "json",
|
|
1138
|
+
// The page sends no header but its content type. Origin, Referer and cookies never ride.
|
|
1139
|
+
passthroughHeaders: [],
|
|
1140
|
+
jsonCardFields: [["number"]]
|
|
1141
|
+
}
|
|
1142
|
+
],
|
|
1143
|
+
// Only the cardholder's device would send this card, after a person approves; no reviewed list names frisbii.
|
|
1144
|
+
refusedOperations: [FRISBII_OPERATION],
|
|
1145
|
+
// Not surveyed: the card request mints a token and moves no money, and the page then charges the session with it
|
|
1146
|
+
// in a card-free request. Whether the session's own read (checkout-api /v1/checkout/<session>) can confirm that
|
|
1147
|
+
// charge was not read.
|
|
1148
|
+
settlementReadback: "not_surveyed",
|
|
1149
|
+
exactUrl: (url) => isFrisbiiTokenUrl(url) || frisbiiRefusedFlowUrl(url) !== null,
|
|
1150
|
+
// A stored card's token and Click to Pay are refused whatever their body; the card request is judged by its body.
|
|
1151
|
+
bodyGate: (url, body) => {
|
|
1152
|
+
if (url === void 0)
|
|
1153
|
+
return frisbiiBodyVerdict(body);
|
|
1154
|
+
const flow = frisbiiRefusedFlowUrl(url);
|
|
1155
|
+
if (flow !== null)
|
|
1156
|
+
return refuse3(flow);
|
|
1157
|
+
return isFrisbiiTokenUrl(url) ? frisbiiBodyVerdict(body, url) : refuse3("frisbii_url_refused");
|
|
1158
|
+
},
|
|
1159
|
+
limitations: ["A live Frisbii card goes only to a merchant account a reviewed pin lists, and none is pinned yet."]
|
|
1160
|
+
});
|
|
1161
|
+
// src/processors/iyzico.js
|
|
1162
|
+
var IYZICO_PSP = "iyzico";
|
|
1163
|
+
var IYZICO_OPERATION = "iyzico.card_request";
|
|
1164
|
+
var PATHS = ["/payment/iyzipos/checkoutform/auth/ecom", "/payment/iyzipos/checkoutform/initialize3ds/ecom"];
|
|
1165
|
+
var IYZICO_CARD_URLS = /* @__PURE__ */ Object.freeze(["https://api.iyzipay.com", "https://sandbox-api.iyzipay.com"].flatMap((origin) => PATHS.map((path) => `${origin}${path}`)));
|
|
1166
|
+
var IYZICO_BODY_KEYS = /* @__PURE__ */ Object.freeze([
|
|
1167
|
+
"installment",
|
|
1168
|
+
"paidPrice",
|
|
1169
|
+
"paymentChannel",
|
|
1170
|
+
"paymentCard",
|
|
1171
|
+
"buyerProtected",
|
|
1172
|
+
"gsmNumber",
|
|
1173
|
+
"dccPayment",
|
|
1174
|
+
"dccQueryRrn",
|
|
1175
|
+
"pwiMetadata"
|
|
1176
|
+
]);
|
|
1177
|
+
var IYZICO_CARD_KEYS = /* @__PURE__ */ Object.freeze([
|
|
1178
|
+
"cardNumber",
|
|
1179
|
+
"cardHolderName",
|
|
1180
|
+
"expireYear",
|
|
1181
|
+
"expireMonth",
|
|
1182
|
+
"cvc",
|
|
1183
|
+
"registerConsumerCard",
|
|
1184
|
+
"registerCard"
|
|
1185
|
+
]);
|
|
1186
|
+
var BODY_LIMIT4 = 4096;
|
|
1187
|
+
var CARD_NUMBER3 = /^[0-9]{12,19}$/;
|
|
1188
|
+
var SECURITY_CODE3 = /^[0-9]{3,4}$/;
|
|
1189
|
+
var MONTH2 = /^(?:0?[1-9]|1[0-2])$/;
|
|
1190
|
+
var YEAR2 = /^(?:[0-9]{2}|20[0-9]{2})$/;
|
|
1191
|
+
var PRICE = /^([1-9][0-9]{0,8}|0)(?:\.([0-9]{1,2}))?$/;
|
|
1192
|
+
var CHANNELS = /* @__PURE__ */ Object.freeze(["WEB", "MOBILE_WEB", "MOBILE_IOS", "MOBILE_ANDROID", "MOBILE_WINDOWS"]);
|
|
1193
|
+
var METADATA_KEYS = /* @__PURE__ */ Object.freeze(["lightRedesign", "pwiGrowthActionDisabled"]);
|
|
1194
|
+
var FLAG = /^[A-Za-z_]{1,16}$/;
|
|
1195
|
+
var HOLDER = /^[^\x00-\x1f\x7f0-9]{3,100}$/u;
|
|
1196
|
+
var record3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1197
|
+
var own4 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1198
|
+
var inOrder2 = (value, keys) => {
|
|
1199
|
+
let at = 0;
|
|
1200
|
+
for (const name of Object.keys(value)) {
|
|
1201
|
+
while (at < keys.length && keys[at] !== name)
|
|
1202
|
+
at += 1;
|
|
1203
|
+
if (at === keys.length)
|
|
1204
|
+
return false;
|
|
1205
|
+
at += 1;
|
|
1206
|
+
}
|
|
1207
|
+
return true;
|
|
1208
|
+
};
|
|
1209
|
+
var refuse4 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
1210
|
+
var CARD5 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
1211
|
+
function isIyzicoCardUrl(url) {
|
|
1212
|
+
return typeof url === "string" && IYZICO_CARD_URLS.includes(url);
|
|
1213
|
+
}
|
|
1214
|
+
function readBody4(body) {
|
|
1215
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT4)
|
|
1216
|
+
return null;
|
|
1217
|
+
try {
|
|
1218
|
+
const value = JSON.parse(body);
|
|
1219
|
+
return record3(value) && JSON.stringify(value) === body ? value : null;
|
|
1220
|
+
}
|
|
1221
|
+
catch {
|
|
1222
|
+
return null;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
function hundredths(price) {
|
|
1226
|
+
const match = typeof price === "number" && Number.isFinite(price) ? PRICE.exec(String(price)) : null;
|
|
1227
|
+
const value = match ? Number(match[1]) * 100 + Number((match[2] ?? "").padEnd(2, "0")) : 0;
|
|
1228
|
+
return value > 0 ? value : null;
|
|
1229
|
+
}
|
|
1230
|
+
var holderName = (name) => typeof name === "string" && HOLDER.test(name) && name.trim().split(/\s+/).filter((word) => word.length > 1).length > 1;
|
|
1231
|
+
var metadata = (value) => record3(value) && inOrder2(value, METADATA_KEYS) && Object.values(value).every((flag) => Array.isArray(flag) && flag.length === 1 && typeof flag[0] === "string" && FLAG.test(flag[0]));
|
|
1232
|
+
function iyzicoBodyVerdict(body) {
|
|
1233
|
+
const value = readBody4(body);
|
|
1234
|
+
if (value === null)
|
|
1235
|
+
return refuse4("iyzico_body_unsupported");
|
|
1236
|
+
const card = value.paymentCard;
|
|
1237
|
+
if (record3(card) && (own4(card, "cardToken") || own4(card, "ucsToken") || own4(card, "consumerToken")) && !own4(card, "cardNumber"))
|
|
1238
|
+
return refuse4("iyzico_saved_card");
|
|
1239
|
+
if (own4(value, "dccPayment") || own4(value, "dccQueryRrn"))
|
|
1240
|
+
return refuse4("iyzico_dcc_refused");
|
|
1241
|
+
if (own4(value, "gsmNumber") || own4(value, "buyerProtected") && value.buyerProtected !== false || record3(card) && (own4(card, "registerCard") && card.registerCard !== 0 || own4(card, "registerConsumerCard") && card.registerConsumerCard !== false)) {
|
|
1242
|
+
return refuse4("iyzico_keeps_card");
|
|
1243
|
+
}
|
|
1244
|
+
if (Number.isSafeInteger(value.installment) && value.installment > 1)
|
|
1245
|
+
return refuse4("iyzico_installments_refused");
|
|
1246
|
+
if (!inOrder2(value, IYZICO_BODY_KEYS) || !["installment", "paidPrice", "paymentChannel", "paymentCard"].every((key) => own4(value, key)) || value.installment !== 1 || hundredths(value.paidPrice) === null || !CHANNELS.includes(value.paymentChannel) || own4(value, "pwiMetadata") && !metadata(value.pwiMetadata))
|
|
1247
|
+
return refuse4("iyzico_body_unsupported");
|
|
1248
|
+
if (!record3(card) || Object.keys(card).join() !== IYZICO_CARD_KEYS.join() || typeof card.cardNumber !== "string" || !CARD_NUMBER3.test(card.cardNumber) || !holderName(card.cardHolderName) || typeof card.expireYear !== "string" || !YEAR2.test(card.expireYear) || typeof card.expireMonth !== "string" || !MONTH2.test(card.expireMonth) || typeof card.cvc !== "string" || !SECURITY_CODE3.test(card.cvc))
|
|
1249
|
+
return refuse4("iyzico_body_unsupported");
|
|
1250
|
+
return CARD5;
|
|
1251
|
+
}
|
|
1252
|
+
var iyzico_default = /* @__PURE__ */ registerProcessor({
|
|
1253
|
+
psp: IYZICO_PSP,
|
|
1254
|
+
definitions: [
|
|
1255
|
+
{
|
|
1256
|
+
psp: "iyzico",
|
|
1257
|
+
// The Checkout Form's card payment, as the header above reads it. Sandbox has its own host, so the device sends
|
|
1258
|
+
// a test-mode payment only iyzico's documented test cards (hostEnvironmentPinned, device-replay.js S7). Ships dark:
|
|
1259
|
+
// served only to a client that declares `iyzico_checkout_form`, for a company the backend's gate turns iyzico on
|
|
1260
|
+
// for, and autopilot never sends it.
|
|
1261
|
+
capability: "iyzico_checkout_form",
|
|
1262
|
+
match: "(?:sandbox-)?api\\.iyzipay\\.com/payment/iyzipos/checkoutform/(?:auth|initialize3ds)/ecom",
|
|
1263
|
+
hosts: ["^api\\.iyzipay\\.com$", "^sandbox-api\\.iyzipay\\.com$"],
|
|
1264
|
+
sandboxHosts: ["^sandbox-api\\.iyzipay\\.com$"],
|
|
1265
|
+
hostEnvironmentPinned: true,
|
|
1266
|
+
encoding: "json",
|
|
1267
|
+
// The form's session token and its Accept. Origin, Referer and cookies never ride, and neither does IYZI_LC,
|
|
1268
|
+
// which iyzico's preflight does not allow.
|
|
1269
|
+
passthroughHeaders: ["^x-iyzi-token$", "^accept$"],
|
|
1270
|
+
jsonCardFields: [["paymentCard", "cardNumber"]]
|
|
1271
|
+
}
|
|
1272
|
+
],
|
|
1273
|
+
// Only the cardholder's device sends it, after a person approves; 3-D Secure needs that person at the browser.
|
|
1274
|
+
refusedOperations: [IYZICO_OPERATION],
|
|
1275
|
+
// iyzico answers the form's result (CF retrieve) only to the merchant's API key and secret.
|
|
1276
|
+
settlementReadback: {
|
|
1277
|
+
answer: "none",
|
|
1278
|
+
reason: "merchant_credential_required",
|
|
1279
|
+
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.",
|
|
1280
|
+
source: "https://docs.iyzico.com/en/payment-methods/checkoutform/cf-implementation/cf-retrieve"
|
|
1281
|
+
},
|
|
1282
|
+
exactUrl: isIyzicoCardUrl,
|
|
1283
|
+
bodyGate: (url, body) => url !== void 0 && !isIyzicoCardUrl(url) ? refuse4("iyzico_url_refused") : iyzicoBodyVerdict(body)
|
|
1284
|
+
});
|
|
1285
|
+
// src/processors/midtrans.js
|
|
1286
|
+
var MIDTRANS_PSP = "midtrans";
|
|
1287
|
+
var MIDTRANS_OPERATION = "midtrans.card_request";
|
|
1288
|
+
var MIDTRANS_TOKEN_URL = "https://api.midtrans.com/v2/token";
|
|
1289
|
+
var MIDTRANS_SANDBOX_TOKEN_URL = "https://api.sandbox.midtrans.com/v2/token";
|
|
1290
|
+
var MIDTRANS_TOKEN_KEYS = /* @__PURE__ */ Object.freeze(["card_cvv", "card_number", "card_exp_month", "card_exp_year", "installment_term"]);
|
|
1291
|
+
var BODY_LIMIT5 = 4096;
|
|
1292
|
+
var CARD_NUMBER4 = /^[0-9]{12,19}$/;
|
|
1293
|
+
var SECURITY_CODE4 = /^[0-9]{3,4}$/;
|
|
1294
|
+
var MONTH3 = /^(?:0[1-9]|1[0-2])$/;
|
|
1295
|
+
var YEAR3 = /^20[0-9]{2}$/;
|
|
1296
|
+
var TERM = /^[0-9]{1,3}$/;
|
|
1297
|
+
var record4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1298
|
+
var own5 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1299
|
+
var inOrder3 = (value, keys) => {
|
|
1300
|
+
let at = 0;
|
|
1301
|
+
for (const name of Object.keys(value)) {
|
|
1302
|
+
while (at < keys.length && keys[at] !== name)
|
|
1303
|
+
at += 1;
|
|
1304
|
+
if (at === keys.length)
|
|
1305
|
+
return false;
|
|
1306
|
+
at += 1;
|
|
1307
|
+
}
|
|
1308
|
+
return true;
|
|
1309
|
+
};
|
|
1310
|
+
var refuse5 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
1311
|
+
var CARD6 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
1312
|
+
function isMidtransTokenUrl(url) {
|
|
1313
|
+
return url === MIDTRANS_TOKEN_URL || url === MIDTRANS_SANDBOX_TOKEN_URL;
|
|
1314
|
+
}
|
|
1315
|
+
function readBody5(body) {
|
|
1316
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT5)
|
|
1317
|
+
return null;
|
|
1318
|
+
let value;
|
|
1319
|
+
try {
|
|
1320
|
+
value = JSON.parse(body);
|
|
1321
|
+
if (!record4(value) || JSON.stringify(value) !== body)
|
|
1322
|
+
return null;
|
|
1323
|
+
}
|
|
1324
|
+
catch {
|
|
1325
|
+
return null;
|
|
1326
|
+
}
|
|
1327
|
+
return value;
|
|
1328
|
+
}
|
|
1329
|
+
function midtransBodyVerdict(body) {
|
|
1330
|
+
const value = readBody5(body);
|
|
1331
|
+
if (value === null || !inOrder3(value, MIDTRANS_TOKEN_KEYS)) {
|
|
1332
|
+
if (record4(value) && (own5(value, "token_id") || own5(value, "two_click")) && !own5(value, "card_number"))
|
|
1333
|
+
return refuse5("midtrans_saved_card");
|
|
1334
|
+
return refuse5("midtrans_body_unsupported");
|
|
1335
|
+
}
|
|
1336
|
+
if (!own5(value, "card_cvv") || !own5(value, "card_number") || !own5(value, "card_exp_month") || !own5(value, "card_exp_year")) {
|
|
1337
|
+
return refuse5("midtrans_body_unsupported");
|
|
1338
|
+
}
|
|
1339
|
+
if (typeof value.card_cvv !== "string" || !SECURITY_CODE4.test(value.card_cvv) || typeof value.card_number !== "string" || !CARD_NUMBER4.test(value.card_number) || typeof value.card_exp_month !== "string" || !MONTH3.test(value.card_exp_month) || typeof value.card_exp_year !== "string" || !YEAR3.test(value.card_exp_year))
|
|
1340
|
+
return refuse5("midtrans_body_unsupported");
|
|
1341
|
+
if (own5(value, "installment_term") && (typeof value.installment_term !== "string" || !TERM.test(value.installment_term)))
|
|
1342
|
+
return refuse5("midtrans_body_unsupported");
|
|
1343
|
+
return CARD6;
|
|
1344
|
+
}
|
|
1345
|
+
var midtrans_default = /* @__PURE__ */ registerProcessor({
|
|
1346
|
+
psp: MIDTRANS_PSP,
|
|
1347
|
+
definitions: [
|
|
1348
|
+
{
|
|
1349
|
+
psp: "midtrans",
|
|
1350
|
+
// Snap's token request, as the header above reads it. Sandbox has its own host, so the device sends a
|
|
1351
|
+
// test-mode request only Midtrans' documented test cards (hostEnvironmentPinned, device-replay.js S7).
|
|
1352
|
+
// Ships dark: served only to a client that declares `midtrans_card_token`, gated off for every org until an
|
|
1353
|
+
// operator lists one (`midtrans:<org>`), and the backend's gate serves only Agentcard's own company until the
|
|
1354
|
+
// token's publishable key is bound to the merchant (backend config.ts MIDTRANS_KEY_BOUND_TO_MERCHANT).
|
|
1355
|
+
capability: "midtrans_card_token",
|
|
1356
|
+
match: "api\\.(?:sandbox\\.)?midtrans\\.com/v2/token",
|
|
1357
|
+
hosts: ["^api\\.midtrans\\.com$", "^api\\.sandbox\\.midtrans\\.com$"],
|
|
1358
|
+
sandboxHosts: ["^api\\.sandbox\\.midtrans\\.com$"],
|
|
1359
|
+
hostEnvironmentPinned: true,
|
|
1360
|
+
encoding: "json",
|
|
1361
|
+
// Snap's own headers: the publishable client key (Authorization Basic) and X-Service. Origin, Referer and
|
|
1362
|
+
// cookies never ride.
|
|
1363
|
+
passthroughHeaders: ["^authorization$", "^x-service$"],
|
|
1364
|
+
jsonCardFields: [["card_number"]]
|
|
1365
|
+
}
|
|
1366
|
+
],
|
|
1367
|
+
// Only the cardholder's device sends a token, after a person approves; no reviewed list names midtrans.
|
|
1368
|
+
refusedOperations: [MIDTRANS_OPERATION],
|
|
1369
|
+
// Not surveyed: the token moves no money, and the merchant's own charge names its status by the order id alone.
|
|
1370
|
+
settlementReadback: "not_surveyed",
|
|
1371
|
+
exactUrl: isMidtransTokenUrl,
|
|
1372
|
+
bodyGate: (url, body) => url !== void 0 && !isMidtransTokenUrl(url) ? { verdict: "refuse", code: "midtrans_url_refused" } : midtransBodyVerdict(body)
|
|
1373
|
+
});
|
|
1374
|
+
// src/processors/monei.js
|
|
1375
|
+
var MONEI_PSP = "monei";
|
|
1376
|
+
var MONEI_OPERATION = "monei.card_request";
|
|
1377
|
+
var MONEI_TOKENS_URL = "https://api.monei.com/v1/tokens";
|
|
1378
|
+
var BODY_LIMIT6 = 1024;
|
|
1379
|
+
var PAYMENT_ID = /^(?:[0-9a-f]{32}|[0-9a-f]{40})$/;
|
|
1380
|
+
var MONEI_CARD_KEYS = /* @__PURE__ */ Object.freeze(["number", "expMonth", "expYear", "cvc"]);
|
|
1381
|
+
var NUMBER = /^[0-9]{12,19}$/;
|
|
1382
|
+
var MONTH4 = /^(?:0[1-9]|1[0-2])$/;
|
|
1383
|
+
var YEAR4 = /^[0-9]{2}$/;
|
|
1384
|
+
var CODE = /^[0-9]{3,4}$/;
|
|
1385
|
+
var record5 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1386
|
+
var keysAre = (value, keys) => {
|
|
1387
|
+
const found = Object.keys(value);
|
|
1388
|
+
return found.length === keys.length && found.every((key, at) => key === keys[at]);
|
|
1389
|
+
};
|
|
1390
|
+
var refuse6 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
1391
|
+
var CARD7 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
1392
|
+
function luhn2(digits2) {
|
|
1393
|
+
let sum = 0;
|
|
1394
|
+
for (let at = 0; at < digits2.length; at += 1) {
|
|
1395
|
+
let digit = Number(digits2[digits2.length - 1 - at]);
|
|
1396
|
+
if (at % 2 === 1) {
|
|
1397
|
+
digit *= 2;
|
|
1398
|
+
if (digit > 9)
|
|
1399
|
+
digit -= 9;
|
|
1400
|
+
}
|
|
1401
|
+
sum += digit;
|
|
1402
|
+
}
|
|
1403
|
+
return sum % 10 === 0;
|
|
1404
|
+
}
|
|
1405
|
+
function isMoneiTokensUrl(url) {
|
|
1406
|
+
return url === MONEI_TOKENS_URL;
|
|
1407
|
+
}
|
|
1408
|
+
function readBody6(body) {
|
|
1409
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT6)
|
|
1410
|
+
return null;
|
|
1411
|
+
try {
|
|
1412
|
+
const value = JSON.parse(body);
|
|
1413
|
+
return record5(value) && JSON.stringify(value) === body ? value : null;
|
|
1414
|
+
}
|
|
1415
|
+
catch {
|
|
1416
|
+
return null;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
function moneiBodyVerdict(body, url) {
|
|
1420
|
+
if (url !== void 0 && !isMoneiTokensUrl(url))
|
|
1421
|
+
return refuse6("monei_url_refused");
|
|
1422
|
+
const value = readBody6(body);
|
|
1423
|
+
if (value === null || !keysAre(value, ["paymentId", "paymentMethod"]) || typeof value.paymentId !== "string" || !PAYMENT_ID.test(value.paymentId))
|
|
1424
|
+
return refuse6("monei_body_unsupported");
|
|
1425
|
+
const method = value.paymentMethod;
|
|
1426
|
+
if (!record5(method) || !keysAre(method, ["card"]) || !record5(method.card) || !keysAre(method.card, MONEI_CARD_KEYS))
|
|
1427
|
+
return refuse6("monei_body_unsupported");
|
|
1428
|
+
const { number, expMonth, expYear, cvc } = method.card;
|
|
1429
|
+
if (![number, expMonth, expYear, cvc].every((part) => typeof part === "string"))
|
|
1430
|
+
return refuse6("monei_body_unsupported");
|
|
1431
|
+
if (!NUMBER.test(number) || !luhn2(number) || !MONTH4.test(expMonth) || !YEAR4.test(expYear) || !CODE.test(cvc))
|
|
1432
|
+
return refuse6("monei_body_unsupported");
|
|
1433
|
+
return CARD7;
|
|
1434
|
+
}
|
|
1435
|
+
var MONEI_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
1436
|
+
Object.freeze({ merchant: "Genuins", accountIds: Object.freeze(["8d58ab4c-4ad0-4053-b18f-79d80e9ee158"]), merchantUrls: Object.freeze(["https://genuins.com/"]) })
|
|
1437
|
+
]);
|
|
1438
|
+
var monei_default = /* @__PURE__ */ registerProcessor({
|
|
1439
|
+
psp: MONEI_PSP,
|
|
1440
|
+
definitions: [
|
|
1441
|
+
{
|
|
1442
|
+
psp: "monei",
|
|
1443
|
+
// The card frame's token request, as the header above reads it. One host serves test and live payments alike,
|
|
1444
|
+
// so no sandbox host is marked: MONEI's record of the payment names its mode, and the device sends a test payment
|
|
1445
|
+
// only MONEI's documented test cards (moneiDeviceRefusal). The frame sets no deadline on the fetch, so the
|
|
1446
|
+
// cardholder approves at the shopper's Pay. `(?![\w/.%-])` ends the path for a consumer that tests `match`
|
|
1447
|
+
// unanchored, and the exact-URL rule below holds the rest. Ships dark: served only to a client that declares
|
|
1448
|
+
// `monei_card_token`, and gated off for every company until the backend's gate names one.
|
|
1449
|
+
capability: "monei_card_token",
|
|
1450
|
+
match: "api\\.monei\\.com/v1/tokens(?![\\w/.%-])",
|
|
1451
|
+
hosts: ["^api\\.monei\\.com$"],
|
|
1452
|
+
encoding: "json",
|
|
1453
|
+
// The frame's two device headers. Origin, Referer and cookies never ride.
|
|
1454
|
+
passthroughHeaders: ["^x-client-env$", "^x-client-fingerprint$"],
|
|
1455
|
+
jsonCardFields: [["paymentMethod", "card", "number"]]
|
|
1456
|
+
}
|
|
1457
|
+
],
|
|
1458
|
+
// Only the cardholder's device sends a card, after a person approves; no reviewed list names monei.
|
|
1459
|
+
refusedOperations: [MONEI_OPERATION],
|
|
1460
|
+
// Not surveyed: the card request mints a token and moves no money; MONEI's confirm, which the page sends, charges it.
|
|
1461
|
+
settlementReadback: "not_surveyed",
|
|
1462
|
+
exactUrl: isMoneiTokensUrl,
|
|
1463
|
+
bodyGate: (url, body) => moneiBodyVerdict(body, url)
|
|
1464
|
+
// No amount reader: the request names none. MONEI's record of the payment names it, and the device holds that record
|
|
1465
|
+
// to the approved amount before it writes any card.
|
|
1466
|
+
});
|
|
1467
|
+
// src/processors/oceanpayment.js
|
|
1468
|
+
var OCEANPAYMENT_PSP = "oceanpayment";
|
|
1469
|
+
var OCEANPAYMENT_OPERATION = "oceanpayment.card_request";
|
|
1470
|
+
var OCEANPAYMENT_HOSTS = /* @__PURE__ */ Object.freeze({ "secure.oceanpayment.com": "production", "test-secure.oceanpayment.com": "sandbox" });
|
|
1471
|
+
var OCEANPAYMENT_FORM_FIELDS = /* @__PURE__ */ Object.freeze([
|
|
1472
|
+
"card_number_three",
|
|
1473
|
+
"card_number_two",
|
|
1474
|
+
"card_number_temp",
|
|
1475
|
+
"card_number",
|
|
1476
|
+
"card_date",
|
|
1477
|
+
"card_year",
|
|
1478
|
+
"card_month",
|
|
1479
|
+
"card_secureCode",
|
|
1480
|
+
"copyCard",
|
|
1481
|
+
"closePage",
|
|
1482
|
+
"starttime",
|
|
1483
|
+
"endtime",
|
|
1484
|
+
"comloadpage",
|
|
1485
|
+
"timezone",
|
|
1486
|
+
"OSLang",
|
|
1487
|
+
"os",
|
|
1488
|
+
"brower",
|
|
1489
|
+
"BrowerLang",
|
|
1490
|
+
"resolution",
|
|
1491
|
+
"methods",
|
|
1492
|
+
"reference_id",
|
|
1493
|
+
"methods",
|
|
1494
|
+
"reference"
|
|
1495
|
+
]);
|
|
1496
|
+
var URL_LIMIT3 = 2048;
|
|
1497
|
+
var BODY_LIMIT7 = 8192;
|
|
1498
|
+
var SEND_PAY = /^\/gateway\/sendPay;jsessionid=[A-Za-z0-9._!-]{16,128}$/;
|
|
1499
|
+
var own6 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1500
|
+
var exact = (pattern, value) => typeof value === "string" && pattern.test(value);
|
|
1501
|
+
var CARD_RUN = /[0-9]{12}/;
|
|
1502
|
+
var printable = (max) => (value) => typeof value === "string" && value.length <= max && /^[\x20-\x7e]*$/.test(value) && !CARD_RUN.test(value);
|
|
1503
|
+
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})$/;
|
|
1504
|
+
var LANGUAGE = /^(?:|[A-Za-z]{2,8}(?:[-_][A-Za-z0-9]{1,8}){0,3})$/;
|
|
1505
|
+
var SHAPES = /* @__PURE__ */ new Map([
|
|
1506
|
+
["customerCardType", (v) => v === ""],
|
|
1507
|
+
// The page's paste and typing markers: "0" until typed, the number's length when its key handler read it, or "N"
|
|
1508
|
+
// after a paste.
|
|
1509
|
+
["card_number_three", (v) => exact(/^(?:0|N|[1-9]|1[0-9])$/, v)],
|
|
1510
|
+
["card_number_two", (v) => exact(/^(?:0|[1-9]|1[0-9])$/, v)],
|
|
1511
|
+
["card_number_temp", (v) => exact(/^[0-9]{4}(?: ?[0-9]{4}){3}$/, v)],
|
|
1512
|
+
["card_number", (v) => exact(/^[0-9]{16}$/, v)],
|
|
1513
|
+
["card_date", (v) => exact(/^(?:0[1-9]|1[0-2])\/[0-9]{2}$/, v)],
|
|
1514
|
+
["card_year", (v) => exact(/^20[0-9]{2}$/, v)],
|
|
1515
|
+
["card_month", (v) => exact(/^(?:0[1-9]|1[0-2])$/, v)],
|
|
1516
|
+
["card_secureCode", (v) => exact(/^[0-9]{3,4}$/, v)],
|
|
1517
|
+
["copyCard", (v) => v === "" || v === "0" || v === "1"],
|
|
1518
|
+
// PAY NOW's handler sets it to 1 before the page submits.
|
|
1519
|
+
["closePage", (v) => v === "1"],
|
|
1520
|
+
["starttime", (v) => exact(STAMP, v)],
|
|
1521
|
+
["endtime", (v) => exact(STAMP, v)],
|
|
1522
|
+
["comloadpage", (v) => v === "0" || v === "1"],
|
|
1523
|
+
// getTimezoneOffset()/60*-1: whole or fractional hours.
|
|
1524
|
+
["timezone", (v) => exact(/^(?:|-?(?:[0-9]|1[0-4])(?:\.[0-9]{1,2})?)$/, v)],
|
|
1525
|
+
["OSLang", (v) => exact(LANGUAGE, v)],
|
|
1526
|
+
["os", printable(64)],
|
|
1527
|
+
["brower", printable(128)],
|
|
1528
|
+
["BrowerLang", (v) => exact(LANGUAGE, v)],
|
|
1529
|
+
["resolution", printable(32)],
|
|
1530
|
+
["methods", (v) => v === "1"],
|
|
1531
|
+
["reference_id", (v) => v === ""],
|
|
1532
|
+
// The page's own trade number.
|
|
1533
|
+
["reference", (v) => exact(/^[0-9]{1,40}$/, v)],
|
|
1534
|
+
["button", (v) => v === ""]
|
|
1535
|
+
]);
|
|
1536
|
+
function oceanpaymentSendPayUrl(url) {
|
|
1537
|
+
if (typeof url !== "string" || url.length > URL_LIMIT3 || url.includes("?") || url.includes("#"))
|
|
1538
|
+
return null;
|
|
1539
|
+
let parsed;
|
|
1540
|
+
try {
|
|
1541
|
+
parsed = new URL(url);
|
|
1542
|
+
}
|
|
1543
|
+
catch {
|
|
1544
|
+
return null;
|
|
1545
|
+
}
|
|
1546
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own6(OCEANPAYMENT_HOSTS, parsed.hostname) || !SEND_PAY.test(parsed.pathname))
|
|
1547
|
+
return null;
|
|
1548
|
+
return Object.freeze({ host: parsed.hostname, environment: OCEANPAYMENT_HOSTS[parsed.hostname] });
|
|
1549
|
+
}
|
|
1550
|
+
var isOceanpaymentSendPayUrl = (url) => oceanpaymentSendPayUrl(url) !== null;
|
|
1551
|
+
function formEncode(value) {
|
|
1552
|
+
let encoded;
|
|
1553
|
+
try {
|
|
1554
|
+
encoded = encodeURIComponent(value);
|
|
1555
|
+
}
|
|
1556
|
+
catch {
|
|
1557
|
+
return null;
|
|
1558
|
+
}
|
|
1559
|
+
return encoded.replace(/[!'()~]/g, (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase()}`).replace(/%20/g, "+");
|
|
1560
|
+
}
|
|
1561
|
+
function formDecode(raw) {
|
|
1562
|
+
if (!/^(?:[A-Za-z0-9*._+-]|%[0-9A-F]{2})*$/.test(raw))
|
|
1563
|
+
return null;
|
|
1564
|
+
let value;
|
|
1565
|
+
try {
|
|
1566
|
+
value = decodeURIComponent(raw.replace(/\+/g, "%20"));
|
|
1567
|
+
}
|
|
1568
|
+
catch {
|
|
1569
|
+
return null;
|
|
1570
|
+
}
|
|
1571
|
+
return formEncode(value) === raw ? value : null;
|
|
1572
|
+
}
|
|
1573
|
+
function readPairs(body) {
|
|
1574
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT7)
|
|
1575
|
+
return null;
|
|
1576
|
+
const pairs = [];
|
|
1577
|
+
for (const chunk of body.split("&")) {
|
|
1578
|
+
const separator = chunk.indexOf("=");
|
|
1579
|
+
if (separator < 1)
|
|
1580
|
+
return null;
|
|
1581
|
+
const rawName = chunk.slice(0, separator), raw = chunk.slice(separator + 1);
|
|
1582
|
+
const name = formDecode(rawName), value = formDecode(raw);
|
|
1583
|
+
if (name === null || value === null)
|
|
1584
|
+
return null;
|
|
1585
|
+
pairs.push({ name, rawName, raw, value });
|
|
1586
|
+
}
|
|
1587
|
+
return pairs;
|
|
1588
|
+
}
|
|
1589
|
+
function formPairs(body) {
|
|
1590
|
+
const pairs = readPairs(body);
|
|
1591
|
+
if (!pairs)
|
|
1592
|
+
return null;
|
|
1593
|
+
const start = pairs[0].name === "customerCardType" ? 1 : 0;
|
|
1594
|
+
const end = pairs[pairs.length - 1].name === "button" ? pairs.length - 1 : pairs.length;
|
|
1595
|
+
if (end - start !== OCEANPAYMENT_FORM_FIELDS.length || OCEANPAYMENT_FORM_FIELDS.some((name, i) => pairs[start + i].name !== name))
|
|
1596
|
+
return null;
|
|
1597
|
+
return pairs;
|
|
1598
|
+
}
|
|
1599
|
+
var valueOf = (pairs, name) => pairs.find((pair) => pair.name === name)?.value;
|
|
1600
|
+
function bodyRefusal(body) {
|
|
1601
|
+
const pairs = formPairs(body);
|
|
1602
|
+
if (!pairs)
|
|
1603
|
+
return "oceanpayment_body_unsupported";
|
|
1604
|
+
if (pairs[0].name === "customerCardType" && pairs[0].value !== "")
|
|
1605
|
+
return "oceanpayment_card_brand_refused";
|
|
1606
|
+
if (valueOf(pairs, "reference_id") !== "")
|
|
1607
|
+
return "oceanpayment_device_data_refused";
|
|
1608
|
+
if (pairs.some(({ name, value }) => !SHAPES.get(name)(value)))
|
|
1609
|
+
return "oceanpayment_body_unsupported";
|
|
1610
|
+
const number = valueOf(pairs, "card_number");
|
|
1611
|
+
const temp = valueOf(pairs, "card_number_temp");
|
|
1612
|
+
const [month, year] = valueOf(pairs, "card_date").split("/");
|
|
1613
|
+
if (temp.replace(/ /g, "") !== number || temp !== number && temp !== spaced(number))
|
|
1614
|
+
return "oceanpayment_body_unsupported";
|
|
1615
|
+
if (valueOf(pairs, "card_month") !== month || valueOf(pairs, "card_year") !== `20${year}`)
|
|
1616
|
+
return "oceanpayment_body_unsupported";
|
|
1617
|
+
return null;
|
|
1618
|
+
}
|
|
1619
|
+
var spaced = (number) => number.replace(/([0-9]{4})(?=[0-9])/g, "$1 ");
|
|
1620
|
+
function oceanpaymentBodyVerdict(body) {
|
|
1621
|
+
const code = bodyRefusal(body);
|
|
1622
|
+
return code ? Object.freeze({ verdict: "refuse", code }) : Object.freeze({ verdict: "card" });
|
|
1623
|
+
}
|
|
1624
|
+
var oceanpayment_default = /* @__PURE__ */ registerProcessor({
|
|
1625
|
+
psp: OCEANPAYMENT_PSP,
|
|
1626
|
+
definitions: [
|
|
1627
|
+
{
|
|
1628
|
+
psp: "oceanpayment",
|
|
1629
|
+
// The hosted page's card post, as the header above reads it. The sandbox has its own host, so a test row's device
|
|
1630
|
+
// sends only Oceanpayment's documented test cards (hostEnvironmentPinned, device-replay.js S7).
|
|
1631
|
+
// Ships dark: served only to a client that declares `oceanpayment_hosted_payment_page`, and only for a company the
|
|
1632
|
+
// backend's processor gate turns Oceanpayment on for. `(?![\w/.%;=!-])` ends the path for a consumer that tests
|
|
1633
|
+
// `match` unanchored.
|
|
1634
|
+
capability: "oceanpayment_hosted_payment_page",
|
|
1635
|
+
match: "(?:test-)?secure\\.oceanpayment\\.com/gateway/sendPay;jsessionid=[A-Za-z0-9._!-]{16,128}(?![\\w/.%;=!-])",
|
|
1636
|
+
hosts: ["^secure\\.oceanpayment\\.com$", "^test-secure\\.oceanpayment\\.com$"],
|
|
1637
|
+
sandboxHosts: ["^test-secure\\.oceanpayment\\.com$"],
|
|
1638
|
+
hostEnvironmentPinned: true,
|
|
1639
|
+
encoding: "form",
|
|
1640
|
+
// A form navigation: nothing but its type is replayed. Origin, Referer and cookies never ride.
|
|
1641
|
+
passthroughHeaders: [],
|
|
1642
|
+
cardFields: ["card_number"]
|
|
1643
|
+
}
|
|
1644
|
+
],
|
|
1645
|
+
// Only the cardholder's device sends this card, after a person approves; no reviewed list names oceanpayment.
|
|
1646
|
+
refusedOperations: [OCEANPAYMENT_OPERATION],
|
|
1647
|
+
// Not surveyed: Oceanpayment tells the merchant's server the result (its noticeUrl), and reading a payment back takes the
|
|
1648
|
+
// merchant's own secure code, which Agentcard never holds.
|
|
1649
|
+
settlementReadback: "not_surveyed",
|
|
1650
|
+
exactUrl: isOceanpaymentSendPayUrl,
|
|
1651
|
+
bodyGate: (url, body) => url !== void 0 && !isOceanpaymentSendPayUrl(url) ? Object.freeze({ verdict: "refuse", code: "oceanpayment_url_refused" }) : oceanpaymentBodyVerdict(body)
|
|
1652
|
+
// No amount reader: the post names none, so the agent's pair is the figure the cardholder approves.
|
|
1653
|
+
});
|
|
1654
|
+
// src/processors/paymentwall.js
|
|
1655
|
+
var PAYMENTWALL_PSP = "paymentwall";
|
|
1656
|
+
var PAYMENTWALL_OPERATION = "paymentwall.card_request";
|
|
1657
|
+
var PAYMENTWALL_TOKEN_URL = "https://pwgateway.com/api/token";
|
|
1658
|
+
var PAYMENTWALL_SANDBOX_TOKEN_URL = "https://api.paymentwall.com/api/brick/token";
|
|
1659
|
+
var BODY_LIMIT8 = 2048;
|
|
1660
|
+
var KEY = "public_key";
|
|
1661
|
+
var PUBLIC_KEY = /^(?:t_)?[A-Za-z0-9]{16,64}$/;
|
|
1662
|
+
var SHAPES2 = /* @__PURE__ */ Object.freeze({
|
|
1663
|
+
[KEY]: PUBLIC_KEY,
|
|
1664
|
+
"card[number]": /^[0-9]{12,19}$/,
|
|
1665
|
+
"card[exp_month]": /^(?:0?[1-9]|1[0-2])$/,
|
|
1666
|
+
"card[exp_year]": /^(?:[0-9]{2}|20[0-9]{2})$/,
|
|
1667
|
+
"card[cvv]": /^[0-9]{3,4}$/
|
|
1668
|
+
});
|
|
1669
|
+
var refuse7 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
1670
|
+
var CARD8 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
1671
|
+
function luhn3(digits2) {
|
|
1672
|
+
let sum = 0;
|
|
1673
|
+
for (let at = 0; at < digits2.length; at += 1) {
|
|
1674
|
+
let digit = Number(digits2[digits2.length - 1 - at]);
|
|
1675
|
+
if (at % 2 === 1) {
|
|
1676
|
+
digit *= 2;
|
|
1677
|
+
if (digit > 9)
|
|
1678
|
+
digit -= 9;
|
|
1679
|
+
}
|
|
1680
|
+
sum += digit;
|
|
1681
|
+
}
|
|
1682
|
+
return sum % 10 === 0;
|
|
1683
|
+
}
|
|
1684
|
+
function paymentwallUrlEnvironment(url) {
|
|
1685
|
+
if (url === PAYMENTWALL_TOKEN_URL)
|
|
1686
|
+
return "production";
|
|
1687
|
+
return url === PAYMENTWALL_SANDBOX_TOKEN_URL ? "sandbox" : null;
|
|
1688
|
+
}
|
|
1689
|
+
function isPaymentwallTokenUrl(url) {
|
|
1690
|
+
return paymentwallUrlEnvironment(url) !== null;
|
|
1691
|
+
}
|
|
1692
|
+
function paymentwallKeyEnvironment(publicKey) {
|
|
1693
|
+
if (typeof publicKey !== "string" || !PUBLIC_KEY.test(publicKey))
|
|
1694
|
+
return null;
|
|
1695
|
+
return publicKey.startsWith("t_") ? "sandbox" : "production";
|
|
1696
|
+
}
|
|
1697
|
+
function readPairs2(body) {
|
|
1698
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT8 || !/^[A-Za-z0-9_[\]=&]+$/.test(body))
|
|
1699
|
+
return null;
|
|
1700
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
1701
|
+
for (const chunk of body.split("&")) {
|
|
1702
|
+
const eq = chunk.indexOf("=");
|
|
1703
|
+
if (eq <= 0 || chunk.indexOf("=", eq + 1) !== -1)
|
|
1704
|
+
return null;
|
|
1705
|
+
const key = chunk.slice(0, eq);
|
|
1706
|
+
if (pairs.has(key))
|
|
1707
|
+
return null;
|
|
1708
|
+
pairs.set(key, chunk.slice(eq + 1));
|
|
1709
|
+
}
|
|
1710
|
+
return pairs;
|
|
1711
|
+
}
|
|
1712
|
+
function paymentwallBodyVerdict(body, url) {
|
|
1713
|
+
if (url !== void 0 && !isPaymentwallTokenUrl(url))
|
|
1714
|
+
return refuse7("paymentwall_url_refused");
|
|
1715
|
+
const pairs = readPairs2(body);
|
|
1716
|
+
if (pairs === null)
|
|
1717
|
+
return refuse7("paymentwall_body_unsupported");
|
|
1718
|
+
if (pairs.has("card[token]") && !pairs.has("card[number]"))
|
|
1719
|
+
return refuse7("paymentwall_saved_card");
|
|
1720
|
+
const keys = Object.keys(SHAPES2);
|
|
1721
|
+
if (pairs.size !== keys.length || !keys.every((key) => pairs.has(key) && SHAPES2[key].test(pairs.get(key)))) {
|
|
1722
|
+
return refuse7("paymentwall_body_unsupported");
|
|
1723
|
+
}
|
|
1724
|
+
if (!luhn3(pairs.get("card[number]")))
|
|
1725
|
+
return refuse7("paymentwall_body_unsupported");
|
|
1726
|
+
if (url !== void 0 && paymentwallKeyEnvironment(pairs.get(KEY)) !== paymentwallUrlEnvironment(url))
|
|
1727
|
+
return refuse7("paymentwall_key_refused");
|
|
1728
|
+
return CARD8;
|
|
1729
|
+
}
|
|
1730
|
+
var paymentwall_default = /* @__PURE__ */ registerProcessor({
|
|
1731
|
+
psp: PAYMENTWALL_PSP,
|
|
1732
|
+
definitions: [
|
|
1733
|
+
{
|
|
1734
|
+
psp: "paymentwall",
|
|
1735
|
+
// Brick's token request, as the header above reads it. A test key's request has its own host, so the device sends
|
|
1736
|
+
// it only Paymentwall's documented test cards (hostEnvironmentPinned, device-replay.js S7). Ships dark: served only
|
|
1737
|
+
// to a client that declares `paymentwall_card_token`, for a company the backend's gate turns it on for
|
|
1738
|
+
// (checkout-processor-gate.ts), and the device sends a live card only under a key a reviewed pin names.
|
|
1739
|
+
capability: "paymentwall_card_token",
|
|
1740
|
+
match: "(?:pwgateway\\.com/api/token|api\\.paymentwall\\.com/api/brick/token)",
|
|
1741
|
+
hosts: ["^pwgateway\\.com$", "^api\\.paymentwall\\.com$"],
|
|
1742
|
+
sandboxHosts: ["^api\\.paymentwall\\.com$"],
|
|
1743
|
+
hostEnvironmentPinned: true,
|
|
1744
|
+
encoding: "form",
|
|
1745
|
+
// Brick's XHR sets the form Content-Type alone, and that always rides. Origin, Referer and cookies never do.
|
|
1746
|
+
passthroughHeaders: [],
|
|
1747
|
+
cardFields: ["card[number]"]
|
|
1748
|
+
}
|
|
1749
|
+
],
|
|
1750
|
+
// Only the cardholder's device sends a card request, after a person approves; no reviewed list names paymentwall.
|
|
1751
|
+
refusedOperations: [PAYMENTWALL_OPERATION],
|
|
1752
|
+
// Not surveyed: the token moves no money, and the charge that spends it happens out of this request.
|
|
1753
|
+
settlementReadback: "not_surveyed",
|
|
1754
|
+
exactUrl: isPaymentwallTokenUrl,
|
|
1755
|
+
bodyGate: (url, body) => paymentwallBodyVerdict(body, url)
|
|
1756
|
+
});
|
|
1757
|
+
// src/processors/payplug.js
|
|
1758
|
+
var PAYPLUG_PSP = "payplug";
|
|
1759
|
+
var PAYPLUG_OPERATION = "payplug.hosted_sale";
|
|
1760
|
+
var PAYPLUG_HOST = "secure.payplug.com";
|
|
1761
|
+
var ENTRY_PATH = /^\/pay\/(?:(test)\/)?([A-Za-z0-9]{22})$/;
|
|
1762
|
+
var MAX_URL3 = 256;
|
|
1763
|
+
var field3 = (name, reason) => ({ ok: false, code: "hosted_form_field_refused", field: name, reason });
|
|
1764
|
+
function payplugEntry(raw) {
|
|
1765
|
+
if (typeof raw !== "string" || raw.length > MAX_URL3 || raw.includes("?") || raw.includes("#"))
|
|
1766
|
+
return null;
|
|
1767
|
+
let url;
|
|
1768
|
+
try {
|
|
1769
|
+
url = new URL(raw);
|
|
1770
|
+
}
|
|
1771
|
+
catch {
|
|
1772
|
+
return null;
|
|
1773
|
+
}
|
|
1774
|
+
if (url.href !== raw || url.protocol !== "https:" || url.hostname !== PAYPLUG_HOST || url.port || url.username || url.password)
|
|
1775
|
+
return null;
|
|
1776
|
+
const match = ENTRY_PATH.exec(url.pathname);
|
|
1777
|
+
return match ? Object.freeze({ id: match[2], test: match[1] === "test" }) : null;
|
|
1778
|
+
}
|
|
1779
|
+
function isPayplugEntryUrl(raw) {
|
|
1780
|
+
return payplugEntry(raw) !== null;
|
|
1781
|
+
}
|
|
1782
|
+
var PAYPLUG_MERCHANTS = Object.freeze([
|
|
1783
|
+
Object.freeze({ merchant: "Lazartigue", origins: Object.freeze(["https://lazartigue.com"]), payee: null, account: null })
|
|
1784
|
+
]);
|
|
1785
|
+
var ACCOUNT_ID = /^[A-Za-z0-9-]{1,64}$/;
|
|
1786
|
+
function payplugMerchant(checkoutOrigin, merchants = PAYPLUG_MERCHANTS) {
|
|
1787
|
+
if (typeof checkoutOrigin !== "string" || checkoutOrigin.length > MAX_URL3 || !Array.isArray(merchants))
|
|
1788
|
+
return null;
|
|
1789
|
+
let url;
|
|
1790
|
+
try {
|
|
1791
|
+
url = new URL(checkoutOrigin);
|
|
1792
|
+
}
|
|
1793
|
+
catch {
|
|
1794
|
+
return null;
|
|
1795
|
+
}
|
|
1796
|
+
if (url.protocol !== "https:" || url.origin !== checkoutOrigin || url.port)
|
|
1797
|
+
return null;
|
|
1798
|
+
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));
|
|
1799
|
+
return found.length === 1 ? found[0] : null;
|
|
1800
|
+
}
|
|
1801
|
+
function checkPayplugEntry(body, { url = null, checkoutOrigin = null, merchants = PAYPLUG_MERCHANTS } = {}) {
|
|
1802
|
+
if (body !== void 0 && body !== null && body !== "")
|
|
1803
|
+
return field3("(body)", "not_an_entry");
|
|
1804
|
+
const entry = payplugEntry(url);
|
|
1805
|
+
if (!entry)
|
|
1806
|
+
return field3("(url)", "malformed_field");
|
|
1807
|
+
const seller = payplugMerchant(checkoutOrigin, merchants);
|
|
1808
|
+
if (!seller)
|
|
1809
|
+
return field3("(checkout_origin)", "seller_unreviewed");
|
|
1810
|
+
return { ok: true, pairs: [], gated: false, dedupe: [entry.id], paymentId: entry.id, sandbox: entry.test, seller };
|
|
1811
|
+
}
|
|
1812
|
+
var MAX_PAGE5 = 512 * 1024;
|
|
1813
|
+
var PAYPLUG_REFUSALS = Object.freeze(["payplug_failed", "payplug_expired", "payplug_cancelled"]);
|
|
1814
|
+
var payplug_default = /* @__PURE__ */ registerProcessor({
|
|
1815
|
+
psp: PAYPLUG_PSP,
|
|
1816
|
+
definitions: [
|
|
1817
|
+
{
|
|
1818
|
+
psp: "payplug",
|
|
1819
|
+
// The merchant's redirect to PayPlug's payment page, as the header above reads it: a Document navigation that
|
|
1820
|
+
// carries no card. The cardholder's device repeats it over the end-to-end TLS relay and pays on the page PayPlug
|
|
1821
|
+
// returns to it, and the runtime resolves the paused navigation with the hosted_form notice. Only the entry is
|
|
1822
|
+
// matched (isPayplugEntryUrl): the page's card post and its 3-D Secure steps share the host, and none of them is
|
|
1823
|
+
// the entry. Test and live payments share the host, and the entry's path says which it is. Ships dark: served
|
|
1824
|
+
// only to a client that declares `payplug_hosted_payment_page`, and the backend's gate serves only Agentcard's
|
|
1825
|
+
// own company until a reviewed merchant pays.
|
|
1826
|
+
capability: "payplug_hosted_payment_page",
|
|
1827
|
+
match: "secure\\.payplug\\.com/pay/(?:test/)?[A-Za-z0-9]{22}",
|
|
1828
|
+
hosts: ["^secure\\.payplug\\.com$"],
|
|
1829
|
+
// `encoding` describes the page's own card post, which the device makes as the page does, since the entry has no
|
|
1830
|
+
// body. No captured header is ever replayed.
|
|
1831
|
+
encoding: "form",
|
|
1832
|
+
passthroughHeaders: [],
|
|
1833
|
+
request: { method: "GET", cardIn: "none", response: "html_page" },
|
|
1834
|
+
mode: "hosted_form",
|
|
1835
|
+
hostedForm: {
|
|
1836
|
+
// The card goes into PayPlug's page on the device, never into the entry, which carries no body at all. The
|
|
1837
|
+
// entry's own rules come with this registration (hostedEntry below), so no policy is named here.
|
|
1838
|
+
cardIn: "processor_page",
|
|
1839
|
+
required: [],
|
|
1840
|
+
// The page's card inputs, by the data-payplug role its script reads them by: they carry no name, and the
|
|
1841
|
+
// script posts the card only as its ciphertext, encryptedCard.
|
|
1842
|
+
card: { number: "card_number", expiry: "card_month_year", cvc: "card_cvv" },
|
|
1843
|
+
// The payment's id in the entry's URL names the one payment the merchant created; the entry's rules read it
|
|
1844
|
+
// there (checkPayplugEntry's dedupe), since no form field holds it.
|
|
1845
|
+
dedupe: ["(paymentId)"]
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
],
|
|
1849
|
+
// Only the cardholder's device repeats an entry, after a person approves; no reviewed list names payplug.
|
|
1850
|
+
refusedOperations: [PAYPLUG_OPERATION],
|
|
1851
|
+
// Not surveyed: PayPlug tells only the merchant's server the result, and the browser returns whatever it was.
|
|
1852
|
+
settlementReadback: "not_surveyed",
|
|
1853
|
+
exactUrl: isPayplugEntryUrl,
|
|
1854
|
+
hostedEntry: checkPayplugEntry,
|
|
1855
|
+
limitations: [
|
|
1856
|
+
"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.",
|
|
1857
|
+
"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.",
|
|
1858
|
+
"PayPlug runs 3-D Secure on the card. A challenge ends the payment on the device with nothing charged.",
|
|
1859
|
+
"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."
|
|
1860
|
+
]
|
|
1861
|
+
});
|
|
1862
|
+
// src/rsa-pkcs1v15.js
|
|
1863
|
+
var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
|
|
1864
|
+
var typedArrayName = Object.getOwnPropertyDescriptor(TYPED_ARRAY, Symbol.toStringTag).get;
|
|
1865
|
+
// src/processors/paystack.js
|
|
1866
|
+
var PAYSTACK_PSP = "paystack";
|
|
1867
|
+
var PAYSTACK_OPERATION = "paystack.card_request";
|
|
1868
|
+
var PAYSTACK_CHARGE_URL = "https://standard.paystack.co/charge/";
|
|
1869
|
+
var PAYSTACK_BODY_KEYS = /* @__PURE__ */ Object.freeze([
|
|
1870
|
+
"clientdata",
|
|
1871
|
+
"last4",
|
|
1872
|
+
"trans",
|
|
1873
|
+
"access_code",
|
|
1874
|
+
"device",
|
|
1875
|
+
"offset",
|
|
1876
|
+
"remember_card",
|
|
1877
|
+
"card_holder_name",
|
|
1878
|
+
"transaction_type"
|
|
1879
|
+
]);
|
|
1880
|
+
var OPTIONAL = /* @__PURE__ */ new Set(["access_code", "card_holder_name", "transaction_type"]);
|
|
1881
|
+
var BODY_LIMIT9 = 4096;
|
|
1882
|
+
var CIPHERTEXT_BYTES = [62, 63, 64];
|
|
1883
|
+
var BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
1884
|
+
var SHAPES3 = /* @__PURE__ */ Object.freeze({
|
|
1885
|
+
last4: /^[0-9]{4}$/,
|
|
1886
|
+
trans: /^[0-9]{1,20}$/,
|
|
1887
|
+
access_code: /^[A-Za-z0-9]{1,64}$/,
|
|
1888
|
+
device: /^[\x21-\x7e]{1,512}$/,
|
|
1889
|
+
offset: /^-?[0-9]{1,3}$/,
|
|
1890
|
+
remember_card: /^false$/,
|
|
1891
|
+
// A name carries no digit, so no card number can ride in it.
|
|
1892
|
+
card_holder_name: /^[^\x00-\x1f\x7f0-9]{1,128}$/u,
|
|
1893
|
+
transaction_type: /^[a-z_]{1,32}$/
|
|
1894
|
+
});
|
|
1895
|
+
var own7 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
1896
|
+
var refuse8 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
1897
|
+
function paystackFormValue(value) {
|
|
1898
|
+
return encodeURIComponent(String(value)).replace(/%20/g, "+").replace(/[!'()*~]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
1899
|
+
}
|
|
1900
|
+
function paystackFormBody(entries) {
|
|
1901
|
+
return entries.map(([key, value]) => `${paystackFormValue(key)}=${paystackFormValue(value)}`).join("&");
|
|
1902
|
+
}
|
|
1903
|
+
function isPaystackChargeUrl(url) {
|
|
1904
|
+
return url === PAYSTACK_CHARGE_URL;
|
|
1905
|
+
}
|
|
1906
|
+
function isCiphertext(value) {
|
|
1907
|
+
if (value.length % 4 !== 0 || !BASE64.test(value))
|
|
1908
|
+
return false;
|
|
1909
|
+
let binary;
|
|
1910
|
+
try {
|
|
1911
|
+
binary = atob(value);
|
|
1912
|
+
}
|
|
1913
|
+
catch {
|
|
1914
|
+
return false;
|
|
1915
|
+
}
|
|
1916
|
+
return btoa(binary) === value && CIPHERTEXT_BYTES.includes(binary.length);
|
|
1917
|
+
}
|
|
1918
|
+
function readForm(body) {
|
|
1919
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT9)
|
|
1920
|
+
return null;
|
|
1921
|
+
const entries = [];
|
|
1922
|
+
for (const part of body.split("&")) {
|
|
1923
|
+
const at = part.indexOf("=");
|
|
1924
|
+
if (at <= 0)
|
|
1925
|
+
return null;
|
|
1926
|
+
try {
|
|
1927
|
+
entries.push([decodeURIComponent(part.slice(0, at).replace(/\+/g, " ")), decodeURIComponent(part.slice(at + 1).replace(/\+/g, " "))]);
|
|
1928
|
+
}
|
|
1929
|
+
catch {
|
|
1930
|
+
return null;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
return paystackFormBody(entries) === body ? entries : null;
|
|
1934
|
+
}
|
|
1935
|
+
function paystackBodyVerdict(body) {
|
|
1936
|
+
const entries = readForm(body);
|
|
1937
|
+
if (entries === null)
|
|
1938
|
+
return refuse8("paystack_body_unsupported");
|
|
1939
|
+
const keys = entries.map(([key]) => key);
|
|
1940
|
+
if (keys.includes("subscription"))
|
|
1941
|
+
return refuse8("paystack_subscription");
|
|
1942
|
+
if (keys.includes("remember_card") && entries.find(([key]) => key === "remember_card")[1] !== "false")
|
|
1943
|
+
return refuse8("paystack_saved_card");
|
|
1944
|
+
const expected = PAYSTACK_BODY_KEYS.filter((key) => !OPTIONAL.has(key) || keys.includes(key));
|
|
1945
|
+
if (keys.length !== expected.length || keys.some((key, i) => key !== expected[i]))
|
|
1946
|
+
return refuse8("paystack_body_unsupported");
|
|
1947
|
+
const fields = Object.fromEntries(entries);
|
|
1948
|
+
if (!isCiphertext(fields.clientdata))
|
|
1949
|
+
return refuse8("paystack_body_unsupported");
|
|
1950
|
+
for (const [key, shape] of Object.entries(SHAPES3)) {
|
|
1951
|
+
if (own7(fields, key) && !shape.test(fields[key]))
|
|
1952
|
+
return refuse8("paystack_body_unsupported");
|
|
1953
|
+
}
|
|
1954
|
+
return Object.freeze({ verdict: "card", fields: Object.freeze(fields) });
|
|
1955
|
+
}
|
|
1956
|
+
var paystack_default = /* @__PURE__ */ registerProcessor({
|
|
1957
|
+
psp: PAYSTACK_PSP,
|
|
1958
|
+
definitions: [
|
|
1959
|
+
{
|
|
1960
|
+
psp: "paystack",
|
|
1961
|
+
// The card page's charge, as the header above reads it. Live and test transactions share standard.paystack.co,
|
|
1962
|
+
// so no sandbox host is listed and no environment is pinned. Ships dark: served only to a client that declares
|
|
1963
|
+
// `paystack_pinned_key`, and only for a company the backend's processor gate turns Paystack on for.
|
|
1964
|
+
// `(?![\w/.%?#-])` ends the path for a consumer that tests `match` unanchored; the exact-URL rule takes no query.
|
|
1965
|
+
capability: "paystack_pinned_key",
|
|
1966
|
+
match: "standard\\.paystack\\.co/charge/(?![\\w/.%?#-])",
|
|
1967
|
+
hosts: ["^standard\\.paystack\\.co$"],
|
|
1968
|
+
encoding: "form",
|
|
1969
|
+
// The browser's language rides as the page sent it; Origin, Referer and cookies never do (the page sends no cookie).
|
|
1970
|
+
passthroughHeaders: ["^accept-language$"],
|
|
1971
|
+
cardFields: ["clientdata"]
|
|
1972
|
+
}
|
|
1973
|
+
],
|
|
1974
|
+
// Only the cardholder's device sends this charge, after a person approves; no reviewed list names paystack.
|
|
1975
|
+
refusedOperations: [PAYSTACK_OPERATION],
|
|
1976
|
+
// Not surveyed: reading a charge back takes the merchant's secret key, which Agentcard never holds.
|
|
1977
|
+
settlementReadback: "not_surveyed",
|
|
1978
|
+
exactUrl: isPaystackChargeUrl,
|
|
1979
|
+
bodyGate: (url, body) => url !== void 0 && !isPaystackChargeUrl(url) ? refuse8("paystack_url_refused") : paystackBodyVerdict(body),
|
|
1980
|
+
// No amount reader: the charge names none, so the agent's pair is the figure the cardholder approves.
|
|
1981
|
+
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."]
|
|
1982
|
+
});
|
|
1983
|
+
// src/processors/processout.js
|
|
1984
|
+
var PROCESSOUT_PSP = "processout";
|
|
1985
|
+
var PROCESSOUT_OPERATION = "processout.card_request";
|
|
1986
|
+
var URL_LIMIT4 = 512;
|
|
1987
|
+
var BODY_LIMIT10 = 4096;
|
|
1988
|
+
var CARD_URL = /^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})$/;
|
|
1989
|
+
var PAGE_KEYS2 = /* @__PURE__ */ Object.freeze(["name", "contact", "preferred_scheme"]);
|
|
1990
|
+
var CONTACT_KEYS = /* @__PURE__ */ Object.freeze(["address1", "address2", "city", "state", "country_code", "zip"]);
|
|
1991
|
+
var DEVICE_KEYS = /* @__PURE__ */ Object.freeze([
|
|
1992
|
+
"request_origin",
|
|
1993
|
+
"app_color_depth",
|
|
1994
|
+
"app_language",
|
|
1995
|
+
"app_screen_height",
|
|
1996
|
+
"app_screen_width",
|
|
1997
|
+
"app_timezone_offset",
|
|
1998
|
+
"app_java_enabled"
|
|
1999
|
+
]);
|
|
2000
|
+
var PROCESSOUT_CARD_KEYS = /* @__PURE__ */ Object.freeze(["number", "exp_month", "exp_year", "cvc2"]);
|
|
2001
|
+
var BODY_KEYS = /* @__PURE__ */ new Set([...PAGE_KEYS2, "device", ...DEVICE_KEYS, ...PROCESSOUT_CARD_KEYS]);
|
|
2002
|
+
var NUMBER2 = /^[0-9]{12,19}$/;
|
|
2003
|
+
var MONTH5 = /^(?:[1-9]|1[0-2])$/;
|
|
2004
|
+
var YEAR5 = /^20[0-9]{2}$/;
|
|
2005
|
+
var CODE2 = /^[0-9]{3,4}$/;
|
|
2006
|
+
var TEXT_LIMIT = 256;
|
|
2007
|
+
var SCHEME = /^[A-Za-z][A-Za-z0-9 _-]{0,31}$/;
|
|
2008
|
+
var LANGUAGE2 = /^[A-Za-z]{1,8}(?:-[A-Za-z0-9]{1,8}){0,4}$/;
|
|
2009
|
+
var PAN_LIKE = /(?:[0-9][^0-9A-Za-z]*){12,}/;
|
|
2010
|
+
var record6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2011
|
+
var own8 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
2012
|
+
var refuse9 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
2013
|
+
var CARD9 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
2014
|
+
var BASE642 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
2015
|
+
function base64Of(text3) {
|
|
2016
|
+
let out = "";
|
|
2017
|
+
for (let at = 0; at < text3.length; at += 3) {
|
|
2018
|
+
const a = text3.charCodeAt(at);
|
|
2019
|
+
const b = at + 1 < text3.length ? text3.charCodeAt(at + 1) : NaN;
|
|
2020
|
+
const c = at + 2 < text3.length ? text3.charCodeAt(at + 2) : NaN;
|
|
2021
|
+
out += BASE642[a >> 2] + BASE642[(a & 3) << 4 | (Number.isNaN(b) ? 0 : b >> 4)] + (Number.isNaN(b) ? "=" : BASE642[(b & 15) << 2 | (Number.isNaN(c) ? 0 : c >> 6)]) + (Number.isNaN(c) ? "=" : BASE642[c & 63]);
|
|
2022
|
+
}
|
|
2023
|
+
return out;
|
|
2024
|
+
}
|
|
2025
|
+
var basicOf = (projectId) => base64Of(`${projectId}:`);
|
|
2026
|
+
function luhn4(digits2) {
|
|
2027
|
+
let sum = 0;
|
|
2028
|
+
for (let at = 0; at < digits2.length; at += 1) {
|
|
2029
|
+
let digit = Number(digits2[digits2.length - 1 - at]);
|
|
2030
|
+
if (at % 2 === 1) {
|
|
2031
|
+
digit *= 2;
|
|
2032
|
+
if (digit > 9)
|
|
2033
|
+
digit -= 9;
|
|
2034
|
+
}
|
|
2035
|
+
sum += digit;
|
|
2036
|
+
}
|
|
2037
|
+
return sum % 10 === 0;
|
|
2038
|
+
}
|
|
2039
|
+
function processoutCardTarget(url) {
|
|
2040
|
+
if (typeof url !== "string" || url.length > URL_LIMIT4)
|
|
2041
|
+
return null;
|
|
2042
|
+
const match = CARD_URL.exec(url);
|
|
2043
|
+
if (!match || match[2] !== basicOf(match[1]))
|
|
2044
|
+
return null;
|
|
2045
|
+
return Object.freeze({ projectId: match[1], environment: match[1].startsWith("test-") ? "sandbox" : "production" });
|
|
2046
|
+
}
|
|
2047
|
+
function isProcessoutCardUrl(url) {
|
|
2048
|
+
return processoutCardTarget(url) !== null;
|
|
2049
|
+
}
|
|
2050
|
+
function readBody7(body) {
|
|
2051
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT10)
|
|
2052
|
+
return null;
|
|
2053
|
+
try {
|
|
2054
|
+
const value = JSON.parse(body);
|
|
2055
|
+
return record6(value) && JSON.stringify(value) === body ? value : null;
|
|
2056
|
+
}
|
|
2057
|
+
catch {
|
|
2058
|
+
return null;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
var pageText = (value) => value === null || typeof value === "string" && value.length <= TEXT_LIMIT && !PAN_LIKE.test(value);
|
|
2062
|
+
var DEVICE_RULES = /* @__PURE__ */ Object.freeze({
|
|
2063
|
+
request_origin: (value) => value === "web",
|
|
2064
|
+
app_color_depth: (value) => Number.isSafeInteger(value) && value >= 1 && value <= 64,
|
|
2065
|
+
app_language: (value) => typeof value === "string" && value.length <= 64 && LANGUAGE2.test(value),
|
|
2066
|
+
app_screen_height: (value) => Number.isSafeInteger(value) && value >= 1 && value <= 1e5,
|
|
2067
|
+
app_screen_width: (value) => Number.isSafeInteger(value) && value >= 1 && value <= 1e5,
|
|
2068
|
+
app_timezone_offset: (value) => Number.isSafeInteger(value) && value >= -1440 && value <= 1440,
|
|
2069
|
+
app_java_enabled: (value) => typeof value === "boolean"
|
|
2070
|
+
});
|
|
2071
|
+
function soundDevice(value) {
|
|
2072
|
+
const device = value.device;
|
|
2073
|
+
if (!record6(device) || !own8(device, "request_origin") || !own8(device, "app_timezone_offset"))
|
|
2074
|
+
return false;
|
|
2075
|
+
return DEVICE_KEYS.every((key) => own8(device, key) ? DEVICE_RULES[key](device[key]) && own8(value, key) && value[key] === device[key] : !own8(value, key)) && Object.keys(device).every((key) => DEVICE_KEYS.includes(key));
|
|
2076
|
+
}
|
|
2077
|
+
function soundPageData(value) {
|
|
2078
|
+
if (own8(value, "name") && !pageText(value.name))
|
|
2079
|
+
return false;
|
|
2080
|
+
if (own8(value, "preferred_scheme") && !(value.preferred_scheme === null || typeof value.preferred_scheme === "string" && SCHEME.test(value.preferred_scheme)))
|
|
2081
|
+
return false;
|
|
2082
|
+
const contact = value.contact;
|
|
2083
|
+
return record6(contact) && Object.keys(contact).every((key) => CONTACT_KEYS.includes(key) && pageText(contact[key]));
|
|
2084
|
+
}
|
|
2085
|
+
function processoutBodyVerdict(body, url) {
|
|
2086
|
+
if (url !== void 0 && processoutCardTarget(url) === null)
|
|
2087
|
+
return refuse9("processout_url_refused");
|
|
2088
|
+
const value = readBody7(body);
|
|
2089
|
+
if (value === null || !Object.keys(value).every((key) => BODY_KEYS.has(key)))
|
|
2090
|
+
return refuse9("processout_body_unsupported");
|
|
2091
|
+
if (!PROCESSOUT_CARD_KEYS.every((key) => typeof value[key] === "string"))
|
|
2092
|
+
return refuse9("processout_body_unsupported");
|
|
2093
|
+
if (!NUMBER2.test(value.number) || !luhn4(value.number) || !MONTH5.test(value.exp_month) || !YEAR5.test(value.exp_year) || !CODE2.test(value.cvc2))
|
|
2094
|
+
return refuse9("processout_body_unsupported");
|
|
2095
|
+
if (!soundPageData(value) || !soundDevice(value))
|
|
2096
|
+
return refuse9("processout_body_unsupported");
|
|
2097
|
+
return CARD9;
|
|
2098
|
+
}
|
|
2099
|
+
var processout_default = /* @__PURE__ */ registerProcessor({
|
|
2100
|
+
psp: PROCESSOUT_PSP,
|
|
2101
|
+
definitions: [
|
|
2102
|
+
{
|
|
2103
|
+
psp: "processout",
|
|
2104
|
+
// ProcessOut.js's card request, as the header above reads it. One host serves every project, live and sandbox
|
|
2105
|
+
// alike, so no sandbox host is marked: the project id names the environment, and the device sends a sandbox
|
|
2106
|
+
// project only ProcessOut's documented test cards (processoutDeviceRefusal). The page gives up 20 seconds after
|
|
2107
|
+
// its tokenize message, so the lane is prepared only (preparationRequired). The match reads the host and the path,
|
|
2108
|
+
// and ends where the path does, as Pin Payments' does: a card's own record under /cards/, where the code refresh
|
|
2109
|
+
// goes, is never paused. The exact-URL rule below holds the query, the project id and its Basic credential among it.
|
|
2110
|
+
// Ships dark: served only to a client that declares `processout_card_token`, and gated off for every org until
|
|
2111
|
+
// the backend's gate names one.
|
|
2112
|
+
capability: "processout_card_token",
|
|
2113
|
+
match: "api\\.processout\\.com/cards(?![\\w/.%-])",
|
|
2114
|
+
hosts: ["^api\\.processout\\.com$"],
|
|
2115
|
+
preparationRequired: true,
|
|
2116
|
+
encoding: "json",
|
|
2117
|
+
// ProcessOut.js's own headers: the project's Basic credential and the API version. Origin, Referer and cookies
|
|
2118
|
+
// never ride.
|
|
2119
|
+
passthroughHeaders: ["^authorization$", "^api-version$"],
|
|
2120
|
+
jsonCardFields: [["number"]]
|
|
2121
|
+
}
|
|
2122
|
+
],
|
|
2123
|
+
// Only the cardholder's device sends a card, after a person approves; no reviewed list names processout.
|
|
2124
|
+
refusedOperations: [PROCESSOUT_OPERATION],
|
|
2125
|
+
// Not surveyed: the card request mints a token and moves no money; the store's server charges it under its own
|
|
2126
|
+
// secret key, which Agentcard never holds.
|
|
2127
|
+
settlementReadback: "not_surveyed",
|
|
2128
|
+
exactUrl: isProcessoutCardUrl,
|
|
2129
|
+
bodyGate: (url, body) => processoutBodyVerdict(body, url)
|
|
2130
|
+
});
|
|
2131
|
+
// src/processors/usaepay.js
|
|
2132
|
+
var USAEPAY_PSP = "usaepay";
|
|
2133
|
+
var USAEPAY_OPERATION = "usaepay.card_request";
|
|
2134
|
+
var USAEPAY_HOSTS = /* @__PURE__ */ Object.freeze({
|
|
2135
|
+
"www.usaepay.com": "production",
|
|
2136
|
+
"secure.usaepay.com": "production",
|
|
2137
|
+
"sandbox.usaepay.com": "sandbox"
|
|
2138
|
+
});
|
|
2139
|
+
var USAEPAY_PAYMENT_KEYS_PATH = "/api/v2/pub/payment_keys";
|
|
2140
|
+
var BODY_LIMIT11 = 512;
|
|
2141
|
+
var URL_LIMIT5 = 256;
|
|
2142
|
+
var CARD_NUMBER5 = /^[0-9]{13,19}$/;
|
|
2143
|
+
var EXPIRATION = /^(?:0[1-9]|1[0-2])[0-9]{2}$/;
|
|
2144
|
+
var SECURITY_CODE5 = /^(?:[0-9]{3,4})?$/;
|
|
2145
|
+
var record7 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2146
|
+
var own9 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
2147
|
+
var refuse10 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
2148
|
+
var CARD10 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
2149
|
+
function usaepayPaymentKeysUrl(url) {
|
|
2150
|
+
if (typeof url !== "string" || url.length > URL_LIMIT5 || url.includes("?") || url.includes("#"))
|
|
2151
|
+
return null;
|
|
2152
|
+
let parsed;
|
|
2153
|
+
try {
|
|
2154
|
+
parsed = new URL(url);
|
|
2155
|
+
}
|
|
2156
|
+
catch {
|
|
2157
|
+
return null;
|
|
2158
|
+
}
|
|
2159
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own9(USAEPAY_HOSTS, parsed.hostname) || parsed.pathname !== USAEPAY_PAYMENT_KEYS_PATH)
|
|
2160
|
+
return null;
|
|
2161
|
+
return Object.freeze({ host: parsed.hostname, environment: USAEPAY_HOSTS[parsed.hostname] });
|
|
2162
|
+
}
|
|
2163
|
+
var isUsaepayPaymentKeysUrl = (url) => usaepayPaymentKeysUrl(url) !== null;
|
|
2164
|
+
function luhn5(digits2) {
|
|
2165
|
+
let sum = 0;
|
|
2166
|
+
for (let at = digits2.length - 1, double = false; at >= 0; at -= 1, double = !double) {
|
|
2167
|
+
let digit = digits2.charCodeAt(at) - 48;
|
|
2168
|
+
if (double)
|
|
2169
|
+
digit = digit * 2 > 9 ? digit * 2 - 9 : digit * 2;
|
|
2170
|
+
sum += digit;
|
|
2171
|
+
}
|
|
2172
|
+
return sum % 10 === 0;
|
|
2173
|
+
}
|
|
2174
|
+
function readBody8(body) {
|
|
2175
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT11)
|
|
2176
|
+
return null;
|
|
2177
|
+
try {
|
|
2178
|
+
const value = JSON.parse(body);
|
|
2179
|
+
return record7(value) && JSON.stringify(value) === body ? value : null;
|
|
2180
|
+
}
|
|
2181
|
+
catch {
|
|
2182
|
+
return null;
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
function usaepayBodyVerdict(body) {
|
|
2186
|
+
const value = readBody8(body);
|
|
2187
|
+
const card = value === null ? null : value.creditcard;
|
|
2188
|
+
if (value === null || Object.keys(value).join() !== "creditcard" || !record7(card) || Object.keys(card).join() !== "number,expiration,cvc" || typeof card.number !== "string" || !CARD_NUMBER5.test(card.number) || !luhn5(card.number) || typeof card.expiration !== "string" || !EXPIRATION.test(card.expiration) || typeof card.cvc !== "string" || !SECURITY_CODE5.test(card.cvc))
|
|
2189
|
+
return refuse10("usaepay_body_unsupported");
|
|
2190
|
+
return CARD10;
|
|
2191
|
+
}
|
|
2192
|
+
var usaepay_default = /* @__PURE__ */ registerProcessor({
|
|
2193
|
+
psp: USAEPAY_PSP,
|
|
2194
|
+
definitions: [
|
|
2195
|
+
{
|
|
2196
|
+
psp: "usaepay",
|
|
2197
|
+
// The frame's card request, as the header above reads it. sandbox.usaepay.com is USAePay's sandbox, pinned to test
|
|
2198
|
+
// rows, which send only USAePay's documented test cards (hostEnvironmentPinned, device-replay.js S7).
|
|
2199
|
+
// Ships dark: served only to a client that declares `usaepay_payment_key`, and only for a company the backend's
|
|
2200
|
+
// processor gate turns USAePay on for. `(?![\w/.%-])` ends the path for a consumer that tests `match` unanchored.
|
|
2201
|
+
capability: "usaepay_payment_key",
|
|
2202
|
+
match: "(?:www|secure|sandbox)\\.usaepay\\.com/api/v2/pub/payment_keys(?![\\w/.%-])",
|
|
2203
|
+
hosts: ["^www\\.usaepay\\.com$", "^secure\\.usaepay\\.com$", "^sandbox\\.usaepay\\.com$"],
|
|
2204
|
+
sandboxHosts: ["^sandbox\\.usaepay\\.com$"],
|
|
2205
|
+
hostEnvironmentPinned: true,
|
|
2206
|
+
encoding: "json",
|
|
2207
|
+
// The frame's Authorization, which carries the merchant's public key. Origin, Referer and cookies never ride.
|
|
2208
|
+
passthroughHeaders: ["^authorization$"],
|
|
2209
|
+
jsonCardFields: [["creditcard", "number"]]
|
|
2210
|
+
}
|
|
2211
|
+
],
|
|
2212
|
+
// Only the cardholder's device sends this card, after a person approves; no reviewed list names usaepay.
|
|
2213
|
+
refusedOperations: [USAEPAY_OPERATION],
|
|
2214
|
+
// The public key mints a payment key and reads nothing: the merchant's server runs the sale with its private key.
|
|
2215
|
+
settlementReadback: {
|
|
2216
|
+
answer: "none",
|
|
2217
|
+
reason: "tokenization_credential_cannot_read_charges",
|
|
2218
|
+
note: "The tokenization credential cannot read a charge; the shop charges the token later with its own credentials.",
|
|
2219
|
+
source: "https://help.usaepay.info/developer/payjs-v2/ , https://help.usaepay.info/api/rest/"
|
|
2220
|
+
},
|
|
2221
|
+
exactUrl: isUsaepayPaymentKeysUrl,
|
|
2222
|
+
bodyGate: (url, body) => url !== void 0 && !isUsaepayPaymentKeysUrl(url) ? refuse10("usaepay_url_refused") : usaepayBodyVerdict(body)
|
|
2223
|
+
// No amount reader: the request names none, so the agent's pair is the figure the cardholder approves.
|
|
2224
|
+
});
|
|
2225
|
+
// src/processors/viva_wallet.js
|
|
2226
|
+
var VIVA_WALLET_PSP = "viva_wallet";
|
|
2227
|
+
var VIVA_WALLET_OPERATION = "viva_wallet.card_request";
|
|
2228
|
+
var VIVA_WALLET_HOSTS = /* @__PURE__ */ Object.freeze({ "www.vivapayments.com": "production", "demo.vivapayments.com": "sandbox" });
|
|
2229
|
+
var VIVA_WALLET_CHARGE_TOKENS_PATH = "/web2/checkout/v2/chargetokens";
|
|
2230
|
+
var VIVA_WALLET_BODY_KEYS = /* @__PURE__ */ Object.freeze([
|
|
2231
|
+
"orderCode",
|
|
2232
|
+
"amount",
|
|
2233
|
+
"currencyCode",
|
|
2234
|
+
"holderName",
|
|
2235
|
+
"holderMail",
|
|
2236
|
+
"cvc",
|
|
2237
|
+
"number",
|
|
2238
|
+
"expirationMonth",
|
|
2239
|
+
"expirationYear",
|
|
2240
|
+
"installments",
|
|
2241
|
+
"customer",
|
|
2242
|
+
"rememberCard",
|
|
2243
|
+
"friendlyName",
|
|
2244
|
+
"maskedNumber",
|
|
2245
|
+
"bankId",
|
|
2246
|
+
"selectedBrand",
|
|
2247
|
+
"cardholderBrandSelection",
|
|
2248
|
+
"dccOptions",
|
|
2249
|
+
"dccAccepted",
|
|
2250
|
+
"offerCodes",
|
|
2251
|
+
"loyaltySupported",
|
|
2252
|
+
"redeemedAmount",
|
|
2253
|
+
"retrievalReferenceNumber",
|
|
2254
|
+
"scaRequestedTransactionId",
|
|
2255
|
+
"merchantTrns",
|
|
2256
|
+
"captchaToken"
|
|
2257
|
+
]);
|
|
2258
|
+
var BODY_LIMIT12 = 16384;
|
|
2259
|
+
var URL_LIMIT6 = 256;
|
|
2260
|
+
var ORDER_CODE = /^[0-9]{16}$/;
|
|
2261
|
+
var CARD_NUMBER6 = /^[0-9]{13,19}$/;
|
|
2262
|
+
var MONTH6 = /^(?:0[1-9]|1[0-2])$/;
|
|
2263
|
+
var YEAR6 = /^[0-9]{2}$/;
|
|
2264
|
+
var SECURITY_CODE6 = /^[0-9]{3,4}$/;
|
|
2265
|
+
var CAPTCHA_TOKEN = /^[A-Za-z0-9_.-]{20,8192}$/;
|
|
2266
|
+
var MEMBER_NAME = /^[A-Za-z][A-Za-z0-9]{0,31}$/;
|
|
2267
|
+
var SHORT_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
2268
|
+
var TEXT = /^[^\u0000-\u001f\u007f]{0,200}$/;
|
|
2269
|
+
var CARD_DIGITS = /[0-9]{12,}/;
|
|
2270
|
+
var record8 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2271
|
+
var own10 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
2272
|
+
var refuse11 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
2273
|
+
var CARD11 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
2274
|
+
var inOrder4 = (value, keys) => {
|
|
2275
|
+
let at = 0;
|
|
2276
|
+
for (const name of Object.keys(value)) {
|
|
2277
|
+
while (at < keys.length && keys[at] !== name)
|
|
2278
|
+
at += 1;
|
|
2279
|
+
if (at === keys.length)
|
|
2280
|
+
return false;
|
|
2281
|
+
at += 1;
|
|
2282
|
+
}
|
|
2283
|
+
return true;
|
|
2284
|
+
};
|
|
2285
|
+
var cardDigits = (text3) => CARD_DIGITS.test(text3.replace(/[^0-9A-Za-z]/g, ""));
|
|
2286
|
+
var plainText = (value) => typeof value === "string" && TEXT.test(value) && !cardDigits(value);
|
|
2287
|
+
var scalar = (value) => value === null || typeof value === "boolean" || Number.isSafeInteger(value) && Math.abs(value) < 1e9 || plainText(value);
|
|
2288
|
+
var flatRecord = (value, limit) => record8(value) && Object.keys(value).length <= limit && Object.entries(value).every(([key, item]) => MEMBER_NAME.test(key) && scalar(item));
|
|
2289
|
+
function vivaWalletChargeTokensUrl(url) {
|
|
2290
|
+
if (typeof url !== "string" || url.length > URL_LIMIT6 || url.includes("?") || url.includes("#"))
|
|
2291
|
+
return null;
|
|
2292
|
+
let parsed;
|
|
2293
|
+
try {
|
|
2294
|
+
parsed = new URL(url);
|
|
2295
|
+
}
|
|
2296
|
+
catch {
|
|
2297
|
+
return null;
|
|
2298
|
+
}
|
|
2299
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !own10(VIVA_WALLET_HOSTS, parsed.hostname) || parsed.pathname !== VIVA_WALLET_CHARGE_TOKENS_PATH)
|
|
2300
|
+
return null;
|
|
2301
|
+
return Object.freeze({ host: parsed.hostname, environment: VIVA_WALLET_HOSTS[parsed.hostname] });
|
|
2302
|
+
}
|
|
2303
|
+
var isVivaWalletChargeTokensUrl = (url) => vivaWalletChargeTokensUrl(url) !== null;
|
|
2304
|
+
function luhn6(digits2) {
|
|
2305
|
+
let sum = 0;
|
|
2306
|
+
for (let at = digits2.length - 1, double = false; at >= 0; at -= 1, double = !double) {
|
|
2307
|
+
let digit = digits2.charCodeAt(at) - 48;
|
|
2308
|
+
if (double)
|
|
2309
|
+
digit = digit * 2 > 9 ? digit * 2 - 9 : digit * 2;
|
|
2310
|
+
sum += digit;
|
|
2311
|
+
}
|
|
2312
|
+
return sum % 10 === 0;
|
|
2313
|
+
}
|
|
2314
|
+
function vivaWalletMaskedNumber(number) {
|
|
2315
|
+
return `${number.slice(0, 6)}${"X".repeat(Math.max(0, number.length - 10))}${number.slice(-4)}`;
|
|
2316
|
+
}
|
|
2317
|
+
function readBody9(body) {
|
|
2318
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT12)
|
|
2319
|
+
return null;
|
|
2320
|
+
try {
|
|
2321
|
+
const value = JSON.parse(body);
|
|
2322
|
+
return record8(value) && JSON.stringify(value) === body ? value : null;
|
|
2323
|
+
}
|
|
2324
|
+
catch {
|
|
2325
|
+
return null;
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
function currencyNumber(value) {
|
|
2329
|
+
if (Number.isSafeInteger(value) && value > 0 && value < 1e3)
|
|
2330
|
+
return value;
|
|
2331
|
+
return typeof value === "string" && /^[0-9]{3}$/.test(value) ? Number(value) : null;
|
|
2332
|
+
}
|
|
2333
|
+
function vivaWalletBodyVerdict(body) {
|
|
2334
|
+
const value = readBody9(body);
|
|
2335
|
+
if (value === null || !Object.keys(value).every((key) => VIVA_WALLET_BODY_KEYS.includes(key))) {
|
|
2336
|
+
return value !== null && (own10(value, "creditCardId") || own10(value, "token")) ? refuse11("viva_wallet_stored_card") : refuse11("viva_wallet_body_unsupported");
|
|
2337
|
+
}
|
|
2338
|
+
if (value.rememberCard !== false)
|
|
2339
|
+
return refuse11(value.rememberCard === true ? "viva_wallet_keep_on_file" : "viva_wallet_body_unsupported");
|
|
2340
|
+
if (value.dccAccepted === true)
|
|
2341
|
+
return refuse11("viva_wallet_currency_conversion");
|
|
2342
|
+
if (own10(value, "dccAccepted") && value.dccAccepted !== false)
|
|
2343
|
+
return refuse11("viva_wallet_body_unsupported");
|
|
2344
|
+
if (own10(value, "scaRequestedTransactionId"))
|
|
2345
|
+
return refuse11("viva_wallet_retry_refused");
|
|
2346
|
+
if (!(value.installments === 0 || value.installments === 1)) {
|
|
2347
|
+
return refuse11(Number.isSafeInteger(value.installments) && value.installments > 1 ? "viva_wallet_installments" : "viva_wallet_body_unsupported");
|
|
2348
|
+
}
|
|
2349
|
+
if (!inOrder4(value, VIVA_WALLET_BODY_KEYS) || ["offerCodes", "loyaltySupported", "redeemedAmount", "retrievalReferenceNumber", "merchantTrns"].some((key) => own10(value, key)))
|
|
2350
|
+
return refuse11("viva_wallet_body_unsupported");
|
|
2351
|
+
const number = value.number;
|
|
2352
|
+
const sound = typeof value.orderCode === "string" && ORDER_CODE.test(value.orderCode) && Number.isSafeInteger(value.amount) && value.amount > 0 && currencyNumber(value.currencyCode) !== null && plainText(value.holderName) && value.holderName.trim() !== "" && plainText(value.holderMail) && (value.cvc === null || typeof value.cvc === "string" && SECURITY_CODE6.test(value.cvc)) && typeof number === "string" && CARD_NUMBER6.test(number) && luhn6(number) && typeof value.expirationMonth === "string" && MONTH6.test(value.expirationMonth) && typeof value.expirationYear === "string" && YEAR6.test(value.expirationYear) && flatRecord(value.customer, 12) && (!own10(value, "friendlyName") || plainText(value.friendlyName)) && value.maskedNumber === vivaWalletMaskedNumber(number) && (!own10(value, "bankId") || typeof value.bankId === "string" && SHORT_ID.test(value.bankId) || Number.isSafeInteger(value.bankId) && value.bankId >= 0) && (!own10(value, "selectedBrand") || value.selectedBrand === null || flatRecord(value.selectedBrand, 16)) && (!own10(value, "cardholderBrandSelection") || typeof value.cardholderBrandSelection === "boolean") && (!own10(value, "dccOptions") || flatRecord(value.dccOptions, 16)) && (!own10(value, "captchaToken") || typeof value.captchaToken === "string" && CAPTCHA_TOKEN.test(value.captchaToken));
|
|
2353
|
+
return sound ? CARD11 : refuse11("viva_wallet_body_unsupported");
|
|
2354
|
+
}
|
|
2355
|
+
var VIVA_WALLET_CURRENCIES = /* @__PURE__ */ Object.freeze({
|
|
2356
|
+
978: "eur",
|
|
2357
|
+
826: "gbp",
|
|
2358
|
+
946: "ron",
|
|
2359
|
+
985: "pln",
|
|
2360
|
+
203: "czk",
|
|
2361
|
+
348: "huf",
|
|
2362
|
+
752: "sek",
|
|
2363
|
+
208: "dkk"
|
|
2364
|
+
});
|
|
2365
|
+
function vivaWalletAmount(body) {
|
|
2366
|
+
if (vivaWalletBodyVerdict(body).verdict !== "card")
|
|
2367
|
+
return null;
|
|
2368
|
+
const value = JSON.parse(body);
|
|
2369
|
+
const currency = VIVA_WALLET_CURRENCIES[currencyNumber(value.currencyCode)];
|
|
2370
|
+
return currency ? { amountCents: value.amount, currency } : null;
|
|
2371
|
+
}
|
|
2372
|
+
var VIVA_WALLET_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
2373
|
+
Object.freeze({
|
|
2374
|
+
id: "klimaka_donation",
|
|
2375
|
+
merchant: "Klimaka",
|
|
2376
|
+
tradeName: "ΚΛΙΜΑΚΑ ΑΜΚΕ",
|
|
2377
|
+
orderCodes: Object.freeze(["7871752880772607"]),
|
|
2378
|
+
origin: "https://www.vivapayments.com",
|
|
2379
|
+
currencyCode: 978
|
|
2380
|
+
}),
|
|
2381
|
+
Object.freeze({
|
|
2382
|
+
id: "desmos_donation",
|
|
2383
|
+
merchant: "Desmos",
|
|
2384
|
+
tradeName: "DESMOS",
|
|
2385
|
+
orderCodes: Object.freeze(["8156257435672606"]),
|
|
2386
|
+
origin: "https://www.vivapayments.com",
|
|
2387
|
+
currencyCode: 978
|
|
2388
|
+
})
|
|
2389
|
+
]);
|
|
2390
|
+
var CARD_MEMBERS = Object.freeze(["cvc", "number", "expirationMonth", "expirationYear", "maskedNumber"]);
|
|
2391
|
+
var viva_wallet_default = /* @__PURE__ */ registerProcessor({
|
|
2392
|
+
psp: VIVA_WALLET_PSP,
|
|
2393
|
+
definitions: [
|
|
2394
|
+
{
|
|
2395
|
+
psp: "viva_wallet",
|
|
2396
|
+
// The page's card request, as the header above reads it. demo.vivapayments.com is Viva's sandbox, pinned to test
|
|
2397
|
+
// rows, which send only Viva's documented test cards (hostEnvironmentPinned, device-replay.js S7).
|
|
2398
|
+
// Ships dark: served only to a client that declares `viva_smart_checkout_chargetoken`, and only for a company the
|
|
2399
|
+
// backend's processor gate turns Viva Wallet on for. `(?![\w/.%-])` ends the path for a consumer that tests `match`
|
|
2400
|
+
// unanchored.
|
|
2401
|
+
capability: "viva_smart_checkout_chargetoken",
|
|
2402
|
+
match: "(?:www|demo)\\.vivapayments\\.com/web2/checkout/v2/chargetokens(?![\\w/.%-])",
|
|
2403
|
+
hosts: ["^www\\.vivapayments\\.com$", "^demo\\.vivapayments\\.com$"],
|
|
2404
|
+
sandboxHosts: ["^demo\\.vivapayments\\.com$"],
|
|
2405
|
+
hostEnvironmentPinned: true,
|
|
2406
|
+
encoding: "json",
|
|
2407
|
+
// The page sends no Authorization; Origin, Referer, cookies and the reCAPTCHA state never ride.
|
|
2408
|
+
passthroughHeaders: [],
|
|
2409
|
+
jsonCardFields: [["number"]]
|
|
2410
|
+
}
|
|
2411
|
+
],
|
|
2412
|
+
// Only the cardholder's device sends this card, after a person approves; no reviewed list names viva_wallet.
|
|
2413
|
+
refusedOperations: [VIVA_WALLET_OPERATION],
|
|
2414
|
+
settlementReadback: "not_surveyed",
|
|
2415
|
+
exactUrl: isVivaWalletChargeTokensUrl,
|
|
2416
|
+
bodyGate: (url, body) => url !== void 0 && !isVivaWalletChargeTokensUrl(url) ? refuse11("viva_wallet_url_refused") : vivaWalletBodyVerdict(body),
|
|
2417
|
+
// The body names the order's amount in cents and its numeric currency, which the page's card-free charge repeats.
|
|
2418
|
+
amount: (template) => record8(template) && isVivaWalletChargeTokensUrl(template.url) ? vivaWalletAmount(template.body) : null
|
|
2419
|
+
});
|
|
2420
|
+
// src/processors/vtex_payments.js
|
|
2421
|
+
var VTEX_PAYMENTS_PSP = "vtex_payments";
|
|
2422
|
+
var VTEX_PAYMENTS_OPERATION = "vtex_payments.card_request";
|
|
2423
|
+
var VTEX_PAYMENTS_FALLBACK_HOST = "api.vtexvault.com";
|
|
2424
|
+
var VTEX_PAYMENTS_LINE_KEYS = /* @__PURE__ */ Object.freeze([
|
|
2425
|
+
"currencyCode",
|
|
2426
|
+
"paymentSystem",
|
|
2427
|
+
"accountId",
|
|
2428
|
+
"value",
|
|
2429
|
+
"referenceValue",
|
|
2430
|
+
"installments",
|
|
2431
|
+
"installmentsInterestRate",
|
|
2432
|
+
"installmentsValue",
|
|
2433
|
+
"groupName",
|
|
2434
|
+
"fields",
|
|
2435
|
+
"transaction",
|
|
2436
|
+
"id"
|
|
2437
|
+
]);
|
|
2438
|
+
var VTEX_PAYMENTS_FIELD_KEYS = /* @__PURE__ */ Object.freeze([
|
|
2439
|
+
"address",
|
|
2440
|
+
"accountId",
|
|
2441
|
+
"validationCode",
|
|
2442
|
+
"metadata",
|
|
2443
|
+
"document",
|
|
2444
|
+
"holderName",
|
|
2445
|
+
"cardNumber",
|
|
2446
|
+
"dueDate",
|
|
2447
|
+
"deviceFingerprint",
|
|
2448
|
+
"addressId"
|
|
2449
|
+
]);
|
|
2450
|
+
var VTEX_PAYMENTS_ADDRESS_KEYS = /* @__PURE__ */ Object.freeze([
|
|
2451
|
+
"street",
|
|
2452
|
+
"complement",
|
|
2453
|
+
"number",
|
|
2454
|
+
"city",
|
|
2455
|
+
"reference",
|
|
2456
|
+
"addressType",
|
|
2457
|
+
"neighborhood",
|
|
2458
|
+
"addressId",
|
|
2459
|
+
"state",
|
|
2460
|
+
"country",
|
|
2461
|
+
"postalCode"
|
|
2462
|
+
]);
|
|
2463
|
+
var VTEX_PAYMENTS_NETWORKS = /* @__PURE__ */ Object.freeze({ 1: "amex", 2: "visa", 4: "mastercard", 5: "discover" });
|
|
2464
|
+
var VTEX_PAYMENTS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
2465
|
+
Object.freeze({ account: "alssports", origin: "https://www.als.com", merchant: "Al's Sporting Goods", currency: "USD" }),
|
|
2466
|
+
Object.freeze({ account: "roadrunnersports", origin: "https://www.roadrunnersports.com", merchant: "Road Runner Sports", currency: "USD" })
|
|
2467
|
+
]);
|
|
2468
|
+
var BODY_LIMIT13 = 16384;
|
|
2469
|
+
var ACCOUNT_HOST = /^([a-z0-9]{1,63})\.vtexvault\.com$/;
|
|
2470
|
+
var PATH = /^\/api\/payments\/transactions\/([0-9A-Fa-f]{32})\/payments$/;
|
|
2471
|
+
var ORDER_GROUP = /^[0-9]{6,24}$/;
|
|
2472
|
+
var BASE643 = /^[A-Za-z0-9+/]{4,1020}={0,2}$/;
|
|
2473
|
+
var CARD_NUMBER7 = /^[0-9]{12,19}$/;
|
|
2474
|
+
var SECURITY_CODE7 = /^[0-9]{3,4}$/;
|
|
2475
|
+
var DUE_DATE = /^(?:0[1-9]|1[0-2])\/[0-9]{2}$/;
|
|
2476
|
+
var CURRENCY = /^[A-Z]{3}$/;
|
|
2477
|
+
var TRANSACTION_ID = /^[0-9A-Fa-f]{32}$/;
|
|
2478
|
+
var MERCHANT_NAME = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
2479
|
+
var SHORT_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
|
|
2480
|
+
var FINGERPRINT = /^[A-Za-z0-9_.:=+/-]{1,256}$/;
|
|
2481
|
+
var TEXT2 = /^[^\u0000-\u001f\u007f]{1,200}$/;
|
|
2482
|
+
var CARD_DIGITS2 = /[0-9]{12,}/;
|
|
2483
|
+
var DEVICE_INFO_KEYS = Object.freeze(["sw", "sh", "cd", "tz", "lang", "java", "sourceApplication"]);
|
|
2484
|
+
var record9 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2485
|
+
var own11 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
2486
|
+
var refuse12 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
2487
|
+
var CARD12 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
2488
|
+
var inOrder5 = (value, keys) => {
|
|
2489
|
+
let at = 0;
|
|
2490
|
+
for (const name of Object.keys(value)) {
|
|
2491
|
+
while (at < keys.length && keys[at] !== name)
|
|
2492
|
+
at += 1;
|
|
2493
|
+
if (at === keys.length)
|
|
2494
|
+
return false;
|
|
2495
|
+
at += 1;
|
|
2496
|
+
}
|
|
2497
|
+
return true;
|
|
2498
|
+
};
|
|
2499
|
+
var cardDigits2 = (text3) => CARD_DIGITS2.test(text3.replace(/[^0-9A-Za-z]/g, ""));
|
|
2500
|
+
var plainText2 = (value) => typeof value === "string" && TEXT2.test(value) && !cardDigits2(value);
|
|
2501
|
+
var count = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
2502
|
+
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
2503
|
+
function base64Text(input) {
|
|
2504
|
+
if (input.length % 4 !== 0)
|
|
2505
|
+
return null;
|
|
2506
|
+
const stripped = input.replace(/={1,2}$/, "");
|
|
2507
|
+
let out = "";
|
|
2508
|
+
let bits = 0;
|
|
2509
|
+
let value = 0;
|
|
2510
|
+
for (const character of stripped) {
|
|
2511
|
+
const sextet = BASE64_ALPHABET.indexOf(character);
|
|
2512
|
+
if (sextet < 0)
|
|
2513
|
+
return null;
|
|
2514
|
+
value = value << 6 | sextet;
|
|
2515
|
+
bits += 6;
|
|
2516
|
+
if (bits >= 8) {
|
|
2517
|
+
bits -= 8;
|
|
2518
|
+
out += String.fromCharCode(value >> bits & 255);
|
|
2519
|
+
value &= (1 << bits) - 1;
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
return out;
|
|
2523
|
+
}
|
|
2524
|
+
function deviceInfoSound(text3) {
|
|
2525
|
+
if (typeof text3 !== "string" || !BASE643.test(text3))
|
|
2526
|
+
return false;
|
|
2527
|
+
const decoded = base64Text(text3);
|
|
2528
|
+
if (decoded === null)
|
|
2529
|
+
return false;
|
|
2530
|
+
let info;
|
|
2531
|
+
try {
|
|
2532
|
+
info = JSON.parse(decoded);
|
|
2533
|
+
}
|
|
2534
|
+
catch {
|
|
2535
|
+
return false;
|
|
2536
|
+
}
|
|
2537
|
+
if (!record9(info) || !Object.keys(info).every((key) => DEVICE_INFO_KEYS.includes(key)))
|
|
2538
|
+
return false;
|
|
2539
|
+
for (const key of ["sw", "sh", "cd"])
|
|
2540
|
+
if (own11(info, key) && !(count(info[key]) && info[key] <= 1e5))
|
|
2541
|
+
return false;
|
|
2542
|
+
if (own11(info, "tz") && !(Number.isSafeInteger(info.tz) && Math.abs(info.tz) <= 1440))
|
|
2543
|
+
return false;
|
|
2544
|
+
if (own11(info, "lang") && !(typeof info.lang === "string" && /^[A-Za-z]{0,8}$/.test(info.lang)))
|
|
2545
|
+
return false;
|
|
2546
|
+
if (own11(info, "java") && typeof info.java !== "boolean")
|
|
2547
|
+
return false;
|
|
2548
|
+
return !own11(info, "sourceApplication") || typeof info.sourceApplication === "string" && /^[A-Za-z0-9_.-]{1,32}$/.test(info.sourceApplication);
|
|
2549
|
+
}
|
|
2550
|
+
function vtexPaymentsCardTarget(url) {
|
|
2551
|
+
if (typeof url !== "string" || url.length > 8192)
|
|
2552
|
+
return null;
|
|
2553
|
+
let parsed;
|
|
2554
|
+
try {
|
|
2555
|
+
parsed = new URL(url);
|
|
2556
|
+
}
|
|
2557
|
+
catch {
|
|
2558
|
+
return null;
|
|
2559
|
+
}
|
|
2560
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || parsed.hash)
|
|
2561
|
+
return null;
|
|
2562
|
+
const path = PATH.exec(parsed.pathname);
|
|
2563
|
+
const host = ACCOUNT_HOST.exec(parsed.hostname);
|
|
2564
|
+
if (!path || !host)
|
|
2565
|
+
return null;
|
|
2566
|
+
const fallback = parsed.hostname === VTEX_PAYMENTS_FALLBACK_HOST;
|
|
2567
|
+
const names = [...parsed.searchParams.keys()];
|
|
2568
|
+
const expected = ["orderId", "deviceInfo", ...parsed.searchParams.has("callbackUrl") ? ["callbackUrl"] : [], ...fallback ? ["an"] : []];
|
|
2569
|
+
if (names.length !== expected.length || names.some((name, i) => name !== expected[i]))
|
|
2570
|
+
return null;
|
|
2571
|
+
const orderId = parsed.searchParams.get("orderId");
|
|
2572
|
+
if (!ORDER_GROUP.test(orderId) || !deviceInfoSound(parsed.searchParams.get("deviceInfo")))
|
|
2573
|
+
return null;
|
|
2574
|
+
if (parsed.searchParams.has("callbackUrl")) {
|
|
2575
|
+
let callback;
|
|
2576
|
+
try {
|
|
2577
|
+
callback = new URL(parsed.searchParams.get("callbackUrl"));
|
|
2578
|
+
}
|
|
2579
|
+
catch {
|
|
2580
|
+
return null;
|
|
2581
|
+
}
|
|
2582
|
+
if (callback.protocol !== "https:" || callback.username || callback.password || callback.searchParams.get("step") !== "payment" || callback.searchParams.get("og") !== orderId)
|
|
2583
|
+
return null;
|
|
43
2584
|
}
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (problems2.length)
|
|
49
|
-
throw new Error(`payment-core registration refused: ${problems2.join("; ")}`);
|
|
50
|
-
return deepFreeze({ ...spec });
|
|
51
|
-
}
|
|
52
|
-
function registerProcessor(spec) {
|
|
53
|
-
return registered(spec, PARTS);
|
|
2585
|
+
const account = fallback ? parsed.searchParams.get("an") : host[1];
|
|
2586
|
+
if (!/^[a-z0-9]{1,63}$/.test(account) || account === "api")
|
|
2587
|
+
return null;
|
|
2588
|
+
return Object.freeze({ account, transactionId: path[1], orderId, fallback });
|
|
54
2589
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
var MIDTRANS_TOKEN_URL = "https://api.midtrans.com/v2/token";
|
|
59
|
-
var MIDTRANS_SANDBOX_TOKEN_URL = "https://api.sandbox.midtrans.com/v2/token";
|
|
60
|
-
var MIDTRANS_TOKEN_KEYS = /* @__PURE__ */ Object.freeze(["card_cvv", "card_number", "card_exp_month", "card_exp_year", "installment_term"]);
|
|
61
|
-
var BODY_LIMIT = 4096;
|
|
62
|
-
var CARD_NUMBER = /^[0-9]{12,19}$/;
|
|
63
|
-
var SECURITY_CODE = /^[0-9]{3,4}$/;
|
|
64
|
-
var MONTH = /^(?:0[1-9]|1[0-2])$/;
|
|
65
|
-
var YEAR = /^20[0-9]{2}$/;
|
|
66
|
-
var TERM = /^[0-9]{1,3}$/;
|
|
67
|
-
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
68
|
-
var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
69
|
-
var inOrder = (value, keys) => {
|
|
70
|
-
let at = 0;
|
|
71
|
-
for (const name of Object.keys(value)) {
|
|
72
|
-
while (at < keys.length && keys[at] !== name)
|
|
73
|
-
at += 1;
|
|
74
|
-
if (at === keys.length)
|
|
75
|
-
return false;
|
|
76
|
-
at += 1;
|
|
77
|
-
}
|
|
78
|
-
return true;
|
|
79
|
-
};
|
|
80
|
-
var refuse = (code) => Object.freeze({ verdict: "refuse", code });
|
|
81
|
-
var CARD = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
82
|
-
function isMidtransTokenUrl(url) {
|
|
83
|
-
return url === MIDTRANS_TOKEN_URL || url === MIDTRANS_SANDBOX_TOKEN_URL;
|
|
2590
|
+
function isVtexPaymentsCardUrl(url) {
|
|
2591
|
+
const target = vtexPaymentsCardTarget(url);
|
|
2592
|
+
return target !== null && !target.fallback;
|
|
84
2593
|
}
|
|
85
|
-
function
|
|
86
|
-
if (typeof body !== "string" || body === "" || body.length >
|
|
2594
|
+
function readBody10(body) {
|
|
2595
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT13)
|
|
87
2596
|
return null;
|
|
88
2597
|
let value;
|
|
89
2598
|
try {
|
|
90
2599
|
value = JSON.parse(body);
|
|
91
|
-
if (!
|
|
2600
|
+
if (!Array.isArray(value) || JSON.stringify(value) !== body)
|
|
92
2601
|
return null;
|
|
93
2602
|
}
|
|
94
2603
|
catch {
|
|
@@ -96,54 +2605,143 @@ function readBody(body) {
|
|
|
96
2605
|
}
|
|
97
2606
|
return value;
|
|
98
2607
|
}
|
|
99
|
-
function
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (!
|
|
107
|
-
return
|
|
2608
|
+
function cardLine(line) {
|
|
2609
|
+
if (!record9(line))
|
|
2610
|
+
return false;
|
|
2611
|
+
const fields = record9(line.fields) ? line.fields : {};
|
|
2612
|
+
return line.groupName === "creditCardPaymentGroup" || line.groupName === "debitCardPaymentGroup" || own11(line, "accountId") || own11(fields, "accountId") || own11(fields, "cardNumber") || own11(fields, "validationCode") || own11(fields, "dueDate");
|
|
2613
|
+
}
|
|
2614
|
+
function addressSound(address) {
|
|
2615
|
+
if (!record9(address) || !inOrder5(address, VTEX_PAYMENTS_ADDRESS_KEYS))
|
|
2616
|
+
return false;
|
|
2617
|
+
for (const [key, value] of Object.entries(address)) {
|
|
2618
|
+
if (key === "addressType") {
|
|
2619
|
+
if (value !== "billing")
|
|
2620
|
+
return false;
|
|
2621
|
+
continue;
|
|
2622
|
+
}
|
|
2623
|
+
if (key === "addressId") {
|
|
2624
|
+
if (!(typeof value === "string" && SHORT_ID2.test(value)))
|
|
2625
|
+
return false;
|
|
2626
|
+
continue;
|
|
2627
|
+
}
|
|
2628
|
+
if (value === null && (key === "complement" || key === "reference"))
|
|
2629
|
+
continue;
|
|
2630
|
+
if (!(value === "" || plainText2(value)))
|
|
2631
|
+
return false;
|
|
108
2632
|
}
|
|
109
|
-
|
|
110
|
-
return refuse("midtrans_body_unsupported");
|
|
111
|
-
if (own(value, "installment_term") && (typeof value.installment_term !== "string" || !TERM.test(value.installment_term)))
|
|
112
|
-
return refuse("midtrans_body_unsupported");
|
|
113
|
-
return CARD;
|
|
2633
|
+
return true;
|
|
114
2634
|
}
|
|
115
|
-
|
|
116
|
-
|
|
2635
|
+
function fieldsSound(fields) {
|
|
2636
|
+
if (!record9(fields) || !inOrder5(fields, VTEX_PAYMENTS_FIELD_KEYS) || own11(fields, "metadata"))
|
|
2637
|
+
return false;
|
|
2638
|
+
if (!(typeof fields.cardNumber === "string" && CARD_NUMBER7.test(fields.cardNumber)))
|
|
2639
|
+
return false;
|
|
2640
|
+
if (!(typeof fields.validationCode === "string" && SECURITY_CODE7.test(fields.validationCode)))
|
|
2641
|
+
return false;
|
|
2642
|
+
if (!(typeof fields.dueDate === "string" && DUE_DATE.test(fields.dueDate)))
|
|
2643
|
+
return false;
|
|
2644
|
+
if (!plainText2(fields.holderName))
|
|
2645
|
+
return false;
|
|
2646
|
+
if (own11(fields, "document") && !(fields.document === "" || plainText2(fields.document) && fields.document.length <= 32))
|
|
2647
|
+
return false;
|
|
2648
|
+
if (own11(fields, "address") && !addressSound(fields.address))
|
|
2649
|
+
return false;
|
|
2650
|
+
if (own11(fields, "deviceFingerprint") && !(typeof fields.deviceFingerprint === "string" && FINGERPRINT.test(fields.deviceFingerprint)))
|
|
2651
|
+
return false;
|
|
2652
|
+
return !own11(fields, "addressId") || typeof fields.addressId === "string" && SHORT_ID2.test(fields.addressId);
|
|
2653
|
+
}
|
|
2654
|
+
function vtexPaymentsBodyVerdict(body, target) {
|
|
2655
|
+
const lines = readBody10(body);
|
|
2656
|
+
if (lines === null || lines.length === 0 || !lines.every(record9))
|
|
2657
|
+
return refuse12("vtex_payments_body_unsupported");
|
|
2658
|
+
const cards = lines.filter(cardLine);
|
|
2659
|
+
if (cards.some((line2) => own11(line2, "accountId") || own11(line2.fields ?? {}, "accountId")))
|
|
2660
|
+
return refuse12("vtex_payments_saved_card");
|
|
2661
|
+
if (cards.length === 0)
|
|
2662
|
+
return refuse12("vtex_payments_body_unsupported");
|
|
2663
|
+
if (lines.length !== 1 || own11(lines[0], "id"))
|
|
2664
|
+
return refuse12("vtex_payments_split_payment");
|
|
2665
|
+
const line = lines[0];
|
|
2666
|
+
if (!inOrder5(line, VTEX_PAYMENTS_LINE_KEYS) || line.groupName !== "creditCardPaymentGroup")
|
|
2667
|
+
return refuse12("vtex_payments_body_unsupported");
|
|
2668
|
+
if (!(typeof line.currencyCode === "string" && CURRENCY.test(line.currencyCode)) || !own11(VTEX_PAYMENTS_NETWORKS, line.paymentSystem) || !Number.isSafeInteger(line.paymentSystem) || !(count(line.value) && line.value > 0))
|
|
2669
|
+
return refuse12("vtex_payments_body_unsupported");
|
|
2670
|
+
if (line.installments !== 1 || line.referenceValue !== line.value || own11(line, "installmentsInterestRate") && line.installmentsInterestRate !== 0 || own11(line, "installmentsValue") && line.installmentsValue !== line.value)
|
|
2671
|
+
return refuse12("vtex_payments_installments");
|
|
2672
|
+
const transaction = line.transaction;
|
|
2673
|
+
if (!record9(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)))
|
|
2674
|
+
return refuse12("vtex_payments_body_unsupported");
|
|
2675
|
+
if (target && transaction.id.toUpperCase() !== target.transactionId.toUpperCase())
|
|
2676
|
+
return refuse12("vtex_payments_split_payment");
|
|
2677
|
+
return fieldsSound(line.fields) ? CARD12 : refuse12("vtex_payments_body_unsupported");
|
|
2678
|
+
}
|
|
2679
|
+
function vtexPaymentsAmount(body) {
|
|
2680
|
+
if (vtexPaymentsBodyVerdict(body).verdict !== "card")
|
|
2681
|
+
return null;
|
|
2682
|
+
const [line] = JSON.parse(body);
|
|
2683
|
+
return { amountCents: line.value, currency: line.currencyCode.toLowerCase() };
|
|
2684
|
+
}
|
|
2685
|
+
var NETWORK_OF = Object.freeze({
|
|
2686
|
+
visa: (number) => /^4[0-9]{12}(?:[0-9]{3}){0,2}$/.test(number),
|
|
2687
|
+
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),
|
|
2688
|
+
amex: (number) => /^3[47][0-9]{13}$/.test(number),
|
|
2689
|
+
discover: (number) => /^(?:6011[0-9]{12}|64[4-9][0-9]{13}|65[0-9]{14})$/.test(number)
|
|
2690
|
+
});
|
|
2691
|
+
var NETWORK_NAME = Object.freeze({ visa: "Visa", mastercard: "Mastercard", amex: "American Express", discover: "Discover" });
|
|
2692
|
+
var vtex_payments_default = /* @__PURE__ */ registerProcessor({
|
|
2693
|
+
psp: VTEX_PAYMENTS_PSP,
|
|
117
2694
|
definitions: [
|
|
118
2695
|
{
|
|
119
|
-
psp: "
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
capability: "
|
|
126
|
-
match: "
|
|
127
|
-
hosts: ["^
|
|
128
|
-
|
|
129
|
-
hostEnvironmentPinned: true,
|
|
2696
|
+
psp: "vtex_payments",
|
|
2697
|
+
// Ollie's card post to a VTEX account's own vault, as the header above reads it, and the fallback host, which
|
|
2698
|
+
// the gate recognizes only to refuse, so the agent's placeholder never reaches it either. VTEX has no test host:
|
|
2699
|
+
// every request is live. Prepared only: Ollie gives the post 12 seconds. Ships dark: served only to a client that
|
|
2700
|
+
// declares `vtex_payments_card_payment`, on for Agentcard's own company alone (backend
|
|
2701
|
+
// checkout-processor-gate.ts), and autopilot never sends it.
|
|
2702
|
+
capability: "vtex_payments_card_payment",
|
|
2703
|
+
match: "[a-z0-9-]{1,63}\\.vtexvault\\.com/api/payments/transactions/[A-Za-z0-9-]{1,64}/payments(?![\\w/.%-])",
|
|
2704
|
+
hosts: ["^[a-z0-9-]{1,63}\\.vtexvault\\.com$"],
|
|
2705
|
+
preparationRequired: true,
|
|
130
2706
|
encoding: "json",
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
jsonCardFields: [["card_number"]]
|
|
2707
|
+
// Ollie's fetch sets the JSON content type alone. Origin, Referer and cookies never ride.
|
|
2708
|
+
passthroughHeaders: [],
|
|
2709
|
+
jsonCardFields: [[0, "fields", "cardNumber"]]
|
|
135
2710
|
}
|
|
136
2711
|
],
|
|
137
|
-
// Only the cardholder's device sends
|
|
138
|
-
refusedOperations: [
|
|
139
|
-
// Not surveyed:
|
|
2712
|
+
// Only the cardholder's device sends it, after a person approves; no reviewed list names vtex_payments.
|
|
2713
|
+
refusedOperations: [VTEX_PAYMENTS_OPERATION],
|
|
2714
|
+
// Not surveyed: VTEX names a payment's end only to the store's own API keys and at the gatewayCallback that follows.
|
|
140
2715
|
settlementReadback: "not_surveyed",
|
|
141
|
-
exactUrl:
|
|
142
|
-
bodyGate: (url, body) =>
|
|
2716
|
+
exactUrl: isVtexPaymentsCardUrl,
|
|
2717
|
+
bodyGate: (url, body) => {
|
|
2718
|
+
if (url === void 0)
|
|
2719
|
+
return vtexPaymentsBodyVerdict(body);
|
|
2720
|
+
const target = vtexPaymentsCardTarget(url);
|
|
2721
|
+
if (target === null)
|
|
2722
|
+
return refuse12("vtex_payments_url_refused");
|
|
2723
|
+
return target.fallback ? refuse12("vtex_payments_fallback_refused") : vtexPaymentsBodyVerdict(body, target);
|
|
2724
|
+
},
|
|
2725
|
+
amount: (template) => record9(template) && isVtexPaymentsCardUrl(template.url) ? vtexPaymentsAmount(template.body) : null
|
|
143
2726
|
});
|
|
144
2727
|
// src/processors/index.generated.js
|
|
145
2728
|
var REGISTERED_MODULES = Object.freeze({
|
|
146
|
-
|
|
2729
|
+
aurus: aurus_default,
|
|
2730
|
+
bluesnap: bluesnap_default,
|
|
2731
|
+
cardlink_vpos: cardlink_vpos_default,
|
|
2732
|
+
eghl: eghl_default,
|
|
2733
|
+
frisbii: frisbii_default,
|
|
2734
|
+
iyzico: iyzico_default,
|
|
2735
|
+
midtrans: midtrans_default,
|
|
2736
|
+
monei: monei_default,
|
|
2737
|
+
oceanpayment: oceanpayment_default,
|
|
2738
|
+
paymentwall: paymentwall_default,
|
|
2739
|
+
payplug: payplug_default,
|
|
2740
|
+
paystack: paystack_default,
|
|
2741
|
+
processout: processout_default,
|
|
2742
|
+
usaepay: usaepay_default,
|
|
2743
|
+
viva_wallet: viva_wallet_default,
|
|
2744
|
+
vtex_payments: vtex_payments_default
|
|
147
2745
|
});
|
|
148
2746
|
// src/registry.js
|
|
149
2747
|
var REGISTERED_PROCESSORS = Object.values(REGISTERED_MODULES);
|
|
@@ -231,16 +2829,28 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
231
2829
|
// Flow 1.226.0's card controller selects api or card-acquisition-gateway
|
|
232
2830
|
// for the same card-token body and Bearer public-key Authorization.
|
|
233
2831
|
// Native source: checkout-web-components.checkout.com/pages/1.226.0/index.html.
|
|
2832
|
+
// Checkout.com gives each merchant account a subdomain of its own, the base
|
|
2833
|
+
// URL prefix (alphanumeric: the first eight characters of the account's
|
|
2834
|
+
// client id after cli_), and both card frames use it when the merchant
|
|
2835
|
+
// names it. Frames 2.69.0 then sends the card to
|
|
2836
|
+
// <prefix>.api[.sandbox].checkout.com/tokens. Flow 1.235.0 sends it through
|
|
2837
|
+
// the devices API when the payment session turns that on: /cag/tokens, then
|
|
2838
|
+
// /tokens if the gateway call fails, on devices.api[.sandbox].checkout.com,
|
|
2839
|
+
// under the prefix or, on the hosted payments page, none. Any one
|
|
2840
|
+
// alphanumeric label is taken, so every merchant account works whatever its
|
|
2841
|
+
// prefix, and no second label or other path is.
|
|
2842
|
+
// Native sources: js.checkout.com/framesv2/?v=2.69.0 and
|
|
2843
|
+
// checkout-web-components.sandbox.checkout.com/pages/1.235.0/index.html.
|
|
234
2844
|
// Endpoint recognition does not establish consumer-wallet, CVV-only,
|
|
235
2845
|
// reusable-token, 3DS or merchant payment completion compatibility.
|
|
236
|
-
match: "(
|
|
2846
|
+
match: "(?:card-acquisition-gateway(?:\\.sandbox)?\\.checkout\\.com/tokens|(?:[a-z0-9]+\\.)?api(?:\\.sandbox)?\\.checkout\\.com/tokens|(?:[a-z0-9]+\\.)?devices\\.api(?:\\.sandbox)?\\.checkout\\.com/(?:cag/)?tokens)",
|
|
237
2847
|
hosts: [
|
|
238
|
-
"^api\\.checkout\\.com$",
|
|
239
|
-
"^api\\.sandbox\\.checkout\\.com$",
|
|
2848
|
+
"^(?:[a-z0-9]+\\.)?(?:devices\\.)?api\\.checkout\\.com$",
|
|
2849
|
+
"^(?:[a-z0-9]+\\.)?(?:devices\\.)?api\\.sandbox\\.checkout\\.com$",
|
|
240
2850
|
"^card-acquisition-gateway\\.checkout\\.com$",
|
|
241
2851
|
"^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"
|
|
242
2852
|
],
|
|
243
|
-
sandboxHosts: ["^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"],
|
|
2853
|
+
sandboxHosts: ["^(?:[a-z0-9]+\\.)?(?:devices\\.)?api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"],
|
|
244
2854
|
encoding: "json",
|
|
245
2855
|
passthroughHeaders: ["^authorization$"]
|
|
246
2856
|
},
|
|
@@ -964,15 +3574,6 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
|
|
|
964
3574
|
jsonCardFields: [["paymentOption", "card", "cardNumber"], ["cardData", "cardNumber"]],
|
|
965
3575
|
passWithoutCard: "(?:secure|ppp-test)\\.safecharge\\.com/ppp/api/v1/(?:clientPayment|websdk/initPaymentWithCardTokenization)\\.do"
|
|
966
3576
|
},
|
|
967
|
-
// bluesnap: DELIBERATELY NOT SHIPPED — it cannot be intercepted at all. Its tokenizer is a PUT, and isCardRequest
|
|
968
|
-
// gates on POST — but accepting PUT is not enough on its own. hpf.js fires the
|
|
969
|
-
// same token PUT SEVERAL TIMES per checkout (blur and submit each send a delta
|
|
970
|
-
// body), so intercepting it would raise one approval prompt per fire and hand the
|
|
971
|
-
// device partial card data. An entry that cannot actually be intercepted does not
|
|
972
|
-
// belong in an allowlist that advertises interception: it reads as support we do
|
|
973
|
-
// not have, and on the CDP path it arms Fetch.enable, gets refused by the POST
|
|
974
|
-
// gate, and is then continued straight to the PSP while the integrator believes
|
|
975
|
-
// the card was protected. Ship it when the multi-fire semantics are handled.
|
|
976
3577
|
{
|
|
977
3578
|
psp: "airwallex",
|
|
978
3579
|
// PAN@ payment_method.card.number (payment_intents/confirm,
|
|
@@ -3173,7 +5774,7 @@ var PADDLE_VGS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
|
3173
5774
|
pin2({ id: "rectangle_pro", merchant: "Rectangle Pro", origins: ["https://rectangleapp.com"], sellerClaim: null })
|
|
3174
5775
|
]);
|
|
3175
5776
|
var FACT_KEYS = /* @__PURE__ */ Object.freeze(["card_first_six", "card_last_four", "expiry_month", "expiry_year", "card_brand"]);
|
|
3176
|
-
var
|
|
5777
|
+
var METADATA_KEYS2 = /* @__PURE__ */ Object.freeze(["cardholder_name", ...FACT_KEYS]);
|
|
3177
5778
|
// src/payfast.js
|
|
3178
5779
|
var PAYFAST_PAY_HOSTS = /* @__PURE__ */ Object.freeze({
|
|
3179
5780
|
production: Object.freeze(["payment.payfast.io", "www.payfast.co.za"]),
|
|
@@ -3192,9 +5793,6 @@ var PAYFAST_BODY_KEYS = /* @__PURE__ */ Object.freeze([
|
|
|
3192
5793
|
]);
|
|
3193
5794
|
var CAPTCHA_ANSWER = "g-recaptcha-response";
|
|
3194
5795
|
var UNANSWERED_KEYS = /* @__PURE__ */ Object.freeze(PAYFAST_BODY_KEYS.filter((key) => key !== CAPTCHA_ANSWER));
|
|
3195
|
-
// src/rsa-pkcs1v15.js
|
|
3196
|
-
var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
|
|
3197
|
-
var typedArrayName = Object.getOwnPropertyDescriptor(TYPED_ARRAY, Symbol.toStringTag).get;
|
|
3198
5796
|
// src/paddle-keys.js
|
|
3199
5797
|
var PADDLE_TOKENEX_KEYS = /* @__PURE__ */ Object.freeze({
|
|
3200
5798
|
sandbox: Object.freeze({
|
|
@@ -3208,7 +5806,7 @@ var PADDLE_TOKENEX_KEYS = /* @__PURE__ */ Object.freeze({
|
|
|
3208
5806
|
});
|
|
3209
5807
|
// src/paddle-tokenex.js
|
|
3210
5808
|
var PADDLE_TOKENEX_FACT_KEYS = /* @__PURE__ */ Object.freeze(["card_first_six", "card_last_four", "expiry_month", "expiry_year", "card_brand"]);
|
|
3211
|
-
var
|
|
5809
|
+
var METADATA_KEYS3 = /* @__PURE__ */ Object.freeze(["cardholder_name", ...PADDLE_TOKENEX_FACT_KEYS]);
|
|
3212
5810
|
var CARD_PATH = /* @__PURE__ */ Object.freeze(["data", "payment_method_data", "card"]);
|
|
3213
5811
|
var TOKENEX_PATH = /* @__PURE__ */ Object.freeze([...CARD_PATH, "tokenex_card"]);
|
|
3214
5812
|
// src/lyra.js
|
|
@@ -3297,7 +5895,7 @@ var HIPAY_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
|
3297
5895
|
pin6({ id: "happybulle", merchant: "HappyBulle", origins: ["https://www.happybulle.com"], usernames: ["94683309.secure-gateway.hipay-tpp.com"] })
|
|
3298
5896
|
]);
|
|
3299
5897
|
// src/amazon-payment-services.js
|
|
3300
|
-
var
|
|
5898
|
+
var BODY_LIMIT14 = 32 * 1024;
|
|
3301
5899
|
var ANSWER_LIMIT = 64 * 1024;
|
|
3302
5900
|
// src/clover.js
|
|
3303
5901
|
var REQUIRED_KEYS = /* @__PURE__ */ Object.freeze(["encrypted_pan", "exp_month", "exp_year", "cvv", "first6", "last4", "brand"]);
|
|
@@ -3308,8 +5906,8 @@ var LETTERS = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u017F";
|
|
|
3308
5906
|
var PAGE_NAME = new RegExp(`^[${LETTERS} .'-]{1,64}$`);
|
|
3309
5907
|
var HAS_LETTER = new RegExp(`[${LETTERS}]`);
|
|
3310
5908
|
var ADDRESS_VALUE = new RegExp(`^[\\x20-\\x7e\\u00a0-\\u017f]{0,128}$`);
|
|
3311
|
-
var
|
|
3312
|
-
var
|
|
5909
|
+
var PAN_LIKE2 = new RegExp(`(?:[0-9][^0-9${LETTERS}]*){12,}`);
|
|
5910
|
+
var HOLDER2 = new RegExp(`^[${LETTERS}](?:[${LETTERS} .'-]{0,62}[${LETTERS}.])?$`);
|
|
3313
5911
|
var ERROR_TYPE_STATUS = /* @__PURE__ */ Object.freeze({
|
|
3314
5912
|
malformed_request_error: 400,
|
|
3315
5913
|
authentication_error: 401,
|
|
@@ -3354,11 +5952,11 @@ var TOKENEX_IFRAME_ACCOUNT_NAMES = Object.freeze({
|
|
|
3354
5952
|
"htp.tokenex.com": Object.freeze({ "9014311640612780": "JetBlue" }),
|
|
3355
5953
|
"test-htp.tokenex.com": Object.freeze({})
|
|
3356
5954
|
});
|
|
3357
|
-
var
|
|
3358
|
-
var
|
|
5955
|
+
var exact2 = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
|
|
5956
|
+
var text2 = (value, max) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
|
|
3359
5957
|
var digits = (value, min, max) => typeof value === "string" && value.length >= min && value.length <= max && !/[^0-9]/.test(value);
|
|
3360
5958
|
var panLike = (value) => (value.match(/\p{Nd}/gu) ?? []).length >= 12;
|
|
3361
|
-
var plain = (value, max) =>
|
|
5959
|
+
var plain = (value, max) => text2(value, max) && !panLike(value);
|
|
3362
5960
|
var TOKENEX_ID = /^[0-9]{16}$/;
|
|
3363
5961
|
var AUTHENTICATION_KEY = /^[A-Za-z0-9+/]{43}=$/;
|
|
3364
5962
|
var TIMESTAMP = /^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]$/;
|
|
@@ -3373,10 +5971,10 @@ function isOrigin(value) {
|
|
|
3373
5971
|
}
|
|
3374
5972
|
}
|
|
3375
5973
|
var BOUND = {
|
|
3376
|
-
TokenExID: (value) =>
|
|
5974
|
+
TokenExID: (value) => exact2(TOKENEX_ID, value),
|
|
3377
5975
|
Origin: isOrigin,
|
|
3378
|
-
AuthenticationKey: (value) =>
|
|
3379
|
-
Timestamp: (value) =>
|
|
5976
|
+
AuthenticationKey: (value) => exact2(AUTHENTICATION_KEY, value),
|
|
5977
|
+
Timestamp: (value) => exact2(TIMESTAMP, value),
|
|
3380
5978
|
TokenScheme: (value) => TOKENEX_IFRAME_TOKEN_SCHEMES.includes(value)
|
|
3381
5979
|
};
|
|
3382
5980
|
var BOUND_KEYS = Object.keys(BOUND);
|
|
@@ -3384,19 +5982,19 @@ var BOOLEAN = /^(?:true|false)$/i;
|
|
|
3384
5982
|
var QUERY_RULES = {
|
|
3385
5983
|
...BOUND,
|
|
3386
5984
|
Mode: (value) => value === "Data",
|
|
3387
|
-
PCI: (value) =>
|
|
3388
|
-
CVV: (value) =>
|
|
3389
|
-
Container: (value) =>
|
|
3390
|
-
CvvContainer: (value) =>
|
|
3391
|
-
EnforceLuhnCompliance: (value) =>
|
|
5985
|
+
PCI: (value) => exact2(/^true$/i, value),
|
|
5986
|
+
CVV: (value) => exact2(/^true$/i, value),
|
|
5987
|
+
Container: (value) => exact2(/^[A-Za-z][A-Za-z0-9_-]{0,63}$/, value),
|
|
5988
|
+
CvvContainer: (value) => exact2(/^[A-Za-z][A-Za-z0-9_-]{0,63}$/, value),
|
|
5989
|
+
EnforceLuhnCompliance: (value) => exact2(BOOLEAN, value),
|
|
3392
5990
|
CustomDataLabel: (value) => plain(value, 64),
|
|
3393
5991
|
CustomCvvDataLabel: (value) => plain(value, 64),
|
|
3394
|
-
ExpiresInSeconds: (value) =>
|
|
3395
|
-
ReturnAutoCompleteValues: (value) =>
|
|
5992
|
+
ExpiresInSeconds: (value) => exact2(/^[1-9][0-9]{0,3}$/, value),
|
|
5993
|
+
ReturnAutoCompleteValues: (value) => exact2(BOOLEAN, value)
|
|
3396
5994
|
};
|
|
3397
5995
|
var QUERY_REQUIRED = [...BOUND_KEYS, "Mode", "PCI", "CVV"];
|
|
3398
5996
|
var PLACEHOLDER = /^[0-9]{1,19}(?: [0-9]{1,19}){0,5}$/;
|
|
3399
|
-
var placeholderDigits = (value) =>
|
|
5997
|
+
var placeholderDigits = (value) => exact2(PLACEHOLDER, value) && value.length <= 23 ? value.replace(/ /g, "") : null;
|
|
3400
5998
|
var RULES = {
|
|
3401
5999
|
...BOUND,
|
|
3402
6000
|
Data: (value) => {
|
|
@@ -3423,8 +6021,8 @@ var SUCCESS_RULES = {
|
|
|
3423
6021
|
token: (value) => digits(value, 13, 19),
|
|
3424
6022
|
firstSix: (value) => digits(value, 6, 6),
|
|
3425
6023
|
lastFour: (value) => digits(value, 4, 4),
|
|
3426
|
-
referenceNumber: (value) =>
|
|
3427
|
-
tokenHMAC: (value) =>
|
|
6024
|
+
referenceNumber: (value) => exact2(/^[A-Za-z0-9-]{1,64}$/, value),
|
|
6025
|
+
tokenHMAC: (value) => exact2(/^[A-Za-z0-9+/]{1,128}={0,2}$/, value),
|
|
3428
6026
|
cvvIncluded: (value) => typeof value === "boolean"
|
|
3429
6027
|
};
|
|
3430
6028
|
var SUCCESS_KEYS = Object.keys(SUCCESS_RULES);
|
|
@@ -3433,7 +6031,7 @@ var LETTERS2 = "A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u017F";
|
|
|
3433
6031
|
var PAGE_NAME2 = new RegExp(`^[${LETTERS2} .'-]{1,64}$`);
|
|
3434
6032
|
var HAS_LETTER2 = new RegExp(`[${LETTERS2}]`);
|
|
3435
6033
|
var ADDRESS_VALUE2 = new RegExp(`^[\\x20-\\x7e\\u00a0-\\u017f]{0,128}$`);
|
|
3436
|
-
var
|
|
6034
|
+
var PAN_LIKE3 = new RegExp(`(?:[0-9][^0-9${LETTERS2}]*){12,}`);
|
|
3437
6035
|
var pin7 = (fields) => Object.freeze({ ...fields, origins: Object.freeze([...fields.origins]), publicKeys: Object.freeze([...fields.publicKeys]) });
|
|
3438
6036
|
var OPENPAY_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
3439
6037
|
pin7({
|
|
@@ -3487,7 +6085,7 @@ var FASTSPRING_STORE_PINS = /* @__PURE__ */ Object.freeze([
|
|
|
3487
6085
|
Object.freeze({ environment: "production", store: "stardock", storefront: "/popup-store", merchant: "Stardock" })
|
|
3488
6086
|
]);
|
|
3489
6087
|
var STORE = "[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?";
|
|
3490
|
-
var
|
|
6088
|
+
var CARD_URL2 = new RegExp(`^https://(${STORE})(\\.test)?\\.onfastspring\\.com((?:/(?:popup|embedded)-[A-Za-z0-9_-]{1,64})?)/session/([A-Za-z0-9_-]{16,64})/payment$`);
|
|
3491
6089
|
// src/omise.js
|
|
3492
6090
|
var pin9 = (fields) => Object.freeze({ ...fields, origins: Object.freeze([...fields.origins]), keys: Object.freeze([...fields.keys]) });
|
|
3493
6091
|
var OMISE_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
@@ -3649,7 +6247,7 @@ var RECORD_MEMBERS = /* @__PURE__ */ Object.freeze({
|
|
|
3649
6247
|
]
|
|
3650
6248
|
});
|
|
3651
6249
|
// src/pin-payments.js
|
|
3652
|
-
var
|
|
6250
|
+
var CARD_KEYS3 = /* @__PURE__ */ Object.freeze(["name", "number", "cvc", "expiry_month", "expiry_year"]);
|
|
3653
6251
|
var ADDRESS_KEYS = /* @__PURE__ */ Object.freeze([
|
|
3654
6252
|
"address_line1",
|
|
3655
6253
|
"address_line2",
|
|
@@ -3658,9 +6256,9 @@ var ADDRESS_KEYS = /* @__PURE__ */ Object.freeze([
|
|
|
3658
6256
|
"address_state",
|
|
3659
6257
|
"address_country"
|
|
3660
6258
|
]);
|
|
3661
|
-
var
|
|
6259
|
+
var KEY2 = "publishable_api_key";
|
|
3662
6260
|
var METHOD = "_method";
|
|
3663
|
-
var DOCUMENTED = /* @__PURE__ */ new Set([
|
|
6261
|
+
var DOCUMENTED = /* @__PURE__ */ new Set([KEY2, METHOD, ...CARD_KEYS3, ...ADDRESS_KEYS]);
|
|
3664
6262
|
var TOKEN_FACTS = /* @__PURE__ */ Object.freeze([
|
|
3665
6263
|
"token",
|
|
3666
6264
|
"scheme",
|
|
@@ -3727,8 +6325,8 @@ var MESSAGES = Object.freeze({
|
|
|
3727
6325
|
dcp_field_config_unreviewed: "Refusing to pay: Agentcard has not reviewed this merchant's Amadeus card form yet. Nothing was sent."
|
|
3728
6326
|
});
|
|
3729
6327
|
var SDK_FLAVORS = Object.freeze(["Core-Sdk", "Angular-Web-Sdk"]);
|
|
3730
|
-
var
|
|
3731
|
-
var SDK_HOST = new RegExp(`^${
|
|
6328
|
+
var LABEL2 = "[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?";
|
|
6329
|
+
var SDK_HOST = new RegExp(`^${LABEL2}(?:\\.${LABEL2})+(?::[0-9]{1,5})?$`, "i");
|
|
3732
6330
|
var SDK_HEADERS = Object.freeze(["amadeus-checkout-sdk-version", "amadeus-checkout-sdk-host", "amadeus-checkout-sdk-flavor"]);
|
|
3733
6331
|
var SDK_DATA_KEYS = Object.freeze(["mopid", "mopdata", "fingerprint"]);
|
|
3734
6332
|
var SDK_MOPDATA_KEYS = Object.freeze(["pan", "CVV", "holdername", "expmonth", "expyear", "vendor", "address", "contact"]);
|
|
@@ -3747,162 +6345,6 @@ var DECLINE_LABELS = Object.freeze(["label_error_payment", "label_error_bin", "l
|
|
|
3747
6345
|
var EXPIRED_LABELS = Object.freeze(["session_timeout", "ppid_expired"]);
|
|
3748
6346
|
var REF_KEYS = Object.freeze(["recloc", "orderId", "mopId", "pri", "approvalcode", "externalId", "paymentMerchantReference", "prr"]);
|
|
3749
6347
|
var PAYMENT_INFORMATION_KEYS = Object.freeze(["approvalcode", "pri", "externalId", "mopId"]);
|
|
3750
|
-
// src/processors/ekashu.js
|
|
3751
|
-
var EKASHU_HOSTS = Object.freeze(["live.ekashu.com", "test.ekashu.com"]);
|
|
3752
|
-
var EKASHU_TEST_PANS = Object.freeze(["4100000000000100", "5100000000000107"]);
|
|
3753
|
-
var EKASHU_SIGNED_FIELDS = Object.freeze([
|
|
3754
|
-
"ekashu_3d_secure_verify",
|
|
3755
|
-
"ekashu_amount",
|
|
3756
|
-
"ekashu_amount_format",
|
|
3757
|
-
"ekashu_auto_confirm",
|
|
3758
|
-
"ekashu_callback_failure_url",
|
|
3759
|
-
"ekashu_callback_include_post",
|
|
3760
|
-
"ekashu_callback_success_url",
|
|
3761
|
-
"ekashu_card_address_editable",
|
|
3762
|
-
"ekashu_card_address_required",
|
|
3763
|
-
"ekashu_card_address_verify",
|
|
3764
|
-
"ekashu_card_email_address_mandatory",
|
|
3765
|
-
"ekashu_card_phone_number_mandatory",
|
|
3766
|
-
"ekashu_card_title_mandatory",
|
|
3767
|
-
"ekashu_card_zip_code_verify",
|
|
3768
|
-
"ekashu_currency",
|
|
3769
|
-
"ekashu_delivery_address_editable",
|
|
3770
|
-
"ekashu_delivery_address_required",
|
|
3771
|
-
"ekashu_delivery_email_address_mandatory",
|
|
3772
|
-
"ekashu_delivery_phone_number_mandatory",
|
|
3773
|
-
"ekashu_delivery_title_mandatory",
|
|
3774
|
-
"ekashu_description",
|
|
3775
|
-
"ekashu_device",
|
|
3776
|
-
"ekashu_duplicate_check",
|
|
3777
|
-
"ekashu_duplicate_minutes",
|
|
3778
|
-
"ekashu_failure_return_text",
|
|
3779
|
-
"ekashu_failure_url",
|
|
3780
|
-
"ekashu_hash_code_format",
|
|
3781
|
-
"ekashu_hash_code_type",
|
|
3782
|
-
"ekashu_hash_code_version",
|
|
3783
|
-
"ekashu_include_post",
|
|
3784
|
-
"ekashu_invoice_address_editable",
|
|
3785
|
-
"ekashu_invoice_address_required",
|
|
3786
|
-
"ekashu_invoice_email_address_mandatory",
|
|
3787
|
-
"ekashu_invoice_phone_number_mandatory",
|
|
3788
|
-
"ekashu_invoice_title_mandatory",
|
|
3789
|
-
"ekashu_locale",
|
|
3790
|
-
"ekashu_payment_methods",
|
|
3791
|
-
"ekashu_reference",
|
|
3792
|
-
"ekashu_request_type",
|
|
3793
|
-
"ekashu_return_text",
|
|
3794
|
-
"ekashu_seller_address",
|
|
3795
|
-
"ekashu_seller_email_address",
|
|
3796
|
-
"ekashu_seller_id",
|
|
3797
|
-
"ekashu_seller_key",
|
|
3798
|
-
"ekashu_seller_name",
|
|
3799
|
-
"ekashu_shortcut_icon",
|
|
3800
|
-
"ekashu_style_sheet",
|
|
3801
|
-
"ekashu_success_url",
|
|
3802
|
-
"ekashu_title",
|
|
3803
|
-
"ekashu_verification_value_mask",
|
|
3804
|
-
"ekashu_verification_value_verify",
|
|
3805
|
-
"ekashu_viewport"
|
|
3806
|
-
]);
|
|
3807
|
-
var REQUIRED = Object.freeze([
|
|
3808
|
-
"ekashu_seller_id",
|
|
3809
|
-
"ekashu_seller_key",
|
|
3810
|
-
"ekashu_amount",
|
|
3811
|
-
"ekashu_currency",
|
|
3812
|
-
"ekashu_reference",
|
|
3813
|
-
"ekashu_hash_code",
|
|
3814
|
-
"ekashu_hash_code_type",
|
|
3815
|
-
"ekashu_hash_code_version",
|
|
3816
|
-
"ekashu_success_url",
|
|
3817
|
-
"ekashu_failure_url",
|
|
3818
|
-
"ekashu_callback_success_url"
|
|
3819
|
-
]);
|
|
3820
|
-
var CARD_KEYS2 = Object.freeze([
|
|
3821
|
-
"ekashu_card_number",
|
|
3822
|
-
"ekashu_expires_end_month",
|
|
3823
|
-
"ekashu_expires_end_year",
|
|
3824
|
-
"ekashu_verification_value",
|
|
3825
|
-
"ekashu_valid_from_month",
|
|
3826
|
-
"ekashu_valid_from_year",
|
|
3827
|
-
"ekashu_issue_number"
|
|
3828
|
-
]);
|
|
3829
|
-
var PAGE_KEYS = Object.freeze(["ekashu_stage", "ekashu_context", "ekashu_submission_id"]);
|
|
3830
|
-
var STORED_KEYS = Object.freeze(["ekashu_card_hash", "ekashu_card_reference", "ekashu_cof_initiated_by", "ekashu_cof_reason", "ekashu_cof_id"]);
|
|
3831
|
-
var REDIRECT_KEYS = Object.freeze(["ekashu_success_url", "ekashu_failure_url", "ekashu_return_url"]);
|
|
3832
|
-
var CALLBACK_KEYS = Object.freeze(["ekashu_callback_success_url", "ekashu_callback_failure_url"]);
|
|
3833
|
-
var MAX_ENTRY = 16 * 1024;
|
|
3834
|
-
var MAX_PAGE = 256 * 1024;
|
|
3835
|
-
var EKASHU_SELLERS = Object.freeze([
|
|
3836
|
-
Object.freeze({ sellerId: "25060100", merchant: "Heathrow Drop-off", entryHost: "heathrowdropoff.apcoa.com", callbackHost: "incomingapi.apcoa.co.uk" })
|
|
3837
|
-
]);
|
|
3838
|
-
var CARD_FIELDS = Object.freeze({
|
|
3839
|
-
number: "ekashu_card_number",
|
|
3840
|
-
month: "ekashu_expires_end_month",
|
|
3841
|
-
year: "ekashu_expires_end_year",
|
|
3842
|
-
cvc: "ekashu_verification_value"
|
|
3843
|
-
});
|
|
3844
|
-
var NAME_FIELDS = Object.freeze({ first: "ekashu_card_first_name", last: "ekashu_card_last_name" });
|
|
3845
|
-
var LEFT_EMPTY = Object.freeze(["ekashu_card_title", "ekashu_valid_from_month", "ekashu_valid_from_year", "ekashu_issue_number"]);
|
|
3846
|
-
var VISIBLE = /* @__PURE__ */ new Set([...Object.values(CARD_FIELDS), ...Object.values(NAME_FIELDS), ...LEFT_EMPTY]);
|
|
3847
|
-
// src/processors/redsys.js
|
|
3848
|
-
var REDSYS_HOSTS = Object.freeze(["sis.redsys.es"]);
|
|
3849
|
-
var REDSYS_ENTRY_PATHS = Object.freeze(["/sis/realizarPago", "/sis/realizarPago/utf-8"]);
|
|
3850
|
-
var REDSYS_MERCHANTS = Object.freeze([]);
|
|
3851
|
-
var MAX_ENTRY2 = 16 * 1024;
|
|
3852
|
-
var MAX_PARAMETERS = 8 * 1024;
|
|
3853
|
-
var ENTRY_KEYS = Object.freeze(["Ds_SignatureVersion", "Ds_MerchantParameters", "Ds_Signature"]);
|
|
3854
|
-
var REQUIRED2 = Object.freeze([
|
|
3855
|
-
"DS_MERCHANT_AMOUNT",
|
|
3856
|
-
"DS_MERCHANT_CURRENCY",
|
|
3857
|
-
"DS_MERCHANT_MERCHANTCODE",
|
|
3858
|
-
"DS_MERCHANT_ORDER",
|
|
3859
|
-
"DS_MERCHANT_TERMINAL",
|
|
3860
|
-
"DS_MERCHANT_TRANSACTIONTYPE",
|
|
3861
|
-
"DS_MERCHANT_MERCHANTURL",
|
|
3862
|
-
"DS_MERCHANT_URLOK",
|
|
3863
|
-
"DS_MERCHANT_URLKO"
|
|
3864
|
-
]);
|
|
3865
|
-
var STORED = Object.freeze([
|
|
3866
|
-
"DS_MERCHANT_IDENTIFIER",
|
|
3867
|
-
"DS_MERCHANT_GROUP",
|
|
3868
|
-
"DS_MERCHANT_COF_INI",
|
|
3869
|
-
"DS_MERCHANT_COF_TYPE",
|
|
3870
|
-
"DS_MERCHANT_COF_TXNID"
|
|
3871
|
-
]);
|
|
3872
|
-
var SPECIAL = Object.freeze([
|
|
3873
|
-
"DS_MERCHANT_DIRECTPAYMENT",
|
|
3874
|
-
"DS_MERCHANT_SUMTOTAL",
|
|
3875
|
-
"DS_MERCHANT_DATEFRECUENCY",
|
|
3876
|
-
"DS_MERCHANT_CHARGEEXPIRYDATE",
|
|
3877
|
-
"DS_MERCHANT_IDOPER"
|
|
3878
|
-
]);
|
|
3879
|
-
var CARD_PARAMETERS = Object.freeze(["DS_MERCHANT_PAN", "DS_MERCHANT_EXPIRYDATE", "DS_MERCHANT_CVV2"]);
|
|
3880
|
-
var CURRENCIES = Object.freeze({ 978: "eur", 840: "usd", 826: "gbp", 756: "chf" });
|
|
3881
|
-
var MAX_PAGE2 = 256 * 1024;
|
|
3882
|
-
var CARD_FIELDS2 = Object.freeze({
|
|
3883
|
-
shown: "Sis_card-number",
|
|
3884
|
-
expiry: "SIS_card-expiration",
|
|
3885
|
-
cvc: "Sis_Tarjeta_CVV2",
|
|
3886
|
-
holder: "cardholderName",
|
|
3887
|
-
number: "Sis_Numero_Tarjeta",
|
|
3888
|
-
month: "Sis_Caducidad_Tarjeta_Mes",
|
|
3889
|
-
year: "Sis_Caducidad_Tarjeta_Anno"
|
|
3890
|
-
});
|
|
3891
|
-
var BROWSER_FIELDS = Object.freeze([
|
|
3892
|
-
"browserJavaEnabled",
|
|
3893
|
-
"browserJavascriptEnabled",
|
|
3894
|
-
"browserLanguage",
|
|
3895
|
-
"browserColorDepth",
|
|
3896
|
-
"browserScreenHeight",
|
|
3897
|
-
"browserScreenWidth",
|
|
3898
|
-
"browserTZ",
|
|
3899
|
-
"browserUserAgent"
|
|
3900
|
-
]);
|
|
3901
|
-
var AS_SERVED = Object.freeze(["cvvObligatorio", "threeDSCompInd", "fuc", "terminal", "merchantOrder", "bcancel"]);
|
|
3902
|
-
var CARD_PAGE = /* @__PURE__ */ new Set([...Object.values(CARD_FIELDS2), ...BROWSER_FIELDS, ...AS_SERVED]);
|
|
3903
|
-
var VISIBLE2 = /* @__PURE__ */ new Set([CARD_FIELDS2.shown, CARD_FIELDS2.expiry, CARD_FIELDS2.cvc, CARD_FIELDS2.holder]);
|
|
3904
|
-
var METHOD_PAGE = /* @__PURE__ */ new Set(["resultadoMethod", ...BROWSER_FIELDS, "threeDSCompInd"]);
|
|
3905
|
-
var REDSYS_REFUSALS = Object.freeze(["redsys_card_page", "redsys_3ds_challenge", "redsys_declined"]);
|
|
3906
6348
|
// src/processors/quickpay.js
|
|
3907
6349
|
var QUICKPAY_HOSTS = Object.freeze(["payment.quickpay.net"]);
|
|
3908
6350
|
var QUICKPAY_MERCHANTS = Object.freeze([
|
|
@@ -3914,8 +6356,8 @@ var QUICKPAY_MERCHANTS = Object.freeze([
|
|
|
3914
6356
|
callbackHost: "shop.skandinaviskdyrepark.dk"
|
|
3915
6357
|
})
|
|
3916
6358
|
]);
|
|
3917
|
-
var
|
|
3918
|
-
var
|
|
6359
|
+
var MAX_ENTRY4 = 16 * 1024;
|
|
6360
|
+
var REQUIRED5 = Object.freeze([
|
|
3919
6361
|
"version",
|
|
3920
6362
|
"merchant_id",
|
|
3921
6363
|
"agreement_id",
|
|
@@ -3928,7 +6370,7 @@ var REQUIRED3 = Object.freeze([
|
|
|
3928
6370
|
"checksum"
|
|
3929
6371
|
]);
|
|
3930
6372
|
var SCALARS = /* @__PURE__ */ new Set([
|
|
3931
|
-
...
|
|
6373
|
+
...REQUIRED5,
|
|
3932
6374
|
"type",
|
|
3933
6375
|
"language",
|
|
3934
6376
|
"autocapture",
|
|
@@ -3946,12 +6388,12 @@ var SCALARS = /* @__PURE__ */ new Set([
|
|
|
3946
6388
|
"invoice_address_selection",
|
|
3947
6389
|
"shipping_address_selection"
|
|
3948
6390
|
]);
|
|
3949
|
-
var
|
|
3950
|
-
var
|
|
6391
|
+
var CURRENCIES4 = Object.freeze({ DKK: "dkk", EUR: "eur", USD: "usd", SEK: "sek", NOK: "nok", GBP: "gbp", CHF: "chf", PLN: "pln" });
|
|
6392
|
+
var MAX_PAGE6 = 256 * 1024;
|
|
3951
6393
|
var CARD_FIELDS3 = Object.freeze({ number: "cardnumber", month: "expiration[month]", year: "expiration[year]", cvc: "cvd", holder: "cardholder" });
|
|
3952
6394
|
var TYPED = /* @__PURE__ */ new Set([CARD_FIELDS3.number, CARD_FIELDS3.month, CARD_FIELDS3.year, CARD_FIELDS3.cvc]);
|
|
3953
6395
|
var CARD_PAGE2 = /* @__PURE__ */ new Set(["session_id", ...TYPED]);
|
|
3954
|
-
var
|
|
6396
|
+
var OPTIONAL2 = Object.freeze({ brand: "radio", "3d": "checkbox", cardholder: "text" });
|
|
3955
6397
|
var AUTH_FIELDS = Object.freeze([
|
|
3956
6398
|
"[auth]browserColorDepth",
|
|
3957
6399
|
"[auth]browserJavaEnabled",
|
|
@@ -3973,7 +6415,7 @@ var COMGATE_MERCHANTS = Object.freeze([
|
|
|
3973
6415
|
Object.freeze({ merchant: "Dárek pro Beskydy", origins: Object.freeze(["https://darekprobeskydy.info"]), merchantIds: Object.freeze([]) })
|
|
3974
6416
|
]);
|
|
3975
6417
|
var MAX_LOAD = 1024 * 1024;
|
|
3976
|
-
var
|
|
6418
|
+
var MAX_ANSWER2 = 64 * 1024;
|
|
3977
6419
|
var HEADER_NAMES = Object.freeze(["content-type", "x-cg-origin", "origin"]);
|
|
3978
6420
|
var COMGATE_REFUSALS = Object.freeze(["comgate_3ds_challenge", "comgate_declined"]);
|
|
3979
6421
|
// src/processors/przelewy24.js
|
|
@@ -3982,8 +6424,8 @@ var PRZELEWY24_SANDBOX_HOSTS = Object.freeze(["sandbox.przelewy24.pl"]);
|
|
|
3982
6424
|
var PRZELEWY24_MERCHANTS = Object.freeze([
|
|
3983
6425
|
Object.freeze({ id: "kupbilet", merchant: "KupBilet.pl", merchantId: null, origins: Object.freeze(["https://www.kupbilet.pl"]) })
|
|
3984
6426
|
]);
|
|
3985
|
-
var
|
|
3986
|
-
var
|
|
6427
|
+
var MAX_PAGE7 = 256 * 1024;
|
|
6428
|
+
var CURRENCIES5 = Object.freeze(["PLN", "EUR", "GBP", "USD", "CZK", "CHF", "DKK", "NOK", "SEK", "RON", "BGN", "HUF"]);
|
|
3987
6429
|
var PRZELEWY24_AJAX_HEADERS = Object.freeze({ Accept: "*/*", "X-Requested-With": "XMLHttpRequest" });
|
|
3988
6430
|
var MONTHS = Object.freeze(["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]);
|
|
3989
6431
|
var CARD_TYPES = Object.freeze([
|
|
@@ -4014,7 +6456,7 @@ var TRANSBANK_MERCHANTS = Object.freeze([
|
|
|
4014
6456
|
returnUrl: null
|
|
4015
6457
|
})
|
|
4016
6458
|
]);
|
|
4017
|
-
var
|
|
6459
|
+
var MAX_PAGE8 = 64 * 1024;
|
|
4018
6460
|
var JSON_HEADERS = Object.freeze({ "content-type": "application/json", accept: "application/json, text/plain, */*" });
|
|
4019
6461
|
var FORM_HEADERS = Object.freeze({ "content-type": "application/x-www-form-urlencoded", accept: "application/json, text/plain, */*" });
|
|
4020
6462
|
var TRANSBANK_REFUSALS = Object.freeze(["transbank_3ds_challenge", "transbank_aborted", "transbank_error"]);
|
|
@@ -4034,20 +6476,20 @@ var PAYTRAIL_MERCHANTS = Object.freeze([
|
|
|
4034
6476
|
]);
|
|
4035
6477
|
var UUID_SOURCE = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
4036
6478
|
var UUID2 = new RegExp(`^${UUID_SOURCE}$`);
|
|
4037
|
-
var
|
|
6479
|
+
var ENTRY_PATH2 = new RegExp(`^/payments/(${UUID_SOURCE})/click-to-pay/loading-and-redirect$`);
|
|
4038
6480
|
var SIGNATURES = Object.freeze({ sha256: /^[0-9a-f]{64}$/, sha512: /^[0-9a-f]{128}$/ });
|
|
4039
6481
|
var PAYMENT_HIGHWAY_HOSTS = Object.freeze(["v1.api.paymenthighway.io"]);
|
|
4040
6482
|
var CARD_PAGE_PATH = new RegExp(`^/form/(${UUID_SOURCE})/pay_with_click_to_pay$`);
|
|
4041
|
-
var
|
|
6483
|
+
var MAX_PAGE9 = 256 * 1024;
|
|
4042
6484
|
var PAYTRAIL_CARD_HEADERS = Object.freeze({ "Content-Type": "application/json", "X-Requested-With": "PH-Form", Accept: "application/json" });
|
|
4043
6485
|
var PAYTRAIL_REFUSALS = Object.freeze(["paytrail_3ds_challenge", "paytrail_card_refused"]);
|
|
4044
6486
|
// src/processors/eximbay.js
|
|
4045
6487
|
var EXIMBAY_HOSTS = Object.freeze(["secureapi.eximbay.com", "secureapi.test.eximbay.com"]);
|
|
4046
6488
|
var EXIMBAY_MERCHANTS = Object.freeze([]);
|
|
4047
|
-
var
|
|
4048
|
-
var
|
|
4049
|
-
var
|
|
4050
|
-
var
|
|
6489
|
+
var MAX_ENTRY5 = 16 * 1024;
|
|
6490
|
+
var REQUIRED6 = Object.freeze(["ver", "mid", "txntype", "ref", "cur", "amt", "buyer", "email", "lang", "returnurl", "statusurl", "fgkey"]);
|
|
6491
|
+
var CURRENCIES6 = Object.freeze({ USD: 2, KRW: 0, JPY: 0, EUR: 2, GBP: 2, SGD: 2, HKD: 2, CAD: 2, AUD: 2, THB: 2 });
|
|
6492
|
+
var MAX_PAGE10 = 512 * 1024;
|
|
4051
6493
|
var ATTRS = `(?:[^>"']|"[^"]{0,1024}"|'[^']{0,1024}'){0,512}`;
|
|
4052
6494
|
var startTag = (name) => new RegExp(`<${name}(?=[\\t\\n\\f\\r />])${ATTRS}>`, "gi");
|
|
4053
6495
|
var FORM_START = startTag("form");
|
|
@@ -4100,8 +6542,8 @@ var RESULT_BINDS = Object.freeze(["mid", "txntype", "ref", "cur", "amt"]);
|
|
|
4100
6542
|
var BARION_HOSTS = Object.freeze(["secure.barion.com", "secure.test.barion.com"]);
|
|
4101
6543
|
var BARION_SANDBOX_HOSTS = Object.freeze(["secure.test.barion.com"]);
|
|
4102
6544
|
var BARION_SHOPS = Object.freeze([]);
|
|
4103
|
-
var
|
|
4104
|
-
var
|
|
6545
|
+
var MAX_PAGE11 = 512 * 1024;
|
|
6546
|
+
var CURRENCIES7 = Object.freeze(["HUF", "EUR", "USD", "CZK", "RON", "PLN"]);
|
|
4105
6547
|
var CARD_INPUTS = Object.freeze({ number: "cc-number", expiry: "cc-exp-date", cvc: "CardCVC", holder: "CardHolderName" });
|
|
4106
6548
|
var CHECKBOXES = Object.freeze(["RegisterUser", "AcceptedTerms", "HasEmailConsent"]);
|
|
4107
6549
|
var OTHER_INPUTS = Object.freeze({ FirstPassword: ["password"], RecaptchaToken: ["hidden"], __RequestVerificationToken: ["hidden"], Identifier: ["hidden"] });
|
|
@@ -4113,7 +6555,7 @@ var BARION_AJAX_HEADERS = Object.freeze({
|
|
|
4113
6555
|
var CARD_TYPES2 = Object.freeze([{ prefix: /^4/, type: 20 }, { prefix: /^5[1-5]|^2[2-7]/, type: 10 }, { prefix: /^3[47]/, type: 30 }]);
|
|
4114
6556
|
var COLOR_DEPTHS = Object.freeze([1, 4, 8, 15, 16, 24, 32, 48]);
|
|
4115
6557
|
var BARION_REFUSALS = Object.freeze(["barion_declined", "barion_3ds_challenge", "barion_sca_soft_decline"]);
|
|
4116
|
-
var
|
|
6558
|
+
var MAX_ANSWER3 = 64 * 1024;
|
|
4117
6559
|
var DECLINE_CODES = Object.freeze([
|
|
4118
6560
|
"CardError",
|
|
4119
6561
|
"CardExpired",
|
|
@@ -4152,7 +6594,7 @@ var SBPS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
|
4152
6594
|
]);
|
|
4153
6595
|
var ERROR_TYPES = /* @__PURE__ */ Object.freeze(["03", "04", "05", "07", "99"]);
|
|
4154
6596
|
var ERROR_FIELDS = /* @__PURE__ */ Object.freeze(["001", "002", "003", "004", "005", "999"]);
|
|
4155
|
-
var SBPS_REFUSAL_CODES = /* @__PURE__ */ Object.freeze(ERROR_TYPES.flatMap((type) => ERROR_FIELDS.map((
|
|
6597
|
+
var SBPS_REFUSAL_CODES = /* @__PURE__ */ Object.freeze(ERROR_TYPES.flatMap((type) => ERROR_FIELDS.map((field4) => `${type}${field4}`)));
|
|
4156
6598
|
// src/recognition.js
|
|
4157
6599
|
var PATTERN_WITHOUT_CARD_FIELDS = Object.freeze({
|
|
4158
6600
|
stripe: "api\\.stripe\\.com/v1/(payment_methods|tokens|setup_intents/seti_\\w+/confirm|payment_intents/pi_\\w+/confirm)"
|
|
@@ -4235,7 +6677,7 @@ var replayPolicy = Object.freeze({ contentTypeFor, HEADER_NEVER_FORWARD });
|
|
|
4235
6677
|
var STRIPE_CHECKOUT_OPERATION = "stripe.device_checkout_confirm.v1";
|
|
4236
6678
|
var STRIPE_CHECKOUT_CONTEXT_HEADER = "x-agentcard-stripe-checkout-context";
|
|
4237
6679
|
var SESSION = /^cs_(?:test|live)_[A-Za-z0-9]{1,200}(?![\s\S])/;
|
|
4238
|
-
var
|
|
6680
|
+
var KEY3 = /^pk_(?:test|live)_[A-Za-z0-9_]{1,256}(?![\s\S])/;
|
|
4239
6681
|
var SYNTHETIC = /^pm_agentcard_checkout_[A-Za-z0-9_-]{16,80}(?![\s\S])/;
|
|
4240
6682
|
var STRIPE_CHECKOUT_VALIDATION_CODES = Object.freeze({
|
|
4241
6683
|
unclassified: "unclassified",
|
|
@@ -4278,7 +6720,7 @@ function validateStripeCheckoutIdentity(value) {
|
|
|
4278
6720
|
reject("mode_binding");
|
|
4279
6721
|
const environment = value.environment ?? "test", livemode = environment === "production";
|
|
4280
6722
|
const mode = livemode ? "live" : "test";
|
|
4281
|
-
if (Object.hasOwn(value, "sessionId") && (typeof value.sessionId !== "string" || !SESSION.test(value.sessionId) || !value.sessionId.startsWith(`cs_${mode}_`)) || Object.hasOwn(value, "publishableKey") && (typeof value.publishableKey !== "string" || !
|
|
6723
|
+
if (Object.hasOwn(value, "sessionId") && (typeof value.sessionId !== "string" || !SESSION.test(value.sessionId) || !value.sessionId.startsWith(`cs_${mode}_`)) || Object.hasOwn(value, "publishableKey") && (typeof value.publishableKey !== "string" || !KEY3.test(value.publishableKey) || !value.publishableKey.startsWith(`pk_${mode}_`)) || Object.hasOwn(value, "livemode") && value.livemode !== livemode)
|
|
4282
6724
|
reject("mode_binding");
|
|
4283
6725
|
return Object.freeze({ environment, livemode });
|
|
4284
6726
|
}
|
|
@@ -4314,16 +6756,16 @@ function isStripeCheckoutHostedMode(value) {
|
|
|
4314
6756
|
return value === "hosted" || value === "hosted_page";
|
|
4315
6757
|
}
|
|
4316
6758
|
function encodeAscii(value) {
|
|
4317
|
-
let result = "", bits = 0,
|
|
6759
|
+
let result = "", bits = 0, count2 = 0;
|
|
4318
6760
|
for (const char of value) {
|
|
4319
6761
|
bits = bits << 8 | char.charCodeAt(0);
|
|
4320
|
-
|
|
4321
|
-
while (
|
|
4322
|
-
|
|
4323
|
-
result += alphabet[bits >>>
|
|
6762
|
+
count2 += 8;
|
|
6763
|
+
while (count2 >= 6) {
|
|
6764
|
+
count2 -= 6;
|
|
6765
|
+
result += alphabet[bits >>> count2 & 63];
|
|
4324
6766
|
}
|
|
4325
6767
|
}
|
|
4326
|
-
return result + (
|
|
6768
|
+
return result + (count2 ? alphabet[bits << 6 - count2 & 63] : "");
|
|
4327
6769
|
}
|
|
4328
6770
|
function context(value) {
|
|
4329
6771
|
if (!object(value) || Object.keys(value).length !== 3 || value.version !== 1 || !["version", "session_id", "synthetic_payment_method_id"].every((key) => Object.hasOwn(value, key)) || !SESSION.test(value.session_id) || !SYNTHETIC.test(value.synthetic_payment_method_id))
|
|
@@ -4343,18 +6785,18 @@ function parseStripeCheckoutContext(request) {
|
|
|
4343
6785
|
if (entries.length !== 1 || typeof entries[0][1] !== "string" || !/^[A-Za-z0-9_-]{1,1024}$/.test(entries[0][1]))
|
|
4344
6786
|
reject("context_invalid");
|
|
4345
6787
|
const encoded = entries[0][1];
|
|
4346
|
-
let
|
|
6788
|
+
let text3 = "", bits = 0, count2 = 0;
|
|
4347
6789
|
for (const char of encoded) {
|
|
4348
6790
|
bits = bits << 6 | alphabet.indexOf(char);
|
|
4349
|
-
|
|
4350
|
-
if (
|
|
4351
|
-
|
|
4352
|
-
|
|
6791
|
+
count2 += 6;
|
|
6792
|
+
if (count2 >= 8) {
|
|
6793
|
+
count2 -= 8;
|
|
6794
|
+
text3 += String.fromCharCode(bits >>> count2 & 255);
|
|
4353
6795
|
}
|
|
4354
6796
|
}
|
|
4355
6797
|
let value;
|
|
4356
6798
|
try {
|
|
4357
|
-
value = context(JSON.parse(
|
|
6799
|
+
value = context(JSON.parse(text3));
|
|
4358
6800
|
}
|
|
4359
6801
|
catch {
|
|
4360
6802
|
reject("context_invalid");
|
|
@@ -4482,7 +6924,7 @@ function keyFor(request, values, expected) {
|
|
|
4482
6924
|
headerKey = match[1];
|
|
4483
6925
|
}
|
|
4484
6926
|
const key = values.get("key") || headerKey;
|
|
4485
|
-
if (!
|
|
6927
|
+
if (!KEY3.test(key) || headerKey && headerKey !== key || expected !== void 0 && expected !== key)
|
|
4486
6928
|
reject("publishable_key");
|
|
4487
6929
|
return key;
|
|
4488
6930
|
}
|
|
@@ -4504,13 +6946,13 @@ function attachStripeCheckoutBilling(request, captured, options) {
|
|
|
4504
6946
|
const phase = classifyStripeCheckoutRequest(request, options);
|
|
4505
6947
|
if (phase?.phase !== "final" || !object(captured) || Object.keys(captured).length !== 3 || !["session_id", "synthetic_payment_method_id", "email"].every((key) => Object.hasOwn(captured, key)) || captured.session_id !== phase.session_id || captured.synthetic_payment_method_id !== phase.synthetic_payment_method_id || !billingEmail(captured.email))
|
|
4506
6948
|
reject("billing_binding");
|
|
4507
|
-
const
|
|
4508
|
-
const existing = form(request, finalFields).values.get(
|
|
6949
|
+
const field4 = "payment_method_data[billing_details][email]";
|
|
6950
|
+
const existing = form(request, finalFields).values.get(field4);
|
|
4509
6951
|
if (existing !== void 0 && existing !== captured.email)
|
|
4510
6952
|
reject("billing_conflict");
|
|
4511
6953
|
if (captured.email === null || existing !== void 0)
|
|
4512
6954
|
return { ...request };
|
|
4513
|
-
const body = `${request.body}&${encodeURIComponent(
|
|
6955
|
+
const body = `${request.body}&${encodeURIComponent(field4)}=${encodeURIComponent(captured.email)}`;
|
|
4514
6956
|
const result = { ...request, body };
|
|
4515
6957
|
classifyStripeCheckoutRequest(result, options);
|
|
4516
6958
|
return result;
|