q-koa 13.8.37 → 13.8.38

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.
@@ -118,19 +118,29 @@ const validateUnionNotifySign = ({ notifyData, signType, publicKey, md5Key }) =>
118
118
  return expected === sign.toUpperCase()
119
119
  }
120
120
 
121
- // 默认 RSA-SHA1(与 allinpay.js verifySign 保持一致)
121
+ // RSA 双算法兜底:先试 RSA-SHA256(通联 2048-bit 新平台证书),失败再退 RSA-SHA1(1024-bit 老平台证书)
122
+ // 两份证书的签名/密钥长度天然不同,1024-bit 公钥永远验不出 256 字节签名,2048-bit 公钥也验不出 128 字节签名,
123
+ // 所以顺序上即使「错算法试一次」也不会误判,只是多一次 CPU crypto 调用(微秒级,可忽略)。
122
124
  if (!publicKey) return false
123
- try {
124
- // 兼容两种配置格式:已经带 PEM 头尾的直接用;纯 base64 body 再包裹头尾
125
- const pem = String(publicKey).includes('-----BEGIN')
126
- ? String(publicKey)
127
- : `-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`
128
- const verify = crypto.createVerify('RSA-SHA1')
129
- verify.update(signStr, 'utf8')
130
- return verify.verify(pem, sign, 'base64')
131
- } catch (e) {
132
- return false
125
+ // PEM 标准化:无头尾则包 SPKI 头尾 + 内容单换行;已有头尾若一行无换行,补换行让 OpenSSL 稳定识别
126
+ let pem = String(publicKey)
127
+ if (!pem.includes('-----BEGIN')) {
128
+ pem = `-----BEGIN PUBLIC KEY-----\n${pem}\n-----END PUBLIC KEY-----`
129
+ } else if (!pem.includes('\n')) {
130
+ pem = pem
131
+ .replace('-----BEGIN PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----\n')
132
+ .replace('-----END PUBLIC KEY-----', '\n-----END PUBLIC KEY-----')
133
+ }
134
+ for (const alg of ['RSA-SHA256', 'RSA-SHA1']) {
135
+ try {
136
+ const verify = crypto.createVerify(alg)
137
+ verify.update(signStr, 'utf8')
138
+ if (verify.verify(pem, sign, 'base64')) return true
139
+ } catch (e) {
140
+ // key 跟算法不兼容(比如 1024-bit 公钥试 SHA256 在极旧 Node 下可能 throw),静默下一轮
141
+ }
133
142
  }
143
+ return false
134
144
  }
135
145
 
136
146
  const check = ({ timestamp, nonce, signature, token }) => {
@@ -67,10 +67,15 @@ class AllinPay {
67
67
  const signStr = this.buildSignStr(params)
68
68
 
69
69
  if (this.signType === 'RSA') {
70
- // 兼容三种配置格式:已经带 PEM 头尾直接使用;否则默认包 PKCS#1 (BEGIN RSA PRIVATE KEY) 头尾
70
+ // PEM 标准化:已有头尾直接用(缺换行补换行);否则默认包 PKCS#1 (BEGIN RSA PRIVATE KEY) 头尾
71
71
  let pem
72
- if (String(this.privateKey).includes('-----BEGIN')) {
73
- pem = String(this.privateKey)
72
+ const raw = String(this.privateKey)
73
+ if (raw.includes('-----BEGIN')) {
74
+ pem = raw.includes('\n')
75
+ ? raw
76
+ : raw
77
+ .replace(/-----(BEGIN[^-]+KEY)-----/, '-----$1-----\n')
78
+ .replace(/-----(END[^-]+KEY)-----/, '\n-----$1-----')
74
79
  } else {
75
80
  pem = `-----BEGIN RSA PRIVATE KEY-----\n${this.privateKey}\n-----END RSA PRIVATE KEY-----`
76
81
  }
@@ -99,15 +104,24 @@ class AllinPay {
99
104
 
100
105
  const signStr = this.buildSignStr(paramsCopy)
101
106
 
102
- // 兼容两种配置格式:已经带 PEM 头尾的直接用;纯 base64 body 再包裹头尾
103
- const pem = String(this.publicKey).includes('-----BEGIN')
104
- ? String(this.publicKey)
105
- : `-----BEGIN PUBLIC KEY-----\n${this.publicKey}\n-----END PUBLIC KEY-----`
106
- const verify = crypto.createVerify('RSA-SHA1')
107
- verify.update(signStr, 'utf8')
108
- const result = verify.verify(pem, sign, 'base64')
109
-
110
- return result
107
+ // PEM 标准化:无头尾则包 SPKI 头尾 + 内容单换行;已有头尾若一行无换行补换行
108
+ let pem = String(this.publicKey)
109
+ if (!pem.includes('-----BEGIN')) {
110
+ pem = `-----BEGIN PUBLIC KEY-----\n${pem}\n-----END PUBLIC KEY-----`
111
+ } else if (!pem.includes('\n')) {
112
+ pem = pem
113
+ .replace('-----BEGIN PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----\n')
114
+ .replace('-----END PUBLIC KEY-----', '\n-----END PUBLIC KEY-----')
115
+ }
116
+ // RSA 双算法兜底:先 SHA256(新 2048-bit 证书),失败再 SHA1(老 1024-bit 证书)
117
+ for (const alg of ['RSA-SHA256', 'RSA-SHA1']) {
118
+ try {
119
+ const verify = crypto.createVerify(alg)
120
+ verify.update(signStr, 'utf8')
121
+ if (verify.verify(pem, sign, 'base64')) return true
122
+ } catch (e) {}
123
+ }
124
+ return false
111
125
  }
112
126
 
113
127
  async request(url, params) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q-koa",
3
- "version": "13.8.37",
3
+ "version": "13.8.38",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {