#!/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())