From bb02b33c488c8672b43596bbb3cba8d78ca01f6f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 16:17:34 +0000 Subject: [PATCH] refactor: harden registration runtime --- .../workflows/temp-remaining-review-fixes.yml | 30 ---- config.example.json | 5 +- grok_register_ttk.py | 45 +++++- tools/apply_remaining_review_fixes.py | 149 ------------------ 4 files changed, 44 insertions(+), 185 deletions(-) delete mode 100644 .github/workflows/temp-remaining-review-fixes.yml delete mode 100644 tools/apply_remaining_review_fixes.py diff --git a/.github/workflows/temp-remaining-review-fixes.yml b/.github/workflows/temp-remaining-review-fixes.yml deleted file mode 100644 index 30e0cfe..0000000 --- a/.github/workflows/temp-remaining-review-fixes.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Temporary remaining review fixes - -on: - push: - branches: [main] - paths: - - tools/apply_remaining_review_fixes.py - -permissions: - contents: write - -jobs: - apply: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Apply remaining review fixes - run: python tools/apply_remaining_review_fixes.py - - name: Commit fixes and remove temporary files - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git rm -f tools/apply_remaining_review_fixes.py .github/workflows/temp-remaining-review-fixes.yml - git add -A - if git diff --cached --quiet; then - echo "No changes to commit" - else - git commit -m "refactor: harden registration runtime" - git push - fi diff --git a/config.example.json b/config.example.json index 98e9f7f..9d111a7 100755 --- a/config.example.json +++ b/config.example.json @@ -35,5 +35,8 @@ "defaultDomains": "example.com", "email_provider": "cloudflare", "yyds_api_key": "", - "yyds_jwt": "" + "yyds_jwt": "", + "cpa_oidc_request_timeout_sec": 15, + "cpa_oidc_poll_timeout_sec": 15, + "grok2api_allow_legacy_full_save": false } diff --git a/grok_register_ttk.py b/grok_register_ttk.py index 48ba4e7..ee35fba 100755 --- a/grok_register_ttk.py +++ b/grok_register_ttk.py @@ -94,6 +94,10 @@ DEFAULT_CONFIG = { "cpa_oidc_request_timeout_sec": 15, "cpa_oidc_poll_timeout_sec": 15, "grok2api_allow_legacy_full_save": False, + "email_provider": "duckmail", + "yyds_api_key": "", + "yyds_jwt": "", + "defaultDomains": "", } config = DEFAULT_CONFIG.copy() @@ -188,6 +192,34 @@ def validate_config(raw): if value not in allowed: raise ConfigError(f"配置项 {key} 的值无效: {value!r}; 允许值: {sorted(allowed)}") cfg[key] = value + + api_path_keys = { + "cloudflare_path_domains", "cloudflare_path_accounts", + "cloudflare_path_token", "cloudflare_path_messages", + "cloudmail_path_messages", + } + for key in api_path_keys: + value = cfg[key] + if value and not value.startswith("/"): + value = "/" + value + cfg[key] = value + + url_keys = { + "cloudflare_api_base", "cloudmail_api_base", + "grok2api_remote_base", "cpa_base_url", + } + for key in url_keys: + value = cfg[key] + if not value: + continue + parsed = urllib.parse.urlsplit(value) + if parsed.scheme not in ("http", "https") or not parsed.netloc: + raise ConfigError(f"配置项 {key} 必须是有效的 http/https URL") + + for key in path_keys: + value = cfg[key] + if value.startswith("~"): + cfg[key] = os.path.expanduser(value) return cfg @@ -968,11 +1000,12 @@ def add_token_to_grok2api_remote_pool(raw_token, email="", log_callback=None): if token not in existing: pool.append({"token": token, "tags": ["auto-register"], "note": email}) current[pool_name] = pool + if not etag: + raise RemoteTokenCompatibilityError( + "旧版远端接口未提供 ETag,无法保证并发安全,已拒绝全量保存" + ) save_headers = dict(headers) - if etag: - save_headers["If-Match"] = etag - elif log_callback: - log_callback("[!] 旧版远端接口未提供 ETag;已由显式配置允许,但仍不建议多实例并发") + save_headers["If-Match"] = etag endpoint = f"{fallback_base}/tokens" try: response = http_post(endpoint, headers=save_headers, params=query, json=current, timeout=30) @@ -3523,6 +3556,8 @@ class GrokRegisterGUI: line = event[1] self.log_text.insert(tk.END, f"{line}\n") self.log_text.see(tk.END) + elif kind == "clear_log": + self.log_text.delete(1.0, tk.END) elif kind == "stats": self.stats_var.set(f"成功: {event[1]} | 失败: {event[2]}") elif kind == "running": @@ -3550,7 +3585,7 @@ class GrokRegisterGUI: self.ui_queue.put(("log", line)) def clear_log(self): - self.log_text.delete(1.0, tk.END) + self.ui_queue.put(("clear_log",)) def update_stats(self): self.ui_queue.put(("stats", self.success_count, self.fail_count)) diff --git a/tools/apply_remaining_review_fixes.py b/tools/apply_remaining_review_fixes.py deleted file mode 100644 index 9b6bc65..0000000 --- a/tools/apply_remaining_review_fixes.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -from pathlib import Path -import ast -import json - -ROOT = Path(__file__).resolve().parents[1] -MAIN = ROOT / "grok_register_ttk.py" -CONFIG_EXAMPLE = ROOT / "config.example.json" - - -def read(path): - return path.read_text(encoding="utf-8-sig") - - -def replace_once(text, old, new, label): - count = text.count(old) - if count != 1: - raise RuntimeError(f"{label}: expected one match, got {count}") - return text.replace(old, new, 1) - - -main = read(MAIN) - -main = replace_once( - main, - ' "grok2api_allow_legacy_full_save": False,\n}', - ' "grok2api_allow_legacy_full_save": False,\n' - ' "email_provider": "duckmail",\n' - ' "yyds_api_key": "",\n' - ' "yyds_jwt": "",\n' - ' "defaultDomains": "",\n' - '}', - "complete default config", -) - -main = replace_once( - main, - ''' for key, allowed in enums.items(): - value = cfg.get(key, DEFAULT_CONFIG.get(key, "")) - if value not in allowed: - raise ConfigError(f"配置项 {key} 的值无效: {value!r}; 允许值: {sorted(allowed)}") - cfg[key] = value - return cfg -''', - ''' for key, allowed in enums.items(): - value = cfg.get(key, DEFAULT_CONFIG.get(key, "")) - if value not in allowed: - raise ConfigError(f"配置项 {key} 的值无效: {value!r}; 允许值: {sorted(allowed)}") - cfg[key] = value - - api_path_keys = { - "cloudflare_path_domains", "cloudflare_path_accounts", - "cloudflare_path_token", "cloudflare_path_messages", - "cloudmail_path_messages", - } - for key in api_path_keys: - value = cfg[key] - if value and not value.startswith("/"): - value = "/" + value - cfg[key] = value - - url_keys = { - "cloudflare_api_base", "cloudmail_api_base", - "grok2api_remote_base", "cpa_base_url", - } - for key in url_keys: - value = cfg[key] - if not value: - continue - parsed = urllib.parse.urlsplit(value) - if parsed.scheme not in ("http", "https") or not parsed.netloc: - raise ConfigError(f"配置项 {key} 必须是有效的 http/https URL") - - for key in path_keys: - value = cfg[key] - if value.startswith("~"): - cfg[key] = os.path.expanduser(value) - return cfg -''', - "normalize validated config", -) - -main = replace_once( - main, - ''' save_headers = dict(headers) - if etag: - save_headers["If-Match"] = etag - elif log_callback: - log_callback("[!] 旧版远端接口未提供 ETag;已由显式配置允许,但仍不建议多实例并发") -''', - ''' if not etag: - raise RemoteTokenCompatibilityError( - "旧版远端接口未提供 ETag,无法保证并发安全,已拒绝全量保存" - ) - save_headers = dict(headers) - save_headers["If-Match"] = etag -''', - "require ETag for legacy save", -) - -main = replace_once( - main, - ''' if kind == "log": - line = event[1] - self.log_text.insert(tk.END, f"{line}\\n") - self.log_text.see(tk.END) - elif kind == "stats": -''', - ''' if kind == "log": - line = event[1] - self.log_text.insert(tk.END, f"{line}\\n") - self.log_text.see(tk.END) - elif kind == "clear_log": - self.log_text.delete(1.0, tk.END) - elif kind == "stats": -''', - "GUI clear event", -) - -main = replace_once( - main, - ''' def clear_log(self): - self.log_text.delete(1.0, tk.END) -''', - ''' def clear_log(self): - self.ui_queue.put(("clear_log",)) -''', - "queue clear log", -) - -ast.parse(main, filename=str(MAIN)) -MAIN.write_text(main, encoding="utf-8") - -if CONFIG_EXAMPLE.exists(): - data = json.loads(read(CONFIG_EXAMPLE)) - data.setdefault("email_provider", "duckmail") - data.setdefault("yyds_api_key", "") - data.setdefault("yyds_jwt", "") - data.setdefault("defaultDomains", "") - data.setdefault("cpa_oidc_request_timeout_sec", 15) - data.setdefault("cpa_oidc_poll_timeout_sec", 15) - data.setdefault("grok2api_allow_legacy_full_save", False) - CONFIG_EXAMPLE.write_text( - json.dumps(data, ensure_ascii=False, indent=2) + "\n", - encoding="utf-8", - ) - -print("remaining review fixes applied")