Th3-822

[rapidleech][d] mega_co_nz.php

Feb 25th, 2013
6,182
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 24.69 KB | None | 0 0
  1. <?php
  2. if (!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/
  7. class mega_co_nz extends DownloadClass {
  8.     private $useOpenSSL, $useOldFilter, $seqno, $cookie;
  9.     public function Download($link) {
  10.         $this->checkCryptDependences();
  11.         $this->checkBug78902($link);
  12.  
  13.         $this->seqno = mt_rand();
  14.         $this->changeMesg(lang(300).'<br />Mega.co.nz plugin by Th3-822'); // Please, do not remove or change this line contents. - Th3-822
  15.  
  16.         $fragment = parse_url($link, PHP_URL_FRAGMENT);
  17.         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));
  18.         if (!preg_match('@^(T8|N)?!([^!]{8})!([\w\-\,]{43})(?:(?:!|=###n=)([^!#]{8})(?:!|$))?@i', $fragment, $fid)) html_error('FileID or Key not found at link.');
  19.  
  20.         $pA = (empty($_REQUEST['premium_user']) || empty($_REQUEST['premium_pass']) ? false : true);
  21.         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'])))) {
  22.             $user = ($pA ? $_REQUEST['premium_user'] : $GLOBALS['premium_acc']['mega_co_nz']['user']);
  23.             $pass = ($pA ? $_REQUEST['premium_pass'] : $GLOBALS['premium_acc']['mega_co_nz']['pass']);
  24.             if ($pA && !empty($_POST['pA_encrypted'])) {
  25.                 $user = decrypt(urldecode($user));
  26.                 $pass = decrypt(urldecode($pass));
  27.                 unset($_POST['pA_encrypted']);
  28.             }
  29.         }
  30.  
  31.         do {
  32.             $reply = $this->apiReq(array('a' => 'g', 'g' => 1, (empty($fid[1]) ? 'p' : 'n') => $fid[2], 'ssl' => 0), (!empty($fid[1]) && !empty($fid[4]) ? $fid[4] : ''));
  33.             if (is_numeric($reply[0])) $this->CheckErr($reply[0]);
  34.             if (!empty($reply[0]['e']) && is_numeric($reply[0]['e'])) $this->CheckErr($reply[0]['e']);
  35.             $tLimit = $this->checkTrafficLimit($reply[0]['g']);
  36.         } while (!empty($user) && !empty($pass) && empty($this->cookie['sid']) && $tLimit && $this->cJar_load($user, $pass));
  37.  
  38.         if ($tLimit) {
  39.             if (empty($this->cookie['sid'])) html_error('Anonymous Traffic Limit Reached, add an account then try again.');
  40.             else html_error('Traffic Limit Reached.');
  41.         }
  42.  
  43.         $key = $this->base64_to_a32($fid[3]);
  44.         $key = array($key[0] ^ $key[4], $key[1] ^ $key[5], $key[2] ^ $key[6], $key[3] ^ $key[7]);
  45.         $attr = $this->dec_attr($this->base64url_decode($reply[0]['at']), $key);
  46.         if (empty($attr)) html_error((!empty($fid[1]) ? 'Folder Error: ' : '').'File\'s key isn\'t correct.');
  47.  
  48.         $this->RedirectDownload($reply[0]['g'], $attr['n'], 0, 0, $link, 0, 0, array('T8[fkey]' => $fid[3]));
  49.     }
  50.  
  51.     private function checkBug78902($link = '') {
  52.         // 7.4 - 7.4.2, 7.3.11 - 7.3.14, 7.2.24 - 7.2.*
  53.         if (substr(PHP_OS, 0, 3) == 'WIN' || version_compare(PHP_VERSION, '7.2.24', '<') || version_compare(PHP_VERSION, '7.4.2', '>') || !version_compare(PHP_VERSION, '7.3.14', '<=')) return;
  54.  
  55.         if (empty($link)) echo('<div id="mesg" width="100%" align="center"></div><br />');
  56.         $this->changeMesg('Warning: Running on PHP v' . PHP_VERSION . ' (Please Upgrade)<br />Downloads with this PHP release will be affected by the bug <a href="https://bugs.php.net/bug.php?id=78902">#78902</a> and will leak RAM until exhausted.<br />File may stop at a random size (up to ~1 GB).');
  57.  
  58.         if (!empty($_GET['method']) && $_GET['method'] == '78902') return;
  59.         if (!empty($link)) {
  60.             $form = $this->DefaultParamArr($link);
  61.             $form['method'] = '78902';
  62.  
  63.             echo "\n<form name='f78902' action='{$_SERVER['SCRIPT_NAME']}' method='POST'>\n";
  64.             foreach ($form as $name => $input) echo "\t<input type='hidden' name='$name' id='$name' value='" . htmlspecialchars($input, ENT_QUOTES) . "' />\n";
  65.             echo "\t<div><br /><input type='submit' value='Continue' /></div></form>\n";
  66.             include(TEMPLATE_DIR.'footer.php');
  67.             exit();
  68.         }
  69.     }
  70.  
  71.     private function checkCryptDependences() {
  72.         $this->useOpenSSL = (version_compare(PHP_VERSION, '5.4.0', '>=') && extension_loaded('openssl') && in_array('aes-128-cbc', ($ossl_ciphers = openssl_get_cipher_methods()), true));
  73.  
  74.         if (!$this->useOpenSSL || !in_array('aes-128-ctr', $ossl_ciphers, true))
  75.         {
  76.             $this->useOldFilter = true;
  77.             if (!extension_loaded('mcrypt') || !in_array('rijndael-128', mcrypt_list_algorithms(), true)) html_error("OpenSSL / Mcrypt module isn't installed or it doesn't have support for the needed encryption.");
  78.         } else $this->useOldFilter = false;
  79.     }
  80.  
  81.     // It's seems to not work properly with a HEAD request neither with a GET with a small Range (TODO: Add here a small copy of geturl that stops after getting the headers or add a parameter to geturl that does that)
  82.     private function checkTrafficLimit($link) {
  83.         if (extension_loaded('curl') && function_exists('curl_init') && function_exists('curl_exec')) {
  84.             $page = cURL($link, 0, 0, 0, 0, array(CURLOPT_NOBODY => true));
  85.         } else if (function_exists('readCustomHeaders')) {
  86.             $page = $this->GetPage($link, 0, 0, "https://mega.nz/\r\n:HEAD " . parse_url($link, PHP_URL_PATH) . " HTTP/1.1");
  87.         } else html_error('Your rapidleech is outdated and doesn\'t support a required check.');
  88.         return (intval(substr($page, 9, 3)) == 509);
  89.     }
  90.  
  91.     private function CheckErr($code, $prefix = 'Error') {
  92.         $isLogin = (stripos($prefix, 'login') !== false);
  93.         switch ($code) {
  94.             default: $msg = '*No message for this error*';break;
  95.             case -1: $msg = 'An internal error has occurred';break;
  96.             case -2: $msg = 'You have passed invalid arguments to this command, your rapidleech is outdated?';break;
  97.             case -3: $msg = 'A temporary congestion or server malfunction prevented your request from being processed';break;
  98.             case -4: $msg = 'You have exceeded your command weight per time quota. Please wait a few seconds, then try again';break;
  99.             case -9: $msg = ($isLogin ? 'Email/Password incorrect' : 'File/Folder not found');break;
  100.             case -11: $msg = 'Access violation';break;
  101.             case -13: $msg = ($isLogin ? 'Account not Activated yet' : 'Trying to access an incomplete file');break;
  102.             case -14: $msg = 'A decryption operation failed';break;
  103.             case -15: $msg = 'Invalid or expired user session, please relogin';break;
  104.             case -16: $msg = ($isLogin ? 'Account blocked' : 'File/Folder not available, uploader\'s account is banned');break;
  105.             case -17: $msg = 'Request over quota';break;
  106.             case -18: $msg = ($isLogin ? 'Login service' : 'File/Folder') . ' temporarily not available, please try again later';break;
  107.             // Confirmed at page:
  108.             case -6: $msg = 'File not found, account was deleted';break;
  109.         }
  110.         html_error("$prefix: [$code] $msg.");
  111.     }
  112.  
  113.     private function apiReq($atrr, $node = '') {
  114.         $try = 0;
  115.         do {
  116.             if ($try > 0) sleep(2);
  117.             $ret = $this->doApiReq($atrr, $node);
  118.             $try++;
  119.         } while ($try < 6 && $ret[0] == -3);
  120.         return $ret;
  121.     }
  122.  
  123.     private function doApiReq($atrr, $node='') {
  124.         if (!function_exists('json_encode')) html_error('Error: Please enable JSON in php.');
  125.         $page = $this->GetPage('https://g.api.mega.co.nz/cs?id=' . ($this->seqno++) . (!empty($node) ? "&n=$node" : '') . (!empty($this->cookie['sid']) ? "&sid={$this->cookie['sid']}" : ''), 0, json_encode((!empty($atrr[0]) && is_array($atrr[0])) ? $atrr : array($atrr)), "https://mega.nz/\r\nContent-Type: application/json");
  126.         if (in_array(intval(substr($page, 9, 3)), array(500, 503))) return array(-3); //  500 Server Too Busy
  127.         list ($header, $page) = array_map('trim', explode("\r\n\r\n", $page, 2));
  128.         if (is_numeric($page)) return array(intval($page));
  129.         return $this->json2array($page);
  130.     }
  131.  
  132.     private function str_to_a32($b) {
  133.         // Add padding, we need a string with a length multiple of 4
  134.         $b = str_pad($b, 4 * ceil(strlen($b) / 4), "\0");
  135.         return array_values(unpack('N*', $b));
  136.     }
  137.  
  138.     private function a32_to_str($hex) {
  139.         return call_user_func_array('pack', array_merge(array('N*'), $hex));
  140.     }
  141.  
  142.     private function base64url_encode($data) {
  143.         return strtr(rtrim(base64_encode($data), '='), '+/', '-_');
  144.     }
  145.  
  146.     private function a32_to_base64($a) {
  147.         return $this->base64url_encode($this->a32_to_str($a));
  148.     }
  149.  
  150.     private function base64url_decode($data) {
  151.         if (($s = (2 - strlen($data) * 3) % 4) < 2) $data .= substr(',,', $s);
  152.         return base64_decode(strtr($data, '-_,', '+/='));
  153.     }
  154.  
  155.     private function base64_to_a32($s) {
  156.         return $this->str_to_a32($this->base64url_decode($s));
  157.     }
  158.  
  159.     private function aes_cbc_encrypt($data, $key) {
  160.         if ($this->useOpenSSL) {
  161.             $data = str_pad($data, 16 * ceil(strlen($data) / 16), "\0"); // OpenSSL needs this padded.
  162.             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");
  163.         } 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");
  164.     }
  165.  
  166.     private function aes_cbc_decrypt($data, $key) {
  167.         if ($this->useOpenSSL) {
  168.             $data = str_pad($data, 16 * ceil(strlen($data) / 16), "\0"); // OpenSSL needs this padded.
  169.             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");
  170.         } 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");
  171.     }
  172.  
  173.     private function aes_cbc_encrypt_a32($data, $key) {
  174.         return $this->str_to_a32($this->aes_cbc_encrypt($this->a32_to_str($data), $this->a32_to_str($key)));
  175.     }
  176.  
  177.     private function aes_cbc_decrypt_a32($data, $key) {
  178.         return $this->str_to_a32($this->aes_cbc_decrypt($this->a32_to_str($data), $this->a32_to_str($key)));
  179.     }
  180.  
  181.     private function stringhash($s, $aeskey) {
  182.         $s32 = $this->str_to_a32($s);
  183.         $h32 = array(0, 0, 0, 0);
  184.         for ($i = 0; $i < count($s32); $i++) $h32[$i % 4] ^= $s32[$i];
  185.         for ($i = 0; $i < 0x4000; $i++) $h32 = $this->aes_cbc_encrypt_a32($h32, $aeskey);
  186.         return $this->a32_to_base64(array($h32[0], $h32[2]));
  187.     }
  188.  
  189.     private function prepare_key($a) {
  190.         $pkey = array(0x93C467E3, 0x7DB0C7A4, 0xD1BE3F81, 0x0152CB56);
  191.         $count_a = count($a);
  192.         for ($r = 0; $r < 0x10000; $r++) {
  193.             for ($j = 0; $j < $count_a; $j += 4) {
  194.                 $key = array(0, 0, 0, 0);
  195.                 for ($i = 0; $i < 4; $i++) if ($i + $j < $count_a) $key[$i] = $a[$i + $j];
  196.                 $pkey = $this->aes_cbc_encrypt_a32($pkey, $key);
  197.             }
  198.         }
  199.         return $pkey;
  200.     }
  201.  
  202.     private function decrypt_key($a, $key) {
  203.         $x = array();
  204.         for ($i = 0; $i < count($a); $i += 4) $x = array_merge($x, $this->aes_cbc_decrypt_a32(array_slice($a, $i, 4), $key));
  205.         return $x;
  206.     }
  207.  
  208.     private function mpi2bc($s) {
  209.         $s = bin2hex(substr($s, 2));
  210.         $len = strlen($s);
  211.         $n = 0;
  212.         for ($i = 0; $i < $len; $i++) $n = bcadd($n, bcmul(hexdec($s[$i]), bcpow(16, $len - $i - 1)));
  213.         return $n;
  214.     }
  215.  
  216.     private function bin2int($str) {
  217.         $result = 0;
  218.         $n = strlen($str);
  219.         do {
  220.             $result = bcadd(bcmul($result, 256), ord($str[--$n]));
  221.         } while ($n > 0);
  222.         return $result;
  223.     }
  224.  
  225.     private function int2bin($num) {
  226.         $result = '';
  227.         do {
  228.             $result .= chr(bcmod($num, 256));
  229.             $num = bcdiv($num, 256);
  230.         } while (bccomp($num, 0));
  231.         return $result;
  232.     }
  233.  
  234.     private function bitOr($num1, $num2, $start_pos) {
  235.         $start_byte = intval($start_pos / 8);
  236.         $start_bit = $start_pos % 8;
  237.         $tmp1 = $this->int2bin($num1);
  238.         $num2 = bcmul($num2, 1 << $start_bit);
  239.         $tmp2 = $this->int2bin($num2);
  240.         if ($start_byte < strlen($tmp1)) {
  241.             $tmp2 |= substr($tmp1, $start_byte);
  242.             $tmp1 = substr($tmp1, 0, $start_byte) . $tmp2;
  243.         } else $tmp1 = str_pad($tmp1, $start_byte, "\0") . $tmp2;
  244.         return $this->bin2int($tmp1);
  245.     }
  246.  
  247.     private function bitLen($num) {
  248.         $tmp = $this->int2bin($num);
  249.         $bit_len = strlen($tmp) * 8;
  250.         $tmp = ord($tmp[strlen($tmp) - 1]);
  251.         if (!$tmp) $bit_len -= 8;
  252.         else while (!($tmp & 0x80)) {
  253.             $bit_len--;
  254.             $tmp <<= 1;
  255.         }
  256.         return $bit_len;
  257.     }
  258.  
  259.     private function rsa_decrypt($enc_data, $p, $q, $d) {
  260.         $enc_data = $this->int2bin($enc_data);
  261.         $exp = $d;
  262.         $modulus = bcmul($p, $q);
  263.         $data_len = strlen($enc_data);
  264.         $chunk_len = $this->bitLen($modulus) - 1;
  265.         $block_len = intval(ceil($chunk_len / 8));
  266.         $curr_pos = 0;
  267.         $bit_pos = 0;
  268.         $plain_data = 0;
  269.         while ($curr_pos < $data_len) {
  270.             $tmp = $this->bin2int(substr($enc_data, $curr_pos, $block_len));
  271.             $tmp = bcpowmod($tmp, $exp, $modulus);
  272.             $plain_data = $this->bitOr($plain_data, $tmp, $bit_pos);
  273.             $bit_pos += $chunk_len;
  274.             $curr_pos += $block_len;
  275.         }
  276.         return $this->int2bin($plain_data);
  277.     }
  278.  
  279.     private function dec_attr($attr, $key) {
  280.         $attr = trim($this->aes_cbc_decrypt($attr, $this->a32_to_str($key)));
  281.         if (substr($attr, 0, 6) != 'MEGA{"') return false;
  282.         $attr = substr($attr, 4);$attr = substr($attr, 0, strrpos($attr, '}') + 1);
  283.         return $this->json2array($attr);
  284.     }
  285.  
  286.     public function CheckBack($header) {
  287.         $this->checkBug78902();
  288.         if (($statuscode = intval(substr($header, 9, 3))) != 200) {
  289.             switch ($statuscode) {
  290.                 case 509: html_error('[Mega_co_nz] Transfer quota exceeded.');
  291.                 case 503: html_error('[Mega_co_nz] Too many connections for this download.');
  292.                 case 403: html_error('[Mega_co_nz] Link used/expired.');
  293.                 case 404: html_error('[Mega_co_nz] Link expired.');
  294.                 default : html_error('[Mega_co_nz][HTTP] '.trim(substr($header, 9, strpos($header, "\n") - 8)));
  295.             }
  296.         }
  297.  
  298.         global $fp, $sFilters;
  299.         if (empty($fp) || !is_resource($fp)) html_error("Error: Your rapidleech version is outdated and it doesn't support this plugin.");
  300.         $this->checkCryptDependences();
  301.         if (!empty($_GET['T8']['fkey'])) $key = $this->base64_to_a32(urldecode($_GET['T8']['fkey']));
  302.         elseif (preg_match('@^(T8|N)?!([^!]{8})!([\w\-\,]{43})@i', parse_url($_GET['referer'], PHP_URL_FRAGMENT), $dat)) $key = $this->base64_to_a32($dat[2]);
  303.         else html_error("[CB] File's key not found.");
  304.         $iv = array_merge(array_slice($key, 4, 2), array(0, 0));
  305.         $key = array($key[0] ^ $key[4], $key[1] ^ $key[5], $key[2] ^ $key[6], $key[3] ^ $key[7]);
  306.         $opts = array('iv' => $this->a32_to_str($iv), 'key' => $this->a32_to_str($key));
  307.  
  308.         if (!stream_filter_register('MegaDlDecrypt', ($this->useOldFilter ? 'Th3822_MegaDlDecrypt_Old' : 'Th3822_MegaDlDecrypt')) && !in_array('MegaDlDecrypt', stream_get_filters())) html_error('Error: Cannot register "MegaDlDecrypt" filter.');
  309.  
  310.         if (!isset($sFilters) || !is_array($sFilters)) $sFilters = array();
  311.         if (empty($sFilters['MegaDlDecrypt'])) $sFilters['MegaDlDecrypt'] = stream_filter_append($fp, 'MegaDlDecrypt', STREAM_FILTER_READ, $opts);
  312.         if (!$sFilters['MegaDlDecrypt']) html_error('Error: Unknown error while initializing MegaDlDecrypt filter, cannot continue download.');
  313.     }
  314.  
  315.     private function FSort($a, $b) {
  316.         return strcmp($a['n'], $b['n']);
  317.     }
  318.  
  319.     private function Folder($fnid, $fnk, $sfolder, $recursive) {
  320.         $files = $this->apiReq(array('a' => 'f', 'c' => 1, 'r' => (!empty($sfolder) || $recursive ? 1 : 0)), $fnid);
  321.         if (is_numeric($files[0])) $this->CheckErr($files[0], 'Cannot get folder contents');
  322.         $sfolder = (!empty($sfolder) ? array($sfolder => 1) : array());
  323.  
  324.         foreach ($files[0]['f'] as $file) {
  325.             switch ($file['t']) {
  326.                 case 0: // File
  327.                     if (!empty($sfolder) && empty($sfolder[$file['p']])) break;
  328.                     $keys = array();
  329.                     foreach (explode('/', $file['k']) as $key) if (strpos($key, ':') !== false && $key = explode(':', $key, 2)) $keys[$key[0]] = $key[1];
  330.                     if (empty($keys)) {
  331.                         $key = $this->base64_to_a32($fnk);
  332.                         $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]));
  333.                         if (!empty($attr)) textarea($attr);
  334.                         break;
  335.                     }
  336.                     $key = $this->decrypt_key($this->base64_to_a32(reset($keys)), $this->base64_to_a32($fnk));
  337.                     if (empty($key)) break;
  338.                     $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]));
  339.                     if (!empty($attr)) $dfiles[$file['h']] = array('k' => $this->a32_to_base64($key), 'n' => $attr['n'], 'p' => $file['p']);
  340.                     break;
  341.                 case 1: // Folder
  342.                     if (!empty($sfolder) && $recursive && !empty($sfolder[$file['p']])) $sfolder[$file['h']] = 1;
  343.                     break;
  344.             }
  345.         }
  346.  
  347.         if (empty($dfiles)) html_error('Error while decoding folder: Empty'.(!empty($sfolder) ? ' or Inexistent Sub-' : ' ').'Folder? [Subfolders: '.(!empty($sfolder) || $recursive ? 'Yes' : 'No').']');
  348.         uasort($dfiles, array($this, 'FSort'));
  349.  
  350.         $files = array();
  351.         foreach ($dfiles as $file => $key) $files[] = "https://mega.nz/#N!$file!{$key['k']}!$fnid!Rapidleech";
  352.         $this->moveToAutoDownloader($files);
  353.     }
  354.  
  355.     private function cJar_encrypt($data, $key = 0) {
  356.         if (empty($data)) return false;
  357.         if (!empty($key)) {
  358.             global $secretkey;
  359.             $_secretkey = $secretkey;
  360.             $secretkey = $key;
  361.         }
  362.         if (is_array($data)) {
  363.             $data = array_combine(array_map('base64_encode', array_map('encrypt', array_keys($data))), array_map('base64_encode', array_map('encrypt', array_values($data))));
  364.         } else {
  365.             $data = base64_encode(encrypt($data));
  366.         }
  367.         if (!empty($key)) $secretkey = $_secretkey;
  368.         return $data;
  369.     }
  370.  
  371.     private function cJar_decrypt($data, $key = 0) {
  372.         if (empty($data)) return false;
  373.         if (!empty($key)) {
  374.             global $secretkey;
  375.             $_secretkey = $secretkey;
  376.             $secretkey = $key;
  377.         }
  378.         if (is_array($data)) {
  379.             $data = array_combine(array_map('decrypt', array_map('base64_decode', array_keys($data))), array_map('decrypt', array_map('base64_decode', array_values($data))));
  380.         } else {
  381.             $data = decrypt(base64_decode($data));
  382.         }
  383.         if (!empty($key)) $secretkey = $_secretkey;
  384.         return $data;
  385.     }
  386.  
  387.     private function cJar_load($user, $pass, $filename = 'mega_dl.php') {
  388.         if (empty($user) || empty($pass)) html_error('Login Failed: User or Password is empty.');
  389.  
  390.         $user = strtolower($user);
  391.         $filename = DOWNLOAD_DIR . basename($filename);
  392.         if (!file_exists($filename) || !($savedcookies = file($filename)) || !is_array($savedcookies = unserialize($savedcookies[1]))) return $this->Login($user, $pass);
  393.  
  394.         $hash = sha1("$user$pass");
  395.         if (array_key_exists($hash, $savedcookies)) {
  396.             $key = substr(base64_encode(hash('sha512', "$user$pass", true)), 0, 56); // 56 chars cropped base64 encoded key to avoid blowfish issues with \0
  397.             $testCookie = ($this->cJar_decrypt($savedcookies[$hash]['enc'], $key) == 'OK') ? $this->cJar_decrypt($savedcookies[$hash]['cookie'], $key) : 0;
  398.             if (!empty($testCookie)) return $this->cJar_test($user, $pass, $testCookie, true);
  399.         }
  400.         return $this->Login($user, $pass);
  401.     }
  402.  
  403.     private function cJar_test($user, $pass, $cookie, $preLogin = false) {
  404.         $this->cookie = array('sid' => $cookie['sid']);
  405.         $quota = $this->apiReq(array('a' => 'uq')); // I'm using the 'User quota details' request for validating the session id.
  406.         if (is_numeric($quota[0]) && $quota[0] < 0) {
  407.             if ($quota[0] == -15) { // Session code expired... We need to get a newer one.
  408.                 if (!extension_loaded('bcmath')) html_error('This plugin needs BCMath extension for re-login.');
  409.                 $this->cookie['sid'] = $cookie['sid'] = false; // Do not send old sid or it will get '-15' error.
  410.                 $res = $this->apiReq(array('a' => 'us', 'user' => $user, 'uh' => $cookie['user_handle']));
  411.                 if (is_numeric($res[0])) $this->CheckEr($res[0], 'Cannot re-login');
  412.                 $rsa_priv_key = explode('/T8\\', $cookie['rsa_priv_key']);
  413.                 $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));
  414.             } else $this->CheckEr($quota[0], 'Cannot validate saved-login');
  415.         }
  416.         $this->cookie = $cookie;
  417.         $this->cJar_save($user, $pass); // Update last used time.
  418.         return true;
  419.     }
  420.  
  421.     private function cJar_save($user, $pass, $filename = 'mega_dl.php') {
  422.         $maxTime = 31 * 86400; // Max time to keep unused cookies saved (31 days)
  423.         $filename = DOWNLOAD_DIR . basename($filename);
  424.         if (file_exists($filename) && ($savedcookies = file($filename)) && is_array($savedcookies = unserialize($savedcookies[1]))) {
  425.             // Remove old cookies
  426.             foreach ($savedcookies as $k => $v) if (time() - $v['time'] >= $maxTime) unset($savedcookies[$k]);
  427.         } else $savedcookies = array();
  428.         $hash = sha1("$user$pass");
  429.         $key = substr(base64_encode(hash('sha512', "$user$pass", true)), 0, 56); // 56 chars cropped base64 encoded key to avoid blowfish issues with \0
  430.         $savedcookies[$hash] = array('time' => time(), 'enc' => $this->cJar_encrypt('OK', $key), 'cookie' => $this->cJar_encrypt($this->cookie, $key));
  431.  
  432.         file_put_contents($filename, "<?php exit(); ?>\r\n" . serialize($savedcookies), LOCK_EX);
  433.     }
  434.  
  435.     private function Login($user, $pass) {
  436.         if (!extension_loaded('bcmath')) html_error('This plugin needs BCMath extension for login.');
  437.         $this->cookie = array();
  438.         $password_aes = $this->prepare_key($this->str_to_a32($pass));
  439.         $this->cookie['user_handle'] = $this->stringhash($user, $password_aes);
  440.         $res = $this->apiReq(array('a' => 'us', 'user' => $user, 'uh' => $this->cookie['user_handle']));
  441.         if (is_numeric($res[0])) $this->CheckEr($res[0], 'Cannot login');
  442.         $master_key = $this->decrypt_key($this->base64_to_a32($res[0]['k']), $password_aes);
  443.         $privk = $this->a32_to_str($this->decrypt_key($this->base64_to_a32($res[0]['privk']), $master_key));
  444.         $rsa_priv_key = array(0, 0, 0, 0);
  445.         for ($i = 0; $i < 4; $i++) {
  446.             $l = ((ord($privk[0]) * 256 + ord($privk[1]) + 7) / 8) + 2;
  447.             $rsa_priv_key[$i] = $this->mpi2bc(substr($privk, 0, $l));
  448.             $privk = substr($privk, $l);
  449.         }
  450.         unset($privk, $rsa_priv_key[3]);
  451.         $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));
  452.         $this->cookie['rsa_priv_key'] = implode('/T8\\', $rsa_priv_key);
  453.         $this->cJar_save($user, $pass); // Update cookies file.
  454.         return true;
  455.     }
  456. }
  457.  
  458. class Th3822_MegaDlDecrypt extends php_user_filter {
  459.     private $key, $iv, $start, $lastBlock, $waste;
  460.     public function onCreate() {
  461.         if (empty($this->params['iv']) || empty($this->params['key'])) return false;
  462.         $this->key = $this->params['key'];
  463.         $this->iv = $this->params['iv'];
  464.         $this->waste = $this->lastBlock = $this->start = 0;
  465.         if (!empty($this->params['startFrom']) && is_numeric($this->params['startFrom']) && $this->params['startFrom'] > 0) {
  466.             $this->setNextStart($this->params['startFrom']);
  467.         }
  468.         return true;
  469.     }
  470.  
  471.     public function filter($in, $out, &$consumed, $stop) {
  472.         while ($bucket = stream_bucket_make_writeable($in)) {
  473.             if ($bucket->datalen > 0) {
  474.                 if ($this->waste > 0) $bucket->data = str_repeat('*', $this->waste) . $bucket->data;
  475.                 $bucket->data = openssl_decrypt($bucket->data, 'aes-128-ctr', $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
  476.                 if ($this->waste > 0) $bucket->data = substr($bucket->data, $this->waste);
  477.                 $consumed += $bucket->datalen;
  478.                 $this->setNextStart($bucket->datalen);
  479.                 stream_bucket_append($out, $bucket);
  480.             }
  481.         }
  482.         return PSFS_PASS_ON;
  483.     }
  484.  
  485.     private function setNextStart($nextStart) {
  486.         $start = $this->start + $nextStart;
  487.         $block = floor($start / 16);
  488.         if (($incBlocks = $block - $this->lastBlock) > 0) $this->increaseIV($incBlocks);
  489.         $this->start = $start;
  490.         $this->lastBlock = $block;
  491.         $this->waste = $start % 16;
  492.     }
  493.  
  494.     private function increaseIV($inc) {
  495.         $i = 16;
  496.         while ($inc > 0 && --$i >= 0) {
  497.             $sum = ord($this->iv{$i}) + $inc;
  498.             $this->iv{$i} = chr($sum & 0xFF);
  499.             $inc = $sum >> 8;
  500.         }
  501.     }
  502. }
  503.  
  504. class Th3822_MegaDlDecrypt_Old extends php_user_filter {
  505.     private $td;
  506.     public function onCreate() {
  507.         if (empty($this->params['iv']) || empty($this->params['key'])) return false;
  508.         $this->td = mcrypt_module_open('rijndael-128', '', 'ctr', '');
  509.         $iv = $this->params['iv'];
  510.         if (!empty($this->params['startFrom']) && is_numeric($this->params['startFrom']) && $this->params['startFrom'] > 0) {
  511.             $blocks = floor($this->params['startFrom'] / 16);
  512.             $waste = $this->params['startFrom'] % 16;
  513.             if ($blocks > 0) $this->increaseIV($iv, $blocks);
  514.         } else $waste = 0;
  515.         $init = mcrypt_generic_init($this->td, $this->params['key'], $iv);
  516.         if ($init === false || $init < 0) return false;
  517.         if ($waste > 0) mdecrypt_generic($this->td, str_repeat('*', $waste));
  518.         return true;
  519.     }
  520.  
  521.     public function filter($in, $out, &$consumed, $stop) {
  522.         while ($bucket = stream_bucket_make_writeable($in)) {
  523.             if ($bucket->datalen > 0) {
  524.                 $bucket->data = mdecrypt_generic($this->td, $bucket->data);
  525.                 $consumed += $bucket->datalen;
  526.                 stream_bucket_append($out, $bucket);
  527.             }
  528.         }
  529.         return PSFS_PASS_ON;
  530.     }
  531.  
  532.     public function onClose() {
  533.         mcrypt_generic_deinit($this->td);
  534.         mcrypt_module_close($this->td);
  535.     }
  536.  
  537.     private function increaseIV(&$iv, $inc = 1) {
  538.         $i = 16;
  539.         while ($inc > 0 && --$i >= 0) {
  540.             $sum = ord($iv{$i}) + $inc;
  541.             $iv{$i} = chr($sum & 0xFF);
  542.             $inc = $sum >> 8;
  543.         }
  544.     }
  545. }
  546.  
  547. //[24-2-2013] Written by Th3-822. (Rapidleech r415 or newer required)
  548. //[02-3-2013] Added "checks" for validating rapidleech version & added 2 error msg. - Th3-822
  549. //[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
  550. //[20-7-2013] Fixed link regexp. - Th3-822
  551. //[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
  552. //[30-1-2014] Fixed download from folders. - Th3-822
  553. //[09-2-2014] Fixed issues at link parsing. - Th3-822
  554. //[29-1-2015] Replaced 'T8' prefix at folder->file links for support on third-party downloaders using links with 'N' as prefix. - Th3-822
  555. //[04-2-2016] Added sub-folders support (fully) and added support for link suffix "!less" to disable recursive sub-folder download. - Th3-822
  556. //[27-12-2016] Added Login support for increase traffic limits & forced SSL on downloads to avoid corrupted downloads. - Th3-822
  557. //[12-11-2017] Removed SSL from downloads to increase download speed & updated Th3822_MegaDlDecrypt class. - Th3-822
  558. //[18-10-2019] Added new Th3822_MegaDlDecrypt class using OpenSSL & Removed mcrypt dependence to run, now it can be used with only the OpenSSL module (Btw, it's Faster). - Th3-822
Add Comment
Please, Sign In to add comment