Back to Home
Gistify Snippet
kyiov
1h ago·1 file(s)
Public

Mega.nz Direct Link Resolver & AES Decryptor

Bypasses Mega.nz file & folder share links into direct CDN download URLs by querying Mega API (g.api.mega.co.nz) and decrypting file attributes using 128-bit AES keys.

#mega#downloader#aes#crypto#javascript#tools
2
Raw
mega.jsjavascript
157 lines
1// mega.js — bundle standalone. npm deps: crypto, node:url
2
3/**
4 * Scraper: mega.js
5 * Source : mithra/mega.js
6 *
7 * Input : Function parameters / CLI args (e.g. query: string, url: string, options: object)
8 * Output : Promise<Object | Array | Buffer> (JSON formatted scraping response / stream URL / media metadata)
9 *
10 * CLI Run:
11 * node mithra/mega.js [functionName] [args...]
12 * node cli.js mithra/mega.js [functionName] [args...]
13 */
14
15import * as __ns_685 from 'crypto'
16const crypto = __ns_685.default
17import * as __ns_686 from 'node:url'
18const pathToFileURL = __ns_686.pathToFileURL
19
20/**
21 * Mega.nz link resolver — bypass link mega.nz menjadi direct download URL.
22 *
23 * Mendukung format:
24 * - https://mega.nz/#!<id>!<key>
25 * - https://mega.nz/file/<id>#<key>
26 *
27 * Menggunakan API publik g.api.mega.co.nz (a='g', g=1) untuk mengambil
28 * URL download + atribut terenkripsi, lalu mendekripsi nama file dengan key.
29 */
30
31const API = 'https://g.api.mega.co.nz/cs'
32const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
33
34function base64UrlDecode(str) {
35 const b64 = String(str).replace(/-/g, '+').replace(/_/g, '/')
36 const pad = b64.length % 4 ? '='.repeat(4 - (b64.length % 4)) : ''
37 return Buffer.from(b64 + pad, 'base64')
38}
39
40function parseMegaUrl(url) {
41 const u = String(url || '').trim()
42 let m = u.match(/mega\.nz\/#!([A-Za-z0-9_-]+)!([A-Za-z0-9_,-]+)/)
43 if (!m) m = u.match(/mega\.nz\/file\/([A-Za-z0-9_-]+)#([A-Za-z0-9_,-]+)/)
44 if (!m) m = u.match(/mega\.nz\/folder\/([A-Za-z0-9_-]+)#([A-Za-z0-9_,-]+)/)
45 if (!m) return null
46 return { id: m[1], key: m[2], isFolder: u.includes('/folder/') }
47}
48
49function decryptAttributes(at, keyBytes) {
50 // key dari link = 32 byte: 16 byte AES key + 8 byte IV + 8 byte checksum
51 // atribut dienkripsi AES-128-CBC dengan key 16 byte pertama & IV dari 8 byte berikutnya
52 try {
53 const aesKey = keyBytes.slice(0, 16)
54 const iv = Buffer.concat([keyBytes.slice(16, 24), Buffer.alloc(8)])
55 const decipher = crypto.createDecipheriv('aes-128-cbc', aesKey, iv)
56 let out = Buffer.concat([decipher.update(at), decipher.final()])
57 // hilangkan padding nol di akhir
58 let end = out.length
59 while (end > 0 && out[end - 1] === 0) end--
60 out = out.slice(0, end)
61 const text = out.toString('utf8')
62 if (!text.startsWith('MEGA')) return null
63 return JSON.parse(text.slice(4))
64 } catch {
65 return null
66 }
67}
68
69/**
70 * Resolve link mega.nz → { ok, name, size, url, direct_url, host, isFolder }
71 */
72async function resolveMega(url) {
73 const parsed = parseMegaUrl(url)
74 if (!parsed) return { ok: false, error: 'Format link mega tidak dikenali.' }
75
76 const seq = Math.floor(Math.random() * 1e6)
77 const body = [{ a: 'g', g: 1, p: parsed.id }]
78
79 try {
80 const r = await fetch(`${API}?id=${seq}&ak=&k=`, {
81 method: 'POST',
82 headers: {
83 'Content-Type': 'application/json',
84 'User-Agent': UA,
85 'Origin': 'https://mega.nz',
86 'Referer': 'https://mega.nz/',
87 },
88 body: JSON.stringify(body),
89 signal: AbortSignal.timeout(30000),
90 })
91 if (!r.ok) throw new Error(`HTTP ${r.status}`)
92 const json = await r.json()
93 const item = Array.isArray(json) ? json[0] : json
94
95 if (!item || item === -9) return { ok: false, error: 'File tidak ditemukan di Mega (node tidak valid).' }
96 if (item === -3) return { ok: false, error: 'Link Mega telah kadaluarsa.' }
97 if (typeof item !== 'object' || !item.g) {
98 return { ok: false, error: `Mega API error: ${JSON.stringify(item)}` }
99 }
100
101 const keyBytes = base64UrlDecode(parsed.key)
102 const attrs = decryptAttributes(Buffer.from(item.at || '', 'base64'), keyBytes)
103 const size = item.s ? Number(item.s) : 0
104
105 return {
106 ok: true,
107 id: parsed.id,
108 name: attrs?.n || `mega-file-${parsed.id.slice(0, 6)}`,
109 size,
110 sizeText: size ? (size / 1024 / 1024).toFixed(1) + ' MB' : '?',
111 direct_url: item.g,
112 url,
113 host: 'mega.nz',
114 isFolder: parsed.isFolder,
115 }
116 } catch (e) {
117 return { ok: false, error: e.message || String(e) }
118 }
119}
120
121export { resolveMega };
122export default resolveMega;
123
124
125// ─────────────────────────────────────────────────────────────────────
126// Self-test: jalankan langsung dengan `node mega.js [args...]`
127// ─────────────────────────────────────────────────────────────────────
128if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
129 const __exports = { resolveMega: resolveMega, default: resolveMega }
130 const __fns = Object.fromEntries(Object.entries(__exports).filter(([, v]) => typeof v === 'function'))
131 const __names = Object.keys(__fns)
132 if (__names.length === 0) {
133 console.log('Tidak ada fungsi yang bisa di-demo. Import modul ini dari kode lain.')
134 } else {
135 const __search = __names.find((n) => /search|cari/i.test(n))
136 const __name = __search || __names[0]
137 const __fn = __fns[__name]
138 const __isClass = /^class\s/.test(Function.prototype.toString.call(__fn))
139 let __args = process.argv.slice(2).map((a) => { try { return JSON.parse(a) } catch { return a } })
140 if (__args.length === 0 && __search) __args.push('naruto')
141 if (__args.length === 0 && !__search && !__isClass && __fn.length > 0) {
142 console.log('Fungsi: ' + __names.join(', '))
143 console.log('Contoh: node ' + "mega.js" + ' ' + __name + ' <arg>')
144 } else {
145 ;(async () => {
146 try {
147 const r = __isClass ? new __fn(...__args) : await __fn(...__args)
148 console.log(JSON.stringify(r, null, 2))
149 } catch (e) {
150 console.error('Error: ' + (e && e.message ? e.message : e))
151 process.exitCode = 1
152 }
153 })()
154 }
155 }
156}
157
Discussion & Comments0

No comments yet — be the first to leave feedback or start a code discussion.

Sign in with your GitHub account to write comments and join the discussion.