修复快手销毁请求验签
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import {
|
||||
buildKuaishouIndustrySignSource,
|
||||
signKuaishouIndustryPayload,
|
||||
verifyKuaishouIndustrySignature,
|
||||
} from './crypto.js'
|
||||
|
||||
const TEST_CONFIG = { signSecret: 'test-secret' } as any
|
||||
|
||||
test('buildKuaishouIndustrySignSource keeps nested eticket fields for destroy-code payload', () => {
|
||||
const source = buildKuaishouIndustrySignSource(
|
||||
{
|
||||
appkey: 'ks-test',
|
||||
param: {
|
||||
oid: '2618901686368642',
|
||||
reason: 'USER_APPLY_REFUND',
|
||||
etickets: [
|
||||
{
|
||||
code: null,
|
||||
goodsValue: 3800,
|
||||
id: 'KSVW9JTD4FZM4VDHKBV',
|
||||
num: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
signMethod: 'MD5',
|
||||
timestamp: 1783497998539,
|
||||
version: '1',
|
||||
},
|
||||
TEST_CONFIG,
|
||||
)
|
||||
|
||||
assert.match(
|
||||
source,
|
||||
/param=\{"etickets":\[\{"code":null,"goodsValue":3800,"id":"KSVW9JTD4FZM4VDHKBV","num":1\}\],"oid":"2618901686368642","reason":"USER_APPLY_REFUND"\}/,
|
||||
)
|
||||
assert.doesNotMatch(source, /"etickets":\[\{\}\]/)
|
||||
})
|
||||
|
||||
test('verifyKuaishouIndustrySignature accepts nested object payload signed by the same canonical source', () => {
|
||||
const payload = {
|
||||
appkey: 'ks-test',
|
||||
param: {
|
||||
oid: '2618901686368642',
|
||||
reason: 'USER_APPLY_REFUND',
|
||||
etickets: [
|
||||
{
|
||||
code: null,
|
||||
goodsValue: 3800,
|
||||
id: 'KSVW9JTD4FZM4VDHKBV',
|
||||
num: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
signMethod: 'MD5',
|
||||
timestamp: 1783497998539,
|
||||
version: '1',
|
||||
}
|
||||
|
||||
const sign = signKuaishouIndustryPayload(payload, 'MD5', TEST_CONFIG)
|
||||
|
||||
assert.equal(verifyKuaishouIndustrySignature({ ...payload, sign }, TEST_CONFIG), true)
|
||||
})
|
||||
@@ -103,8 +103,28 @@ function stringifySignValue(value: unknown) {
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
return JSON.stringify(value, Object.keys(value as Record<string, unknown>).sort())
|
||||
return JSON.stringify(normalizeSignJsonValue(value))
|
||||
}
|
||||
|
||||
return String(value)
|
||||
}
|
||||
|
||||
function normalizeSignJsonValue(value: unknown): unknown {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((item) => normalizeSignJsonValue(item))
|
||||
}
|
||||
|
||||
if (value && typeof value === 'object') {
|
||||
const record = value as Record<string, unknown>
|
||||
const normalized: Record<string, unknown> = {}
|
||||
for (const key of Object.keys(record).sort()) {
|
||||
const current = normalizeSignJsonValue(record[key])
|
||||
if (current !== undefined) {
|
||||
normalized[key] = current
|
||||
}
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user