diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b60651..5e1af74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -405,3 +405,8 @@ - `ensure_logged_in()` now automatically obtains a new transit token with the approved local device when the token is missing or expired. - Falls back to the normal secret-key login prompt when trusted-device renewal is unavailable. - Authorization testing passed; included in the private repository release. +## 1.5.40 (2026-08-17) + +### Trusted-device key location +- Store the trusted-device key at `~/.oracle-jump-query/device-key.json`, shared by all installations of the Skill for the same Windows user. +- Never migrate or overwrite another key; the private key is created once and never committed or uploaded. diff --git a/SKILL.md b/SKILL.md index 4b5273d..995d25b 100644 --- a/SKILL.md +++ b/SKILL.md @@ -57,6 +57,8 @@ python scripts/oracle_skill.py login [clientCode] | `clients` | 无感刷新当前用户最新授权的 client 列表(只使用当前登录 token) | | `device_register [deviceName]` | 在本机生成 Ed25519 密钥并提交可信设备注册请求;后台审批前状态为 `PENDING` | | `device_login [clientCode]` | 使用本机密钥完成 challenge/signature 可信设备登录;仅限后台已审批设备 | + +可信设备私钥和 `device_id` 保存在当前 Windows 用户目录的 `~/.oracle-jump-query/device-key.json`,同一用户下的不同 Skill 安装共享该文件。首次执行 `device_register` 时生成设备 ID;之后始终从该文件读取,不会覆盖或重新生成,因此同一台电脑的设备 ID 不会变化。该文件不提交到 Git。 | `switch ` | 按 code 或名称切换当前 client;找不到时自动刷新 client 列表 | | `analyze ` | 完整分析存储过程 | | `source ` | 获取存储过程源码 | diff --git a/VERSION b/VERSION index 9caff18..adecc24 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.39 +1.5.40 diff --git a/scripts/oracle_skill.py b/scripts/oracle_skill.py index 2a1b1d5..aea62a1 100644 --- a/scripts/oracle_skill.py +++ b/scripts/oracle_skill.py @@ -2002,7 +2002,7 @@ def cmd_login(secret_key: str, client_code: str = ""): def _device_key_path() -> str: - return os.path.join(get_script_dir(), "device-key.json") + return os.path.join(os.path.expanduser("~"), ".oracle-jump-query", "device-key.json") def _load_device_key() -> Dict[str, Any]: @@ -2012,7 +2012,8 @@ def _load_device_key() -> Dict[str, Any]: def _save_device_key(item: Dict[str, Any]) -> None: path = _device_key_path() - with open(path, "w", encoding="utf-8") as f: + os.makedirs(os.path.dirname(path), mode=0o700, exist_ok=True) + with open(path, "x", encoding="utf-8") as f: json.dump(item, f, ensure_ascii=False, indent=2) try: os.chmod(path, 0o600) @@ -2043,7 +2044,11 @@ def cmd_device_register(device_name: str = ""): private = Ed25519PrivateKey.generate() public = private.public_key().public_bytes_raw() key = {"device_id": "device-" + secrets.token_hex(12), "private_key": base64.b64encode(private.private_bytes_raw()).decode("ascii"), "public_key": base64.b64encode(public).decode("ascii"), "key_fingerprint": hashlib.sha256(public).hexdigest()} - _save_device_key(key) + try: + _save_device_key(key) + except FileExistsError: + # Another Skill process created the stable key first; never overwrite it. + key = _load_device_key() mac_hash, mac_masked = _device_identity() body = {"device_id": key["device_id"], "device_name": device_name or platform.node() or "Trusted device", "computer_name": platform.node(), "os_name": platform.platform(), "key_algorithm": "ED25519", "public_key": key["public_key"], "key_fingerprint": key["key_fingerprint"], "mac_hash": mac_hash, "mac_masked": mac_masked, "description": "Registered by oracle-jump-query skill"} try: