fix(recover): wrap embedded-manifest atob in try/catch for corrupt base64#154
Merged
eljojo merged 1 commit intoeljojo:mainfrom Apr 17, 2026
Merged
Conversation
…se64 atob() throws DOMException when its input isn't valid base64. The embedded manifest lives in recover.html, which is meant to be archived long-term; bit rot, truncated copies, or storage degradation can leave the base64 payload unreadable. Previously the exception propagated, leaving Step 2 asking the user to load MANIFEST.age manually — but the whole point of embedding was to avoid needing the separate file. Catch the decode failure and surface a toast so the user knows their copy of recover.html is damaged and to try another copy. The i18n function t() already falls back to English when a locale is missing translations, so the three new keys work across all languages even before translators catch up. Fixes eljojo#107
eljojo
approved these changes
Apr 17, 2026
Owner
eljojo
left a comment
There was a problem hiding this comment.
thanks for submitting this fix!
PS: I made an edit to the PR description so it can fit the contribution guidelines. AI footers are not allowed on this repository.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wrap
atob(personalization.manifestB64)ininternal/html/assets/src/app.tsin atry/catchso a corrupted embedded manifest shows a toast instead of silently leaving Step 2 asking the user to loadMANIFEST.age. Addresses #107.Why
The whole point of embedding the manifest in
recover.htmlis so the user doesn't need a separateMANIFEST.agefile after their archive has been sitting on disk for years. If the base64 payload insiderecover.htmldegrades (bit rot, truncated copy, storage corruption),atobthrows aDOMExceptionand the recovery page falls back to asking the user for a file that, by design, they may not have.The existing flow at
app.ts:341-349had no error handler for that path, so:recover.htmllooks broken rather than specifically corrupted.Changes
internal/html/assets/src/app.ts: wrap the embedded-manifest decode intry { ... } catch (err) { showError(...) }. The success path is unchanged; on failure the user gets a toast whose guidance tells them to try another copy ofrecover.htmlor fall back to loadingMANIFEST.agemanually in Step 2.internal/translations/recover/en.json: add three keys —error_corrupt_embedded_manifest_title,error_corrupt_embedded_manifest_message,error_corrupt_embedded_manifest_guidance. Other locales fall back to English automatically (translations[currentLang][key] || translations['en'][key] || keyini18n.js:7), so no translator action is required to ship this; translators can add their own strings later via the normal flow.Testing
go test ./internal/translations/...— pass (existing parity test is opt-in viaREMEMORY_CHECK_TRANSLATIONS=1).npx esbuild internal/html/assets/src/app.ts --bundle --format=iife --target=es2020— clean build.npx tsc --noEmit— clean.manifestB64(swap a byte to!), the page now shows the "Corrupted embedded archive" toast and Step 2 still works via file upload.Fixes #107