feat(mega): session-token auth, 2FA, worker hardening + thumbnails - #239
Merged
Conversation
Replace plaintext password storage with a reused, revocable session token (megajs toJSON/fromJSON); add two-step 2FA login; replace the share-link download hack and upload-worker password with lightweight session-based file access. Phased: auth+upload worker, then download workers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ardening Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anitizer, key encoder) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…kens Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rsistence Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… meaningful Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t re-login Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…epalive leak Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…estore Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…assword Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…share links Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o share links) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…set test chunks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… upload-cred shape Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…place
ROOT CAUSE of live ESID(-15) on reused sessions: megajs storage.close()
issues {a:'sml'}, terminating the session sid server-side. The branch reuses
ONE persisted sid across all storages (login, restore, reinitialize, upload
worker), so closing any of them invalidated the persisted token — the next
reload's fromJSON+reload and all downloads then failed with ESID(-15). The
pre-branch code minted a fresh sid per login, so close() was harmless.
- reinitialize(): refresh the file tree in place via reload(true) on the
existing session; remove the fromJSON-rebuild + oldStorage.close().
- resetUploadStorage(): use api.close() (aborts the keepalive poll only)
instead of storage.close() (which kills the session).
Regression tests assert reinitialize calls reload(true) and never close().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MEGA's browser only previews a node when it has an encrypted thumbnail
file-attribute (fa); a raw upload has none, so uploaded thumbnail images
showed no preview. In the upload worker, when the uploaded file is an image
(by mimeType/extension), render a 120x120 JPEG from the blob via
OffscreenCanvas and attach it with node.uploadAttribute('thumbnail', ...).
Best-effort and fully self-contained in the provider: failures (incl. no
OffscreenCanvas) never fail the upload; non-image uploads (cbz/json) skip it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MEGA type-0 thumbnails must be square 120x120, but cover-cropping chopped portrait manga covers. Switch to contain-fit (preserve aspect, center, white letterbox) so the full cover shows. Quality 0.7->0.8. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…elete toast Three issues found deleting a MEGA-backed volume: - Sidecars (.mokuro, thumbnail .webp) were orphaned: deleteFile removes only one node. Add unifiedCloudManager.deleteManagedVolume() which deletes the archive + all managed sidecars (sidecars first, .cbz last so a sidecar failure leaves the volume retryable). VolumeItem's two delete paths use it. - Toast 'Cannot read properties of undefined (reading provider)': onBackupClicked read the reactive cloudFile after the await re-derived it to undefined. Capture the provider before the await. - megajs 'Cannot read properties of undefined (reading parent)' crash: the keepalive server-change (sc) poll has a buggy delete handler. We never use push updates (we reload explicitly), so create sessions with keepalive:false (login + both fromJSON restore sites). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
adrian-tompkins
pushed a commit
to adrian-tompkins/mokuro-reader
that referenced
this pull request
Aug 2, 2026
feat: Add service worker update notification banner
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
Security rework of the MEGA cloud-sync provider, plus thumbnail support and several bugs found during live verification.
Auth (the security fix):
toJSON()/fromJSON()), restored on load without a re-login.secondFactorCode→EMFAREQUIRED→ reveal a code field).ESID(expired/revoked session) — no password is ever stored to fall back on.Worker hardening:
{ sid, nodeId, fileKey }— the share-link hack is removed, and the download worker never receives the account master key.Thumbnails: uploaded image files now get a MEGA thumbnail attribute (
uploadAttribute) so they preview in MEGA's browser — a contain-fit 120×120 JPEG rendered in the worker, dark letterbox, best-effort.Bugs found in live verification:
storage.close()issues{a:'sml'}which terminates the shared session sid →ESID(-15)on every reused session. Neverclose()a reused session;reinitialize()reloads in place;keepalive:falsedisables the buggy server-change poll that also crashed on deletes..mokuro, thumbnail.webp), not just the archive.VolumeItem.Security notes
No plaintext MEGA password is persisted in
localStorageor sent to any worker. The persisted token is a sanitizedtoJSON()blob (sid + master key, no password) — strictly less dangerous than the password (revocable; can't change account credentials or disable 2FA). The download worker never sees the master key.Testing
749 unit tests passing;
npm run check0/0; eslint 0 errors; prettier clean. Live-verified against a real MEGA account: non-2FA login + reload reuses the session (nousrequest, no stored password), worker downloads issue nolink/unshare, image uploads preview in MEGA, volume delete removes sidecars with nosccrash. Built subagent-driven with per-task review; design + plan underdocs/superpowers/.Notes
develop; rebase/merge is clean (no overlapping files with develop's recent commits).🤖 Generated with Claude Code