security(exposure): owner-only ACLs on Windows, auto-clearing export copy, require SHA-256 for bootstrap

- writeFileAtomically honored restrictPermissions only on POSIX (0600); on
  Windows it was a no-op, so exported keys / seed backups / the vault / chat
  exports inherited the parent dir's ACL. It now builds a PROTECTED owner-only
  DACL (current-user SID, SE_DACL_PROTECTED) on the temp file before the atomic
  rename; best-effort, falling back to default ACLs on failure. (Verified it
  compiles under mingw-w64; the POSIX path is unchanged.)
- The key-export dialog's Copy wrote the private key to the plain, permanent
  clipboard; it now goes through copySecretToClipboard() (45s armed auto-wipe +
  its own "copied, auto-clears" notice), like the seed backup copy.
- Bootstrap archive verification dropped the collision-prone MD5 fallback: it now
  requires a published SHA-256 and fails closed otherwise. (Authenticity vs a
  malicious server still needs a detached ed25519 signature like the updaters —
  a separate release-coordinated change.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 10:34:47 -05:00
co-authored by Claude Opus 4.8
parent 6b0f2eda22
commit 31e9c2ee2c
3 changed files with 71 additions and 50 deletions
+3 -2
View File
@@ -4344,8 +4344,9 @@ void App::renderExportKeyDialog()
ImGui::InputTextMultiline("##exportresult", export_result_, sizeof(export_result_),
ImVec2(-1, 60.0f * dp), ImGuiInputTextFlags_ReadOnly);
if (m::TactileButton(TR("copy"))) {
ImGui::SetClipboardText(export_result_);
ui::Notifications::instance().info(TR("copied_to_clipboard"));
// A private key is a secret — route through the auto-clearing clipboard path (45s armed wipe
// + its own "copied, auto-clears" toast) instead of a plain, permanent clipboard write.
copySecretToClipboard(export_result_);
}
} else if (export_error_) {
ImGui::Spacing();