verifyWebhook.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. const fs = require("fs");
  2. const path = require("path");
  3. const { parse } = require("querystring");
  4. const { createVerify, createPrivateKey } = require("crypto");
  5. const NodeRSA = require('node-rsa');
  6. const base64 = require('base-64');
  7. const PRIVATE_KEY =`-----BEGIN RSA PRIVATE KEY-----
  8. MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK/q2uuuf+s4pd2gkVAyhHkpog1o4RL5+Dm2ZOe5i7O/ELKJvj/9JIrNO1abNNuG8g2nvBnOeJ5uii1q83Qy9C4aaey1UjqYd3iVupuO8Xfmr/3sHTec6R8X0HZnuQ/fsU8uREYEQFUfBFcZtiNz2TqXfjJXMXAeTpXc6CbKOLe3AgMBAAECgYAYDVvWSnsJ7apb9Ya4uNd8+3DBNZxEbHIAbgw41Jkhv9doGcYt2I4k/i+FRV5CP56buFnTC3RZcRKqaAuWURsqcnDG8ufFIhoSEiD11FcFrXanFdixfj9gijuPiTE4w9f07eDVEfdQjFMSO8tYDbsMUoaMPUTOoreqyy86uW0G0QJBAN5zaUsxjgtJhqO3OsoHXpu+67bsM2ounuoHWq7KehiVeb9ykrS6quZ1+r5+0SIMEFkKZKbpwfIG+Hi9NII85/ECQQDKctaP1WQzuLQvm97lfQEfgY/JWL9RZuWriGd7fDT7Nrl0FTK5O9q22HvJdwIQktaTOQca28KzHucIxa7ouYInAkB1KehteF5OR52ooRtPyW3lLjvMjr/Nz1xX+yOiKHcCd8g2M8xdcGwPEljM+NKB0kTSAQ1edIR4S3+XaGA9sIKhAkEAsfVaqJry9wgw0/zXZbGJsDFKvLpXiu3BjBReqszXIdDMGr+bk/qKWtpXjhQf64O4PTgPB8wQDTZn7m0fQJH5VwJBAIDnGXiaoMRammmmOl6sYwar8APUMhRkCNqxzwiEokmwRsrR0GKuKtLKpRg/jNAAQbj2ajVihhgR7F3/04kc/jE=
  9. -----END RSA PRIVATE KEY-----`
  10. const PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" + "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv6trrrn/rOKXdoJFQMoR5KaINaOES+fg5tmTnuYuzvxCyib4//SSKzTtWmzTbhvINp7wZzniebootavN0MvQuGmnstVI6mHd4lbqbjvF35q/97B03nOkfF9B2Z7kP37FPLkRGBEBVHwRXGbYjc9k6l34yVzFwHk6V3Ogmyji3twIDAQAB" + "\n-----END PUBLIC KEY-----";
  11. function longDecrypt(privateKey, msg) {
  12. // Format the private key
  13. privateKey = privateKey.match(/.{1,64}/g).join('\n');
  14. privateKey = `-----BEGIN RSA PRIVATE KEY-----\n${privateKey}\n-----END RSA PRIVATE KEY-----`;
  15. // Decode the base64 message
  16. const bufferMsg = Buffer.from(msg, 'base64');
  17. const length = bufferMsg.length;
  18. const defaultLength = 128;
  19. const key = new NodeRSA(privateKey, 'pkcs1');
  20. key.setOptions({ encryptionScheme: 'pkcs1' });
  21. let offset = 0;
  22. let res = [];
  23. while (length - offset > 0) {
  24. if (length - offset > defaultLength) {
  25. res.push(key.decrypt(bufferMsg.slice(offset, offset + defaultLength)));
  26. } else {
  27. res.push(key.decrypt(bufferMsg.slice(offset)));
  28. }
  29. offset += defaultLength;
  30. }
  31. return Buffer.concat(res).toString('utf8');
  32. }
  33. function verifyWebhook() {
  34. const parsedData = {"meta":{"success":true,"code":"0000","message":"Request Success"},"data":{"merchantNo":"AC202299319","merchantOrderNo":"DS202412311005240317","orderNo":"R08OC0241231100525384624557803","currency":"JPY","payType":"JAPAN_PAY","orderAmount":10000,"paidAmount":null,"orderFee":700,"payModel":"BankTransfer","orderStatus":"PENDING","webUrl":null,"page":null,"orderTime":1735610725000,"finishTime":0,"sign":"V0EZCULoPBG7q8CuWxSnAkTnigjPbX49IquVzqH8TZ2Kp+SYJmXAmAWPLKPWWTQdvAw99T3PrkEMmutKfCE2zEay5uKhtHU8BY4T0phLr8cU3G9MTWNjp3AJ/dtJ6nh19/L20vis5anvj0aC4ShnEcIzfVeWtWszT+meu7LC4Js52C9vmGGKtPWUUbD6zV/+3YYnNxf/BIEBLOewWIaHccne6E37wbzjbHWczAPecka/E7KOGPyG2PPa67Y5ixsGUjhSD6RHHjbXKJatD8+vTa4BpwieQ4FZTF1dF2oCWJjVOLiB4ZSwMs4vRf9bb0GhWmJuf1N45eWWJkMRJ+392A==","remark":"","errorMessage":null,"descriptor":null},"sign":"589092dbe5aca882cfcc409d1f868d0e"};
  35. const dataJson = parsedData.data;
  36. console.log("Decoded data:", JSON.stringify(dataJson, null, 2));
  37. // 提取签名
  38. const sign = dataJson.sign;
  39. delete dataJson.sign;
  40. console.log("Signature:", sign);
  41. // 生成待签名的字符串
  42. function createSortedDataString(data) {
  43. const validKeys = [
  44. "merchantNo",
  45. "merchantOrderNo",
  46. "orderNo",
  47. "currency",
  48. "orderAmount",
  49. "orderFee",
  50. "payModel",
  51. "orderStatus",
  52. "payType",
  53. ];
  54. const sortedData = Object.keys(data)
  55. .filter((key) => validKeys.includes(key))
  56. .sort()
  57. .map((key) => `${key}=${data[key]}`)
  58. .join("&");
  59. return sortedData;
  60. }
  61. const signStr = createSortedDataString(dataJson);
  62. console.log("String to be signed:", signStr);
  63. // 验证签名
  64. try {
  65. const verify = createVerify("SHA256");
  66. verify.update(signStr);
  67. verify.end();
  68. // const isVerified = verify.verify(PRIVATE_KEY, sign, "base64");
  69. const isVerified = longDecrypt(PRIVATE_KEY, sign);
  70. console.log(58, isVerified);
  71. if (isVerified) {
  72. console.log("Verification passed");
  73. return true;
  74. } else {
  75. console.log("Verification failed");
  76. return false;
  77. }
  78. } catch (error) {
  79. console.error(`Decryption error: ${error.message}`);
  80. return false;
  81. }
  82. }
  83. verifyWebhook();