#!/usr/bin/env node // /oapi 签名票据生成器(对齐 yh-platform-net SignUtil.SignRequest / SignCanonical 协议) // // 协议:signature = Base64(HmacSHA256(METHOD + "\n" + path[?sortedQuery] + "\n" + timestamp, secret)) // - query 按 k=v 整体字典序排序后拼接参与签名 // - timestamp 为毫秒级 Unix 时间戳(服务端校验 5 分钟窗口) // // 用法: // node scripts/oapi-sign.js [METHOD] [path?query] // node scripts/oapi-sign.js --curl POST /oapi/print/submit # 输出可直接复制的 curl 命令 // // 密钥来源(优先级):环境变量 APP_KEY / APP_SECRET → 文件默认值(开发联调密钥) // 生产环境务必通过环境变量注入,勿提交真实密钥。 const crypto = require('crypto'); const APP_KEY = process.env.APP_KEY || '100002'; const APP_SECRET = process.env.APP_SECRET || '2314a3b158b24a838b2b9b69fd3db118'; // 排序 query(对齐 SignCanonical.SortRawQuery:k=v 整体排序,空值保留 = 号) function sortQuery(raw) { if (!raw) return ''; return raw.split('&').filter(Boolean).map(p => { const i = p.indexOf('='); return (i < 0 ? p : p.slice(0, i)) + '=' + (i < 0 ? '' : p.slice(i + 1)); }).sort().join('&'); } function sign(method, pathWithQuery, ts) { const qi = pathWithQuery.indexOf('?'); const target = qi >= 0 ? pathWithQuery.slice(0, qi) + '?' + sortQuery(pathWithQuery.slice(qi + 1)) : pathWithQuery; const source = method.toUpperCase() + '\n' + target + '\n' + ts; const sig = crypto.createHmac('sha256', APP_SECRET).update(source, 'utf8').digest('base64'); return { ts, target, signature: sig }; } const args = process.argv.slice(2); let method = 'GET'; let pathWithQuery = '/oapi/hello'; let curlMode = false; for (let i = 0; i < args.length; i++) { const a = args[i]; if (a === '--curl') { curlMode = true; continue; } if (!/^-/.test(a)) { if (method === 'GET' && !/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)$/i.test(a) && !a.startsWith('/')) { // 第一个非选项参数若不像 METHOD 也不像路径,则视为路径 pathWithQuery = a; } else if (a.startsWith('/')) { pathWithQuery = a; } else { method = a; } } } const { ts, target, signature } = sign(method, pathWithQuery, Date.now().toString()); if (curlMode) { const u = target.replace(/^\//, ''); console.log(`curl -i -X ${method.toUpperCase()} "http://localhost:PORT/${u}" \\`); console.log(` -H "X-App-Key: ${APP_KEY}" \\`); console.log(` -H "X-Timestamp: ${ts}" \\`); console.log(` -H "X-Signature: ${signature}"`); } else { console.log(JSON.stringify({ appKey: APP_KEY, method, target, ts, signature, curl: [ '-H', `X-App-Key: ${APP_KEY}`, '-H', `X-Timestamp: ${ts}`, '-H', `X-Signature: ${signature}` ].join(' ') }, null, 2)); }