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:
@@ -194,6 +194,23 @@ function storageSet(items) {
|
||||
return Promise.resolve(storage.set(items));
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase stored keys. The one caller is the destructive reset on the recovery
|
||||
* screen (src/popup/views/stateRecovery.js), which is the only way out of a
|
||||
* profile no build can read; it rejects rather than defaulting for the same
|
||||
* reason the two above do — a reset that silently did nothing would leave the
|
||||
* user in the dead end they were promised an exit from.
|
||||
*
|
||||
* @param {string|string[]} keys
|
||||
* @returns {Promise<void>}
|
||||
* @throws rejects where `storage.local` is absent.
|
||||
*/
|
||||
function storageRemove(keys) {
|
||||
const storage = storageLocal();
|
||||
if (!storage) return storageUnavailable("remove");
|
||||
return Promise.resolve(storage.remove(keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} queryInfo
|
||||
* @returns {Promise<Array>} the matching tabs.
|
||||
@@ -251,6 +268,7 @@ module.exports = {
|
||||
sendMessage,
|
||||
storageGet,
|
||||
storageLocal,
|
||||
storageRemove,
|
||||
storageSet,
|
||||
tabsApi,
|
||||
tabsQuery,
|
||||
|
||||
Reference in New Issue
Block a user