security: wipe RPC creds, lock down generated conf, auto-clear secret clipboard (audit #4-6)

- rpc_client: wipe the plaintext "user:password" temporary with sodium_memzero after
  base64-encoding it into the auth header (std::string doesn't zero its buffer on
  destruction).
- connection: the auto-generated DRAGONX.conf holds rpcuser/rpcpassword in plaintext but
  was written with the default umask (often world-readable 0644). Restrict it to owner
  read/write after creation so another local user can't read the credentials.
- app: copying a seed phrase / private key to the clipboard now arms an auto-clear —
  App::copySecretToClipboard() copies the secret and, after 45s, wipes the clipboard IF it
  still holds that secret (compared via a stored hash, never the plaintext). Wired into the
  lite first-run wizard's seed Copy and the Settings export-secret Copy, with a
  "clipboard auto-clears in 45s" notice. pumpSecretClipboardClear() runs each frame.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 14:00:45 -05:00
parent e40962cdf2
commit 094771af81
5 changed files with 58 additions and 4 deletions

View File

@@ -1709,7 +1709,7 @@ void RenderSettingsPage(App* app) {
}
ImGui::SetCursorScreenPos(ImVec2(leftX, ImGui::GetCursorScreenPos().y));
if (TactileButton("Copy##LiteExportCopy", ImVec2(0, 0), S.resolveFont("button"))) {
ImGui::SetClipboardText(s_settingsState.lite_export_secret.c_str());
app->copySecretToClipboard(s_settingsState.lite_export_secret);
}
ImGui::SameLine(0, Layout::spacingSm());
// Save the seed (+ birthday) to an owner-only (0600) file in the config dir.