feat(xm): 喜马拉雅平台接入——匿名搜索/专辑/免费曲直链(hdaa xm-sign+AES-ECB 解密)、cookie 绑定解锁付费
This commit is contained in:
1 parent
44852864e2
commit
5a9915b74c
8 files changed
+717
No files matched your search
@@ -0,0 +1,53 @@
|
||||
// 喜马拉雅 xm-sign 生成 —— 移植 Ximalaya-Downloader-Next / easy-sign 的 du_web_sdk 签名链
|
||||
// 协议:device_info → JSON → URL 编码字节 → zlib(level 6) → AES-128-ECB(PKCS7, KEY) →
|
||||
// POST https://hdaa.shuzilm.cn/report?v=1.2.0&e=1&c=1&r=<uuid>(octet-stream)→
|
||||
// Base64 响应 → AES-ECB 解密 → JSON 取 cadd/sid → xm-sign = "{cadd}&&{sid}"
|
||||
// KEY 为 du_web_sdk _getDeviceKey(0) 的硬编码密钥;每次签名都重新上报(不缓存)。
|
||||
// 模板为纯 ASCII(Base64/十六进制字段),latin1 取字节与参考实现的 charCode 语义一致。
|
||||
|
||||
import zlib from 'node:zlib'
|
||||
import crypto from 'node:crypto'
|
||||
import { httpFetch } from '../request.ts'
|
||||
import { DEVICE_INFO } from './deviceInfo.ts'
|
||||
|
||||
const SIGN_KEY = 'm9ZtRrz:qujT8@da'
|
||||
const REPORT_URL = 'https://hdaa.shuzilm.cn/report?v=1.2.0&e=1&c=1&r='
|
||||
// 与 device_info.ew1.yV2(Chrome 125 模板)保持一致
|
||||
export const XM_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
|
||||
|
||||
const aesEcb = (data: Buffer, decrypt: boolean) => {
|
||||
const key = Buffer.from(SIGN_KEY, 'utf8')
|
||||
const cipher = decrypt
|
||||
? crypto.createDecipheriv('aes-128-ecb', key, null)
|
||||
: crypto.createCipheriv('aes-128-ecb', key, null)
|
||||
return Buffer.concat([cipher.update(data), cipher.final()])
|
||||
}
|
||||
|
||||
/** 生成 xm-sign(形如 "cadd&&sid");每次调用重新上报设备指纹 */
|
||||
export const makeXmSign = async(): Promise<string> => {
|
||||
const info = { ...DEVICE_INFO, Zf5: Date.now() }
|
||||
const compressed = zlib.deflateSync(Buffer.from(JSON.stringify(info), 'latin1'), { level: 6 })
|
||||
const payload = aesEcb(compressed, false)
|
||||
|
||||
const { statusCode, body, raw } = await httpFetch(`${REPORT_URL}${crypto.randomUUID()}`, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'User-Agent': XM_UA,
|
||||
Host: 'hdaa.shuzilm.cn',
|
||||
},
|
||||
body: payload,
|
||||
timeout: 15000,
|
||||
}).promise as any
|
||||
const respText = raw ? raw.toString('utf8') : String(body ?? '')
|
||||
if (statusCode != 200) throw new Error(`xm-sign 上报失败: HTTP ${statusCode}`)
|
||||
|
||||
const decrypted = aesEcb(Buffer.from(respText, 'base64'), true).toString('utf8')
|
||||
const obj = JSON.parse(decrypted)
|
||||
const cadd = String(obj.cadd || '')
|
||||
const sid = String(obj.sid || '')
|
||||
if (!cadd || !sid) throw new Error('xm-sign 上报响应缺少 cadd/sid')
|
||||
return `${cadd}&&${sid}`
|
||||
}
|
||||
|
||||
export default { makeXmSign, XM_UA }
|
||||
Reference in new issue
Block a user