mirror of
https://github.com/happycola233/tchMaterial-parser.git
synced 2026-10-18 14:34:22 +08:00
e87c6a193e
保存时必须提供 access_token、mac_key、diff,格式错误会提示失败;留空仍可清除。 旧版只存 Access Token 时,设置窗口回填为三项 JSON。
112 lines
4.7 KiB
Python
112 lines
4.7 KiB
Python
# 对照官网 UC SDK 的签名原文与凭据解析。合成 fixture,不要把真实 Token 写进仓库。
|
|
import json
|
|
import unittest
|
|
|
|
from src.tchmaterial_parser.auth import (
|
|
TokenCredentials,
|
|
TokenInputError,
|
|
build_nd_auth,
|
|
format_token_json,
|
|
parse_token_input,
|
|
sign_mac,
|
|
signature_string,
|
|
)
|
|
|
|
|
|
class ParseTokenInputTest(unittest.TestCase):
|
|
def test_reads_json_credentials(self) -> None:
|
|
raw = json.dumps({ "access_token": "tok", "mac_key": "key", "diff": 227 })
|
|
self.assertEqual(parse_token_input(raw), TokenCredentials("tok", "key", 227))
|
|
|
|
def test_reads_pretty_printed_json(self) -> None:
|
|
raw = format_token_json("tok", "key", 227)
|
|
self.assertEqual(parse_token_input(raw), TokenCredentials("tok", "key", 227))
|
|
|
|
def test_reads_json_string_wrapper(self) -> None:
|
|
inner = json.dumps({ "access_token": "tok", "mac_key": "key", "diff": 0 })
|
|
self.assertEqual(parse_token_input(json.dumps(inner)), TokenCredentials("tok", "key", 0))
|
|
|
|
def test_accepts_numeric_string_diff(self) -> None:
|
|
raw = json.dumps({ "access_token": "tok", "mac_key": "key", "diff": "227" })
|
|
self.assertEqual(parse_token_input(raw), TokenCredentials("tok", "key", 227))
|
|
|
|
def test_rejects_raw_access_token(self) -> None:
|
|
with self.assertRaises(TokenInputError):
|
|
parse_token_input("abc123")
|
|
|
|
def test_empty_input_clears_credentials(self) -> None:
|
|
self.assertEqual(parse_token_input(" "), TokenCredentials(""))
|
|
|
|
def test_rejects_json_missing_fields(self) -> None:
|
|
with self.assertRaises(TokenInputError):
|
|
parse_token_input('{"access_token":"tok","mac_key":"key"}')
|
|
with self.assertRaises(TokenInputError):
|
|
parse_token_input('{"mac_key":"key","diff":0}')
|
|
|
|
def test_rejects_empty_mac_key(self) -> None:
|
|
with self.assertRaises(TokenInputError):
|
|
parse_token_input(json.dumps({ "access_token": "tok", "mac_key": "", "diff": 0 }))
|
|
|
|
def test_rejects_nested_local_storage_blob(self) -> None:
|
|
raw = json.dumps({ "value": json.dumps({ "access_token": "tok", "mac_key": "key", "diff": 1 }) })
|
|
with self.assertRaises(TokenInputError):
|
|
parse_token_input(raw)
|
|
|
|
def test_format_token_json_backfills_old_fields(self) -> None:
|
|
self.assertEqual(
|
|
json.loads(format_token_json("old-token", None, 0)),
|
|
{ "access_token": "old-token", "mac_key": "", "diff": 0 },
|
|
)
|
|
|
|
|
|
class BuildNdAuthTest(unittest.TestCase):
|
|
def test_falls_back_to_placeholder_without_mac_key(self) -> None:
|
|
self.assertEqual(
|
|
build_nd_auth("https://r1-ndr-private.ykt.cbern.com.cn/book.pdf", access_token="tok"),
|
|
'MAC id="tok",nonce="0",mac="0"',
|
|
)
|
|
self.assertEqual(
|
|
build_nd_auth("https://example.com/book.pdf"),
|
|
'MAC id="0",nonce="0",mac="0"',
|
|
)
|
|
|
|
def test_matches_official_uc_sdk_signature(self) -> None:
|
|
# 查询串保留;百分号编码的中文路径先解码。期望值由独立 HMAC 预先算好,避免测试自己测自己。
|
|
cases = [
|
|
(
|
|
"GET",
|
|
"https://example.com/v1/users/1?with_ext=true",
|
|
"1:ABCDEFGH",
|
|
"1:ABCDEFGH\nGET\n/v1/users/1?with_ext=true\nexample.com\n",
|
|
"VELg/RgBxeRZJWpku3Ggvkqu18Czem4bYh3D/8r6URA=",
|
|
),
|
|
(
|
|
"GET",
|
|
"https://r1-ndr-private.ykt.cbern.com.cn/edu_product/esp/assets/demo.pkg/ebook_mapping.txt",
|
|
"2:ABCDEFGH",
|
|
"2:ABCDEFGH\nGET\n/edu_product/esp/assets/demo.pkg/ebook_mapping.txt\nr1-ndr-private.ykt.cbern.com.cn\n",
|
|
"n8yszXRHbMEcmrKlNUU0e5ZQak1TO8j1j8GGR8Gkanc=",
|
|
),
|
|
(
|
|
"GET",
|
|
"https://r1-ndr-private.ykt.cbern.com.cn/edu_product/esp/assets/demo.pkg/%E4%B8%AD%E6%96%87%20%E6%95%99%E6%9D%90.pdf",
|
|
"3:ABCDEFGH",
|
|
"3:ABCDEFGH\nGET\n/edu_product/esp/assets/demo.pkg/中文 教材.pdf\nr1-ndr-private.ykt.cbern.com.cn\n",
|
|
"GNgACOhD4wact4qOSsix4gsp9X3oPTX6/Ct0FGFx9II=",
|
|
),
|
|
]
|
|
mac_key = "test-mac-key"
|
|
for method, url, nonce, expect_text, expect_mac in cases:
|
|
with self.subTest(url=url):
|
|
text = signature_string(url, method, nonce)
|
|
self.assertEqual(text, expect_text)
|
|
self.assertEqual(sign_mac(text, mac_key), expect_mac)
|
|
self.assertEqual(
|
|
build_nd_auth(url, method, "tok", mac_key, nonce=nonce),
|
|
f'MAC id="tok",nonce="{nonce}",mac="{expect_mac}"',
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|