diff --git a/.codeclimate.yml b/.codeclimate.yml index 72d1a0307..fe51f29f1 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,5 +1,6 @@ --- -engines: +version: "2" +plugins: csslint: enabled: false duplication: @@ -36,20 +37,25 @@ engines: config: file_extensions: "php" rulesets: "cleancode,unusedcode,codesize" -ratings: - paths: - - "**.css" - - "**.js" - - "**.php" -exclude_paths: -- e107_admin/core_image.php -- e107_plugins/log/js/awesomechart.js -- e107_docs/**/* -- e107_images/**/* -- e107_handlers/hybridauth/**/* -- e107_handlers/jsshrink/**/* -- e107_handlers/phpmailer/**/* -- e107_handlers/phpthumb/**/* -- e107_handlers/xmlrpc/**/* -- e107_web/**/* - +exclude_patterns: +- "config/" +- "db/" +- "dist/" +- "features/" +- "**/node_modules/" +- "script/" +- "**/spec/" +- "**/test/" +- "**/tests/" +- "**/vendor/" +- "**/*.d.ts" +- "e107_admin/core_image.php" +- "e107_plugins/log/js/awesomechart.js" +- "e107_docs/**/*" +- "e107_images/**/*" +- "e107_handlers/hybridauth/**/*" +- "e107_handlers/jsshrink/**/*" +- "e107_handlers/phpmailer/**/*" +- "e107_handlers/phpthumb/**/*" +- "e107_handlers/xmlrpc/**/*" +- "e107_web/**/*" diff --git a/e107_plugins/download/handlers/NginxSecureLinkMd5Decorator.php b/e107_plugins/download/handlers/NginxSecureLinkMd5Decorator.php new file mode 100644 index 000000000..7e36cbace --- /dev/null +++ b/e107_plugins/download/handlers/NginxSecureLinkMd5Decorator.php @@ -0,0 +1,52 @@ +url = $url; + $this->prefs = $preferences; + } + + public function decorate() + { + $prefs = $this->prefs; + $url = $this->url; + $expiry = intval($prefs['download_security_link_expiry']); + if ($expiry <= 0) + $expiry = PHP_INT_MAX; + else + $expiry = time() + $expiry; + $url_parts = parse_url($url); + $evaluation = str_replace( + self::supported_variables(), + array( + $expiry, + $url_parts['path'], + $_SERVER['REMOTE_ADDR'] + ), + $prefs['download_security_expression'] + ); + $query_string = $url_parts['query']; + parse_str($query_string, $query_args); + $query_args['md5'] = str_replace(array('+', '/', '='), array('-', '_', ''), base64_encode(md5($evaluation, true))); + if (strpos($prefs['download_security_expression'], '$secure_link_expires') !== false) + $query_args['expires'] = $expiry; + require_once(__DIR__ . '/../vendor/shim_http_build_url.php'); + return http_build_url($url_parts, array('query' => http_build_query($query_args))); + } +} \ No newline at end of file diff --git a/e107_plugins/download/handlers/SecureLinkDecorator.php b/e107_plugins/download/handlers/SecureLinkDecorator.php new file mode 100644 index 000000000..0dd48ab93 --- /dev/null +++ b/e107_plugins/download/handlers/SecureLinkDecorator.php @@ -0,0 +1,6 @@ + LAN_DL_SECURITY_MODE_NONE, + 'nginx-secure_link_md5' => LAN_DL_SECURITY_MODE_NGINX_SECURELINKMD5 + ); // optional - required only in case of e.g. tables JOIN. This also could be done with custom model (set it in init()) //protected $editQry = "SELECT * FROM #release WHERE release_id = {ID}"; @@ -1133,22 +1137,32 @@ $columnInfo = array( global $admin_log,$pref; $tp = e107::getParser(); + + $expected_params = array( + 'download_php', 'download_view', 'download_sort', 'download_order', + 'mirror_order', 'recent_download_days', 'agree_flag', 'download_email', + 'agree_text', 'download_denied', 'download_reportbroken', + 'download_security_mode', 'download_security_expression', 'download_security_link_expiry' + ); $temp = array(); - $temp['download_php'] = $_POST['download_php']; - $temp['download_view'] = $_POST['download_view']; - $temp['download_sort'] = $_POST['download_sort']; - $temp['download_order'] = $_POST['download_order']; - $temp['mirror_order'] = $_POST['mirror_order']; - $temp['recent_download_days'] = $_POST['recent_download_days']; - $temp['agree_flag'] = $_POST['agree_flag']; - $temp['download_email'] = $_POST['download_email']; - $temp['agree_text'] = $tp->toDB($_POST['agree_text']); - $temp['download_denied'] = $tp->toDB($_POST['download_denied']); - $temp['download_reportbroken'] = $_POST['download_reportbroken']; - - if ($_POST['download_subsub']) $temp['download_subsub'] = '1'; else $temp['download_subsub'] = '0'; - if ($_POST['download_incinfo']) $temp['download_incinfo'] = '1'; else $temp['download_incinfo'] = '0'; + foreach($expected_params as $expected_param) + { + $temp[$expected_param] = $_POST[$expected_param]; + } + + $temp['download_subsub'] = $_POST['download_subsub'] ? '1' : '0'; + $temp['download_incinfo'] = $_POST['download_incinfo'] ? '1' : '0'; + + if ($_POST['download_security_mode'] !== 'nginx-secure_link_md5') + { + unset($temp['download_security_mode']); + unset($temp['download_security_expression']); + unset($temp['download_security_link_expiry']); + e107::getConfig('core')->removePref('download_security_mode'); + e107::getConfig('core')->removePref('download_security_expression'); + e107::getConfig('core')->removePref('download_security_link_expiry'); + } e107::getConfig('core')->setPref($temp)->save(false); @@ -2093,14 +2107,33 @@ $columnInfo = array( } } + private function supported_secure_link_variables_html() + { + require_once(__DIR__."/../handlers/NginxSecureLinkMd5Decorator.php"); + $supported_secure_link_variables_html = ""; + return $supported_secure_link_variables_html; + } + + private function mirror_order_options_html($pref) + { + return ($pref['mirror_order'] == "0" ? "" : ""). + ($pref['mirror_order'] == "1" ? "" : ""). + ($pref['mirror_order'] == "2" ? "" : ""); + } + function show_download_options() { global $pref, $ns; - - require_once(e_HANDLER."form_handler.php"); - $frm = new e_form(true); //enable inner tabindex counter - - $agree_flag = $pref['agree_flag']; + + require_once(e_HANDLER."form_handler.php"); + $frm = new e_form(true); //enable inner tabindex counter + + $agree_flag = $pref['agree_flag']; $agree_text = $pref['agree_text']; $c = $pref['download_php'] ? " checked = 'checked' " : ""; $sacc = (varset($pref['download_incinfo'],0) == '1') ? " checked = 'checked' " : ""; @@ -2115,14 +2148,15 @@ $columnInfo = array( "ASC" => DOWLAN_62, "DESC" => DOWLAN_63 ); - + $text = "
\n @@ -2170,10 +2204,7 @@ $columnInfo = array( ".DOWLAN_160." - ".$this->mirror_order_options_html($pref)." @@ -2226,6 +2257,45 @@ $columnInfo = array(
+
+

+ ".LAN_DL_SECURITY_DESCRIPTION." +

+ + + + + + + + + + + + + + + + + + + +
".LAN_DL_SECURITY_MODE."".$frm->select('download_security_mode', $this->security_options, $pref['download_security_mode'])."
".LAN_DL_SECURITY_NGINX_SECURELINKMD5_EXPRESSION." + ".$frm->text('download_security_expression', $pref['download_security_expression'], 1024)." +
".LAN_DL_SECURITY_NGINX_SECURELINKMD5_EXPRESSION_HELP."
+ + ".LAN_DL_SECURITY_NGINX_SUPPORTED_VARIABLES_TOGGLE." + + +
".LAN_DL_SECURITY_LINK_EXPIRY." + ".$frm->text('download_security_link_expiry', $pref['download_security_link_expiry'], 16, array('pattern' => '\d+'))." +
".LAN_DL_SECURITY_LINK_EXPIRY_HELP."
+
+
+
+
@@ -2246,7 +2316,20 @@ $columnInfo = array( "; - // $ns->tablerender(LAN_DL_OPTIONS, $text); + + e107::js('footer-inline', " + $('#download-security-mode').on('change', function() { + var mode = $(this).val(); + + if (mode == 'nginx-secure_link_md5') { + $('#nginx-secure_link_md5').show('slow'); + return; + } + + $('#nginx-secure_link_md5').hide('slow'); + }); + "); + echo $text; } diff --git a/e107_plugins/download/languages/English/English_admin.php b/e107_plugins/download/languages/English/English_admin.php index 4f5f60ec2..a59d794dc 100644 --- a/e107_plugins/download/languages/English/English_admin.php +++ b/e107_plugins/download/languages/English/English_admin.php @@ -12,6 +12,7 @@ define("LAN_DL_OPTIONS", "Options"); //FIXME Use Generic define("LAN_DL_DOWNLOAD_OPT_GENERAL", "General"); define("LAN_DL_DOWNLOAD_OPT_BROKEN", "Reporting"); define("LAN_DL_DOWNLOAD_OPT_AGREE", "Agreements"); +define("LAN_DL_DOWNLOAD_OPT_SECURITY", "Protection"); define("LAN_DL_UPLOAD", "Upload"); //FIXME Use Generic define("LAN_DL_USE_PHP", "Use PHP"); define("LAN_DL_USE_PHP_INFO", "Checking this will send all download requests through PHP"); @@ -228,4 +229,17 @@ define("DOWLAN_HELP_10", "Help for upload options"); // define("DOWLAN_INSTALL_DONE", "Your download plugin is now installed"); // define("DOWLAN_DESCRIPTION", "This plugin is a fully featured Download system"); // define("DOWLAN_CAPTION", "Configure Download"); -?> + +define("LAN_DL_SECURITY_DESCRIPTION", "Downloads can make use of server-side URL protection features to prevent hotlinking and/or enforce link expiry. " . + "This section should be configured before the download server is configured to reduce the chance of disruption to downloaders."); +define("LAN_DL_SECURITY_MODE", "URL protection mode"); +define("LAN_DL_SECURITY_MODE_NONE", "None (Default)"); +define("LAN_DL_SECURITY_MODE_NGINX_SECURELINKMD5", "NGINX secure_link_md5"); +define("LAN_DL_SECURITY_NGINX_SUPPORTED_VARIABLES_TOGGLE", "Click to toggle list of supported NGINX variables"); +define("LAN_DL_SECURITY_NGINX_SECURELINKMD5_EXPRESSION", + "NGINX secure_link_md5 expression"); +define("LAN_DL_SECURITY_NGINX_SECURELINKMD5_EXPRESSION_HELP", "Same expression as configured on the server"); +define("LAN_DL_SECURITY_LINK_EXPIRY", "Duration of validity in seconds"); +define("LAN_DL_SECURITY_LINK_EXPIRY_HELP", "Number of seconds the download link should last after being generated. " . + "Only effective if the expression supports expiry time. " . + "Defaults to a very long time if this field is left blank."); \ No newline at end of file diff --git a/e107_plugins/download/plugin.xml b/e107_plugins/download/plugin.xml index 08dcdcb01..ece353f73 100755 --- a/e107_plugins/download/plugin.xml +++ b/e107_plugins/download/plugin.xml @@ -1,7 +1,7 @@ - + - This plugin is a fully featured File-download system + This plugin is a fully featured file download system content DOWLAN_CAPTION diff --git a/e107_plugins/download/request.php b/e107_plugins/download/request.php index fecf3c75c..afe4de188 100644 --- a/e107_plugins/download/request.php +++ b/e107_plugins/download/request.php @@ -72,7 +72,7 @@ if(strstr(e_QUERY, "mirror")) } $sql->update("download", "download_requested = download_requested + 1, download_mirror = '{$mstr}' WHERE download_id = '".intval($download_id)."'"); $sql->update("download_mirror", "mirror_count = mirror_count + 1 WHERE mirror_id = '".intval($mirror_id)."'"); - header("Location: {$gaddress}"); + header("Location: ".decorate_download_location($gaddress)); exit(); } @@ -189,7 +189,7 @@ if ($type == "file") $sql->update("download", "download_requested = download_requested + 1, download_mirror = '{$mstr}' WHERE download_id = '".intval($download_id)."'"); $sql->update("download_mirror", "mirror_count = mirror_count + 1 WHERE mirror_id = '".intval($mirror_id)."'"); - header("Location: ".$gaddress); + header("Location: ".decorate_download_location($gaddress)); exit(); } @@ -217,7 +217,7 @@ if ($type == "file") if (strstr($download_url, "http://") || strstr($download_url, "ftp://") || strstr($download_url, "https://")) { $download_url = e107::getParser()->parseTemplate($download_url,true); // support for shortcode-driven dynamic URLS. - e107::redirect($download_url); + e107::redirect(decorate_download_location($download_url)); // header("Location: {$download_url}"); exit(); } @@ -435,4 +435,12 @@ function check_download_limits() } } -?> +function decorate_download_location($url) +{ + $pref = e107::getPref(); + if ($pref['download_security_mode'] !== 'nginx-secure_link_md5') + return $url; + require_once(__DIR__."/handlers/NginxSecureLinkMd5Decorator.php"); + $decorator = new NginxSecureLinkMd5Decorator($url, $pref); + return $decorator->decorate(); +} \ No newline at end of file diff --git a/e107_plugins/download/vendor/shim_http_build_url.php b/e107_plugins/download/vendor/shim_http_build_url.php new file mode 100644 index 000000000..99b3337a3 --- /dev/null +++ b/e107_plugins/download/vendor/shim_http_build_url.php @@ -0,0 +1,104 @@ +