· 9 years ago · Feb 05, 2017, 11:52 PM
1<?php
2if (!defined('RAPIDLEECH')) {
3 require_once('index.html');
4 exit;
5}
6// Using functions from: http://julien-marchand.fr/blog/using-the-mega-api-with-php-examples/
7class mega_co_nz extends DownloadClass {
8 private $useOpenSSL, $alwaysLogin, $seqno, $cookie;
9 public function Download($link) {
10 if (!extension_loaded('mcrypt') || !in_array('rijndael-128', mcrypt_list_algorithms(), true)) html_error("Mcrypt module isn't installed or it doesn't have support for the needed encryption.");
11 $this->useOpenSSL = (version_compare(PHP_VERSION, '5.4.0', '>=') && extension_loaded('openssl') && in_array('AES-128-CBC', openssl_get_cipher_methods(), true));
12 $this->alwaysLogin = false;
13
14 $this->seqno = mt_rand();
15 $this->changeMesg(lang(300).'<br />Mega.co.nz plugin by Th3-822'); // Please, do not remove or change this line contents. - Th3-822
16
17 $fragment = parse_url($link, PHP_URL_FRAGMENT);
18 if (preg_match('@^F!([^!]{8})!([\w\-\,]{22})(?:!([^!#]{8}))?(!less$)?@i', $fragment, $fid)) return $this->Folder($fid[1], $fid[2], (!empty($fid[3]) && $fid[3] != $fid[1] ? $fid[3] : 0), (empty($fid[4]) ? 1 : 0));
19 if (!preg_match('@^(T8|N)?!([^!]{8})!([\w\-\,]{43})(?:(?:!|=###n=)([^!#]{8})(?:!|$))?@i', $fragment, $fid)) html_error('FileID or Key not found at link.');
20
21 $pA = (empty($_REQUEST['premium_user']) || empty($_REQUEST['premium_pass']) ? false : true);
22 if (!empty($_REQUEST['premium_acc']) && $_REQUEST['premium_acc'] == 'on' && ($pA || (!empty($GLOBALS['premium_acc']['mega_co_nz']['user']) && !empty($GLOBALS['premium_acc']['mega_co_nz']['pass'])))) {
23 $user = ($pA ? $_REQUEST['premium_user'] : $GLOBALS['premium_acc']['mega_co_nz']['user']);
24 $pass = ($pA ? $_REQUEST['premium_pass'] : $GLOBALS['premium_acc']['mega_co_nz']['pass']);
25 if ($pA && !empty($_POST['pA_encrypted'])) {
26 $user = decrypt(urldecode($user));
27 $pass = decrypt(urldecode($pass));
28 unset($_POST['pA_encrypted']);
29 }
30 if ($this->alwaysLogin) $this->cJar_load($user, $pass);
31 } else if ($this->alwaysLogin) html_error('[alwaysLogin is Enabled] Add an Account to Download');
32
33 do {
34 $reply = $this->apiReq(array('a' => 'g', 'g' => 1, (empty($fid[1]) ? 'p' : 'n') => $fid[2], 'ssl' => 2), (!empty($fid[1]) && !empty($fid[4]) ? $fid[4] : ''));
35 if (is_numeric($reply[0])) $this->CheckErr($reply[0]);
36 if (!empty($reply[0]['e']) && is_numeric($reply[0]['e'])) $this->CheckErr($reply[0]['e']);
37 if (empty($reply[0]['efq'])) {
38 $tLimit = $this->apiReq(array('a' => 'qbq', 's' => $reply[0]['s']));
39 if (is_numeric($tLimit[0]) && $tLimit[0] < 0) $this->CheckErr($tLimit[0], 'Error querying bandwidth quota');
40 } else $tLimit = array(0);
41 } while (!empty($user) && !empty($pass) && empty($this->cookie['sid']) && (!empty($reply[0]['efq']) || !empty($tLimit[0])) && $this->cJar_load($user, $pass));
42
43 if (!empty($reply[0]['efq'])) {
44 // This shouldn't happen on accounts, but i will check it anyway
45 if (!empty($reply[0]['tl'])) {
46 if (empty($this->cookie['sid'])) html_error('Anonymous Quota Limit Reached, add an account or wait ' . sec2time($reply[0]['tl']) . ' then try again.');
47 else html_error('Free Quota Limit Reached, wait ' . sec2time($reply[0]['tl']) . ' then try again.');
48 } else {
49 if (empty($this->cookie['sid'])) html_error('Anonymous Quota Limit Reached, add an account then try again.');
50 else html_error('Free Quota Limit Reached.');
51 }
52 }
53
54 if (!empty($tLimit[0])) {
55 if (empty($this->cookie['sid'])) html_error('Anonymous Traffic Limit Reached, add an account then try again.');
56 else html_error('Free Traffic Limit Reached.');
57 }
58
59 $key = $this->base64_to_a32($fid[3]);
60 $key = array($key[0] ^ $key[4], $key[1] ^ $key[5], $key[2] ^ $key[6], $key[3] ^ $key[7]);
61 $attr = $this->dec_attr($this->base64url_decode($reply[0]['at']), $key);
62 if (empty($attr)) html_error((!empty($fid[1]) ? 'Folder Error: ' : '').'File\'s key isn\'t correct.');
63
64 $this->RedirectDownload($reply[0]['g'], $attr['n'], 0, 0, $link, 0, 0, array('T8[fkey]' => $fid[3]));
65 }
66
67 private function CheckErr($code, $prefix = 'Error') {
68 $isLogin = (stripos($prefix, 'login') !== false);
69 switch ($err) {
70 default: $msg = '*No message for this error*';break;
71 case -1: $msg = 'An internal error has occurred';break;
72 case -2: $msg = 'You have passed invalid arguments to this command, your rapidleech is outdated?';break;
73 case -3: $msg = 'A temporary congestion or server malfunction prevented your request from being processed';break;
74 case -4: $msg = 'You have exceeded your command weight per time quota. Please wait a few seconds, then try again';break;
75 case -9: $msg = ($isLogin ? 'Email/Password incorrect' : 'File/Folder not found');break;
76 case -11: $msg = 'Access violation';break;
77 case -13: $msg = ($isLogin ? 'Account not Activated yet' : 'Trying to access an incomplete file');break;
78 case -14: $msg = 'A decryption operation failed';break;
79 case -15: $msg = 'Invalid or expired user session, please relogin';break;
80 case -16: $msg = ($isLogin ? 'Account blocked' : 'File/Folder not available, uploader\'s account is banned');break;
81 case -17: $msg = 'Request over quota';break;
82 case -18: $msg = ($isLogin ? 'Login service' : 'File/Folder') . ' temporarily not available, please try again later';break;
83 // Confirmed at page:
84 case -6: $msg = 'File not found, account was deleted';break;
85 }
86 html_error("$prefix: [$err] $msg.");
87 }
88
89 private function apiReq($atrr, $node = '') {
90 $try = 0;
91 do {
92 if ($try > 0) sleep(2);
93 $ret = $this->doApiReq($atrr, $node);
94 $try++;
95 } while ($try < 6 && $ret[0] == -3);
96 return $ret;
97 }
98
99 private function doApiReq($atrr, $node='') {
100 if (!function_exists('json_encode')) html_error('Error: Please enable JSON in php.');
101 $page = $this->GetPage('https://lu1.api.mega.nz/cs?id=' . ($this->seqno++) . (!empty($node) ? "&n=$node" : '') . (!empty($this->cookie['sid']) ? "&sid={$this->cookie['sid']}" : ''), 0, json_encode(array($atrr)), "https://mega.nz/\r\nContent-Type: application/json");
102 if (in_array(intval(substr($page, 9, 3)), array(500, 503))) return array(-3); // 500 Server Too Busy
103 list ($header, $page) = array_map('trim', explode("\r\n\r\n", $page, 2));
104 if (is_numeric($page)) return array(intval($page));
105 return $this->json2array($page);
106 }
107
108 private function str_to_a32($b) {
109 // Add padding, we need a string with a length multiple of 4
110 $b = str_pad($b, 4 * ceil(strlen($b) / 4), "\0");
111 return array_values(unpack('N*', $b));
112 }
113
114 private function a32_to_str($hex) {
115 return call_user_func_array('pack', array_merge(array('N*'), $hex));
116 }
117
118 private function base64url_encode($data) {
119 return strtr(rtrim(base64_encode($data), '='), '+/', '-_');
120 }
121
122 private function a32_to_base64($a) {
123 return $this->base64url_encode($this->a32_to_str($a));
124 }
125
126 private function base64url_decode($data) {
127 if (($s = (2 - strlen($data) * 3) % 4) < 2) $data .= substr(',,', $s);
128 return base64_decode(strtr($data, '-_,', '+/='));
129 }
130
131 private function base64_to_a32($s) {
132 return $this->str_to_a32($this->base64url_decode($s));
133 }
134
135 private function aes_cbc_encrypt($data, $key) {
136 if ($this->useOpenSSL) {
137 $data = str_pad($data, 16 * ceil(strlen($data) / 16), "\0"); // OpenSSL needs this padded.
138 return openssl_encrypt($data, 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
139 } else return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
140 }
141
142 private function aes_cbc_decrypt($data, $key) {
143 if ($this->useOpenSSL) {
144 $data = str_pad($data, 16 * ceil(strlen($data) / 16), "\0"); // OpenSSL needs this padded.
145 return openssl_decrypt($data, 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
146 } else return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
147 }
148
149 private function aes_cbc_encrypt_a32($data, $key) {
150 return $this->str_to_a32($this->aes_cbc_encrypt($this->a32_to_str($data), $this->a32_to_str($key)));
151 }
152
153 private function aes_cbc_decrypt_a32($data, $key) {
154 return $this->str_to_a32($this->aes_cbc_decrypt($this->a32_to_str($data), $this->a32_to_str($key)));
155 }
156
157 private function stringhash($s, $aeskey) {
158 $s32 = $this->str_to_a32($s);
159 $h32 = array(0, 0, 0, 0);
160 for ($i = 0; $i < count($s32); $i++) $h32[$i % 4] ^= $s32[$i];
161 for ($i = 0; $i < 0x4000; $i++) $h32 = $this->aes_cbc_encrypt_a32($h32, $aeskey);
162 return $this->a32_to_base64(array($h32[0], $h32[2]));
163 }
164
165 private function prepare_key($a) {
166 $pkey = array(0x93C467E3, 0x7DB0C7A4, 0xD1BE3F81, 0x0152CB56);
167 $count_a = count($a);
168 for ($r = 0; $r < 0x10000; $r++) {
169 for ($j = 0; $j < $count_a; $j += 4) {
170 $key = array(0, 0, 0, 0);
171 for ($i = 0; $i < 4; $i++) if ($i + $j < $count_a) $key[$i] = $a[$i + $j];
172 $pkey = $this->aes_cbc_encrypt_a32($pkey, $key);
173 }
174 }
175 return $pkey;
176 }
177
178 private function decrypt_key($a, $key) {
179 $x = array();
180 for ($i = 0; $i < count($a); $i += 4) $x = array_merge($x, $this->aes_cbc_decrypt_a32(array_slice($a, $i, 4), $key));
181 return $x;
182 }
183
184 private function mpi2bc($s) {
185 $s = bin2hex(substr($s, 2));
186 $len = strlen($s);
187 $n = 0;
188 for ($i = 0; $i < $len; $i++) $n = bcadd($n, bcmul(hexdec($s[$i]), bcpow(16, $len - $i - 1)));
189 return $n;
190 }
191
192 private function bin2int($str) {
193 $result = 0;
194 $n = strlen($str);
195 do {
196 $result = bcadd(bcmul($result, 256), ord($str[--$n]));
197 } while ($n > 0);
198 return $result;
199 }
200
201 private function int2bin($num) {
202 $result = '';
203 do {
204 $result .= chr(bcmod($num, 256));
205 $num = bcdiv($num, 256);
206 } while (bccomp($num, 0));
207 return $result;
208 }
209
210 private function bitOr($num1, $num2, $start_pos) {
211 $start_byte = intval($start_pos / 8);
212 $start_bit = $start_pos % 8;
213 $tmp1 = $this->int2bin($num1);
214 $num2 = bcmul($num2, 1 << $start_bit);
215 $tmp2 = $this->int2bin($num2);
216 if ($start_byte < strlen($tmp1)) {
217 $tmp2 |= substr($tmp1, $start_byte);
218 $tmp1 = substr($tmp1, 0, $start_byte) . $tmp2;
219 } else $tmp1 = str_pad($tmp1, $start_byte, "\0") . $tmp2;
220 return $this->bin2int($tmp1);
221 }
222
223 private function bitLen($num) {
224 $tmp = $this->int2bin($num);
225 $bit_len = strlen($tmp) * 8;
226 $tmp = ord($tmp[strlen($tmp) - 1]);
227 if (!$tmp) $bit_len -= 8;
228 else while (!($tmp & 0x80)) {
229 $bit_len--;
230 $tmp <<= 1;
231 }
232 return $bit_len;
233 }
234
235 private function rsa_decrypt($enc_data, $p, $q, $d) {
236 $enc_data = $this->int2bin($enc_data);
237 $exp = $d;
238 $modulus = bcmul($p, $q);
239 $data_len = strlen($enc_data);
240 $chunk_len = $this->bitLen($modulus) - 1;
241 $block_len = intval(ceil($chunk_len / 8));
242 $curr_pos = 0;
243 $bit_pos = 0;
244 $plain_data = 0;
245 while ($curr_pos < $data_len) {
246 $tmp = $this->bin2int(substr($enc_data, $curr_pos, $block_len));
247 $tmp = bcpowmod($tmp, $exp, $modulus);
248 $plain_data = $this->bitOr($plain_data, $tmp, $bit_pos);
249 $bit_pos += $chunk_len;
250 $curr_pos += $block_len;
251 }
252 return $this->int2bin($plain_data);
253 }
254
255 private function dec_attr($attr, $key) {
256 $attr = trim($this->aes_cbc_decrypt($attr, $this->a32_to_str($key)));
257 if (substr($attr, 0, 6) != 'MEGA{"') return false;
258 $attr = substr($attr, 4);$attr = substr($attr, 0, strrpos($attr, '}') + 1);
259 return $this->json2array($attr);
260 }
261
262 public function CheckBack($header) {
263 if (($statuscode = intval(substr($header, 9, 3))) != 200) {
264 switch ($statuscode) {
265 case 509: html_error('[Mega_co_nz] Transfer quota exceeded.');
266 case 503: html_error('[Mega_co_nz] Too many connections for this download.');
267 case 403: html_error('[Mega_co_nz] Link used/expired.');
268 case 404: html_error('[Mega_co_nz] Link expired.');
269 default : html_error('[Mega_co_nz][HTTP] '.trim(substr($header, 9, strpos($header, "\n") - 8)));
270 }
271 }
272
273 global $fp, $sFilters;
274 if (empty($fp) || !is_resource($fp)) html_error("Error: Your rapidleech version is outdated and it doesn't support this plugin.");
275 if (!empty($_GET['T8']['fkey'])) $key = $this->base64_to_a32(urldecode($_GET['T8']['fkey']));
276 elseif (preg_match('@^(T8|N)?!([^!]{8})!([\w\-\,]{43})@i', parse_url($_GET['referer'], PHP_URL_FRAGMENT), $dat)) $key = $this->base64_to_a32($dat[2]);
277 else html_error("[CB] File's key not found.");
278 $iv = array_merge(array_slice($key, 4, 2), array(0, 0));
279 $key = array($key[0] ^ $key[4], $key[1] ^ $key[5], $key[2] ^ $key[6], $key[3] ^ $key[7]);
280 $opts = array('iv' => $this->a32_to_str($iv), 'key' => $this->a32_to_str($key));
281
282 if (!stream_filter_register('MegaDlDecrypt', 'Th3822_MegaDlDecrypt') && !in_array('MegaDlDecrypt', stream_get_filters())) html_error('Error: Cannot register "MegaDlDecrypt" filter.');
283
284 if (!isset($sFilters) || !is_array($sFilters)) $sFilters = array();
285 if (empty($sFilters['MegaDlDecrypt'])) $sFilters['MegaDlDecrypt'] = stream_filter_prepend($fp, 'MegaDlDecrypt', STREAM_FILTER_READ, $opts);
286 if (!$sFilters['MegaDlDecrypt']) html_error('Error: Unknown error while initializing MegaDlDecrypt filter, cannot continue download.');
287 }
288
289 private function FSort($a, $b) {
290 return strcmp($a, $b['n']);
291 }
292
293 private function Folder($fnid, $fnk, $sfolder, $recursive) {
294 $files = $this->apiReq(array('a' => 'f', 'c' => 1, 'r' => (!empty($sfolder) || $recursive ? 1 : 0)), $fnid);
295 if (is_numeric($files[0])) $this->CheckErr($files[0], 'Cannot get folder contents');
296 $sfolder = (!empty($sfolder) ? array($sfolder => 1) : array());
297
298 foreach ($files[0]['f'] as $file) {
299 switch ($file['t']) {
300 case 0: // File
301 if (!empty($sfolder) && empty($sfolder[$file['p']])) break;
302 $keys = array();
303 foreach (explode('/', $file['k']) as $key) if (strpos($key, ':') !== false && $key = explode(':', $key, 2)) $keys[$key[0]] = $key[1];
304 if (empty($keys)) {
305 $key = $this->base64_to_a32($fnk);
306 $attr = $this->dec_attr($this->base64url_decode($file['a']), array($key[0] ^ $key[4], $key[1] ^ $key[5], $key[2] ^ $key[6], $key[3] ^ $key[7]));
307 if (!empty($attr)) textarea($attr);
308 break;
309 }
310 $key = $this->decrypt_key($this->base64_to_a32(reset($keys)), $this->base64_to_a32($fnk));
311 if (empty($key)) break;
312 $attr = $this->dec_attr($this->base64url_decode($file['a']), array($key[0] ^ $key[4], $key[1] ^ $key[5], $key[2] ^ $key[6], $key[3] ^ $key[7]));
313 if (!empty($attr)) $dfiles[$file['h']] = array('k' => $this->a32_to_base64($key), 'n' => $attr['n'], 'p' => $file['p']);
314 break;
315 case 1: // Folder
316 if (!empty($sfolder) && $recursive && !empty($sfolder[$file['p']])) $sfolder[$file['h']] = 1;
317 break;
318 }
319 }
320
321 if (empty($dfiles)) html_error('Error while decoding folder: Empty'.(!empty($sfolder) ? ' or Inexistent Sub-' : ' ').'Folder? [Subfolders: '.(!empty($sfolder) || $recursive ? 'Yes' : 'No').']');
322 uasort($dfiles, array($this, 'FSort'));
323
324 $files = array();
325 foreach ($dfiles as $file => $key) $files[] = "https://mega.nz/#N!$file!{$key['k']}!$fnid!Rapidleech";
326 $this->moveToAutoDownloader($files);
327 }
328
329 private function cJar_encrypt($data, $key = 0) {
330 if (empty($data)) return false;
331 if (!empty($key)) {
332 global $secretkey;
333 $_secretkey = $secretkey;
334 $secretkey = $key;
335 }
336 if (is_array($data)) {
337 $data = array_combine(array_map('base64_encode', array_map('encrypt', array_keys($data))), array_map('base64_encode', array_map('encrypt', array_values($data))));
338 } else {
339 $data = base64_encode(encrypt($data));
340 }
341 if (!empty($key)) $secretkey = $_secretkey;
342 return $data;
343 }
344
345 private function cJar_decrypt($data, $key = 0) {
346 if (empty($data)) return false;
347 if (!empty($key)) {
348 global $secretkey;
349 $_secretkey = $secretkey;
350 $secretkey = $key;
351 }
352 if (is_array($data)) {
353 $data = array_combine(array_map('decrypt', array_map('base64_decode', array_keys($data))), array_map('decrypt', array_map('base64_decode', array_values($data))));
354 } else {
355 $data = decrypt(base64_decode($data));
356 }
357 if (!empty($key)) $secretkey = $_secretkey;
358 return $data;
359 }
360
361 private function cJar_load($user, $pass, $filename = 'mega_dl.php') {
362 if (empty($user) || empty($pass)) html_error('Login Failed: User or Password is empty.');
363
364 $user = strtolower($user);
365 $filename = DOWNLOAD_DIR . basename($filename);
366 if (!file_exists($filename) || !($savedcookies = file($filename)) || !is_array($savedcookies = unserialize($savedcookies[1]))) return $this->Login($user, $pass);
367
368 $hash = sha1("$user$pass");
369 if (array_key_exists($hash, $savedcookies)) {
370 $key = substr(base64_encode(hash('sha512', "$user$pass", true)), 0, 56); // 56 chars cropped base64 encoded key to avoid blowfish issues with \0
371 $testCookie = ($this->cJar_decrypt($savedcookies[$hash]['enc'], $key) == 'OK') ? $this->cJar_decrypt($savedcookies[$hash]['cookie'], $key) : 0;
372 if (!empty($testCookie)) return $this->cJar_test($user, $pass, $testCookie, true);
373 }
374 return $this->Login($user, $pass);
375 }
376
377 private function cJar_test($user, $pass, $cookie, $preLogin = false) {
378 $this->cookie = array('sid' => $cookie['sid']);
379 $quota = $this->apiReq(array('a' => 'uq')); // I'm using the 'User quota details' request for validating the session id.
380 if (is_numeric($quota[0]) && $quota[0] < 0) {
381 if ($quota[0] == -15) { // Session code expired... We need to get a newer one.
382 if (!extension_loaded('bcmath')) html_error('This plugin needs BCMath extension for re-login.');
383 $this->cookie['sid'] = $cookie['sid'] = false; // Do not send old sid or it will get '-15' error.
384 $res = $this->apiReq(array('a' => 'us', 'user' => $user, 'uh' => $cookie['user_handle']));
385 if (is_numeric($res[0])) $this->CheckEr($res[0], 'Cannot re-login');
386 $rsa_priv_key = explode('/T8\\', $cookie['rsa_priv_key']);
387 $cookie['sid'] = $this->base64url_encode(substr(strrev($this->rsa_decrypt($this->mpi2bc($this->base64url_decode($res[0]['csid'])), $rsa_priv_key[0], $rsa_priv_key[1], $rsa_priv_key[2])), 0, 43));
388 } else $this->CheckEr($quota[0], 'Cannot validate saved-login');
389 }
390 $this->cookie = $cookie;
391 $this->cJar_save($user, $pass); // Update last used time.
392 return true;
393 }
394
395 private function cJar_save($user, $pass, $filename = 'mega_dl.php') {
396 $maxTime = 31 * 86400; // Max time to keep unused cookies saved (31 days)
397 $filename = DOWNLOAD_DIR . basename($filename);
398 if (file_exists($filename) && ($savedcookies = file($filename)) && is_array($savedcookies = unserialize($savedcookies[1]))) {
399 // Remove old cookies
400 foreach ($savedcookies as $k => $v) if (time() - $v['time'] >= $maxTime) unset($savedcookies[$k]);
401 } else $savedcookies = array();
402 $hash = sha1("$user$pass");
403 $key = substr(base64_encode(hash('sha512', "$user$pass", true)), 0, 56); // 56 chars cropped base64 encoded key to avoid blowfish issues with \0
404 $savedcookies[$hash] = array('time' => time(), 'enc' => $this->cJar_encrypt('OK', $key), 'cookie' => $this->cJar_encrypt($this->cookie, $key));
405
406 file_put_contents($filename, "<?php exit(); ?>\r\n" . serialize($savedcookies), LOCK_EX);
407 }
408
409 private function Login($user, $pass) {
410 if (!extension_loaded('bcmath')) html_error('This plugin needs BCMath extension for login.');
411 $this->cookie = array();
412 $password_aes = $this->prepare_key($this->str_to_a32($pass));
413 $this->cookie['user_handle'] = $this->stringhash($user, $password_aes);
414 $res = $this->apiReq(array('a' => 'us', 'user' => $user, 'uh' => $this->cookie['user_handle']));
415 if (is_numeric($res[0])) $this->CheckEr($res[0], 'Cannot login');
416 $master_key = $this->decrypt_key($this->base64_to_a32($res[0]['k']), $password_aes);
417 $privk = $this->a32_to_str($this->decrypt_key($this->base64_to_a32($res[0]['privk']), $master_key));
418 $rsa_priv_key = array(0, 0, 0, 0);
419 for ($i = 0; $i < 4; $i++) {
420 $l = ((ord($privk[0]) * 256 + ord($privk[1]) + 7) / 8) + 2;
421 $rsa_priv_key[$i] = $this->mpi2bc(substr($privk, 0, $l));
422 $privk = substr($privk, $l);
423 }
424 unset($privk, $rsa_priv_key[3]);
425 $this->cookie['sid'] = $this->base64url_encode(substr(strrev($this->rsa_decrypt($this->mpi2bc($this->base64url_decode($res[0]['csid'])), $rsa_priv_key[0], $rsa_priv_key[1], $rsa_priv_key[2])), 0, 43));
426 $this->cookie['rsa_priv_key'] = implode('/T8\\', $rsa_priv_key);
427 $this->cJar_save($user, $pass); // Update cookies file.
428 return true;
429 }
430}
431
432class Th3822_MegaDlDecrypt extends php_user_filter {
433 private $td;
434 public function onCreate() {
435 if (empty($this->params['iv']) || empty($this->params['key'])) return false;
436 $this->td = mcrypt_module_open('rijndael-128', '', 'ctr', '');
437 $init = mcrypt_generic_init($this->td, $this->params['key'], $this->params['iv']);
438 if ($init === false || $init < 0) return false;
439 if (!empty($this->params['waste']) && is_int($this->params['waste']) && $this->params['waste'] > 0 && $this->params['waste'] < 16) {
440 mdecrypt_generic($this->td, str_repeat('*', $this->params['waste']));
441 }
442 return true;
443 }
444
445 public function filter($in, $out, &$consumed, $stop) {
446 while ($bucket = stream_bucket_make_writeable($in)) {
447 if ($bucket->datalen > 0) {
448 $bucket->data = mdecrypt_generic($this->td, $bucket->data);
449 $consumed += $bucket->datalen;
450 stream_bucket_append($out, $bucket);
451 }
452 }
453 return PSFS_PASS_ON;
454 }
455
456 public function onClose() {
457 mcrypt_generic_deinit($this->td);
458 mcrypt_module_close($this->td);
459 }
460}
461
462//[24-2-2013] Written by Th3-822. (Rapidleech r415 or newer required)
463//[02-3-2013] Added "checks" for validating rapidleech version & added 2 error msg. - Th3-822
464//[27-3-2013] Simplified Stream decrypt function (The other one was not working well... After many tests looks like it's better now :D). - Th3-822
465//[20-7-2013] Fixed link regexp. - Th3-822
466//[09-8-2013] Added folder support and small fixes from upload plugin. (Download links that are fetched from a folder link are not public and only can be downloaded with this plugin.) - Th3-822
467//[30-1-2014] Fixed download from folders. - Th3-822
468//[09-2-2014] Fixed issues at link parsing. - Th3-822
469//[29-1-2015] Replaced 'T8' prefix at folder->file links for support on third-party downloaders using links with 'N' as prefix. - Th3-822
470//[04-2-2016] Added sub-folders support (fully) and added support for link suffix "!less" to disable recursive sub-folder download. - Th3-822
471//[27-12-2016] Added Login support for increase traffic limits & forced SSL on downloads to avoid corrupted downloads. - Th3-822
472//[05/02/2017] The api https://g.api.mega.co.nz/cs?id= has limited broadband, being old you have to change it for lu1.api.mega.nz http://i.imgur.com/ff23OUq.png - guest
473?>