Pre-launch credential-security regression: scans the ENTIRE serialized account
record (meta + encrypted blob) for the secret/access-key strings and asserts
they never appear in plaintext, that listConnections() doesn't expose them, that
they round-trip while unlocked, and that they're unreachable once locked. The
prior check only compared the cipher field to JSON.stringify(payload), which
wouldn't catch a secret leaking into plaintext meta.
Audit conclusion: credential storage is sound — envelope encryption (AES-GCM-256
payload, fresh per-encrypt IV; master key encrypted to-self via the Nostr signer,
NIP-44 preferred / NIP-04 fallback), in-memory master key cleared on logout, no
secret logging, legacy plaintext migrated then cleared.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Previously, `StorageService.saveConnection` allowed multiple connections to be marked as `defaultForUploads: true` because it did not unset the flag on existing connections. This caused `loadFromStorage` (which uses `find`) to potentially pick up an old, invalid connection instead of the newly configured one, leading to a loop where the user is asked to configure credentials again.
This change modifies `saveConnection` to iterate through existing connections and unset `defaultForUploads` if the new connection is being saved as the default. This ensures the "default" invariant is maintained.
Added a unit test case to verify this behavior.