Skip to content

Instantly share code, notes, and snippets.

@qgustavor
Last active October 31, 2020 15:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qgustavor/1308ce4970a7a9eaeef058466d1ec630 to your computer and use it in GitHub Desktop.
Save qgustavor/1308ce4970a7a9eaeef058466d1ec630 to your computer and use it in GitHub Desktop.
Simple MEGA downloader
export async function getMegaFile (megaUrl) {
const { handler, wrappedKey } = parseMegaUrl(megaUrl)
const url = await getDownloadUrl(handler)
const response = await fetch(url)
if (!response.ok) throw Error('MEGA request failed with ' + response.statusText)
const data = await response.arrayBuffer()
return decryptAesCtr(data, unwrapMegaKey(wrappedKey))
}
function unwrapMegaKey (originalKey) {
const key = new Uint8Array(originalKey)
for (let i = 0; i < 16; i++) key[i] = key[i] ^ key[16 + i]
return key
}
async function decryptAesCtr (data, key) {
const keyWrapper = await window.crypto.subtle.importKey('raw', key.slice(0, 16), {
name: 'AES-CTR'
}, false, ['decrypt'])
const counter = new Uint8Array(16)
counter.set(key.slice(16, 24), 0)
const plainText = await crypto.subtle.decrypt({
name: 'AES-CTR',
counter,
length: 64
}, keyWrapper, data)
return plainText
}
export function parseMegaUrl (megaUrl) {
const parsedUrl = new URL(megaUrl)
const handler = parsedUrl.pathname.split('/').pop()
const wrappedKey = decodeBase64(parsedUrl.hash.substr(1))
return { handler, wrappedKey }
}
export async function getDownloadUrl (handler) {
const response = await fetch('https://g.api.mega.co.nz/cs', {
method: 'POST',
body: JSON.stringify([{
a: 'g',
g: 1,
ssl: 2,
p: handler
}])
})
if (!response.ok) throw Error(`MEGA returned with ${response.statusText}`)
const data = await response.json()
return data[0].g
}
function decodeBase64 (s) {
let i
// atob also works without = padding
// https://infra.spec.whatwg.org/#forgiving-base64-decode
const d = atob(s.replace(/-/g, '+').replace(/_/g, '/'))
const b = new Uint8Array(d.length)
for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i)
return b
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment