fix: audit round 2 - DPAPI secrets, pinned hop probe, gost exe hash, admin guard, PID-scoped browser tracking, emergency disengage button, build sidecar
This commit is contained in:
@@ -282,21 +282,30 @@ def resolve_signup_url(draft: SignupDraft) -> str:
|
||||
|
||||
|
||||
def load_draft() -> SignupDraft:
|
||||
from . import secrets_store as _ss
|
||||
p = draft_path()
|
||||
if not p.is_file():
|
||||
return SignupDraft()
|
||||
try:
|
||||
raw = json.loads(p.read_text(encoding="utf-8"))
|
||||
return SignupDraft(**{k: raw.get(k, "") for k in SignupDraft.__dataclass_fields__})
|
||||
kwargs = {k: raw.get(k, "") for k in SignupDraft.__dataclass_fields__}
|
||||
if kwargs.get("password"):
|
||||
kwargs["password"] = _ss.decrypt(kwargs["password"])
|
||||
return SignupDraft(**kwargs)
|
||||
except (OSError, json.JSONDecodeError, TypeError):
|
||||
return SignupDraft()
|
||||
|
||||
|
||||
def save_draft(draft: SignupDraft) -> None:
|
||||
draft_path().write_text(json.dumps(asdict(draft), indent=2), encoding="utf-8")
|
||||
from . import secrets_store as _ss
|
||||
d = asdict(draft)
|
||||
if d.get("password"):
|
||||
d["password"] = _ss.encrypt(d["password"])
|
||||
draft_path().write_text(json.dumps(d, indent=2), encoding="utf-8")
|
||||
|
||||
|
||||
def load_accounts() -> list[AccountRecord]:
|
||||
from . import secrets_store as _ss
|
||||
p = accounts_path()
|
||||
if not p.is_file():
|
||||
return []
|
||||
@@ -312,6 +321,9 @@ def load_accounts() -> list[AccountRecord]:
|
||||
kwargs = {k: item.get(k, "") for k in fields}
|
||||
if not kwargs.get("id"):
|
||||
kwargs["id"] = datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S%f")
|
||||
# Transparent DPAPI decrypt; plaintext passes through.
|
||||
if kwargs.get("password"):
|
||||
kwargs["password"] = _ss.decrypt(kwargs["password"])
|
||||
out.append(AccountRecord(**kwargs))
|
||||
return out
|
||||
except (OSError, json.JSONDecodeError, TypeError):
|
||||
@@ -319,8 +331,17 @@ def load_accounts() -> list[AccountRecord]:
|
||||
|
||||
|
||||
def save_accounts(rows: list[AccountRecord]) -> None:
|
||||
from . import secrets_store as _ss
|
||||
serialized = []
|
||||
for r in rows:
|
||||
d = asdict(r)
|
||||
# Encrypt sensitive fields at rest using Windows DPAPI when available.
|
||||
# Legacy plaintext entries are migrated transparently on first save.
|
||||
if d.get("password"):
|
||||
d["password"] = _ss.encrypt(d["password"])
|
||||
serialized.append(d)
|
||||
accounts_path().write_text(
|
||||
json.dumps([asdict(r) for r in rows], indent=2),
|
||||
json.dumps(serialized, indent=2),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user