fix(client): fail closed on polling configuration drift

This commit is contained in:
QiuSW
2026-08-05 01:59:35 +08:00
parent dfd88c3336
commit 3a27225977
6 changed files with 168 additions and 16 deletions
+13 -3
View File
@@ -353,14 +353,24 @@ class LocalStateStore:
row = connection.execute(
"""SELECT service_url,device_id,adb_path,adb_serial,transport,
poll_interval_seconds,failure_threshold,http_timeout_seconds,step_timeout_seconds,
CASE WHEN length(device_token_cipher) > 0 THEN 1 ELSE 0 END
typeof(device_token_cipher),length(device_token_cipher)
FROM profiles WHERE profile_id=?""",
(profile_id,),
).fetchone()
if row is None:
raise StateError("profile_not_found")
settings = ProfileSettings(profile_id, *row[:9])
return ProfileSummary(settings, bool(row[9]))
# summary 不解密,但也不能把损坏的密文降级成“尚未保存”。否则 UI 会
# 允许覆盖本应进入人工恢复的本地状态。DPAPI 密文长度不固定,只要求
# SQLite storage class 确为 BLOB 且非空。
if row[9] != "blob" or type(row[10]) is not int or row[10] <= 0:
raise StateError("invalid_device_token_cipher")
try:
settings = ProfileSettings(profile_id, *row[:9])
except (TypeError, ValueError, ValidationError):
# 存储字段损坏不得把裸模型异常或实际值带到 UI;也不得以默认配置
# 继续启动。配置修复必须显式进行。
raise StateError("stored_profile_invalid") from None
return ProfileSummary(settings, True)
def start_or_resume_polling(self, profile_id: str) -> PollingSession:
now = self._utc_now()