ksjsb/tests/test_h5_kws.py
2026-07-30 20:25:56 +08:00

134 lines
5.3 KiB
Python

import unittest
import shutil
from core.h5_kws import (
build_h5_kws_script_ticket,
build_h5_kws_config_request_data,
build_h5_kws_default_ticket,
decrypt_h5_kws_config_response_data_rsp,
run_h5_kws_sign_script,
webweapon_aes_decrypt_b64,
)
class H5KwsTests(unittest.TestCase):
@unittest.skipIf(shutil.which("node") is None, "Node.js runner not available")
def test_kws_sign_script_runner_matches_stable_callback_code(self):
"""复现 KWS signUrl 脚本加载后通过 kwscb 交出的本地 code。"""
code = run_h5_kws_sign_script(timeout=10)
self.assertEqual(
code,
"04dd303d63222chdfec0087d058fb1c4c5f2eb16eefgce98b2a503578e5f8433",
)
def test_kws_script_ticket_uses_server_sec_token_and_script_code(self):
ticket = build_h5_kws_script_ticket(
sec_token="S" * 88,
kwscode="04dd303d63222chdfec0087d058fb1c4c5f2eb16eefgce98b2a503578e5f8433",
)
self.assertEqual(
ticket,
{
"kwpsecproductname": "kuaishou-growth",
"kwssectoken": "S" * 88,
"kwscode": "04dd303d63222chdfec0087d058fb1c4c5f2eb16eefgce98b2a503578e5f8433",
},
)
def test_default_ticket_matches_web_bundle_sample(self):
"""复现 WebWeapon `getDefaultData(true)` 的本地 fallback 票据。"""
ticket = build_h5_kws_default_ticket(
url=(
"https://nebula.kuaishou.com/nebula/task/earning?"
"layoutType=4&source=bottom_guide_first&extra=abc"
),
did="ANDROID_0123456789abcdef",
now_ms=1780000000123,
fingerprint_nonce="AbCdEf12",
sec_token="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB",
)
self.assertEqual(ticket.kwpsecproductname, "kuaishou-growth")
self.assertEqual(ticket.kwssectoken, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB")
self.assertEqual(
ticket.kwfv1,
"KQKRjWEINlzEI07iMa8YrvXGWc4qQ2YMsjv4wGL2oLDzOX3k0vIz1mXqAtSlzbvkju0AoWF93jjHXryshL/TDO0VJp/Lota4HFS2Mi5xjOejJCLcEhKThUOWDhQwAGt6BG6mZ0U20xRPtGw3KZrazWgQB6/GztmjF6KxyG5emvHszKVkpm3X5J93BHDdQ3W41Co2/U4S0E86F1q0zW/cyrCwF==",
)
self.assertEqual(
ticket.kwscode,
"K8ZTkWg+lUrqr/+G/DimeUiuHJqKK49sakhu1xkYvFmL7eXw/X0/ikDZVqiPY76dYsTargl4pE6Y6DQay4/0WM9i2PUZz6UITH0zu1YaBVY1JsgUuginAF/E2gZ7rZUcs2JtpERewBFnaT9B0kPW6o5vXmoZ48lifl/l+78Jo7McWyVS1oAr3z793qrkUv01BG0poEd2k90MUgASxjumrZHQS==",
)
self.assertEqual(ticket.kww, ticket.kwfv1)
self.assertEqual(len(ticket.kwfv1), 219)
self.assertEqual(len(ticket.kwscode), 219)
def test_default_ticket_truncates_url_like_encode_uri(self):
ticket = build_h5_kws_default_ticket(
url="https://nebula.kuaishou.com/a b?x=1&y=中文" + "z" * 90,
did="ANDROID_0123456789abcdef",
now_ms=1780000000123,
fingerprint_nonce="AbCdEf12",
sec_token="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB",
)
self.assertIn("%20", ticket.fingerprint_plain)
self.assertIn("%E4%B8%AD%E6%96%87", ticket.fingerprint_plain)
encoded_url = ticket.fingerprint_plain.split("|", 1)[0]
self.assertLessEqual(len("https://nebula.kuaishou.com/a b?x=1&y=中文" + "z" * 90), 160)
self.assertTrue(encoded_url.startswith("https://nebula.kuaishou.com/a%20b?x=1&y="))
def test_config_request_data_matches_webweapon_aes_cbc_sample(self):
request = build_h5_kws_config_request_data(
did="ANDROID_0123456789abcdef",
ts_ms=1780000000123,
)
self.assertEqual(request.product_name, "kuaishou-growth")
self.assertEqual(request.ts, 1780000000123)
self.assertEqual(
request.plain,
(
'{"productName":"kuaishou-growth","ts":1780000000123,'
'"did":"ANDROID_0123456789abcdef"}'
),
)
self.assertEqual(
request.data,
(
"1gCA6FEVQdV1z+g5/OHPFHQhSPtfefhe159CsssADX42V2QfWZ3GbHoE/"
"4/QHLX6YvQ4tHJL9iMgRQSVQNBbxgH7MfSpWk5mt8mPG4/GdzHy1QQ"
"tUJOWB/vFAodCz+wX"
),
)
self.assertEqual(request.body(), {"data": request.data})
def test_config_response_data_rsp_decrypts_webweapon_config(self):
data_rsp = (
"In+WxaasWqdkyNTjF1LD39c5IFwB+VbXF6HHmrBh2/WEAjVtlI9JWGXRsS"
"kun/BRh3XRJLkB8iq8vroBqF33wHdJd/34K3a7bavpQFBOvDBaOY9wtUQ"
"bBbXs+y7JIrarlK4iD1Og6JGNZSvyPm+AwzN28v+foKtnUEA4cGTbYJw"
"5g7TdUtw6h0wtdmNlCn6km9hvsoHOC6FcXBoU1lK5I3vuwAa3bqvLlYQ"
"RKYwm9Cc="
)
config = decrypt_h5_kws_config_response_data_rsp(data_rsp)
self.assertEqual(config["fpUrl"], "https://gdfp.gifshow.com/s/w/fp.js")
self.assertEqual(config["signUrl"], "https://gdfp.gifshow.com/s/w/sign.js")
self.assertEqual(
config["secToken"],
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB",
)
def test_webweapon_aes_decrypt_rejects_bad_padding(self):
with self.assertRaises(ValueError):
webweapon_aes_decrypt_b64("AAAAAAAAAAAAAAAAAAAAAA==")
if __name__ == "__main__":
unittest.main()