@p2pdotme/sdk 1.2.16 → 1.2.18
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/README.md +1 -1
- package/dist/country.cjs +480 -62
- package/dist/country.cjs.map +1 -1
- package/dist/country.d.cts +144 -27
- package/dist/country.d.ts +144 -27
- package/dist/country.mjs +460 -62
- package/dist/country.mjs.map +1 -1
- package/dist/fraud-engine.cjs +1 -0
- package/dist/fraud-engine.cjs.map +1 -1
- package/dist/fraud-engine.mjs +1 -0
- package/dist/fraud-engine.mjs.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/orders.cjs +1 -0
- package/dist/orders.cjs.map +1 -1
- package/dist/orders.d.cts +2 -0
- package/dist/orders.d.ts +2 -0
- package/dist/orders.mjs +1 -0
- package/dist/orders.mjs.map +1 -1
- package/dist/prices.cjs +1 -0
- package/dist/prices.cjs.map +1 -1
- package/dist/prices.d.cts +1 -0
- package/dist/prices.d.ts +1 -0
- package/dist/prices.mjs +1 -0
- package/dist/prices.mjs.map +1 -1
- package/dist/profile.cjs +1 -0
- package/dist/profile.cjs.map +1 -1
- package/dist/profile.d.cts +2 -0
- package/dist/profile.d.ts +2 -0
- package/dist/profile.mjs +1 -0
- package/dist/profile.mjs.map +1 -1
- package/dist/qr-parsers.cjs +205 -11
- package/dist/qr-parsers.cjs.map +1 -1
- package/dist/qr-parsers.d.cts +9 -1
- package/dist/qr-parsers.d.ts +9 -1
- package/dist/qr-parsers.mjs +204 -11
- package/dist/qr-parsers.mjs.map +1 -1
- package/dist/react.cjs +1 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +6 -0
- package/dist/react.d.ts +6 -0
- package/dist/react.mjs +1 -0
- package/dist/react.mjs.map +1 -1
- package/dist/stake.cjs +1 -0
- package/dist/stake.cjs.map +1 -1
- package/dist/stake.d.cts +1 -0
- package/dist/stake.d.ts +1 -0
- package/dist/stake.mjs +1 -0
- package/dist/stake.mjs.map +1 -1
- package/dist/zkkyc.cjs +1 -0
- package/dist/zkkyc.cjs.map +1 -1
- package/dist/zkkyc.mjs +1 -0
- package/dist/zkkyc.mjs.map +1 -1
- package/package.json +1 -1
package/dist/qr-parsers.mjs
CHANGED
|
@@ -20,6 +20,7 @@ var CURRENCY = {
|
|
|
20
20
|
ARS: "ARS",
|
|
21
21
|
MEX: "MEX",
|
|
22
22
|
VEN: "VEN",
|
|
23
|
+
BOB: "BOB",
|
|
23
24
|
EUR: "EUR",
|
|
24
25
|
NGN: "NGN",
|
|
25
26
|
USD: "USD",
|
|
@@ -53,6 +54,98 @@ var ARS_COUNTRY_OPTION = {
|
|
|
53
54
|
disabledPaymentTypes: []
|
|
54
55
|
};
|
|
55
56
|
|
|
57
|
+
// src/country/types.ts
|
|
58
|
+
var PACKED_PAYMENT_ID_SEP = "||";
|
|
59
|
+
|
|
60
|
+
// src/country/qr-validator.ts
|
|
61
|
+
function crc16ccitt(s) {
|
|
62
|
+
let crc = 65535;
|
|
63
|
+
for (let i = 0; i < s.length; i++) {
|
|
64
|
+
crc ^= s.charCodeAt(i) << 8;
|
|
65
|
+
for (let j = 0; j < 8; j++) {
|
|
66
|
+
crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
|
|
67
|
+
crc &= 65535;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return crc.toString(16).toUpperCase().padStart(4, "0");
|
|
71
|
+
}
|
|
72
|
+
function validateEmvcoQr(payload, country, currency) {
|
|
73
|
+
if (!payload || payload.trim().length === 0) return false;
|
|
74
|
+
const data = payload.trim();
|
|
75
|
+
const tags = {};
|
|
76
|
+
let pos = 0;
|
|
77
|
+
while (pos + 4 <= data.length) {
|
|
78
|
+
const tag = data.substring(pos, pos + 2);
|
|
79
|
+
const lengthStr = data.substring(pos + 2, pos + 4);
|
|
80
|
+
if (!/^[0-9]{2}$/.test(tag) || !/^[0-9]{2}$/.test(lengthStr)) break;
|
|
81
|
+
const length = Number.parseInt(lengthStr, 10);
|
|
82
|
+
if (pos + 4 + length > data.length) break;
|
|
83
|
+
tags[tag] = data.substring(pos + 4, pos + 4 + length);
|
|
84
|
+
pos += 4 + length;
|
|
85
|
+
}
|
|
86
|
+
if (tags["58"] !== country) return false;
|
|
87
|
+
if (tags["53"] !== currency) return false;
|
|
88
|
+
const crcTag = tags["63"];
|
|
89
|
+
if (!crcTag) return false;
|
|
90
|
+
const marker = data.lastIndexOf("6304");
|
|
91
|
+
if (marker === -1) return false;
|
|
92
|
+
const expected = crc16ccitt(data.substring(0, marker + 4));
|
|
93
|
+
return expected.toUpperCase() === crcTag.toUpperCase();
|
|
94
|
+
}
|
|
95
|
+
function validatePeruvianQr(payload) {
|
|
96
|
+
return validateEmvcoQr(payload, "PE", "604");
|
|
97
|
+
}
|
|
98
|
+
function isBolivianEncryptedQr(payload) {
|
|
99
|
+
const trimmed = payload.trim();
|
|
100
|
+
if (trimmed.includes(PACKED_PAYMENT_ID_SEP)) return false;
|
|
101
|
+
const sep = trimmed.lastIndexOf("|");
|
|
102
|
+
if (sep < 40) return false;
|
|
103
|
+
const blob = trimmed.slice(0, sep);
|
|
104
|
+
const tag = trimmed.slice(sep + 1);
|
|
105
|
+
if (blob.length % 4 !== 0) return false;
|
|
106
|
+
if (!/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) return false;
|
|
107
|
+
return /^(?:[0-9A-Fa-f]{24}|[0-9A-Fa-f]{32})$/.test(tag);
|
|
108
|
+
}
|
|
109
|
+
function validateBolivianQr(payload) {
|
|
110
|
+
if (!payload || payload.trim().length === 0) return false;
|
|
111
|
+
return isBolivianEncryptedQr(payload) || validateEmvcoQr(payload, "BO", "068");
|
|
112
|
+
}
|
|
113
|
+
function validateVenezuelanQr(payload) {
|
|
114
|
+
if (!payload || typeof payload !== "string") return false;
|
|
115
|
+
const trimmed = payload.trim();
|
|
116
|
+
if (trimmed.includes(PACKED_PAYMENT_ID_SEP)) return false;
|
|
117
|
+
const qIdx = trimmed.indexOf("?");
|
|
118
|
+
if (qIdx < 40) return false;
|
|
119
|
+
const blob = trimmed.substring(0, qIdx);
|
|
120
|
+
if (!/^[A-Za-z0-9+/=]+$/.test(blob)) return false;
|
|
121
|
+
return /(?:^|[?&])merchantId=\d{3,4}(?:&|$)/.test(trimmed.substring(qIdx));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/country/currencies/bob.ts
|
|
125
|
+
var BOB_COUNTRY_OPTION = {
|
|
126
|
+
country: "Bolivia",
|
|
127
|
+
currency: CURRENCY.BOB,
|
|
128
|
+
internationalFormat: "BOB",
|
|
129
|
+
symbolNative: "Bs.",
|
|
130
|
+
locale: "es-BO",
|
|
131
|
+
paymentMethod: "QR_SIMPLE",
|
|
132
|
+
paymentAddressName: "QR_SIMPLE_DETAILS",
|
|
133
|
+
timezone: "America/La_Paz",
|
|
134
|
+
timezone_name: "BOT",
|
|
135
|
+
flag: "\u{1F1E7}\u{1F1F4}",
|
|
136
|
+
flagUrl: "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1e7-1f1f4.png",
|
|
137
|
+
phoneCode: "+591",
|
|
138
|
+
telegramSupportChannel: "https://t.me/p2pmebolivia",
|
|
139
|
+
twitterUsername: "p2pmebolivia",
|
|
140
|
+
smsCountryCodes: ["BO"],
|
|
141
|
+
precision: 2,
|
|
142
|
+
isAlpha: true,
|
|
143
|
+
disabled: false,
|
|
144
|
+
disabledPaymentTypes: [],
|
|
145
|
+
uploadPaymentQR: true,
|
|
146
|
+
validateQr: validateBolivianQr
|
|
147
|
+
};
|
|
148
|
+
|
|
56
149
|
// src/country/currencies/brl.ts
|
|
57
150
|
var BRL_COUNTRY_OPTION = {
|
|
58
151
|
country: "Brazil",
|
|
@@ -254,6 +347,55 @@ var NGN_COUNTRY_OPTION = {
|
|
|
254
347
|
};
|
|
255
348
|
|
|
256
349
|
// src/country/currencies/pen.ts
|
|
350
|
+
function validatePeruvianPhone(value) {
|
|
351
|
+
if (!value || value.trim().length === 0) return false;
|
|
352
|
+
const phone = value.trim().replace(/\s+/g, "").replace(/^\+?51/, "");
|
|
353
|
+
return /^9\d{8}$/.test(phone);
|
|
354
|
+
}
|
|
355
|
+
function normalizePeruvianPaymentKey(value) {
|
|
356
|
+
const trimmed = value.trim();
|
|
357
|
+
const cci = trimmed.replace(/\s+/g, "");
|
|
358
|
+
if (/^\d{20}$/.test(cci)) return cci;
|
|
359
|
+
const phone = trimmed.replace(/\s+/g, "").replace(/^\+?51/, "");
|
|
360
|
+
if (/^9\d{8}$/.test(phone)) return phone;
|
|
361
|
+
return cci;
|
|
362
|
+
}
|
|
363
|
+
function looksLikeTlv(value) {
|
|
364
|
+
if (value.length < 5 || !/^\d{4}/.test(value)) return false;
|
|
365
|
+
const len = Number.parseInt(value.slice(2, 4), 10);
|
|
366
|
+
return !Number.isNaN(len) && len >= 0 && 4 + len <= value.length;
|
|
367
|
+
}
|
|
368
|
+
function phoneFromTlvValue(value) {
|
|
369
|
+
const trimmed = value.trim();
|
|
370
|
+
if (!trimmed) return null;
|
|
371
|
+
if (validatePeruvianPhone(trimmed)) return normalizePeruvianPaymentKey(trimmed);
|
|
372
|
+
if (/^[0-9a-f]+$/i.test(trimmed) && /[a-f]/i.test(trimmed)) return null;
|
|
373
|
+
const match = trimmed.match(/(^|[^0-9])(\+?51)?(9\d{8})(?![0-9])/);
|
|
374
|
+
if (!match) return null;
|
|
375
|
+
const candidate = `${match[2] ?? ""}${match[3]}`;
|
|
376
|
+
return validatePeruvianPhone(candidate) ? normalizePeruvianPaymentKey(candidate) : null;
|
|
377
|
+
}
|
|
378
|
+
function extractPeruvianPhoneFromQr(payload) {
|
|
379
|
+
let pos = 0;
|
|
380
|
+
while (pos + 4 <= payload.length) {
|
|
381
|
+
const tag = payload.slice(pos, pos + 2);
|
|
382
|
+
const len = Number.parseInt(payload.slice(pos + 2, pos + 4), 10);
|
|
383
|
+
if (Number.isNaN(len) || len < 0 || pos + 4 + len > payload.length) break;
|
|
384
|
+
const value = payload.slice(pos + 4, pos + 4 + len);
|
|
385
|
+
const direct = phoneFromTlvValue(value);
|
|
386
|
+
if (direct) return direct;
|
|
387
|
+
if (tag >= "02" && tag <= "51" || tag === "62" || tag === "64" || looksLikeTlv(value)) {
|
|
388
|
+
const nested = extractPeruvianPhoneFromQr(value);
|
|
389
|
+
if (nested) return nested;
|
|
390
|
+
}
|
|
391
|
+
pos += 4 + len;
|
|
392
|
+
}
|
|
393
|
+
const glued = payload.match(/\+51\s*9\d{8}/);
|
|
394
|
+
if (glued && validatePeruvianPhone(glued[0])) {
|
|
395
|
+
return normalizePeruvianPaymentKey(glued[0]);
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
257
399
|
var PEN_COUNTRY_OPTION = {
|
|
258
400
|
country: "Peru",
|
|
259
401
|
currency: CURRENCY.PEN,
|
|
@@ -272,7 +414,13 @@ var PEN_COUNTRY_OPTION = {
|
|
|
272
414
|
precision: 2,
|
|
273
415
|
isAlpha: true,
|
|
274
416
|
disabled: false,
|
|
275
|
-
disabledPaymentTypes: []
|
|
417
|
+
disabledPaymentTypes: [],
|
|
418
|
+
uploadPaymentQR: true,
|
|
419
|
+
validateQr: validatePeruvianQr,
|
|
420
|
+
hydrateFieldsFromQr: (qr) => {
|
|
421
|
+
const phone = extractPeruvianPhoneFromQr(qr);
|
|
422
|
+
return phone ? { phone } : {};
|
|
423
|
+
}
|
|
276
424
|
};
|
|
277
425
|
|
|
278
426
|
// src/country/currencies/php.ts
|
|
@@ -339,7 +487,9 @@ var VEN_COUNTRY_OPTION = {
|
|
|
339
487
|
precision: 2,
|
|
340
488
|
isAlpha: false,
|
|
341
489
|
disabled: false,
|
|
342
|
-
disabledPaymentTypes: []
|
|
490
|
+
disabledPaymentTypes: [],
|
|
491
|
+
uploadPaymentQR: true,
|
|
492
|
+
validateQr: validateVenezuelanQr
|
|
343
493
|
};
|
|
344
494
|
|
|
345
495
|
// src/country/countries.ts
|
|
@@ -350,6 +500,7 @@ var COUNTRY_OPTIONS = [
|
|
|
350
500
|
ARS_COUNTRY_OPTION,
|
|
351
501
|
MEX_COUNTRY_OPTION,
|
|
352
502
|
VEN_COUNTRY_OPTION,
|
|
503
|
+
BOB_COUNTRY_OPTION,
|
|
353
504
|
NGN_COUNTRY_OPTION,
|
|
354
505
|
COP_COUNTRY_OPTION,
|
|
355
506
|
CUP_COUNTRY_OPTION,
|
|
@@ -465,9 +616,6 @@ function parseMercadoPago(qrData, _sellPrice) {
|
|
|
465
616
|
return success({ paymentAddress: merchantName });
|
|
466
617
|
}
|
|
467
618
|
|
|
468
|
-
// src/qr-parsers/parsers/brl.ts
|
|
469
|
-
import { err as err2, ok as ok2 } from "neverthrow";
|
|
470
|
-
|
|
471
619
|
// src/qr-parsers/utils/amount.ts
|
|
472
620
|
var DECIMAL_AMOUNT = /^\d+(\.\d+)?$/;
|
|
473
621
|
function parseAmount(amountStr, sellPrice) {
|
|
@@ -480,7 +628,44 @@ function parseAmount(amountStr, sellPrice) {
|
|
|
480
628
|
return { usdc: fiat / sellPrice, fiat };
|
|
481
629
|
}
|
|
482
630
|
|
|
631
|
+
// src/qr-parsers/parsers/bob.ts
|
|
632
|
+
var BOB_TAGS = { AMOUNT: "54", CURRENCY: "53", COUNTRY: "58" };
|
|
633
|
+
function isBolivianEncryptedQr2(payload) {
|
|
634
|
+
if (payload.includes("||")) return false;
|
|
635
|
+
const sep = payload.lastIndexOf("|");
|
|
636
|
+
if (sep < 40) return false;
|
|
637
|
+
const blob = payload.slice(0, sep);
|
|
638
|
+
const tag = payload.slice(sep + 1);
|
|
639
|
+
if (blob.length % 4 !== 0) return false;
|
|
640
|
+
if (!/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) return false;
|
|
641
|
+
return /^(?:[0-9A-Fa-f]{24}|[0-9A-Fa-f]{32})$/.test(tag);
|
|
642
|
+
}
|
|
643
|
+
function parseBolivia(qrData, sellPrice) {
|
|
644
|
+
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
645
|
+
return failure("INVALID_QR", "QR data is empty or invalid");
|
|
646
|
+
}
|
|
647
|
+
const trimmed = qrData.trim();
|
|
648
|
+
if (isBolivianEncryptedQr2(trimmed)) {
|
|
649
|
+
return success({ paymentAddress: trimmed });
|
|
650
|
+
}
|
|
651
|
+
const tags = extractTags(trimmed, [BOB_TAGS.AMOUNT, BOB_TAGS.CURRENCY, BOB_TAGS.COUNTRY]);
|
|
652
|
+
if (tags[BOB_TAGS.COUNTRY] !== "BO" || tags[BOB_TAGS.CURRENCY] !== "068") {
|
|
653
|
+
return failure("INVALID_QR", "Not a valid Bolivia QR Simple QR");
|
|
654
|
+
}
|
|
655
|
+
const result = { paymentAddress: trimmed };
|
|
656
|
+
const amountStr = tags[BOB_TAGS.AMOUNT];
|
|
657
|
+
if (amountStr) {
|
|
658
|
+
const amount = parseAmount(amountStr, sellPrice);
|
|
659
|
+
if (!amount) {
|
|
660
|
+
return failure("INVALID_AMOUNT", "Invalid amount in QR");
|
|
661
|
+
}
|
|
662
|
+
result.amount = amount;
|
|
663
|
+
}
|
|
664
|
+
return success(result);
|
|
665
|
+
}
|
|
666
|
+
|
|
483
667
|
// src/qr-parsers/parsers/brl.ts
|
|
668
|
+
import { err as err2, ok as ok2 } from "neverthrow";
|
|
484
669
|
var PIX_TAGS = {
|
|
485
670
|
PAYLOAD_FORMAT: "00",
|
|
486
671
|
PIX_KEY_INFO: "26",
|
|
@@ -900,17 +1085,22 @@ function parseQRPh(qrData, sellPrice) {
|
|
|
900
1085
|
}
|
|
901
1086
|
|
|
902
1087
|
// src/qr-parsers/parsers/ven.ts
|
|
903
|
-
function
|
|
1088
|
+
function isPagoMovilQr(qrData) {
|
|
904
1089
|
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
905
|
-
return
|
|
1090
|
+
return false;
|
|
906
1091
|
}
|
|
907
1092
|
const trimmed = qrData.trim();
|
|
908
1093
|
const qIdx = trimmed.indexOf("?");
|
|
909
|
-
if (qIdx === -1)
|
|
910
|
-
return failure("INVALID_QR", "Not a valid Venezuelan QR code");
|
|
911
|
-
}
|
|
1094
|
+
if (qIdx === -1) return false;
|
|
912
1095
|
const payload = trimmed.substring(0, qIdx);
|
|
913
|
-
|
|
1096
|
+
return !!payload && /^[A-Za-z0-9+/=]+$/.test(payload);
|
|
1097
|
+
}
|
|
1098
|
+
function parsePagoMovil(qrData, _sellPrice) {
|
|
1099
|
+
if (!qrData || typeof qrData !== "string" || qrData.trim().length === 0) {
|
|
1100
|
+
return failure("INVALID_QR", "QR data is empty or invalid");
|
|
1101
|
+
}
|
|
1102
|
+
const trimmed = qrData.trim();
|
|
1103
|
+
if (!isPagoMovilQr(trimmed)) {
|
|
914
1104
|
return failure("INVALID_QR", "Not a valid Venezuelan QR code");
|
|
915
1105
|
}
|
|
916
1106
|
return success({ paymentAddress: trimmed });
|
|
@@ -933,6 +1123,8 @@ async function parseQR(params) {
|
|
|
933
1123
|
return parseMercadoPago(qrData, sellPrice);
|
|
934
1124
|
case CURRENCY.VEN:
|
|
935
1125
|
return parsePagoMovil(qrData, sellPrice);
|
|
1126
|
+
case CURRENCY.BOB:
|
|
1127
|
+
return parseBolivia(qrData, sellPrice);
|
|
936
1128
|
case CURRENCY.NGN:
|
|
937
1129
|
return parseNGN(qrData, sellPrice);
|
|
938
1130
|
case CURRENCY.COP:
|
|
@@ -951,6 +1143,7 @@ async function parseQR(params) {
|
|
|
951
1143
|
}
|
|
952
1144
|
export {
|
|
953
1145
|
QRParserError,
|
|
1146
|
+
isPagoMovilQr,
|
|
954
1147
|
parseQR
|
|
955
1148
|
};
|
|
956
1149
|
//# sourceMappingURL=qr-parsers.mjs.map
|