134 lines
5.3 KiB
Python
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()
|