@agent-cards/sdk 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -2
- package/PREFLIGHT.md +32 -0
- package/README.md +1177 -23
- package/dist/aci.d.ts +173 -0
- package/dist/aci.generated.d.ts +87 -0
- package/dist/aci.generated.js +306 -0
- package/dist/aci.js +371 -0
- package/dist/adyen-merchant-hosted.generated.d.ts +3 -3
- package/dist/adyen-merchant-hosted.generated.js +302 -56
- package/dist/agentcard.d.ts +9 -2
- package/dist/agentcard.js +4 -2
- package/dist/amadeus-checkout.generated.d.ts +57 -0
- package/dist/amadeus-checkout.generated.js +549 -0
- package/dist/amadeus.d.ts +41 -0
- package/dist/amadeus.js +81 -0
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/card-endpoint-facts.d.ts +96 -0
- package/dist/card-endpoint-facts.js +275 -0
- package/dist/card-endpoint-page.d.ts +54 -0
- package/dist/card-endpoint-page.js +69 -0
- package/dist/card-endpoint.d.ts +298 -0
- package/dist/card-endpoint.js +438 -0
- package/dist/card-fields.generated.d.ts +5 -3
- package/dist/card-fields.generated.js +284 -7
- package/dist/cdp.d.ts +5 -1
- package/dist/cdp.js +1155 -141
- package/dist/client.d.ts +456 -20
- package/dist/client.js +1072 -104
- package/dist/creditguard.generated.d.ts +79 -0
- package/dist/creditguard.generated.js +662 -0
- package/dist/cse-body.js +11 -1
- package/dist/cybersource-flex.d.ts +30 -0
- package/dist/cybersource-flex.generated.d.ts +27 -1
- package/dist/cybersource-flex.generated.js +42 -2
- package/dist/cybersource-flex.js +46 -0
- package/dist/datatrans.d.ts +96 -0
- package/dist/datatrans.generated.d.ts +64 -0
- package/dist/datatrans.generated.js +426 -0
- package/dist/datatrans.js +178 -0
- package/dist/ekashu.d.ts +35 -0
- package/dist/ekashu.js +55 -0
- package/dist/elavon-converge.d.ts +37 -0
- package/dist/elavon-converge.generated.d.ts +49 -0
- package/dist/elavon-converge.generated.js +439 -0
- package/dist/elavon-converge.js +84 -0
- package/dist/eprotect.d.ts +152 -0
- package/dist/eprotect.generated.d.ts +77 -0
- package/dist/eprotect.generated.js +498 -0
- package/dist/eprotect.js +222 -0
- package/dist/hosted-form.d.ts +3 -2
- package/dist/hosted-form.js +3 -2
- package/dist/index.d.ts +17 -3
- package/dist/index.js +6 -1
- package/dist/juspay-gate.d.ts +82 -0
- package/dist/juspay-gate.js +126 -0
- package/dist/juspay.generated.d.ts +89 -0
- package/dist/juspay.generated.js +705 -0
- package/dist/lifecycle.d.ts +60 -6
- package/dist/lifecycle.js +122 -8
- package/dist/merchant-card-endpoints.generated.d.ts +122 -0
- package/dist/merchant-card-endpoints.generated.js +4261 -0
- package/dist/merchant-hosted.d.ts +4 -1
- package/dist/merchant-hosted.js +5 -2
- package/dist/merchant-session-probe.d.ts +48 -0
- package/dist/merchant-session-probe.js +53 -0
- package/dist/merchant-session.generated.d.ts +69 -0
- package/dist/merchant-session.generated.js +919 -0
- package/dist/payrails.d.ts +133 -0
- package/dist/payrails.generated.d.ts +73 -0
- package/dist/payrails.generated.js +596 -0
- package/dist/payrails.js +305 -0
- package/dist/pelecard.d.ts +32 -0
- package/dist/pelecard.generated.d.ts +32 -0
- package/dist/pelecard.generated.js +283 -0
- package/dist/pelecard.js +42 -0
- package/dist/pre-claim.d.ts +81 -2
- package/dist/pre-claim.js +1023 -5
- package/dist/preflight-catalog.json +2267 -288
- package/dist/preflight-schemas.json +183 -6
- package/dist/preflight.generated.d.ts +1 -1
- package/dist/preflight.generated.js +243 -4
- package/dist/preparation.d.ts +12 -3
- package/dist/preparation.js +63 -12
- package/dist/prepared-processor.d.ts +84 -5
- package/dist/prepared-processor.js +147 -6
- package/dist/primer.d.ts +53 -0
- package/dist/primer.generated.d.ts +38 -0
- package/dist/primer.generated.js +624 -0
- package/dist/primer.js +82 -0
- package/dist/registry.d.ts +100 -8
- package/dist/registry.js +85 -11
- package/dist/shiji-sts.d.ts +144 -0
- package/dist/shiji-sts.generated.d.ts +72 -0
- package/dist/shiji-sts.generated.js +913 -0
- package/dist/shiji-sts.js +222 -0
- package/dist/stripe-checkout.generated.d.ts +1 -1
- package/dist/stripe-checkout.generated.js +764 -9
- package/dist/stripe-setup.d.ts +16 -0
- package/dist/stripe-setup.js +61 -0
- package/dist/substitutions.generated.js +187 -29
- package/dist/verifone.d.ts +68 -0
- package/dist/verifone.generated.d.ts +51 -0
- package/dist/verifone.generated.js +1413 -0
- package/dist/verifone.js +119 -0
- package/dist/voice-types.d.ts +27 -0
- package/dist/voice.d.ts +6 -1
- package/dist/voice.js +6 -1
- package/dist/wspay.d.ts +41 -0
- package/dist/wspay.generated.d.ts +41 -0
- package/dist/wspay.generated.js +370 -0
- package/dist/wspay.js +65 -0
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
+
// artifact-sha256: a9b6c689690a719af354b2f260064b8e276b8566f3b3482f4b1891f6c4db1caa
|
|
4
|
+
// src/deep-freeze.js
|
|
5
|
+
function deepFreeze(value) {
|
|
6
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
7
|
+
for (const child of Object.values(value))
|
|
8
|
+
deepFreeze(child);
|
|
9
|
+
Object.freeze(value);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
// src/test-pans.js
|
|
14
|
+
function immutableSet(values, name) {
|
|
15
|
+
const set = new Set(values);
|
|
16
|
+
for (const method of ["add", "delete", "clear"]) {
|
|
17
|
+
set[method] = () => {
|
|
18
|
+
throw new TypeError(`${name} is immutable`);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return Object.freeze(set);
|
|
22
|
+
}
|
|
23
|
+
var DOCUMENTED_TEST_PANS = /* @__PURE__ */ immutableSet([
|
|
24
|
+
"4242424242424242",
|
|
25
|
+
"4000000000000002",
|
|
26
|
+
"4000002500003155",
|
|
27
|
+
"4111111111111111"
|
|
28
|
+
], "DOCUMENTED_TEST_PANS");
|
|
29
|
+
// src/eprotect.js
|
|
30
|
+
var EPROTECT_PATH = "/eProtect/paypage";
|
|
31
|
+
var EPROTECT_HOSTS = /* @__PURE__ */ Object.freeze({
|
|
32
|
+
production: "request.eprotect.vantivcnp.com",
|
|
33
|
+
sandbox: "request.eprotect.vantivprelive.com"
|
|
34
|
+
});
|
|
35
|
+
var EPROTECT_SECONDARY_HOST = "secondary.eprotect.vantivcnp.com";
|
|
36
|
+
var EPROTECT_KEYS = /* @__PURE__ */ Object.freeze({
|
|
37
|
+
production: /* @__PURE__ */ Object.freeze({
|
|
38
|
+
keyId: "26455500012",
|
|
39
|
+
exponent: "10001",
|
|
40
|
+
modulus: "b9c7095ff203475347a932a6e11bacbb61cfb66a877158683634e5fb1dbf9923401bd7f82c21b67ffd3c82bdc64797c5e2ba4b57c68b1aaccb7fbe847da7234a21df910dfcc0aebacbbd4d36b35c0c35f7ee27358610d2e2fb2aa87d359deda0b5f4d77e31ac5ab98741da5b6052cb657087da05ad496154b8954939ee6fd463301ff15ebca94f210f4627a255a95ca8833728c1ab80b6cc3a874e4d3dce5d40f66c043ba1b042717bb9cc5d89434fa489a51c2ba9a3843b310df58c9e8a54c36cdd5fd66e76651b6fc88850b60e0739abfcf7d0d0cb44beb7e768da3bcea7e743b8c2d57edef59643f54432ccf60c49d4f5f84410ecf9c5a7af19bc5e792801"
|
|
41
|
+
}),
|
|
42
|
+
sandbox: /* @__PURE__ */ Object.freeze({
|
|
43
|
+
keyId: "1",
|
|
44
|
+
exponent: "10001",
|
|
45
|
+
modulus: "bc637dd74ba76507dad5af1c7ad6f97dbef5298c3b9f74caea7301347db7b4a8c37f26491863100667246fd45071f3346bf62239f9b117d06fb67861b66ad0d158beeddd2f6f28be93d846f4c8f9ba1bd7e8f186f36cab0e432f22b3d732c221a9ff00a9bfacb88b24503e2695fd7237835d4936477b21289478906a49b164f52503c20eb29f11fcbda2af94deb9a0bfde5a4589276897436315c5d664d60bf10650164f509283aed39747ad5d6cb2bbe54e1b42306e5db37dfd42dcbfcc689e0ddfe3bc9cb22ae7018e5a4a1ff39813584ac7bd6d6d65ca763f0a672da454081ea20e8b1d403316d80b9353ba396bea8962b1a7d2f775c76612d857c1f7594f"
|
|
46
|
+
})
|
|
47
|
+
});
|
|
48
|
+
var EPROTECT_TEST_PANS = /* @__PURE__ */ immutableSet([
|
|
49
|
+
"5112010000000003",
|
|
50
|
+
"44570100000000009",
|
|
51
|
+
"6011010000000003",
|
|
52
|
+
"51234567898010003",
|
|
53
|
+
"375001000000005",
|
|
54
|
+
"4457010200000007"
|
|
55
|
+
], "EPROTECT_TEST_PANS");
|
|
56
|
+
var EPROTECT_REFUSAL_CODES = /* @__PURE__ */ Object.freeze(["871", "872", "873", "874", "876", "881", "882", "883"]);
|
|
57
|
+
var QUERY_ORDER = [
|
|
58
|
+
"paypageId",
|
|
59
|
+
"reportGroup",
|
|
60
|
+
"id",
|
|
61
|
+
"orderId",
|
|
62
|
+
"encryptedAccount",
|
|
63
|
+
"pciNonSensitive",
|
|
64
|
+
"encryptedCvv",
|
|
65
|
+
"publicKeyId",
|
|
66
|
+
"firstEight",
|
|
67
|
+
"requestType",
|
|
68
|
+
"targetServer",
|
|
69
|
+
"jsoncallback"
|
|
70
|
+
];
|
|
71
|
+
var OPTIONAL = /* @__PURE__ */ new Set(["encryptedCvv", "firstEight", "requestType"]);
|
|
72
|
+
var URL_LIMIT = 4096;
|
|
73
|
+
var VALUE_LIMIT = 1024;
|
|
74
|
+
var CALLBACK = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
75
|
+
var PAYPAGE_ID = /^[A-Za-z0-9]{1,64}$/;
|
|
76
|
+
var exact = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
|
|
77
|
+
var controlFree = (value, min, max) => typeof value === "string" && value.length >= min && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
|
|
78
|
+
function canonicalComponent(value) {
|
|
79
|
+
return encodeURIComponent(value).replace(/'/g, "%27");
|
|
80
|
+
}
|
|
81
|
+
function decodeComponent(raw) {
|
|
82
|
+
try {
|
|
83
|
+
const value = decodeURIComponent(raw);
|
|
84
|
+
return canonicalComponent(value) === raw ? value : null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function eprotectEnvironment(hostname) {
|
|
91
|
+
const host = typeof hostname === "string" ? hostname : "";
|
|
92
|
+
if (host === EPROTECT_HOSTS.production)
|
|
93
|
+
return "production";
|
|
94
|
+
if (host === EPROTECT_HOSTS.sandbox)
|
|
95
|
+
return "sandbox";
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
function failoverEnvironment(hostname) {
|
|
99
|
+
if (hostname === EPROTECT_SECONDARY_HOST)
|
|
100
|
+
return "production";
|
|
101
|
+
if (hostname === EPROTECT_HOSTS.sandbox)
|
|
102
|
+
return "sandbox";
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
function eprotectPreparationUrl(environment) {
|
|
106
|
+
if (environment !== "production" && environment !== "sandbox")
|
|
107
|
+
throw new Error("unsupported_eprotect_environment");
|
|
108
|
+
return `https://${EPROTECT_HOSTS[environment]}${EPROTECT_PATH}`;
|
|
109
|
+
}
|
|
110
|
+
var B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
111
|
+
function bytesToBase64(bytes) {
|
|
112
|
+
let out = "";
|
|
113
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
114
|
+
const n = bytes[i] << 16 | (bytes[i + 1] ?? 0) << 8 | (bytes[i + 2] ?? 0);
|
|
115
|
+
out += B64[n >> 18 & 63] + B64[n >> 12 & 63] + (i + 1 < bytes.length ? B64[n >> 6 & 63] : "=") + (i + 2 < bytes.length ? B64[n & 63] : "=");
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
function base64ToBytes(text) {
|
|
120
|
+
if (typeof text !== "string" || text.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(text))
|
|
121
|
+
return null;
|
|
122
|
+
const pad = text.endsWith("==") ? 2 : text.endsWith("=") ? 1 : 0;
|
|
123
|
+
const bytes = [];
|
|
124
|
+
for (let i = 0; i < text.length; i += 4) {
|
|
125
|
+
const n = [0, 1, 2, 3].reduce((acc, k) => acc << 6 | Math.max(0, B64.indexOf(text[i + k])), 0);
|
|
126
|
+
bytes.push(n >> 16 & 255, n >> 8 & 255, n & 255);
|
|
127
|
+
}
|
|
128
|
+
const out = bytes.slice(0, bytes.length - pad);
|
|
129
|
+
return bytesToBase64(out) === text ? out : null;
|
|
130
|
+
}
|
|
131
|
+
function ciphertext(value) {
|
|
132
|
+
const bytes = base64ToBytes(value);
|
|
133
|
+
return !!bytes && bytes.length >= 248 && bytes.length <= 256;
|
|
134
|
+
}
|
|
135
|
+
var VALUE_RULES = {
|
|
136
|
+
paypageId: (value) => exact(PAYPAGE_ID, value),
|
|
137
|
+
reportGroup: (value) => controlFree(value, 1, VALUE_LIMIT),
|
|
138
|
+
id: (value) => controlFree(value, 1, VALUE_LIMIT),
|
|
139
|
+
orderId: (value) => controlFree(value, 0, VALUE_LIMIT),
|
|
140
|
+
encryptedAccount: ciphertext,
|
|
141
|
+
// true bypasses Worldpay's Mod10 check and hides the BIN: private-label cards only.
|
|
142
|
+
pciNonSensitive: (value) => value === "false",
|
|
143
|
+
encryptedCvv: ciphertext,
|
|
144
|
+
publicKeyId: (value) => exact(/^[0-9]{1,32}$/, value),
|
|
145
|
+
firstEight: (value) => value === "true",
|
|
146
|
+
requestType: (value) => value === "eProtect",
|
|
147
|
+
targetServer: (value) => value === "primary" || value === "secondary",
|
|
148
|
+
jsoncallback: (value) => exact(CALLBACK, value)
|
|
149
|
+
};
|
|
150
|
+
function parseRegistration(url, host) {
|
|
151
|
+
if (typeof url !== "string" || url.length > URL_LIMIT || url.includes("#"))
|
|
152
|
+
return null;
|
|
153
|
+
let parsed;
|
|
154
|
+
try {
|
|
155
|
+
parsed = new URL(url);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password)
|
|
161
|
+
return null;
|
|
162
|
+
const environment = host === "secondary" ? failoverEnvironment(parsed.hostname) : eprotectEnvironment(parsed.hostname);
|
|
163
|
+
if (!environment || parsed.pathname !== EPROTECT_PATH || !parsed.search.startsWith("?"))
|
|
164
|
+
return null;
|
|
165
|
+
const pairs = [];
|
|
166
|
+
const values = /* @__PURE__ */ Object.create(null);
|
|
167
|
+
let last = -1;
|
|
168
|
+
for (const chunk of parsed.search.slice(1).split("&")) {
|
|
169
|
+
const separator = chunk.indexOf("=");
|
|
170
|
+
if (separator < 1)
|
|
171
|
+
return null;
|
|
172
|
+
const name = chunk.slice(0, separator), raw = chunk.slice(separator + 1);
|
|
173
|
+
const position = QUERY_ORDER.indexOf(name);
|
|
174
|
+
if (position <= last)
|
|
175
|
+
return null;
|
|
176
|
+
last = position;
|
|
177
|
+
const value = decodeComponent(raw);
|
|
178
|
+
if (value === null || !VALUE_RULES[name](value))
|
|
179
|
+
return null;
|
|
180
|
+
pairs.push({ name, raw });
|
|
181
|
+
values[name] = value;
|
|
182
|
+
}
|
|
183
|
+
if (QUERY_ORDER.some((name) => !OPTIONAL.has(name) && !(name in values)))
|
|
184
|
+
return null;
|
|
185
|
+
if (values.publicKeyId !== EPROTECT_KEYS[environment].keyId)
|
|
186
|
+
return null;
|
|
187
|
+
if (values.targetServer !== (host === "secondary" ? "secondary" : "primary"))
|
|
188
|
+
return null;
|
|
189
|
+
return { environment, origin: parsed.origin, pairs, values };
|
|
190
|
+
}
|
|
191
|
+
function isEprotectTokenRequest(url, method) {
|
|
192
|
+
return method === "GET" && parseRegistration(url, "primary") !== null;
|
|
193
|
+
}
|
|
194
|
+
function isEprotectRequest(request) {
|
|
195
|
+
return !!request && typeof request === "object" && !Array.isArray(request) && request.method === "GET" && (request.body === void 0 || request.body === null || request.body === "") && isEprotectTokenRequest(request.url, "GET");
|
|
196
|
+
}
|
|
197
|
+
function eprotectRequestFacts(url) {
|
|
198
|
+
const parsed = parseRegistration(url, "primary");
|
|
199
|
+
if (!parsed)
|
|
200
|
+
return null;
|
|
201
|
+
const v = parsed.values;
|
|
202
|
+
return {
|
|
203
|
+
environment: parsed.environment,
|
|
204
|
+
paypageId: v.paypageId,
|
|
205
|
+
id: v.id,
|
|
206
|
+
orderId: v.orderId,
|
|
207
|
+
reportGroup: v.reportGroup,
|
|
208
|
+
callback: v.jsoncallback,
|
|
209
|
+
cvv: "encryptedCvv" in v
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function eprotectSecondaryAttempt(url) {
|
|
213
|
+
const parsed = parseRegistration(url, "secondary");
|
|
214
|
+
return parsed ? { paypageId: parsed.values.paypageId, id: parsed.values.id } : null;
|
|
215
|
+
}
|
|
216
|
+
var CIPHERTEXT_KEYS = /* @__PURE__ */ new Set(["encryptedAccount", "encryptedCvv"]);
|
|
217
|
+
function isEprotectDeviceRequest(templateUrl, deviceUrl) {
|
|
218
|
+
const template = parseRegistration(templateUrl, "primary");
|
|
219
|
+
const device = parseRegistration(deviceUrl, "primary");
|
|
220
|
+
if (!template || !device || device.origin !== template.origin || device.pairs.length !== template.pairs.length)
|
|
221
|
+
return false;
|
|
222
|
+
return device.pairs.every((pair, i) => pair.name === template.pairs[i].name && (CIPHERTEXT_KEYS.has(pair.name) ? pair.raw !== template.pairs[i].raw : pair.raw === template.pairs[i].raw));
|
|
223
|
+
}
|
|
224
|
+
function isPreparedEprotectRequest(url, method, body, environment, paypageId) {
|
|
225
|
+
if (environment !== "production" && environment !== "sandbox")
|
|
226
|
+
return false;
|
|
227
|
+
if (method !== "GET" || body !== void 0 && body !== null && body !== "")
|
|
228
|
+
return false;
|
|
229
|
+
const facts = eprotectRequestFacts(url);
|
|
230
|
+
return !!facts && facts.environment === environment && facts.paypageId === paypageId;
|
|
231
|
+
}
|
|
232
|
+
var EPROTECT_MERCHANT_PINS = /* @__PURE__ */ deepFreeze([]);
|
|
233
|
+
function eprotectMerchantPin(paypageId, merchantOrigin, pins = EPROTECT_MERCHANT_PINS) {
|
|
234
|
+
if (!exact(PAYPAGE_ID, paypageId) || typeof merchantOrigin !== "string" || !Array.isArray(pins))
|
|
235
|
+
return null;
|
|
236
|
+
return pins.find((pin) => !!pin && Array.isArray(pin.paypageIds) && Array.isArray(pin.origins) && pin.paypageIds.includes(paypageId) && pin.origins.includes(merchantOrigin)) ?? null;
|
|
237
|
+
}
|
|
238
|
+
function eprotectMerchantRefusal(environment, paypageId, merchantOrigin, pins = EPROTECT_MERCHANT_PINS) {
|
|
239
|
+
if (!exact(PAYPAGE_ID, paypageId))
|
|
240
|
+
return "invalid_paypage_id";
|
|
241
|
+
if (environment === "sandbox")
|
|
242
|
+
return null;
|
|
243
|
+
if (environment !== "production")
|
|
244
|
+
return "unsupported_environment";
|
|
245
|
+
return eprotectMerchantPin(paypageId, merchantOrigin, pins) ? null : "eprotect_merchant_unreviewed";
|
|
246
|
+
}
|
|
247
|
+
function modPow(base, exponent, modulus) {
|
|
248
|
+
let result = 1n, b = base % modulus, e = exponent;
|
|
249
|
+
while (e > 0n) {
|
|
250
|
+
if (e & 1n)
|
|
251
|
+
result = result * b % modulus;
|
|
252
|
+
b = b * b % modulus;
|
|
253
|
+
e >>= 1n;
|
|
254
|
+
}
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
function randomNonZero(count, random) {
|
|
258
|
+
const out = new Uint8Array(count);
|
|
259
|
+
let filled = 0;
|
|
260
|
+
while (filled < count) {
|
|
261
|
+
const batch = new Uint8Array(count - filled + 16);
|
|
262
|
+
random(batch);
|
|
263
|
+
for (const byte of batch)
|
|
264
|
+
if (byte !== 0 && filled < count)
|
|
265
|
+
out[filled++] = byte;
|
|
266
|
+
}
|
|
267
|
+
return out;
|
|
268
|
+
}
|
|
269
|
+
function defaultRandom(bytes) {
|
|
270
|
+
const source = globalThis.crypto;
|
|
271
|
+
if (!source || typeof source.getRandomValues !== "function")
|
|
272
|
+
throw new Error("Refusing to pay: no secure random source for eProtect.");
|
|
273
|
+
source.getRandomValues(bytes);
|
|
274
|
+
}
|
|
275
|
+
function eprotectEncrypt(text, key, random = defaultRandom) {
|
|
276
|
+
if (typeof text !== "string" || !/^[0-9]{1,19}$/.test(text))
|
|
277
|
+
throw new Error("Refusing to pay: eProtect encrypts digits only.");
|
|
278
|
+
if (!key || !/^[0-9a-f]{256,1024}$/.test(key.modulus) || !/^[0-9a-f]{1,8}$/.test(key.exponent)) {
|
|
279
|
+
throw new Error("Refusing to pay: malformed eProtect key.");
|
|
280
|
+
}
|
|
281
|
+
const n = BigInt(`0x${key.modulus}`), e = BigInt(`0x${key.exponent}`);
|
|
282
|
+
const k = Math.ceil(n.toString(16).length / 2);
|
|
283
|
+
const message = Array.from(text, (ch) => ch.charCodeAt(0));
|
|
284
|
+
const padding = randomNonZero(k - 3 - message.length, random);
|
|
285
|
+
const em = [0, 2, ...padding, 0, ...message];
|
|
286
|
+
const m = BigInt(`0x${em.map((byte) => byte.toString(16).padStart(2, "0")).join("")}`);
|
|
287
|
+
let hex = modPow(m, e, n).toString(16);
|
|
288
|
+
if (hex.length % 2)
|
|
289
|
+
hex = `0${hex}`;
|
|
290
|
+
const bytes = [];
|
|
291
|
+
for (let i = 0; i < hex.length; i += 2)
|
|
292
|
+
bytes.push(parseInt(hex.slice(i, i + 2), 16));
|
|
293
|
+
return bytesToBase64(bytes);
|
|
294
|
+
}
|
|
295
|
+
function luhn(number) {
|
|
296
|
+
let sum = 0;
|
|
297
|
+
for (let i = 0; i < number.length; i++) {
|
|
298
|
+
let digit = number.charCodeAt(number.length - 1 - i) - 48;
|
|
299
|
+
if (i % 2 === 1) {
|
|
300
|
+
digit *= 2;
|
|
301
|
+
if (digit > 9)
|
|
302
|
+
digit -= 9;
|
|
303
|
+
}
|
|
304
|
+
sum += digit;
|
|
305
|
+
}
|
|
306
|
+
return sum % 10 === 0;
|
|
307
|
+
}
|
|
308
|
+
function eprotectCardRefusal(environment, cardNumber) {
|
|
309
|
+
const pan = String(cardNumber ?? "");
|
|
310
|
+
if (environment === "sandbox")
|
|
311
|
+
return EPROTECT_TEST_PANS.has(pan) ? null : "sandbox_host_requires_documented_test_card";
|
|
312
|
+
if (environment !== "production")
|
|
313
|
+
return "unsupported_environment";
|
|
314
|
+
if (!/^[0-9]{13,19}$/.test(pan) || /^([0-9])\1+$/.test(pan) || !luhn(pan))
|
|
315
|
+
return "invalid_card_number";
|
|
316
|
+
return EPROTECT_TEST_PANS.has(pan) || DOCUMENTED_TEST_PANS.has(pan) ? "live_host_refuses_documented_test_card" : null;
|
|
317
|
+
}
|
|
318
|
+
function eprotectDeviceRequest(templateUrl, card, random = defaultRandom) {
|
|
319
|
+
const parsed = parseRegistration(templateUrl, "primary");
|
|
320
|
+
if (!parsed)
|
|
321
|
+
throw new Error("Refusing to pay: unsupported eProtect card request.");
|
|
322
|
+
const refusal = eprotectCardRefusal(parsed.environment, card && card.number);
|
|
323
|
+
if (refusal === "sandbox_host_requires_documented_test_card") {
|
|
324
|
+
throw new Error("Refusing to pay: a sandbox or test host accepts only the processor's documented test cards, not a real card.");
|
|
325
|
+
}
|
|
326
|
+
if (refusal)
|
|
327
|
+
throw new Error("Could not fill the card fields for Worldpay eProtect. Nothing was sent.");
|
|
328
|
+
const withCvv = "encryptedCvv" in parsed.values;
|
|
329
|
+
if (withCvv && (typeof card.cvc !== "string" || !/^[0-9]{3,4}$/.test(card.cvc))) {
|
|
330
|
+
throw new Error("Could not fill the card fields for Worldpay eProtect. Nothing was sent.");
|
|
331
|
+
}
|
|
332
|
+
const key = EPROTECT_KEYS[parsed.environment];
|
|
333
|
+
const fresh = { encryptedAccount: eprotectEncrypt(String(card.number), key, random) };
|
|
334
|
+
if (withCvv)
|
|
335
|
+
fresh.encryptedCvv = eprotectEncrypt(card.cvc, key, random);
|
|
336
|
+
const query = parsed.pairs.map(({ name, raw }) => `${name}=${name in fresh ? canonicalComponent(fresh[name]) : raw}`).join("&");
|
|
337
|
+
const url = `${parsed.origin}${EPROTECT_PATH}?${query}`;
|
|
338
|
+
if (!isEprotectDeviceRequest(templateUrl, url))
|
|
339
|
+
throw new Error("Refusing to pay: unsupported eProtect card request.");
|
|
340
|
+
return { url, method: "GET", headers: {}, body: "", where: Object.keys(fresh) };
|
|
341
|
+
}
|
|
342
|
+
var RESPONSE_LIMIT = 8192;
|
|
343
|
+
var JSON_STRING = '"(?:[^"\\\\\\u0000-\\u001f]|\\\\(?:["\\\\/bfnrt]|u[0-9a-fA-F]{4}))*"';
|
|
344
|
+
function readFlatObject(text) {
|
|
345
|
+
if (typeof text !== "string" || text.length > RESPONSE_LIMIT)
|
|
346
|
+
return null;
|
|
347
|
+
const open = /^\s*\{\s*/.exec(text);
|
|
348
|
+
if (!open)
|
|
349
|
+
return null;
|
|
350
|
+
const scalar = `${JSON_STRING}|-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?|true|false|null`;
|
|
351
|
+
const members = new RegExp(`\\s*(${JSON_STRING})\\s*:\\s*(${scalar})\\s*([,}])`, "y");
|
|
352
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
353
|
+
let at = open[0].length;
|
|
354
|
+
if (text[at] === "}")
|
|
355
|
+
return /^\s*$/.test(text.slice(at + 1)) ? out : null;
|
|
356
|
+
while (true) {
|
|
357
|
+
members.lastIndex = at;
|
|
358
|
+
const member = members.exec(text);
|
|
359
|
+
if (!member)
|
|
360
|
+
return null;
|
|
361
|
+
const key = JSON.parse(member[1]);
|
|
362
|
+
if (Object.prototype.hasOwnProperty.call(out, key) || ["__proto__", "prototype", "constructor"].includes(key))
|
|
363
|
+
return null;
|
|
364
|
+
out[key] = JSON.parse(member[2]);
|
|
365
|
+
at = members.lastIndex;
|
|
366
|
+
if (member[3] === "}")
|
|
367
|
+
return /^\s*$/.test(text.slice(at)) ? out : null;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function readJsonp(text, callback) {
|
|
371
|
+
if (typeof text !== "string" || !exact(CALLBACK, callback) || !text.startsWith(`${callback}(`))
|
|
372
|
+
return null;
|
|
373
|
+
const close = /\);?\s*$/.exec(text);
|
|
374
|
+
if (!close)
|
|
375
|
+
return null;
|
|
376
|
+
return readFlatObject(text.slice(callback.length + 1, close.index));
|
|
377
|
+
}
|
|
378
|
+
var KEEP = [
|
|
379
|
+
"paypageRegistrationId",
|
|
380
|
+
"bin",
|
|
381
|
+
"type",
|
|
382
|
+
"targetServer",
|
|
383
|
+
"vantivTxnId",
|
|
384
|
+
"orderId",
|
|
385
|
+
"response",
|
|
386
|
+
"responseTime",
|
|
387
|
+
"message",
|
|
388
|
+
"reportGroup",
|
|
389
|
+
"id"
|
|
390
|
+
];
|
|
391
|
+
var FIELD_RULES = {
|
|
392
|
+
paypageRegistrationId: (value) => exact(/^[A-Za-z0-9+/=]{8,512}$/, value),
|
|
393
|
+
bin: (value) => exact(/^[0-9]{6}$/, value),
|
|
394
|
+
type: (value) => exact(/^[A-Z]{2}$/, value),
|
|
395
|
+
targetServer: (value) => value === "primary",
|
|
396
|
+
vantivTxnId: (value) => exact(/^[A-Za-z0-9]{1,64}$/, value),
|
|
397
|
+
responseTime: (value) => exact(/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/, value),
|
|
398
|
+
message: (value) => value === "Success"
|
|
399
|
+
};
|
|
400
|
+
var REFUSAL_FIELDS = /* @__PURE__ */ new Set(["response", "message", "responseTime", "id", "orderId", "reportGroup", "vantivTxnId", "targetServer"]);
|
|
401
|
+
function sameAsTemplate(answer, facts) {
|
|
402
|
+
if (answer.id !== facts.id)
|
|
403
|
+
return false;
|
|
404
|
+
for (const key of ["orderId", "reportGroup"]) {
|
|
405
|
+
if (key in answer && answer[key] !== facts[key])
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
return !("targetServer" in answer) || answer.targetServer === "primary";
|
|
409
|
+
}
|
|
410
|
+
function eprotectOutcome(status, bodyText, templateUrl, card) {
|
|
411
|
+
const facts = eprotectRequestFacts(templateUrl);
|
|
412
|
+
if (!facts)
|
|
413
|
+
return { outcome: "unknown", reason: "eprotect_template_invalid" };
|
|
414
|
+
if (status !== 200)
|
|
415
|
+
return { outcome: "unknown", reason: "eprotect_status" };
|
|
416
|
+
const answer = readJsonp(bodyText, facts.callback);
|
|
417
|
+
if (!answer)
|
|
418
|
+
return { outcome: "unknown", reason: "eprotect_unreadable" };
|
|
419
|
+
if (Object.values(answer).some((value) => typeof value !== "string"))
|
|
420
|
+
return { outcome: "unknown", reason: "eprotect_shape" };
|
|
421
|
+
if (!sameAsTemplate(answer, facts))
|
|
422
|
+
return { outcome: "unknown", reason: "eprotect_mismatch" };
|
|
423
|
+
if (EPROTECT_REFUSAL_CODES.includes(answer.response)) {
|
|
424
|
+
return Object.keys(answer).every((key) => REFUSAL_FIELDS.has(key)) ? { outcome: "refused", code: answer.response } : { outcome: "unknown", reason: "eprotect_unconfirmed" };
|
|
425
|
+
}
|
|
426
|
+
if (answer.response !== "870" || !("paypageRegistrationId" in answer))
|
|
427
|
+
return { outcome: "unknown", reason: "eprotect_unconfirmed" };
|
|
428
|
+
for (const [key, rule] of Object.entries(FIELD_RULES)) {
|
|
429
|
+
if (key in answer && !rule(answer[key]))
|
|
430
|
+
return { outcome: "unknown", reason: "eprotect_shape" };
|
|
431
|
+
}
|
|
432
|
+
for (const [key, width] of [["firstSix", 6], ["lastFour", 4], ["firstEight", 8]]) {
|
|
433
|
+
if (key in answer && !exact(new RegExp(`^[0-9]{${width}}$`), answer[key]))
|
|
434
|
+
return { outcome: "unknown", reason: "eprotect_shape" };
|
|
435
|
+
}
|
|
436
|
+
if (card) {
|
|
437
|
+
const pan = String(card.number ?? "");
|
|
438
|
+
const mine = { firstSix: pan.slice(0, 6), lastFour: pan.slice(-4), firstEight: pan.slice(0, 8) };
|
|
439
|
+
if ("bin" in answer && answer.bin !== "000000" && answer.bin !== mine.firstSix || ["firstSix", "lastFour", "firstEight"].some((key) => key in answer && answer[key] !== mine[key])) {
|
|
440
|
+
return { outcome: "unknown", reason: "eprotect_card_mismatch" };
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const kept = {};
|
|
444
|
+
for (const key of KEEP)
|
|
445
|
+
if (key in answer)
|
|
446
|
+
kept[key] = answer[key];
|
|
447
|
+
return { outcome: "registered", sanitizedJson: JSON.stringify(kept) };
|
|
448
|
+
}
|
|
449
|
+
function sanitizeEprotectRegistration(bodyText, templateUrl) {
|
|
450
|
+
const verdict = eprotectOutcome(200, bodyText, templateUrl, void 0);
|
|
451
|
+
if (verdict.outcome !== "registered")
|
|
452
|
+
throw new Error("Invalid eProtect registration response.");
|
|
453
|
+
return verdict.sanitizedJson;
|
|
454
|
+
}
|
|
455
|
+
function eprotectJsonp(callback, json) {
|
|
456
|
+
if (!exact(CALLBACK, callback) || !readFlatObject(json))
|
|
457
|
+
throw new Error("Refusing to answer: malformed eProtect callback.");
|
|
458
|
+
return `${callback}(${json})`;
|
|
459
|
+
}
|
|
460
|
+
function eprotectGiveUp(url) {
|
|
461
|
+
if (typeof url !== "string" || url.length > URL_LIMIT)
|
|
462
|
+
return null;
|
|
463
|
+
let parsed;
|
|
464
|
+
try {
|
|
465
|
+
parsed = new URL(url);
|
|
466
|
+
}
|
|
467
|
+
catch {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
const hosts = [EPROTECT_HOSTS.production, EPROTECT_HOSTS.sandbox, EPROTECT_SECONDARY_HOST];
|
|
471
|
+
if (parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || !hosts.includes(parsed.hostname) || parsed.pathname !== "/eProtect/ppstats")
|
|
472
|
+
return null;
|
|
473
|
+
const seen = /* @__PURE__ */ Object.create(null);
|
|
474
|
+
for (const chunk of parsed.search.slice(1).split("&")) {
|
|
475
|
+
const separator = chunk.indexOf("=");
|
|
476
|
+
if (separator < 1)
|
|
477
|
+
return null;
|
|
478
|
+
const name = chunk.slice(0, separator);
|
|
479
|
+
if (name in seen)
|
|
480
|
+
return null;
|
|
481
|
+
const value = decodeComponent(chunk.slice(separator + 1));
|
|
482
|
+
if (value === null)
|
|
483
|
+
return null;
|
|
484
|
+
seen[name] = value;
|
|
485
|
+
}
|
|
486
|
+
const code = seen.responseCode;
|
|
487
|
+
if (code !== "900" && code !== "901" || !exact(/^[A-Za-z0-9]{1,64}$/, seen.paypageId) || !controlFree(seen.txnId, 1, VALUE_LIMIT))
|
|
488
|
+
return null;
|
|
489
|
+
return { paypageId: seen.paypageId, txnId: seen.txnId, code };
|
|
490
|
+
}
|
|
491
|
+
function eprotectRefusalCode(bodyText) {
|
|
492
|
+
const callback = typeof bodyText === "string" ? /^[A-Za-z_][A-Za-z0-9_]{0,127}(?=\()/.exec(bodyText)?.[0] : void 0;
|
|
493
|
+
const answer = callback ? readJsonp(bodyText, callback) : null;
|
|
494
|
+
if (!answer || !EPROTECT_REFUSAL_CODES.includes(answer.response))
|
|
495
|
+
return null;
|
|
496
|
+
return Object.entries(answer).every(([key, value]) => REFUSAL_FIELDS.has(key) && typeof value === "string") ? answer.response : null;
|
|
497
|
+
}
|
|
498
|
+
export { EPROTECT_HOSTS, EPROTECT_KEYS, EPROTECT_MERCHANT_PINS, EPROTECT_PATH, EPROTECT_REFUSAL_CODES, EPROTECT_SECONDARY_HOST, EPROTECT_TEST_PANS, eprotectCardRefusal, eprotectDeviceRequest, eprotectEncrypt, eprotectEnvironment, eprotectGiveUp, eprotectJsonp, eprotectMerchantPin, eprotectMerchantRefusal, eprotectOutcome, eprotectPreparationUrl, eprotectRefusalCode, eprotectRequestFacts, eprotectSecondaryAttempt, isEprotectDeviceRequest, isEprotectRequest, isEprotectTokenRequest, isPreparedEprotectRequest, sanitizeEprotectRegistration };
|