@crediblemark/buayar 0.3.0 → 0.3.2

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/dist/index.d.mts CHANGED
@@ -222,7 +222,7 @@ declare class MidtransClient {
222
222
  sandbox?: boolean;
223
223
  });
224
224
  private getApiBaseUrl;
225
- request(method: "GET" | "POST" | "PATCH" | "DELETE", path: string, body: any): Promise<any>;
225
+ request(method: "GET" | "POST" | "PATCH" | "DELETE", path: string, body?: any): Promise<any>;
226
226
  cancelTransaction(orderId: string): Promise<any>;
227
227
  refundTransaction(orderId: string, payload: {
228
228
  refund_key?: string;
@@ -1278,8 +1278,22 @@ declare function verifyOyWebhook(headers: Record<string, string | string[] | und
1278
1278
  */
1279
1279
  declare function serializeStripeParams(obj: any, prefix?: string): string;
1280
1280
  /**
1281
- * Verifikasi webhook signature Stripe (stripe-signature header)
1281
+ * Verifikasi webhook signature Stripe (stripe-signature header).
1282
+ *
1282
1283
  * Format header: t=1492774577,v1=5257a869e7ecebeda32affa62cd323fa9d214e1b50613e039f08f6362ced773d
1284
+ *
1285
+ * Keamanan:
1286
+ * - Jika signatureHeader atau webhookSecret tidak ada → return false (TIDAK pernah return true).
1287
+ * Gunakan flag `skipVerification: true` secara eksplisit di kode test jika ingin bypass.
1288
+ * - Pemeriksaan timestamp (replay attack protection): jika selisih antara
1289
+ * timestamp header dan waktu sekarang melebihi `toleranceSeconds`, return false.
1290
+ * - Perbandingan signature menggunakan `safeCompare` (timing-safe via crypto.timingSafeEqual).
1291
+ *
1292
+ * @param rawPayload Body request mentah (string atau object; jika object akan di-JSON.stringify)
1293
+ * @param signatureHeader Nilai header `stripe-signature`
1294
+ * @param webhookSecret Webhook Signing Secret dari dashboard Stripe (`whsec_...`)
1295
+ * @param toleranceSeconds Toleransi selisih timestamp (default: 300 detik / 5 menit)
1296
+ * @returns true jika signature valid dan timestamp dalam toleransi; false selainnya
1283
1297
  */
1284
1298
  declare function verifyStripeWebhook(rawPayload: string | any, signatureHeader: string, webhookSecret: string, toleranceSeconds?: number): boolean;
1285
1299
 
@@ -1373,11 +1387,14 @@ declare function sha256(data: string): string;
1373
1387
  */
1374
1388
  declare function sha512(data: string): string;
1375
1389
  /**
1376
- * Generate HMAC-SHA256 hash string (lowercase)
1390
+ * Generate HMAC-SHA256 hash string (lowercase hex)
1377
1391
  */
1378
1392
  declare function hmacSha256(data: string, secret: string): string;
1379
1393
  /**
1380
- * Timing-safe string comparison to prevent timing attacks on signatures
1394
+ * Timing-safe string comparison menggunakan crypto.timingSafeEqual
1395
+ * untuk mencegah timing attack pada perbandingan signature / token.
1396
+ * Menggunakan SHA-256 digest untuk memastikan kedua buffer selalu berukuran 32 bytes,
1397
+ * mencegah kebocoran informasi panjang string dan mengatasi penanganan string non-hex / ganjil oleh Buffer.from.
1381
1398
  */
1382
1399
  declare function safeCompare(a: string, b: string): boolean;
1383
1400
 
package/dist/index.d.ts CHANGED
@@ -222,7 +222,7 @@ declare class MidtransClient {
222
222
  sandbox?: boolean;
223
223
  });
224
224
  private getApiBaseUrl;
225
- request(method: "GET" | "POST" | "PATCH" | "DELETE", path: string, body: any): Promise<any>;
225
+ request(method: "GET" | "POST" | "PATCH" | "DELETE", path: string, body?: any): Promise<any>;
226
226
  cancelTransaction(orderId: string): Promise<any>;
227
227
  refundTransaction(orderId: string, payload: {
228
228
  refund_key?: string;
@@ -1278,8 +1278,22 @@ declare function verifyOyWebhook(headers: Record<string, string | string[] | und
1278
1278
  */
1279
1279
  declare function serializeStripeParams(obj: any, prefix?: string): string;
1280
1280
  /**
1281
- * Verifikasi webhook signature Stripe (stripe-signature header)
1281
+ * Verifikasi webhook signature Stripe (stripe-signature header).
1282
+ *
1282
1283
  * Format header: t=1492774577,v1=5257a869e7ecebeda32affa62cd323fa9d214e1b50613e039f08f6362ced773d
1284
+ *
1285
+ * Keamanan:
1286
+ * - Jika signatureHeader atau webhookSecret tidak ada → return false (TIDAK pernah return true).
1287
+ * Gunakan flag `skipVerification: true` secara eksplisit di kode test jika ingin bypass.
1288
+ * - Pemeriksaan timestamp (replay attack protection): jika selisih antara
1289
+ * timestamp header dan waktu sekarang melebihi `toleranceSeconds`, return false.
1290
+ * - Perbandingan signature menggunakan `safeCompare` (timing-safe via crypto.timingSafeEqual).
1291
+ *
1292
+ * @param rawPayload Body request mentah (string atau object; jika object akan di-JSON.stringify)
1293
+ * @param signatureHeader Nilai header `stripe-signature`
1294
+ * @param webhookSecret Webhook Signing Secret dari dashboard Stripe (`whsec_...`)
1295
+ * @param toleranceSeconds Toleransi selisih timestamp (default: 300 detik / 5 menit)
1296
+ * @returns true jika signature valid dan timestamp dalam toleransi; false selainnya
1283
1297
  */
1284
1298
  declare function verifyStripeWebhook(rawPayload: string | any, signatureHeader: string, webhookSecret: string, toleranceSeconds?: number): boolean;
1285
1299
 
@@ -1373,11 +1387,14 @@ declare function sha256(data: string): string;
1373
1387
  */
1374
1388
  declare function sha512(data: string): string;
1375
1389
  /**
1376
- * Generate HMAC-SHA256 hash string (lowercase)
1390
+ * Generate HMAC-SHA256 hash string (lowercase hex)
1377
1391
  */
1378
1392
  declare function hmacSha256(data: string, secret: string): string;
1379
1393
  /**
1380
- * Timing-safe string comparison to prevent timing attacks on signatures
1394
+ * Timing-safe string comparison menggunakan crypto.timingSafeEqual
1395
+ * untuk mencegah timing attack pada perbandingan signature / token.
1396
+ * Menggunakan SHA-256 digest untuk memastikan kedua buffer selalu berukuran 32 bytes,
1397
+ * mencegah kebocoran informasi panjang string dan mengatasi penanganan string non-hex / ganjil oleh Buffer.from.
1381
1398
  */
1382
1399
  declare function safeCompare(a: string, b: string): boolean;
1383
1400
 
package/dist/index.js CHANGED
@@ -566,7 +566,19 @@ function hmacSha256(data, secret) {
566
566
  }
567
567
  function safeCompare(a, b) {
568
568
  if (typeof a !== "string" || typeof b !== "string") return false;
569
- return a.toLowerCase() === b.toLowerCase();
569
+ if (!a && !b) return true;
570
+ if (!a || !b) return false;
571
+ const isHexA = /^[0-9a-fA-F]+$/.test(a);
572
+ const isHexB = /^[0-9a-fA-F]+$/.test(b);
573
+ let strA = a;
574
+ let strB = b;
575
+ if (isHexA && isHexB && a.length === b.length) {
576
+ strA = a.toLowerCase();
577
+ strB = b.toLowerCase();
578
+ }
579
+ const hashA = import_crypto.default.createHash("sha256").update(strA).digest();
580
+ const hashB = import_crypto.default.createHash("sha256").update(strB).digest();
581
+ return import_crypto.default.timingSafeEqual(hashA, hashB);
570
582
  }
571
583
 
572
584
  // src/providers/duitku/signature.ts
@@ -2061,7 +2073,7 @@ function getXenditAuthHeader(secretKey) {
2061
2073
  return `Basic ${token}`;
2062
2074
  }
2063
2075
  function verifyXenditWebhookToken(headerToken, expectedToken) {
2064
- if (!headerToken || !expectedToken) return true;
2076
+ if (!headerToken || !expectedToken) return false;
2065
2077
  return safeCompare(headerToken, expectedToken);
2066
2078
  }
2067
2079
 
@@ -2249,8 +2261,14 @@ var XenditProvider = class extends BasePaymentProvider {
2249
2261
  const orderId = body.external_id || body.reference_id || body.data?.reference_id || body.id || "";
2250
2262
  const amount = body.paid_amount || body.amount || body.data?.amount || 0;
2251
2263
  const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
2264
+ const webhookToken = config.extra?.webhookToken;
2265
+ const headerToken = config.extra?.callbackToken || config.extra?.headers?.["x-callback-token"] || config.extra?.headers?.["X-Callback-Token"];
2266
+ let isValid = true;
2267
+ if (webhookToken || headerToken) {
2268
+ isValid = verifyXenditWebhookToken(headerToken, webhookToken);
2269
+ }
2252
2270
  return {
2253
- isValid: true,
2271
+ isValid,
2254
2272
  provider: "xendit",
2255
2273
  orderId: String(orderId),
2256
2274
  amount: Number(amount) || 0,
@@ -2528,11 +2546,12 @@ function verifyDokuWebhookSignature(headers, body, clientId, secretKey, requestT
2528
2546
  const reqId = headers["request-id"] || headers["Request-Id"] || "";
2529
2547
  const reqTimestamp = headers["request-timestamp"] || headers["Request-Timestamp"] || "";
2530
2548
  const incomingSignature = headers["signature"] || headers["Signature"] || "";
2531
- if (!incomingSignature || !secretKey) return true;
2549
+ if (!incomingSignature || !secretKey) return false;
2550
+ const target = headers["request-target"] || headers["Request-Target"] || requestTarget;
2532
2551
  let component = `Client-Id:${reqClientId || clientId}
2533
2552
  Request-Id:${reqId}
2534
2553
  Request-Timestamp:${reqTimestamp}
2535
- Request-Target:${requestTarget}`;
2554
+ Request-Target:${target}`;
2536
2555
  if (body) {
2537
2556
  const rawBody = typeof body === "string" ? body : JSON.stringify(body);
2538
2557
  const digest = import_crypto6.default.createHash("sha256").update(rawBody).digest("base64");
@@ -2756,8 +2775,16 @@ var DokuProvider = class extends BasePaymentProvider {
2756
2775
  const orderId = body.order?.invoice_number || body.invoice_number || body.order_id || "";
2757
2776
  const amount = body.order?.amount || body.amount || 0;
2758
2777
  const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
2778
+ const secretKey = config.secretKey || config.apiKey || "";
2779
+ const headers = config.extra?.headers || {};
2780
+ const signature = headers["signature"] || headers["Signature"] || config.extra?.dokuSignature || config.extra?.signatureHeader;
2781
+ const clientId = config.merchantCode || config.clientKey || "";
2782
+ let isValid = true;
2783
+ if (signature || headers && (headers["request-id"] || headers["Request-Id"])) {
2784
+ isValid = verifyDokuWebhookSignature(headers, body, clientId, secretKey);
2785
+ }
2759
2786
  return {
2760
- isValid: true,
2787
+ isValid,
2761
2788
  provider: "doku",
2762
2789
  orderId: String(orderId),
2763
2790
  amount: Number(amount) || 0,
@@ -3014,7 +3041,7 @@ function generatePrismalinkSignature(merchantId, orderId, amount, secretKey) {
3014
3041
  return sha256(raw);
3015
3042
  }
3016
3043
  function verifyPrismalinkSignature(merchantId, orderId, amount, secretKey, incomingSignature) {
3017
- if (!incomingSignature || !secretKey) return true;
3044
+ if (!incomingSignature || !secretKey) return false;
3018
3045
  const computed = generatePrismalinkSignature(merchantId, orderId, amount, secretKey);
3019
3046
  return safeCompare(incomingSignature, computed);
3020
3047
  }
@@ -3405,7 +3432,7 @@ function generateFaspaySignature(userId, password, billNo) {
3405
3432
  return import_crypto9.default.createHash("sha1").update(md5Hash).digest("hex");
3406
3433
  }
3407
3434
  function verifyFaspaySignature(userId, password, billNo, paymentStatusCode, incomingSignature) {
3408
- if (!incomingSignature || !password) return true;
3435
+ if (!incomingSignature || !password) return false;
3409
3436
  const md5Hash = import_crypto9.default.createHash("md5").update(`${userId}${password}${billNo}${paymentStatusCode}`).digest("hex");
3410
3437
  const computed = import_crypto9.default.createHash("sha1").update(md5Hash).digest("hex");
3411
3438
  const simpleComputed = generateFaspaySignature(userId, password, billNo);
@@ -3826,9 +3853,9 @@ function generateFinpaySignature(merchantId, orderId, amount, merchantKey) {
3826
3853
  return import_crypto11.default.createHmac("sha512", merchantKey).update(data).digest("hex");
3827
3854
  }
3828
3855
  function verifyFinpaySignature(merchantId, orderId, amount, merchantKey, incomingSignature) {
3829
- if (!incomingSignature || !merchantKey) return true;
3856
+ if (!incomingSignature || !merchantKey) return false;
3830
3857
  const computed = generateFinpaySignature(merchantId, orderId, amount, merchantKey);
3831
- return safeCompare(incomingSignature.toLowerCase(), computed.toLowerCase());
3858
+ return safeCompare(incomingSignature, computed);
3832
3859
  }
3833
3860
 
3834
3861
  // src/providers/finpay/provider.ts
@@ -4213,9 +4240,9 @@ function generateNicepayToken(timeStamp, iMid, referenceNo, amt, merchantKey) {
4213
4240
  return sha256(raw);
4214
4241
  }
4215
4242
  function verifyNicepayWebhook(timeStamp, iMid, referenceNo, amt, merchantKey, incomingToken) {
4216
- if (!incomingToken || !merchantKey) return true;
4243
+ if (!incomingToken || !merchantKey) return false;
4217
4244
  const computed = generateNicepayToken(timeStamp, iMid, referenceNo, amt, merchantKey);
4218
- return safeCompare(incomingToken.toLowerCase(), computed.toLowerCase());
4245
+ return safeCompare(incomingToken, computed);
4219
4246
  }
4220
4247
 
4221
4248
  // src/providers/nicepay/provider.ts
@@ -4642,9 +4669,9 @@ function generateOyHeaders(username, apiKey) {
4642
4669
  };
4643
4670
  }
4644
4671
  function verifyOyWebhook(headers, expectedUsername) {
4645
- if (!expectedUsername) return true;
4672
+ if (!expectedUsername) return false;
4646
4673
  const username = headers["x-oy-username"] || headers["X-Oy-Username"] || "";
4647
- if (!username) return true;
4674
+ if (!username) return false;
4648
4675
  return safeCompare(username.toLowerCase(), expectedUsername.toLowerCase());
4649
4676
  }
4650
4677
 
@@ -4806,7 +4833,7 @@ var OyProvider = class extends BasePaymentProvider {
4806
4833
  }
4807
4834
  }
4808
4835
  async verifyCallback(body, config) {
4809
- const username = config.clientKey || config.merchantCode || config.merchantId || "";
4836
+ const username = config.clientKey || config.merchantCode || config.merchantId || config.extra?.username || "";
4810
4837
  const orderId = body.partner_tx_id || body.partner_trx_id || body.trx_id || "";
4811
4838
  const amount = body.amount || body.settlement_amount || 0;
4812
4839
  const rawStatus = (body.status || body.tx_status || "").toUpperCase();
@@ -4815,8 +4842,14 @@ var OyProvider = class extends BasePaymentProvider {
4815
4842
  const isExpired = rawStatus === "EXPIRED";
4816
4843
  const isFailed = rawStatus === "FAILED" || !isPaid && !isPending && !isExpired;
4817
4844
  const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
4845
+ const headers = config.extra?.headers || {};
4846
+ const oyUsernameHeader = headers["x-oy-username"] || headers["X-Oy-Username"] || config.extra?.oyUsername;
4847
+ let isValid = true;
4848
+ if (oyUsernameHeader || username && headers && Object.keys(headers).length > 0) {
4849
+ isValid = verifyOyWebhook(headers, username);
4850
+ }
4818
4851
  return {
4819
- isValid: true,
4852
+ isValid,
4820
4853
  provider: "oy",
4821
4854
  orderId: String(orderId),
4822
4855
  amount: Number(amount) || 0,
@@ -5076,13 +5109,16 @@ function serializeStripeParams(obj, prefix = "") {
5076
5109
  }
5077
5110
  function verifyStripeWebhook(rawPayload, signatureHeader, webhookSecret, toleranceSeconds = 300) {
5078
5111
  if (!signatureHeader || !webhookSecret) {
5079
- return true;
5112
+ return false;
5080
5113
  }
5081
5114
  const items = signatureHeader.split(",");
5082
5115
  let timestamp = "";
5083
5116
  const signatures = [];
5084
5117
  for (const item of items) {
5085
- const [key, value] = item.trim().split("=");
5118
+ const eqIdx = item.indexOf("=");
5119
+ if (eqIdx === -1) continue;
5120
+ const key = item.slice(0, eqIdx).trim();
5121
+ const value = item.slice(eqIdx + 1).trim();
5086
5122
  if (key === "t") {
5087
5123
  timestamp = value;
5088
5124
  } else if (key === "v1") {
@@ -5092,10 +5128,18 @@ function verifyStripeWebhook(rawPayload, signatureHeader, webhookSecret, toleran
5092
5128
  if (!timestamp || signatures.length === 0) {
5093
5129
  return false;
5094
5130
  }
5131
+ const tsNum = Number(timestamp);
5132
+ if (Number.isNaN(tsNum) || tsNum <= 0) {
5133
+ return false;
5134
+ }
5135
+ const nowSec = Math.floor(Date.now() / 1e3);
5136
+ if (Math.abs(nowSec - tsNum) > toleranceSeconds) {
5137
+ return false;
5138
+ }
5095
5139
  const payloadString = typeof rawPayload === "string" ? rawPayload : JSON.stringify(rawPayload);
5096
5140
  const signedPayload = `${timestamp}.${payloadString}`;
5097
5141
  const expectedSignature = hmacSha256(signedPayload, webhookSecret);
5098
- return signatures.some((sig) => safeCompare(sig.toLowerCase(), expectedSignature.toLowerCase()));
5142
+ return signatures.some((sig) => safeCompare(sig, expectedSignature));
5099
5143
  }
5100
5144
 
5101
5145
  // src/providers/stripe/provider.ts
@@ -5721,7 +5765,8 @@ function verifyAdyenWebhook(notificationItem, hmacKey) {
5721
5765
  const signedData = fields.join(":");
5722
5766
  const keyBytes = Buffer.from(hmacKey, "hex");
5723
5767
  const expected = (0, import_crypto16.createHmac)("sha256", keyBytes).update(signedData, "utf8").digest("base64");
5724
- return expected === notificationItem.additionalData?.hmacSignature;
5768
+ const provided = notificationItem.additionalData?.hmacSignature || "";
5769
+ return safeCompare(expected, provided);
5725
5770
  } catch {
5726
5771
  return false;
5727
5772
  }
@@ -5834,7 +5879,7 @@ var AdyenProvider = class extends BasePaymentProvider {
5834
5879
  const hmacKey = config.extra?.hmacKey || config.secretKey || "";
5835
5880
  const notificationItems = body?.notificationItems || [body];
5836
5881
  const item = notificationItems[0]?.NotificationRequestItem || notificationItems[0] || body;
5837
- const isValid = hmacKey ? verifyAdyenWebhook(item, hmacKey) : true;
5882
+ const isValid = hmacKey ? verifyAdyenWebhook(item, hmacKey) : false;
5838
5883
  const eventCode = (item.eventCode || "").toUpperCase();
5839
5884
  const success = item.success === "true" || item.success === true;
5840
5885
  const orderId = item.merchantReference || item.pspReference || "";
@@ -5952,13 +5997,13 @@ var AdyenProvider = class extends BasePaymentProvider {
5952
5997
  };
5953
5998
 
5954
5999
  // src/providers/checkoutcom/signature.ts
5955
- var import_crypto17 = require("crypto");
6000
+ var import_crypto18 = require("crypto");
5956
6001
  function verifyCheckoutComWebhook(body, signatureHeader, secret) {
5957
6002
  if (!secret || !signatureHeader || !body) return false;
5958
6003
  try {
5959
- const expected = (0, import_crypto17.createHmac)("sha256", secret).update(body, "utf8").digest("hex");
6004
+ const expected = (0, import_crypto18.createHmac)("sha256", secret).update(body, "utf8").digest("hex");
5960
6005
  const provided = signatureHeader.replace(/^sha256=/, "");
5961
- return expected === provided;
6006
+ return safeCompare(expected, provided);
5962
6007
  } catch {
5963
6008
  return false;
5964
6009
  }
@@ -6059,7 +6104,7 @@ var CheckoutComProvider = class extends BasePaymentProvider {
6059
6104
  const signatureHeader = config.extra?.signatureHeader || "";
6060
6105
  const rawBody = typeof body === "string" ? body : JSON.stringify(body);
6061
6106
  const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
6062
- const isValid = signatureHeader ? verifyCheckoutComWebhook(rawBody, signatureHeader, webhookSecret) : true;
6107
+ const isValid = signatureHeader ? verifyCheckoutComWebhook(rawBody, signatureHeader, webhookSecret) : false;
6063
6108
  const eventType = parsedBody?.type || "";
6064
6109
  const data = parsedBody?.data || parsedBody;
6065
6110
  const orderId = data?.reference || data?.metadata?.order_id || data?.id || "";
@@ -6176,12 +6221,12 @@ var CheckoutComProvider = class extends BasePaymentProvider {
6176
6221
  };
6177
6222
 
6178
6223
  // src/providers/razorpay/signature.ts
6179
- var import_crypto18 = require("crypto");
6224
+ var import_crypto20 = require("crypto");
6180
6225
  function verifyRazorpayWebhook(rawBody, signature, webhookSecret) {
6181
6226
  if (!webhookSecret || !signature || !rawBody) return false;
6182
6227
  try {
6183
- const expected = (0, import_crypto18.createHmac)("sha256", webhookSecret).update(rawBody).digest("hex");
6184
- return expected === signature;
6228
+ const expected = (0, import_crypto20.createHmac)("sha256", webhookSecret).update(rawBody).digest("hex");
6229
+ return safeCompare(expected, signature);
6185
6230
  } catch {
6186
6231
  return false;
6187
6232
  }
@@ -6290,7 +6335,7 @@ var RazorpayProvider = class extends BasePaymentProvider {
6290
6335
  const signatureHeader = config.extra?.signatureHeader || "";
6291
6336
  const rawBody = typeof body === "string" ? body : JSON.stringify(body);
6292
6337
  const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
6293
- const isValid = signatureHeader ? verifyRazorpayWebhook(rawBody, signatureHeader, webhookSecret) : true;
6338
+ const isValid = signatureHeader ? verifyRazorpayWebhook(rawBody, signatureHeader, webhookSecret) : false;
6294
6339
  const eventType = parsedBody?.event || "";
6295
6340
  const payload = parsedBody?.payload;
6296
6341
  const paymentEntity = payload?.payment?.entity || payload?.payment_link?.entity || parsedBody;
@@ -6406,13 +6451,13 @@ var RazorpayProvider = class extends BasePaymentProvider {
6406
6451
  };
6407
6452
 
6408
6453
  // src/providers/square/signature.ts
6409
- var import_crypto19 = require("crypto");
6454
+ var import_crypto22 = require("crypto");
6410
6455
  function verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) {
6411
6456
  if (!signatureKey || !signatureHeader || !rawBody) return false;
6412
6457
  try {
6413
6458
  const payload = notificationUrl + rawBody;
6414
- const expected = (0, import_crypto19.createHmac)("sha256", signatureKey).update(payload).digest("base64");
6415
- return expected === signatureHeader;
6459
+ const expected = (0, import_crypto22.createHmac)("sha256", signatureKey).update(payload).digest("base64");
6460
+ return safeCompare(expected, signatureHeader);
6416
6461
  } catch {
6417
6462
  return false;
6418
6463
  }
@@ -6532,7 +6577,7 @@ var SquareProvider = class extends BasePaymentProvider {
6532
6577
  const notificationUrl = config.callbackUrl || config.extra?.notificationUrl || "";
6533
6578
  const rawBody = typeof body === "string" ? body : JSON.stringify(body);
6534
6579
  const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
6535
- const isValid = signatureHeader ? verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) : true;
6580
+ const isValid = signatureHeader ? verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) : false;
6536
6581
  const eventType = parsedBody?.type || "";
6537
6582
  const data = parsedBody?.data?.object || parsedBody?.data || parsedBody;
6538
6583
  const payment = data?.payment || data;
@@ -6651,7 +6696,7 @@ var SquareProvider = class extends BasePaymentProvider {
6651
6696
  };
6652
6697
 
6653
6698
  // src/providers/payu/signature.ts
6654
- var import_crypto20 = require("crypto");
6699
+ var import_crypto24 = require("crypto");
6655
6700
  function verifyPayuWebhook(rawBody, signatureHeader, md5Key) {
6656
6701
  if (!md5Key || !signatureHeader || !rawBody) return false;
6657
6702
  try {
@@ -6662,12 +6707,13 @@ function verifyPayuWebhook(rawBody, signatureHeader, md5Key) {
6662
6707
  }
6663
6708
  const providedSig = parts["signature"];
6664
6709
  const algorithm = (parts["algorithm"] || "MD5").toUpperCase();
6710
+ if (!providedSig) return false;
6665
6711
  if (algorithm === "MD5") {
6666
- const expected = (0, import_crypto20.createHash)("md5").update(rawBody + md5Key).digest("hex");
6667
- return expected === providedSig;
6712
+ const expected = (0, import_crypto24.createHash)("md5").update(rawBody + md5Key).digest("hex");
6713
+ return safeCompare(expected, providedSig);
6668
6714
  } else if (algorithm === "SHA-256") {
6669
- const expected = (0, import_crypto20.createHash)("sha256").update(rawBody + md5Key).digest("hex");
6670
- return expected === providedSig;
6715
+ const expected = (0, import_crypto24.createHash)("sha256").update(rawBody + md5Key).digest("hex");
6716
+ return safeCompare(expected, providedSig);
6671
6717
  }
6672
6718
  return false;
6673
6719
  } catch {
@@ -6805,7 +6851,7 @@ var PayuProvider = class extends BasePaymentProvider {
6805
6851
  const signatureHeader = config.extra?.signatureHeader || "";
6806
6852
  const rawBody = typeof body === "string" ? body : JSON.stringify(body);
6807
6853
  const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
6808
- const isValid = signatureHeader ? verifyPayuWebhook(rawBody, signatureHeader, md5Key) : true;
6854
+ const isValid = signatureHeader ? verifyPayuWebhook(rawBody, signatureHeader, md5Key) : false;
6809
6855
  const order = parsedBody?.order || parsedBody;
6810
6856
  const orderId = order.extOrderId || order.orderId || "";
6811
6857
  const amount = Number(order.totalAmount || 0);
@@ -6942,7 +6988,7 @@ var PayuProvider = class extends BasePaymentProvider {
6942
6988
  };
6943
6989
 
6944
6990
  // src/providers/braintree/signature.ts
6945
- var import_crypto21 = require("crypto");
6991
+ var import_crypto26 = require("crypto");
6946
6992
  function verifyBraintreeWebhook(btSignature, btPayload, privateKey) {
6947
6993
  if (!privateKey || !btSignature || !btPayload) return false;
6948
6994
  try {
@@ -6950,9 +6996,9 @@ function verifyBraintreeWebhook(btSignature, btPayload, privateKey) {
6950
6996
  if (parts.length < 2) return false;
6951
6997
  const providedHmac = parts[1];
6952
6998
  const payload = Buffer.from(btPayload, "base64").toString("utf8");
6953
- const secretHash = (0, import_crypto21.createHash)("sha1").update(privateKey).digest("hex");
6954
- const expected = (0, import_crypto21.createHmac)("sha1", secretHash).update(payload).digest("hex");
6955
- return expected === providedHmac;
6999
+ const secretHash = (0, import_crypto26.createHash)("sha1").update(privateKey).digest("hex");
7000
+ const expected = (0, import_crypto26.createHmac)("sha1", secretHash).update(payload).digest("hex");
7001
+ return safeCompare(expected, providedHmac);
6956
7002
  } catch {
6957
7003
  return false;
6958
7004
  }
@@ -7058,7 +7104,7 @@ var BraintreeProvider = class extends BasePaymentProvider {
7058
7104
  const privateKey = config.apiKey || config.secretKey || "";
7059
7105
  const btSignature = config.extra?.btSignature || "";
7060
7106
  const btPayload = config.extra?.btPayload || "";
7061
- const isValid = btSignature && btPayload ? verifyBraintreeWebhook(btSignature, btPayload, privateKey) : true;
7107
+ const isValid = btSignature && btPayload ? verifyBraintreeWebhook(btSignature, btPayload, privateKey) : false;
7062
7108
  const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
7063
7109
  const subject = parsedBody?.subject || parsedBody;
7064
7110
  const transaction = subject?.transaction || subject?.disbursement || parsedBody;
@@ -7178,11 +7224,11 @@ var BraintreeProvider = class extends BasePaymentProvider {
7178
7224
  };
7179
7225
 
7180
7226
  // src/providers/twocheckout/signature.ts
7181
- var import_crypto22 = require("crypto");
7227
+ var import_crypto28 = require("crypto");
7182
7228
  function buildTwoCheckoutAuth(merchantCode, secretKey) {
7183
7229
  const date = Math.floor(Date.now() / 1e3).toString();
7184
7230
  const raw = merchantCode + date;
7185
- const hmac = (0, import_crypto22.createHmac)("sha256", secretKey).update(raw).digest("hex");
7231
+ const hmac = (0, import_crypto28.createHmac)("sha256", secretKey).update(raw).digest("hex");
7186
7232
  const header = `code="${merchantCode}" date="${date}" hash="${hmac}"`;
7187
7233
  return { header, date };
7188
7234
  }
@@ -7190,8 +7236,8 @@ function verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, prov
7190
7236
  if (!secretWord || !providedHash) return false;
7191
7237
  try {
7192
7238
  const raw = secretWord + saleId + productId + invoiceId;
7193
- const expected = (0, import_crypto22.createHash)("md5").update(raw).digest("hex").toUpperCase();
7194
- return expected === (providedHash || "").toUpperCase();
7239
+ const expected = (0, import_crypto28.createHash)("md5").update(raw).digest("hex");
7240
+ return safeCompare(expected, providedHash);
7195
7241
  } catch {
7196
7242
  return false;
7197
7243
  }
@@ -7290,7 +7336,7 @@ var TwoCheckoutProvider = class extends BasePaymentProvider {
7290
7336
  const productId = parsedBody?.IPN_PID?.[0] || parsedBody?.product_id || "";
7291
7337
  const invoiceId = parsedBody?.IPN_PNAME?.[0] || parsedBody?.invoice_id || "";
7292
7338
  const providedHash = parsedBody?.HASH || parsedBody?.hash || "";
7293
- const isValid = secretWord ? verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) : true;
7339
+ const isValid = secretWord ? verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) : false;
7294
7340
  const orderId = parsedBody?.REFNOEXT || parsedBody?.ext_ref_no || parsedBody?.SALE_ID || "";
7295
7341
  const amount = Math.round(Number(parsedBody?.IPN_TOTAL_GENERAL || parsedBody?.total || 0) * 100);
7296
7342
  const statusRaw = (parsedBody?.ORDERSTATUS || parsedBody?.order_status || "").toUpperCase();
@@ -8980,7 +9026,7 @@ function resolveConfigFromEnv(customConfig) {
8980
9026
  merchantCode = merchantCode || env.IPAYMU_VA || env.IPAYMU_MERCHANT_CODE || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
8981
9027
  } else if (provider === "doku") {
8982
9028
  merchantCode = merchantCode || env.DOKU_CLIENT_ID || env.DOKU_MERCHANT_ID || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
8983
- clientKey = clientKey || env.DOKU_CLIENT_ID || env.BUAYAR_CLIENT_KEY;
9029
+ clientKey = clientKey || customConfig?.merchantCode || env.DOKU_CLIENT_ID || env.BUAYAR_CLIENT_KEY;
8984
9030
  } else if (provider === "prismalink") {
8985
9031
  merchantCode = merchantCode || env.PRISMALINK_MERCHANT_ID || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
8986
9032
  merchantId = merchantId || env.PRISMALINK_MERCHANT_ID || env.BUAYAR_MERCHANT_ID;
@@ -8996,7 +9042,7 @@ function resolveConfigFromEnv(customConfig) {
8996
9042
  merchantId = merchantId || env.NICEPAY_IMID || env.BUAYAR_MERCHANT_ID;
8997
9043
  } else if (provider === "oy" || provider === "oyindonesia") {
8998
9044
  merchantCode = merchantCode || env.OY_USERNAME || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
8999
- clientKey = clientKey || env.OY_USERNAME || env.BUAYAR_CLIENT_KEY;
9045
+ clientKey = clientKey || customConfig?.merchantCode || env.OY_USERNAME || env.BUAYAR_CLIENT_KEY;
9000
9046
  } else if (provider === "stripe") {
9001
9047
  clientKey = clientKey || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.BUAYAR_CLIENT_KEY || env.BUAYAR_PUBLIC_KEY;
9002
9048
  merchantCode = merchantCode || clientKey || "stripe";
@@ -9032,12 +9078,12 @@ function resolveConfigFromEnv(customConfig) {
9032
9078
  const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID || env.SQUARE_LOCATION_ID;
9033
9079
  const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.CHECKOUTCOM_PUBLIC_KEY;
9034
9080
  const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY || env.BRAINTREE_PRIVATE_KEY;
9035
- const secretKey = customConfig?.secretKey || env.BUAYAR_SECRET_KEY || env.PG_SECRET_KEY || env.SECRET_KEY || env.XENDIT_SECRET_KEY || env.DOKU_SECRET_KEY || env.PRISMALINK_SECRET_KEY || env.FASPAY_PASSWORD || env.FINPAY_MERCHANT_KEY || env.NICEPAY_KEY || env.OY_API_KEY || env.STRIPE_SECRET_KEY || env.PAYPAL_CLIENT_SECRET || env.CHECKOUTCOM_SECRET_KEY || env.RAZORPAY_KEY_SECRET || env.SQUARE_ACCESS_TOKEN || env.BRAINTREE_PRIVATE_KEY || env.TWOCHECKOUT_SECRET_KEY;
9081
+ const secretKey = customConfig?.secretKey || customConfig?.apiKey || customConfig?.serverKey || env.BUAYAR_SECRET_KEY || env.PG_SECRET_KEY || env.SECRET_KEY || env.XENDIT_SECRET_KEY || env.DOKU_SECRET_KEY || env.PRISMALINK_SECRET_KEY || env.FASPAY_PASSWORD || env.FINPAY_MERCHANT_KEY || env.NICEPAY_KEY || env.OY_API_KEY || env.STRIPE_SECRET_KEY || env.PAYPAL_CLIENT_SECRET || env.CHECKOUTCOM_SECRET_KEY || env.RAZORPAY_KEY_SECRET || env.SQUARE_ACCESS_TOKEN || env.BRAINTREE_PRIVATE_KEY || env.TWOCHECKOUT_SECRET_KEY;
9036
9082
  const callbackUrl = customConfig?.callbackUrl || env.BUAYAR_CALLBACK_URL || env.PG_CALLBACK_URL || env.PAYMENT_CALLBACK_URL;
9037
9083
  const returnUrl = customConfig?.returnUrl || env.BUAYAR_RETURN_URL || env.PG_RETURN_URL || env.PAYMENT_RETURN_URL;
9038
9084
  const extra = {
9039
9085
  webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
9040
- webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
9086
+ webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.RAZORPAY_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
9041
9087
  merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
9042
9088
  userId: env.FASPAY_USER_ID,
9043
9089
  iMid: env.NICEPAY_IMID,
@@ -9143,38 +9189,46 @@ var Buayar = class {
9143
9189
  async verifyWebhook(payload, headers, configOverride) {
9144
9190
  const mergedConfig = { ...this.config, ...configOverride };
9145
9191
  if (headers) {
9192
+ if (!mergedConfig.extra) mergedConfig.extra = {};
9193
+ mergedConfig.extra.headers = headers;
9146
9194
  const stripeSig = headers["stripe-signature"] || headers["Stripe-Signature"];
9147
9195
  if (stripeSig) {
9148
- if (!mergedConfig.extra) mergedConfig.extra = {};
9149
9196
  mergedConfig.extra.signatureHeader = Array.isArray(stripeSig) ? stripeSig[0] : stripeSig;
9150
9197
  }
9151
9198
  const ckoSig = headers["cko-signature"] || headers["Cko-Signature"];
9152
9199
  if (ckoSig) {
9153
- if (!mergedConfig.extra) mergedConfig.extra = {};
9154
9200
  mergedConfig.extra.signatureHeader = Array.isArray(ckoSig) ? ckoSig[0] : ckoSig;
9155
9201
  }
9156
9202
  const rzpSig = headers["x-razorpay-signature"] || headers["X-Razorpay-Signature"];
9157
9203
  if (rzpSig) {
9158
- if (!mergedConfig.extra) mergedConfig.extra = {};
9159
9204
  mergedConfig.extra.signatureHeader = Array.isArray(rzpSig) ? rzpSig[0] : rzpSig;
9160
9205
  }
9161
9206
  const squareSig = headers["x-square-hmacsha256-signature"] || headers["x-square-signature"];
9162
9207
  if (squareSig) {
9163
- if (!mergedConfig.extra) mergedConfig.extra = {};
9164
9208
  mergedConfig.extra.signatureHeader = Array.isArray(squareSig) ? squareSig[0] : squareSig;
9165
9209
  }
9166
9210
  const payuSig = headers["openpayu-signature"] || headers["OpenPayU-Signature"];
9167
9211
  if (payuSig) {
9168
- if (!mergedConfig.extra) mergedConfig.extra = {};
9169
9212
  mergedConfig.extra.signatureHeader = Array.isArray(payuSig) ? payuSig[0] : payuSig;
9170
9213
  }
9171
9214
  const btSig = headers["bt_signature"];
9172
9215
  const btPayload = headers["bt_payload"];
9173
9216
  if (btSig && btPayload) {
9174
- if (!mergedConfig.extra) mergedConfig.extra = {};
9175
9217
  mergedConfig.extra.btSignature = Array.isArray(btSig) ? btSig[0] : btSig;
9176
9218
  mergedConfig.extra.btPayload = Array.isArray(btPayload) ? btPayload[0] : btPayload;
9177
9219
  }
9220
+ const xenditToken = headers["x-callback-token"] || headers["X-Callback-Token"];
9221
+ if (xenditToken) {
9222
+ mergedConfig.extra.callbackToken = Array.isArray(xenditToken) ? xenditToken[0] : xenditToken;
9223
+ }
9224
+ const dokuSig = headers["signature"] || headers["Signature"];
9225
+ if (dokuSig) {
9226
+ mergedConfig.extra.dokuSignature = Array.isArray(dokuSig) ? dokuSig[0] : dokuSig;
9227
+ }
9228
+ const oyUser = headers["x-oy-username"] || headers["X-Oy-Username"];
9229
+ if (oyUser) {
9230
+ mergedConfig.extra.oyUsername = Array.isArray(oyUser) ? oyUser[0] : oyUser;
9231
+ }
9178
9232
  }
9179
9233
  let providerName = configOverride?.provider || this.provider;
9180
9234
  if (payload) {
@@ -9208,8 +9262,6 @@ var Buayar = class {
9208
9262
  providerName = "adyen";
9209
9263
  } else if (payload.type && payload.data?._links && (payload.type.startsWith("payment_") || payload.type.startsWith("refund_"))) {
9210
9264
  providerName = "checkoutcom";
9211
- } else if (payload.event && payload.payload?.payment?.entity) {
9212
- providerName = "razorpay";
9213
9265
  } else if (payload.type && payload.data?.object?.status && payload.merchant_id) {
9214
9266
  providerName = "square";
9215
9267
  } else if (payload.order && payload.order?.status && payload.order?.extOrderId) {