feat(qqmusic): QQ音乐会员成长值+福利站自动签到(zzc签名对拍验证)
- u6.y.qq.com 协议底座: zzc/time33 与 LDP924/auto-checkin qmcommon.py 逐字节对拍 PASS(6向量) - 续期闭环: QQLogin 换新 key + openid/access_token 二级救活, 缓存存 /ql/data/qqmusic_cache(订阅git免疫) - 任务中心三态机: 签到/挂件/装扮/听书/节目, Y零请求/W直领/N动作, 10006写锁即停 - 福利站全量: 每日签到/礼券/旅程激励/月里程碑/月度好礼/臻享抽奖, 先探后做 - env: SH_QQMUSIC_KEY 多账号(uin#key / cookie串 / 混排), code 1000/2000 归一失效语义 - 播放上报(任务20完整+10)默认关闭, 定时 1 0,6 * * * 双轮
This commit is contained in:
64
qqmusic/test_sign_vector.py
Normal file
64
qqmusic/test_sign_vector.py
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""签名对拍(文件交换版,规避 Windows 子进程控制台编码坑):
|
||||
本文件 = LDP924/auto-checkin qmcommon.py 的 zzc/time33 参考实现,生成期望值 JSON;
|
||||
qqmusic/test_sign_run.js = 被测 Node 模块,读取 JSON 逐条比对并给出 PASS/FAIL。
|
||||
两个实现任何一处不一致都会 MISMATCH —— 这是协议调用可用性的硬门槛。"""
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
from base64 import b64encode
|
||||
from hashlib import sha1
|
||||
|
||||
SCRAMBLE = (89, 39, 179, 150, 218, 82, 58, 252, 177, 52,
|
||||
186, 123, 120, 64, 242, 133, 143, 161, 121, 179)
|
||||
|
||||
|
||||
def time33(s):
|
||||
h = 5381
|
||||
for c in s:
|
||||
h += (h << 5) + ord(c)
|
||||
h &= 0xFFFFFFFF
|
||||
return h & 0x7FFFFFFF
|
||||
|
||||
|
||||
def zzc(payload):
|
||||
h = sha1(payload.encode()).hexdigest().upper()
|
||||
p1 = ''.join(h[i] for i in (23, 14, 6, 36, 16, 7, 19))
|
||||
p2 = ''.join(h[i] for i in (16, 1, 32, 12, 19, 27, 8, 5))
|
||||
p3 = bytes(v ^ int(h[i * 2:i * 2 + 2], 16) for i, v in enumerate(SCRAMBLE))
|
||||
mid = b64encode(p3).decode().replace('\\', '').replace('/', '').replace('+', '').replace('=', '')
|
||||
return ('zzc' + p1 + mid + p2).lower()
|
||||
|
||||
|
||||
PAYLOADS = [
|
||||
'{"comm":{"g_tk":962138355,"uin":123456789,"format":"json","inCharset":"utf-8","outCharset":"utf-8","notice":0,"platform":"h5","needNewCode":1,"ct":23,"cv":0},"req_0":{"module":"music.lvz.LevelConfigSvr","method":"GetState","param":{}}}',
|
||||
'{"comm":{},"req_0":{"module":"m","method":"x","param":{}}}',
|
||||
'x',
|
||||
'a' * 10000,
|
||||
'',
|
||||
'unicode测试中文签名输入⏰',
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
expect = {
|
||||
'time33': time33('Q_H_L_testkey1234567890'),
|
||||
'cases': [{'payload': p, 'zzc': zzc(p), 'len': len(zzc(p))} for p in PAYLOADS],
|
||||
}
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
expect_path = os.path.join(here, 'test_sign_expect.json')
|
||||
with open(expect_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(expect, f, ensure_ascii=False)
|
||||
out = subprocess.run(['node', os.path.join(here, 'test_sign_run.js')],
|
||||
capture_output=True, text=True, shell=False, cwd=here,
|
||||
encoding='utf-8', errors='replace')
|
||||
sys.stdout.write(out.stdout)
|
||||
if out.stderr:
|
||||
sys.stderr.write(out.stderr)
|
||||
return out.returncode
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user