Releases: mpiton/vortex-mod-mega
v1.0.0 — Initial release
First release of the MEGA WASM hoster plugin for Vortex.
Overview
vortex-mod-mega resolves public MEGA share URLs into download metadata + per-file decryption material so the Vortex core engine can stream encrypted bytes from the CDN, decrypt in place with AES-128-CTR, and verify integrity via the chunk-MAC fold against the URL's metaMac. No wait timer, no captcha, no subprocess — http capability only.
Both URL shapes are supported, modern and legacy:
- File:
https://mega.nz/file/<id>#<key>orhttps://mega.co.nz/#!<id>!<key> - Folder:
https://mega.nz/folder/<id>#<key>orhttps://mega.co.nz/#F!<id>!<key>
Folder URLs are decrypted in-plugin: each child node's encrypted key blob is unwrapped via AES-128-ECB with the folder master key, the recovered 32-byte raw key is XOR-folded into the same MegaFileKey shape as a URL key, and the encrypted attribute blob is decrypted via AES-128-CBC (IV = 0₁₂₈) to recover the filename. Each child is then re-emitted as a synthetic mega.nz/file/<handle>#<key> URL the host re-feeds through the regular file-URL pipeline.
Plugin contract
| Function | Input | Output |
|---|---|---|
can_handle |
URL string | \"true\" for any mega.nz file or folder URL, \"false\" otherwise |
supports_playlist |
URL string | \"true\" for folder URLs, \"false\" for file URLs |
extract_links |
URL string | JSON {kind: \"file\"|\"folder\", files: [FileLink]} with EncryptionInfo |
resolve_stream_url |
{url} JSON |
Encrypted CDN URL (host fetches the bytes, decrypts in stream) |
FileLink.encryption.scheme = \"mega-aes128-ctr\" carries the per-file AES key, IV and metaMac (all hex-encoded). Hosts unaware of this scheme must refuse the download — the bytes from direct_url are ciphertext.
Crypto core
- AES-128-CTR streaming via RustCrypto (
aes+ctr), counter isiv ‖ 0₆₄, in-place decrypt - Chunk MAC with MEGA's canonical schedule (128, 256, 384, …, 1024 KiB, then 1 MiB) — one CBC-MAC per chunk, all chunk MACs folded through one final CBC-MAC, file MAC = XOR of the two 8-byte halves of the result
- MAC mismatch →
PluginError::MacMismatch(host marks the download as corrupted) - Memory bounds — caller-controlled buffer, decryptor state grows only with
chunk_macs.len()(~64 KB for a 4 GB stream)
API & error handling
JSON-RPC over https://g.api.mega.co.nz/cs?id=<seq>:
gcommand — single-file resolution, returns encrypted CDN URL + sizefcommand — folder enumeration, returns the node tree
MEGA error vocabulary maps onto the Vortex plugin-error type:
| MEGA / HTTP | PluginError |
|---|---|
-9 (ENOENT) |
Offline |
-3, -6 (EAGAIN) |
RateLimited |
| Other negative codes | ApiError(code) |
| HTTP 404 / 410 | Offline |
| HTTP 429 / 509 | RateLimited |
| HTTP other 4xx/5xx | HttpStatus |
Tests
- 61 native unit tests across
error,url_matcher,key_parser,crypto,api_client,node_parser,lib - 4 WASM smoke tests for
can_handle/supports_playlist - 1 end-to-end folder decryption test (loads the WASM artefact via Extism, stubs
http_requestto return a syntheticfresponse built with real AES-128-ECB key wrapping + AES-128-CBC attribute encryption, asserts decrypted child handle / filename / size)
cargo clippy --all-targets -- -D warnings clean, cargo fmt clean.
Checksums
Both assets are published below. Their SHA-256 are pinned in vortex/registry/registry.toml.
| Asset | SHA-256 |
|---|---|
vortex_mod_mega.wasm |
ee4fd7716f56802e43cef2804ddf6a49346177b716afffc974867a3316290f07 |
plugin.toml |
c9420281eb587afc938142c5f70104b0febb176fe68cd2ec441c275c0b4ef805 |
License
GPL-3.0