feat(security): persist unlock lockout across restarts; keep unlock errors visible
- The failed-unlock error message now stays on screen until the next attempt / mode switch / success, instead of fading after ~3s (the reason was often gone before it could be read). - The escalating failed-attempt lockout counter + expiry are now persisted (keyed to the active wallet file) and restored once per lock-screen session, so killing and relaunching the app can no longer reset the lockout curve — a brute-force window. A forward clock change is capped; the PIN/passphrase is never stored. The verification (walletpassphrase/decrypt) path is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -393,6 +393,15 @@ public:
|
||||
bool getSeedBackupReminded() const { return seed_backup_reminded_; }
|
||||
void setSeedBackupReminded(bool v) { seed_backup_reminded_ = v; }
|
||||
|
||||
// Unlock lockout state, persisted across restarts so the failed-attempt curve can't be reset by
|
||||
// killing the app. Keyed by the wallet file it applies to; the PIN/passphrase is never stored.
|
||||
int getLockFailedAttempts() const { return lock_failed_attempts_; }
|
||||
void setLockFailedAttempts(int v) { lock_failed_attempts_ = v; durable_next_save_ = true; }
|
||||
long long getLockoutUntilEpoch() const { return lockout_until_epoch_; }
|
||||
void setLockoutUntilEpoch(long long v) { lockout_until_epoch_ = v; durable_next_save_ = true; }
|
||||
std::string getLockStateWallet() const { return lock_state_wallet_; }
|
||||
void setLockStateWallet(const std::string& v) { lock_state_wallet_ = v; durable_next_save_ = true; }
|
||||
|
||||
// One-time nudge when wallet.dat grows past the bloat threshold (re-armed if it shrinks back).
|
||||
bool getLargeWalletWarned() const { return large_wallet_warned_; }
|
||||
void setLargeWalletWarned(bool v) { large_wallet_warned_ = v; }
|
||||
@@ -736,6 +745,9 @@ private:
|
||||
std::map<std::string, AddressMeta> address_meta_;
|
||||
bool wizard_completed_ = false;
|
||||
bool seed_backup_reminded_ = false;
|
||||
int lock_failed_attempts_ = 0; // persisted unlock-failure count (lockout curve)
|
||||
long long lockout_until_epoch_ = 0; // unix time the current lockout expires (0 = none)
|
||||
std::string lock_state_wallet_; // wallet file the above two apply to
|
||||
bool large_wallet_warned_ = false;
|
||||
std::set<std::string> empty_wallet_warning_acked_; // wallet files whose empty-wallet warning was dismissed
|
||||
bool encryption_pending_ = false;
|
||||
|
||||
Reference in New Issue
Block a user