fix: version stored state, validate its shape, and give a corrupt blob a way out (closes #311)
Stored state had no version and no structural validation, so a corrupt blob produced a completely blank popup with no message and no recovery control, and made every dApp RPC call from every page answer a generic -32603. There was no reset or wipe control anywhere in the UI. saveState() now stamps a schema version and loadState() validates the shape. A version it does not understand, or a wallets array it cannot parse, lands on a recovery screen that names the problem, offers the stored record verbatim for export, and offers a destructive reset behind a typed confirmation. Unversioned but valid state -- which every existing install has -- migrates in place and keeps working; it is never shown a wipe prompt. A dApp call against unusable state answers -32007, which EIP-1474 leaves unassigned, rather than -32603. networkById() refuses an unknown id loudly instead of returning mainnet, and networkId is validated so a corrupt value cannot be used as an object key. Fields the gate does not refuse are floored by type, container and entries both: a malformed trackedTokens or tokenBalances entry is dropped rather than dereferenced. Verified by an independent sweep of 1152 corrupt blobs producing no blank popup, with the same harness showing 9 blanks against the previous revision.
This commit was merged in pull request #360.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// Views the popup may reopen onto.
|
||||
//
|
||||
// The popup persists the current view so that reopening the toolbar popup
|
||||
// lands the user back where they were. Only views that can be fully
|
||||
// re-rendered from persisted state belong here; every other view falls back
|
||||
// to the nearest restorable parent (src/popup/index.js restoreView()).
|
||||
//
|
||||
// A view that displays a secret must NEVER be listed. Restoring onto one
|
||||
// would put a private key or a recovery phrase on screen with no password
|
||||
// prompt in front of it, on a popup the user may have reopened by accident.
|
||||
// That is why "export-privkey" and "show-phrase" are absent.
|
||||
//
|
||||
// Nor may a view whose button destroys a wallet be listed, for the mirror
|
||||
// reason: a popup reopened by accident must not land on the screen that
|
||||
// erases key material. That is why "delete-wallet-confirm" and
|
||||
// "delete-wallet-lost-password" are absent.
|
||||
//
|
||||
// Kept in its own module, with no dependencies, so tests can assert the
|
||||
// exclusion directly rather than trusting a reading of the popup entry
|
||||
// point.
|
||||
//
|
||||
// It sits under src/shared/ rather than src/popup/ because
|
||||
// src/shared/persistedState.js needs it and that module is in the BACKGROUND
|
||||
// bundle: a popup-path module reached from the worker is the shape
|
||||
// script/lib/forbiddenBundleInputs.js exists to keep out, whether or not the
|
||||
// particular module is harmless.
|
||||
const RESTORABLE_VIEWS = new Set([
|
||||
"main",
|
||||
"address",
|
||||
"address-token",
|
||||
"receive",
|
||||
"settings",
|
||||
"settings-addtoken",
|
||||
"confirm-tx",
|
||||
"transaction",
|
||||
"wait-tx",
|
||||
"success-tx",
|
||||
"error-tx",
|
||||
]);
|
||||
|
||||
module.exports = { RESTORABLE_VIEWS };
|
||||
Reference in New Issue
Block a user