const dataJson = {"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"} const express = require('express'); const bodyParser = require('body-parser'); const fs = require('fs'); const path = require('path'); const { createVerify } = require('crypto'); const logger = console; // 创建Express应用 const app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); // 加载配置 const configPath = path.join(__dirname, '../config.ini'); const config = fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf8') : null; // 模拟解析配置文件 const PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n" + "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=\n" + "-----END RSA PRIVATE KEY-----\n"; // 从配置文件中获取私钥 // 创建排序后的数据字符串 function createSortedDataString(data) { const validKeys = ['merchantNo', 'merchantOrderNo', 'orderNo', 'currency', 'orderAmount', 'orderFee', 'payModel', 'orderStatus', 'payType']; const sortedData = Object.keys(data) .filter(key => validKeys.includes(key)) .sort() .map(key => `${key}=${data[key]}`) .join('&'); return sortedData; } // 验证Webhook function verifyWebhook(data) { const sign = data.sign; if (!sign) { logger.warn("No signature found in the data"); return { isValid: false, message: "No signature found" }; } delete data.sign; const signStr = createSortedDataString(data); logger.info(`String to be signed: ${signStr}`); // Verify the signature using RSA const verify = createVerify('SHA256'); verify.update(signStr); verify.end(); try { const isVerified = verify.verify(PRIVATE_KEY, sign, 'base64'); if (isVerified) { logger.info("Verification passed"); return { isValid: true, message: "Verification passed" }; } else { logger.warn("Verification failed"); return { isValid: false, message: "Verification failed" }; } } catch (error) { logger.error(`Verification error: ${error.message}`); return { isValid: false, message: `Verification error: ${error.message}` }; } } // 处理Webhook请求 app.post('/webhook', (req, res) => { logger.info("Received a webhook POST request"); const data = req.body.data; if (!data) { logger.error("Invalid data format received"); return res.status(400).json({ status: "error", message: "Invalid data format" }); } logger.info(`Received data: ${JSON.stringify(data, null, 2)}`); const { isValid, message } = verifyWebhook(data); if (isValid) { logger.info("Webhook verified successfully"); res.status(200).json({ status: "success", message }); } else { logger.warn(`Webhook verification failed: ${message}`); res.status(400).json({ status: "error", message }); } }); // 启动服务器 const PORT = 5000; app.listen(PORT, () => { logger.info(`Server is running on http://127.0.0.1:${PORT}`); });