fix: Fix StorageService Key Encoding cp-7.66.0#26268
Conversation
…orage quirks The redux-persist-filesystem-storage library has two problematic behaviors: 1. Slashes (/) in keys create subdirectories, making keys unreachable via getAllKeys 2. Hyphens (-) get converted to colons (:) by fromFileName, corrupting the key This fix introduces URI-style encoding for these characters: - `/` → `%2F` - `-` → `%2D` - `%` → `%25` (to prevent double-encoding) The encoding is applied only to the key portion, not the namespace, to maintain backward compatibility with existing production keys. Co-authored-by: Cursor <cursoragent@cursor.com>
Extends the key encoding to also encode the namespace portion for future-proofing. Since current namespaces (e.g., TokenListController) have no special characters, this produces identical output and maintains backward compatibility with existing production keys. Co-authored-by: Cursor <cursoragent@cursor.com>
Apply encodeStorageKey to snap IDs when storing snap source code in the filesystem. This ensures snap IDs with special characters (e.g., npm:@metamask/bip32-keyring-snap) are stored correctly. Co-authored-by: Cursor <cursoragent@cursor.com>
| */ | ||
| export const encodeStorageKey = (key: string): string => | ||
| key | ||
| .replace(/%/g, '%25') // Encode % first to avoid double-encoding |
There was a problem hiding this comment.
If we are URI encoding anyway we could consider using encodeURIComponent?
There was a problem hiding this comment.
It doesn't encode -
There was a problem hiding this comment.
Sure, but what about other characters than / and -?
There was a problem hiding this comment.
It encodes : as well I believe? So it would not be backwards compatible
There was a problem hiding this comment.
True. I guess the worry is whether there are characters we haven't considered here that would be problematic in the future?
There was a problem hiding this comment.
I don't think so. I think only - because of the conversion, and / because it was creating folders. But I will create a ticket for us to do a bit more digging after but we could merge this for now to unblock the release if you are ok with it?
Co-authored-by: Cursor <cursoragent@cursor.com>
| const fullKey = `${STORAGE_KEY_PREFIX}SnapController:${snap.id}`; | ||
| // Encode the snap ID to handle special characters (e.g., slashes and hyphens in npm:@metamask/bip32-keyring-snap) | ||
| const encodedSnapId = encodeStorageKey(snap.id as string); | ||
| const fullKey = `${STORAGE_KEY_PREFIX}SnapController:${encodedSnapId}`; |
There was a problem hiding this comment.
Modifying shipped migration breaks existing snap data access
High Severity
Migration 119 is a pre-existing migration being modified to add encodeStorageKey for snap IDs. If any users have already run the original migration, their snap source codes are stored under unencoded keys (e.g., with literal / and -). Since migrations only run once, those keys won't be re-encoded, but the storage adapter now exclusively uses encoded keys (%2F, %2D). This makes previously stored snap source codes permanently inaccessible via getItem. A separate new migration to re-encode existing keys is needed instead of modifying the existing one.
There was a problem hiding this comment.
It's not in production
Explain why we encode `-` and `/` but not `:` - existing production keys use colons, so encoding them would break backward compatibility. Co-authored-by: Cursor <cursoragent@cursor.com>
Update assertions to expect encoded keys (hyphens as %2D) since the migration now uses encodeStorageKey for snap IDs. Co-authored-by: Cursor <cursoragent@cursor.com>
Re-add the production log statement that was accidentally removed when cleaning up debug console.logs. Co-authored-by: Cursor <cursoragent@cursor.com>
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection: Key Changes:
Impact Analysis:
Why FlaskBuildTests:
Why not other tags:
Performance Test Selection: |
|





Description
Problem
The
redux-persist-filesystem-storagelibrary has two problematic behaviors when handling arbitrary keys inStorageService:Slashes (
/) create subdirectories: Keys containing slashes are stored in subdirectories, making them unreachable viagetAllKeys. This breaks theclearmethod for affected keys.Hyphens (
-) get corrupted: The library's internalfromFileNamefunction converts hyphens to colons (:), meaning keys likesimple-keyare returned assimple:keybygetAllKeys. This causes a permanent mismatch between stored keys and returned keys.Solution
This PR introduces URI-style encoding for problematic characters in both namespace and key portions of storage keys:
/→%2F(prevents subdirectory creation)-→%2D(prevents hyphen-to-colon corruption)%→%25(prevents double-encoding issues)The encoding is applied via shared utility functions (
encodeStorageKey/decodeStorageKey) used by both:mobileStorageAdapterinstorage-service-init.tsBackward Compatibility
This change is backward compatible and will NOT break existing production keys.
storageService:TokenListController:tokensChainsCache:0x1are unaffected because:TokenListController) has no special characters → encoding produces identical output:) are not encoded - they pass through unchangedtokensChainsCache:0x1) contains no hyphens or slashes-,/, or%characters produce identical output when encodedExamples
Files Changed
app/core/Engine/utils/storage-service-utils.tsencodeStorageKey/decodeStorageKeyfunctionsapp/core/Engine/utils/storage-service-utils.test.tsapp/core/Engine/controllers/storage-service-init.tsmobileStorageAdaptermethodsapp/core/Engine/controllers/storage-service-init.test.tsapp/store/migrations/119.tsChangelog
CHANGELOG entry: null
Related issues
Refs: StorageService key handling issues with
redux-persist-filesystem-storageManual testing steps
Screenshots/Recordings
N/A - No UI changes
Before
N/A
After
N/A
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Changes the on-disk key format for any namespaces/keys containing
%,/, or-, which could impact access to previously stored data for those cases; behavior is covered by new unit tests but touches persistence and migration logic.Overview
Fixes StorageService filesystem key handling by URI-encoding namespaces and keys (encoding
%,/,-while leaving:intact) before callingredux-persist-filesystem-storage, and decoding keys returned fromgetAllKeys.Updates
mobileStorageAdapterto apply this encoding ingetItem/setItem/removeItem, use encoded namespace prefixes ingetAllKeys/clear, and adds a sharedstorage-service-utilsmodule with thorough unit coverage. Migration119is updated (and its test adjusted) to store snap source code under the encoded snap ID so snap IDs containing slashes/hyphens are retrievable/clearable.Written by Cursor Bugbot for commit 59b39f4. This will update automatically on new commits. Configure here.