Partner.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import crypto from "crypto";
  2. import axios from "axios";
  3. import dotenv from 'dotenv';
  4. import path from "path";
  5. import { fileURLToPath } from "url";
  6. import { getData } from "../libs/cache.js";
  7. import Logs from "../libs/logs.js";
  8. dotenv.config();
  9. const __filename = fileURLToPath(import.meta.url);
  10. const __dirname = path.dirname(__filename);
  11. const PARTNER_DATA_FILE = path.join(__dirname, '../data/partner.json');
  12. /**
  13. * Partner API environment variables
  14. */
  15. const PARTNER_API_BASE = 'https://dev.api.ppai.win/api/p/gate';
  16. const { PARTNER_APP_ID, PARTNER_APP_KEY } = process.env;
  17. const PARTNER_DATA = {};
  18. /**
  19. * 加载本地数据
  20. */
  21. const loadLocalData = async () => {
  22. const data = await getData(PARTNER_DATA_FILE);
  23. Object.assign(PARTNER_DATA, data);
  24. }
  25. loadLocalData().catch(error => {
  26. Logs.out('not load partner data', error.message);
  27. });
  28. /**
  29. * 生成SHA256
  30. */
  31. const generateSHA256 = (message) => {
  32. return crypto.createHash('sha256').update(message).digest('hex');
  33. }
  34. /**
  35. * 生成随机 nonce
  36. */
  37. const generateNonce = () => {
  38. return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
  39. }
  40. /**
  41. * 生成签名
  42. */
  43. const generateSignature = (appKey, action, timestamp, nonce) => {
  44. return generateSHA256(`${appKey}${action}${timestamp}${nonce}`);
  45. }
  46. /**
  47. * 获取时间戳 秒级
  48. */
  49. const getTimestamp = () => {
  50. return Math.floor(Date.now() / 1000);
  51. }
  52. /**
  53. * 时间窗口校验
  54. */
  55. const isTimestampValid = (timestamp, window=300) => {
  56. const now = getTimestamp();
  57. return Math.abs(now - timestamp) <= window;
  58. }
  59. /**
  60. * 请求Partner数据接口
  61. */
  62. export const requestData = async (action, data) => {
  63. const timestamp = getTimestamp();
  64. const nonce = generateNonce();
  65. const sign = generateSignature(PARTNER_APP_KEY, action, timestamp, nonce);
  66. const appid = PARTNER_APP_ID;
  67. const requestData = { action, appid, nonce, sign, timestamp };
  68. if (Object.keys(data).length > 0) {
  69. requestData.params = data;
  70. }
  71. return axios.post(PARTNER_API_BASE, requestData).then(res => res.data);
  72. }
  73. export const updateSolutions = async (solutions) => {
  74. if (process.env.NODE_ENV == 'development') {
  75. return Promise.resolve({ message: 'development mode' });
  76. }
  77. return requestData('opps.soccer', solutions);
  78. }
  79. /**
  80. * 接收Partner数据
  81. */
  82. export const receivePartnerData = async (data) => {
  83. const { action, appid, nonce, sign, timestamp, params } = data;
  84. if (!isTimestampValid(timestamp)) {
  85. return Promise.reject(new Error('timestamp invalid'));
  86. }
  87. const partnerData = PARTNER_DATA[appid];
  88. if (!partnerData) {
  89. return Promise.reject(new Error('appid invalid'));
  90. }
  91. const newSign = generateSignature(partnerData.appkey, action, timestamp, nonce);
  92. if (newSign !== sign) {
  93. return Promise.reject(new Error('sign invalid'));
  94. }
  95. return Promise.resolve({ action, params });
  96. }
  97. export default { updateSolutions, receivePartnerData };