diff --git a/.pr_body.md b/.pr_body.md new file mode 100644 index 0000000..9e39475 --- /dev/null +++ b/.pr_body.md @@ -0,0 +1,34 @@ +## Summary + +`unlock_wallet()` in `scripts/kya_lib.py` has a broken validation check on the JSON-decode fallback path: + +```python +token = out if SIG_RE.pattern and out else "" +``` + +`SIG_RE.pattern` is the *pattern string* of the compiled regex (`"^0x[a-fA-F0-9]{130}$"`), so it is **always truthy**. The expression reduces to `token = out if out else ""`, meaning the fallback path accepts **any non-empty stdout** as a session token — defeating the validation it was meant to provide. A malformed `awp-wallet unlock` output would become a fake token that flows through `os.environ["AWP_WALLET_TOKEN"]` into every subsequent command. + +## Fix + +Current `awp-wallet` (≥ 0.17.0 per SKILL.md) always emits JSON on unlock, so the legacy text fallback is dead code. Replace it with an empty-string sentinel so the existing + +```python +if not token: + die(f"awp-wallet unlock returned no token (stdout={out!r})") +``` + +check triggers cleanly, instead of silently admitting garbage. + +## Diff + +```diff + try: + token = json.loads(out).get("token", "") + except json.JSONDecodeError: +- # 一些老版本支持 `unlock --raw` 直接打印 token;兼容一下 +- token = out if SIG_RE.pattern and out else "" ++ # awp-wallet emits JSON-only now; no legacy text fallback ++ token = "" +``` + +No behaviour change for the common path (successful JSON parse). Only tightens the malformed-output path, which would have previously leaked invalid data forward. diff --git a/scripts/kya_lib.py b/scripts/kya_lib.py index 4851264..c55612a 100644 --- a/scripts/kya_lib.py +++ b/scripts/kya_lib.py @@ -28,7 +28,7 @@ import time import urllib.error import urllib.request -from typing import Any, Optional +from typing import Any, NoReturn, Optional # ── 常量 ──────────────────────────────────────────────── @@ -61,7 +61,7 @@ def step(name: str, **fields: Any) -> None: print(json.dumps(payload, ensure_ascii=False), file=sys.stderr, flush=True) -def die(msg: str, code: int = 1) -> "NoReturn": # type: ignore[name-defined] +def die(msg: str, code: int = 1) -> NoReturn: """打印错误并退出。""" print(json.dumps({"error": msg}, ensure_ascii=False), file=sys.stderr, flush=True) sys.exit(code) diff --git a/scripts/sign-kyc.py b/scripts/sign-kyc.py index 4bb9ba4..205eba8 100644 --- a/scripts/sign-kyc.py +++ b/scripts/sign-kyc.py @@ -112,7 +112,7 @@ def main() -> None: step("kyc.session_created", session_id=session_id) print("\n────── KYC verification ──────", flush=True) - print(f"Open this URL in any browser to complete Didit:", flush=True) + print("Open this URL in any browser to complete Didit:", flush=True) print(verification_url, flush=True) print("──────────────────────────────", flush=True) diff --git a/scripts/sign.py b/scripts/sign.py index aaeee93..ead6953 100644 --- a/scripts/sign.py +++ b/scripts/sign.py @@ -21,7 +21,6 @@ from __future__ import annotations -import argparse import json import shutil import subprocess