From d7418beea3f21ce7346cf39ae13fa77246a615bc Mon Sep 17 00:00:00 2001 From: Thomas M Date: Wed, 22 Mar 2017 23:22:48 +0100 Subject: [PATCH 1/9] Do not delete a folder you deleted before and create after --- index.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/index.php b/index.php index a2ffe79..2163922 100644 --- a/index.php +++ b/index.php @@ -787,7 +787,7 @@ //Polish $_TRANSLATIONS["pl"] = array( "file_name" => "Nazwa pliku", - "size" => "Rozmiar", + "size" => "Rozmiar", "last_changed" => "Data zmiany", "total_used_space" => "Cała przestrzeń", "free_space" => "Wolna przestrzeń", @@ -796,17 +796,17 @@ "failed_upload" => "Przesłanie pliku nie powiodło się", "failed_move" => "Przenoszenie pliku nie powiodło się!", "wrong_password" => "Niepoprawne hasło", - "make_directory" => "Nowy folder", + "make_directory" => "Nowy folder", "new_dir_failed" => "Błąd podczas tworzenia nowego folderu", "chmod_dir_failed" => "Błąd podczas zmiany uprawnień folderu", "unable_to_read_dir" => "Odczytanie folderu nie powiodło się", - "location" => "Miejsce", + "location" => "Miejsce", "root" => "Start", "log_file_permission_error" => "Brak uprawnień aby utworzyć dziennik działań.", "upload_not_allowed" => "Konfiguracja zabrania przesłania pliku do tego folderu.", "upload_dir_not_writable" => "Nie można zapisać pliku do tego folderu.", "mobile_version" => "Wersja mobilna", - "standard_version" => "Widok standardowy", + "standard_version" => "Widok standardowy", "page_load_time" => "Załadowano w %.2f ms", "wrong_pass" => "Niepoprawna nazwa użytkownika lub złe hasło", "username" => "Użytkownik", @@ -1961,7 +1961,7 @@ public static function emailNotification($path, $isFile) mail(EncodeExplorer::getConfig('upload_email'), "Upload notification", $message); } } -} + } // // The class controls logging in and authentication @@ -2265,8 +2265,8 @@ function run($location) FileManager::delete_file($path); } } - } -} + } + } // // Dir class holds the information about one directory in the list @@ -2626,7 +2626,7 @@ function init() if(function_exists('date_default_timezone_get') && function_exists('date_default_timezone_set')) { @date_default_timezone_set(date_default_timezone_get()); - } + } if(isset($_GET['lang']) && is_scalar($_GET['lang']) && isset($_TRANSLATIONS[$_GET['lang']])) $this->lang = $_GET['lang']; @@ -2726,8 +2726,8 @@ function sort() usort($this->dirs, array('EncodeExplorer', 'cmp_'.$sort_by)); if($this->sort_as == "desc") { $this->dirs = array_reverse($this->dirs); - } } + } // Here we filter the comparison functions supported by our file object $sort_by = in_array($this->sort_by, array('name', 'size', 'mod')) ? $this->sort_by : 'name'; @@ -2736,7 +2736,7 @@ function sort() usort($this->files, array('EncodeExplorer', 'cmp_'.$sort_by)); if($this->sort_as == "desc") { $this->files = array_reverse($this->files); - } + } } } @@ -3230,7 +3230,7 @@ function(){ { ?> -
+' : ''?>>
Date: Wed, 22 Mar 2017 23:28:39 +0100 Subject: [PATCH 2/9] Do log file and folder deletion via mail and logfile --- index.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/index.php b/index.php index 2163922..72f4d1a 100644 --- a/index.php +++ b/index.php @@ -1950,6 +1950,14 @@ public static function logCreation($path, $isDir) Logger::log($message); } + public static function logDeletion($path, $isDir) + { + $message = $_SERVER['REMOTE_ADDR']." ".GateKeeper::getUserName()." deleted "; + $message .= $isDir?"dir":"file"; + $message .= " ".$path; + Logger::log($message); + } + public static function emailNotification($path, $isFile) { if(strlen(EncodeExplorer::getConfig('upload_email')) > 0) @@ -1961,7 +1969,19 @@ public static function emailNotification($path, $isFile) mail(EncodeExplorer::getConfig('upload_email'), "Upload notification", $message); } } + + public static function emailNotificationDeletion($path, $isFile) + { + if(strlen(EncodeExplorer::getConfig('upload_email')) > 0) + { + $message = "This is a message to let you know that ".GateKeeper::getUserName()." "; + $message .= ($isFile?"deleted a file":"deleted a directory")." in Encode Explorer.\n\n"; + $message .= "Path : ".$path."\n"; + $message .= "IP : ".$_SERVER['REMOTE_ADDR']."\n"; + mail(EncodeExplorer::getConfig('delete_email'), "Deletion notification", $message); } + } +} // // The class controls logging in and authentication @@ -2221,12 +2241,16 @@ public static function delete_dir($dir) { } reset($objects); rmdir($dir); + Logger::logDeletion("./".$dir, true); + Logger::emailNotificationDeletion("./".$dir, false); } } public static function delete_file($file){ if(is_file($file)){ unlink($file); + Logger::logDeletion("./".$file, false); + Logger::emailNotificationDeletion("./".$file, true); } } From 8be6bcad2113365137620de85a9bed9bcb2265f1 Mon Sep 17 00:00:00 2001 From: Thomas M Date: Wed, 22 Mar 2017 23:36:20 +0100 Subject: [PATCH 3/9] Download column, forces to download instead of showing (example pictures) --- index.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/index.php b/index.php index 72f4d1a..9c74874 100644 --- a/index.php +++ b/index.php @@ -1728,6 +1728,10 @@ function css() $_IMAGES["xlsx"] = $_IMAGES["spreadsheet"]; $_IMAGES["xml"] = $_IMAGES["code"]; $_IMAGES["zip"] = $_IMAGES["archive"]; +$_IMAGES["download"] = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAA +CxMAAAsTAQCanBgAAAAHdElNRQfhAxUJJiDGyieZAAAAeklEQVQoz62QsQqAMAxEn7Wbn9NZP0Dw +/0e/Qu0QGhcrTakI4mVIAncXLvCCzmz+6tImeyKCEG9ioclbX6tcMStquiEMuMLN4xis00hC0KuE +xFgfC0QSipKIhFaKiQNFOZievhLY2dvqjIWFb1jvBLlW+8m5zs3GTzgBdP0qMaa27WIAAAAASUVO"; /***************************************************************************/ /* HERE COMES THE CODE. */ @@ -3131,13 +3135,14 @@ function(){ mobile == false && GateKeeper::isDeleteAllowed()){?> + DL dir - + .. @@ -3170,6 +3175,7 @@ function(){ { print "getName())."\" href=\"".$this->makeLink(false, false, null, null, $this->location->getDir(false, true, false, 0).$dir->getNameEncoded(), $this->location->getDir(false, true, false, 0))."\">\"Delete\""; } + print ""; print "\n"; $row =! $row; } @@ -3214,6 +3220,12 @@ function(){ "; } + + print ""; + print "location->getDir(false, true, false, 0).$file->getNameEncoded()."\" class=\"item file\" download>"; + print "\"download\""; + print "\n"; + print "\n"; $row =! $row; } From 186c04faf65c08dcacaba79d6dd13e298421e1b8 Mon Sep 17 00:00:00 2001 From: Thomas M Date: Wed, 22 Mar 2017 23:52:06 +0100 Subject: [PATCH 4/9] Provide downloadfunctionality through PHP in order to disable direct access through .htaccess --- README.md | 9 ++++++ index.php | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 88 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e77d265..f24a549 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,15 @@ You have to upload index.php into your server. If you open index.php you can edit several settings. You should make sure the edited file will be saved in UTF-8! +An example of how to protect direct Access through .htaccess (apache): +IndexIgnore * +Order Deny,Allow +Deny from all + + + Allow from all + + License ---------------------------------- diff --git a/index.php b/index.php index 9c74874..4a06469 100644 --- a/index.php +++ b/index.php @@ -145,6 +145,10 @@ // If set to true, you should specify some users as well (see below). // Important: This only prevents people from seeing the list. // They will still be able to access the files with a direct link. +// Addition: Combine htaccess and require_login to disallow +// direct access to file. File access gets logged more precisely. +// Attention: Be advised, the file is processed by PHP, +// large/slow downloads might break due to php_script_timeout // Default: $_CONFIG['require_login'] = false; // $_CONFIG['require_login'] = false; @@ -1930,8 +1934,12 @@ public static function log($message) public static function logAccess($path, $isDir) { $message = $_SERVER['REMOTE_ADDR']." ".GateKeeper::getUserName()." accessed "; - $message .= $isDir?"dir":"file"; + $message .= $isDir && !(isset($_GET['file']) || isset($_GET['dl'])) ? "dir" : "file"; $message .= " ".$path; + if (isset($_GET['file'])) + $message.= $_GET['file']; + if (isset($_GET['dl'])) + $message.= $_GET['dl']; Logger::log($message); } @@ -2232,6 +2240,53 @@ function uploadFile($location, $userfile) } } + function downloadFile($filepath) + { + $filepath = EncodeExplorer::getConfig('basedir').$filepath; + if( file_exists( $filepath ) ) + { + header( 'Cache-Control: public' ); + header( 'Content-Description: File Transfer' ); + header( 'Content-Disposition: attachment; filename='.basename($filepath) ); + header( 'Content-Type: '.File::getFileMime($filepath) ); // application/octet-stream + header( 'Content-Length: '.filesize($filepath)); + header( 'Content-Transfer-Encoding: binary' ); + readfile( $filepath ); + exit; + } + } + + function provideFile($filepath) + { + $filepath = EncodeExplorer::getConfig('basedir').$filepath; + if( file_exists( $filepath ) ) + { + + $mtime = gmdate('r', filemtime($_SERVER['SCRIPT_FILENAME'])); + $etag = md5($mtime.$_SERVER['SCRIPT_FILENAME']); + + if ((isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $mtime) + || (isset($_SERVER['HTTP_IF_NONE_MATCH']) && str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])) == $etag)) + { + header('HTTP/1.1 304 Not Modified'); + return true; + } + else { + header( 'ETag: "'.$etag.'"' ); + header( 'Last-Modified: '.$mtime ); + header( 'Cache-Control: public' ); + //header( 'Content-Description: File Transfer' ); + header( 'Content-Disposition: filename='.basename($filepath) ); + header( 'Content-type: '.File::getFileMime($filepath) ); + header( 'Content-Length: '.filesize($filepath)); + header( 'Content-Transfer-Encoding: binary' ); + readfile( $filepath ); + exit; + } + return true; + } + } + public static function delete_dir($dir) { if (is_dir($dir)) { $objects = scandir($dir); @@ -2293,8 +2348,21 @@ function run($location) FileManager::delete_file($path); } } + + if (isset($_GET['dl'])) { + if( (!GateKeeper::isLoginRequired()) || (GateKeeper::isUserLoggedIn() && GateKeeper::isAccessAllowed())) { + if (!empty($_GET['dl'])) + $this->downloadFile($_GET['dl']); } } + if (isset($_GET['file'])) { + if( (!GateKeeper::isLoginRequired()) || (GateKeeper::isUserLoggedIn() && GateKeeper::isAccessAllowed())) { + if (!empty($_GET['file'])) + $this->provideFile($_GET['file']); + } + } + } +} // // Dir class holds the information about one directory in the list @@ -3007,7 +3075,7 @@ function outputHtml() }); logging == true) + if($this->logging == true && !GateKeeper::isLoginRequired()) { ?> function logFileClick(path) @@ -3022,7 +3090,7 @@ function logFileClick(path) } $("a.file").click(function(){ - logFileClick("location->getDir(true, true, false, 0);?>" + $(this).html()); + logFileClick("./" + $(this).attr('href').replace("?dl=","").replace("?file=","")); return true; }); \"Preview\"<\/div>"); + $("body").append("
\"Preview\"<\/div>"); positionThumbnail(e); $("#thumb").fadeIn("medium"); }, @@ -3192,8 +3260,10 @@ function(){ $row_style = ($row ? "one" : "two"); print "files)?" last":"")."\">\n"; print "\"".$file-getType()."\" src=\"".$this->makeIcon($file->getType())."\" />\n"; - print "\n"; - print "\t\tlocation->getDir(false, true, false, 0).$file->getNameEncoded()."\""; + print "\n"; + print GateKeeper::isLoginRequired() + ? "\t\tlocation->getDir(false, true, false, 0).$file->getNameEncoded()."\"" + : "\t\tlocation->getDir(false, true, false, 0).$file->getNameEncoded()."\""; if(EncodeExplorer::getConfig('open_in_new_window') == true) print "target=\"_blank\""; print " class=\"item file"; @@ -3222,7 +3292,9 @@ function(){ } print ""; - print "location->getDir(false, true, false, 0).$file->getNameEncoded()."\" class=\"item file\" download>"; + print GateKeeper::isLoginRequired() + ? "location->getDir(false, true, false, 0).$file->getNameEncoded()."\" class=\"item file\" download>" + : "location->getDir(false, true, false, 0).$file->getNameEncoded()."\" class=\"item file\" download>"; print "\"download\""; print "\n"; From 44985ca91a875c6d33d6e26ea27f52f9e33e7517 Mon Sep 17 00:00:00 2001 From: Thomas M Date: Wed, 22 Mar 2017 23:58:20 +0100 Subject: [PATCH 5/9] Added example of .htaccess --- .htaccess | 8 ++++++++ README.md | 10 ++-------- 2 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 .htaccess diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..1a2c91d --- /dev/null +++ b/.htaccess @@ -0,0 +1,8 @@ +IndexIgnore * +Order Deny,Allow +Deny from all + + + Allow from all + + diff --git a/README.md b/README.md index f24a549..c64b067 100644 --- a/README.md +++ b/README.md @@ -20,14 +20,8 @@ You have to upload index.php into your server. If you open index.php you can edit several settings. You should make sure the edited file will be saved in UTF-8! -An example of how to protect direct Access through .htaccess (apache): -IndexIgnore * -Order Deny,Allow -Deny from all - - - Allow from all - +An example of how to protect direct Access through .htaccess (apache) +is available and must be adjusted to the webserver. License From 89807e5ad243baa43a07f9ea9b36d1d02ab93a67 Mon Sep 17 00:00:00 2001 From: Thomas M Date: Thu, 23 Mar 2017 08:34:20 +0100 Subject: [PATCH 6/9] Deny going directories backwards (..) and access to hidden files/dirs --- index.php | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/index.php b/index.php index 4a06469..f620066 100644 --- a/index.php +++ b/index.php @@ -131,7 +131,7 @@ // The array of folder names that will be hidden from the list. // Default: $_CONFIG['hidden_dirs'] = array(); // -$_CONFIG['hidden_dirs'] = array(); +$_CONFIG['hidden_dirs'] = array("test"); // // Filenames that will be hidden from the list. @@ -151,7 +151,7 @@ // large/slow downloads might break due to php_script_timeout // Default: $_CONFIG['require_login'] = false; // -$_CONFIG['require_login'] = false; +$_CONFIG['require_login'] = true; // // Usernames and passwords for restricting access to the page. @@ -163,7 +163,7 @@ // For example: $_CONFIG['users'] = array(array("username", "password", "admin")); // Default: $_CONFIG['users'] = array(); // -$_CONFIG['users'] = array(); +$_CONFIG['users'] = array(array("x", "y", "admin")); // // Permissions for uploading, creating new directories and deleting. @@ -2129,6 +2129,13 @@ public static function showLoginBox(){ return true; return false; } + + + public static function isAccessAllowedOnFile($filepath) { + $path = str_replace(basename($filepath), "", $filepath); + return empty(array_intersect(explode("/", $path), EncodeExplorer::getConfig('hidden_dirs'))) + && !in_array(basename($filepath), EncodeExplorer::getConfig('hidden_files')); + } } // @@ -2243,6 +2250,8 @@ function uploadFile($location, $userfile) function downloadFile($filepath) { $filepath = EncodeExplorer::getConfig('basedir').$filepath; + if (strpos($filepath, '../') !== false) + return; // Not allowed if( file_exists( $filepath ) ) { header( 'Cache-Control: public' ); @@ -2259,9 +2268,10 @@ function downloadFile($filepath) function provideFile($filepath) { $filepath = EncodeExplorer::getConfig('basedir').$filepath; + if (strpos($filepath, '../') !== false) + return; // Not allowed if( file_exists( $filepath ) ) { - $mtime = gmdate('r', filemtime($_SERVER['SCRIPT_FILENAME'])); $etag = md5($mtime.$_SERVER['SCRIPT_FILENAME']); @@ -2349,18 +2359,10 @@ function run($location) } } - if (isset($_GET['dl'])) { - if( (!GateKeeper::isLoginRequired()) || (GateKeeper::isUserLoggedIn() && GateKeeper::isAccessAllowed())) { - if (!empty($_GET['dl'])) - $this->downloadFile($_GET['dl']); - } - } - if (isset($_GET['file'])) { - if( (!GateKeeper::isLoginRequired()) || (GateKeeper::isUserLoggedIn() && GateKeeper::isAccessAllowed())) { - if (!empty($_GET['file'])) - $this->provideFile($_GET['file']); - } - } + if (isset($_GET['dl']) && !empty($_GET['dl']) && GateKeeper::isAccessAllowed() && GateKeeper::isAccessAllowedOnFile($_GET['dl'])) + $this->downloadFile($_GET['dl']); + if (isset($_GET['file']) && !empty($_GET['file']) && GateKeeper::isAccessAllowed() && GateKeeper::isAccessAllowedOnFile($_GET['file'])) + $this->provideFile($_GET['file']); } } From 9b7b34bf7ef4680bdcaac12395d29aa7a47ea9bc Mon Sep 17 00:00:00 2001 From: Thomas M Date: Thu, 23 Mar 2017 08:35:05 +0100 Subject: [PATCH 7/9] Allow necessary access to directory itself --- .htaccess | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.htaccess b/.htaccess index 1a2c91d..69c1c71 100644 --- a/.htaccess +++ b/.htaccess @@ -5,4 +5,6 @@ Deny from all Allow from all - + + Allow from all + From c985f1220ac4b359599551f49c1d2297d24f9b7e Mon Sep 17 00:00:00 2001 From: Thomas M Date: Thu, 23 Mar 2017 09:10:59 +0100 Subject: [PATCH 8/9] Revert to default Settings --- index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.php b/index.php index f620066..bf7c187 100644 --- a/index.php +++ b/index.php @@ -131,7 +131,7 @@ // The array of folder names that will be hidden from the list. // Default: $_CONFIG['hidden_dirs'] = array(); // -$_CONFIG['hidden_dirs'] = array("test"); +$_CONFIG['hidden_dirs'] = array(); // // Filenames that will be hidden from the list. @@ -151,7 +151,7 @@ // large/slow downloads might break due to php_script_timeout // Default: $_CONFIG['require_login'] = false; // -$_CONFIG['require_login'] = true; +$_CONFIG['require_login'] = false; // // Usernames and passwords for restricting access to the page. @@ -163,7 +163,7 @@ // For example: $_CONFIG['users'] = array(array("username", "password", "admin")); // Default: $_CONFIG['users'] = array(); // -$_CONFIG['users'] = array(array("x", "y", "admin")); +$_CONFIG['users'] = array(); // // Permissions for uploading, creating new directories and deleting. From 9d5faeeb06fb2f4f30b4356e4c9b609d8f260589 Mon Sep 17 00:00:00 2001 From: Thomas M Date: Thu, 23 Mar 2017 09:30:50 +0100 Subject: [PATCH 9/9] Function "array_intersect" probably doesn't exist --- index.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.php b/index.php index bf7c187..6f28446 100644 --- a/index.php +++ b/index.php @@ -2133,8 +2133,13 @@ public static function showLoginBox(){ public static function isAccessAllowedOnFile($filepath) { $path = str_replace(basename($filepath), "", $filepath); - return empty(array_intersect(explode("/", $path), EncodeExplorer::getConfig('hidden_dirs'))) - && !in_array(basename($filepath), EncodeExplorer::getConfig('hidden_files')); + + foreach(explode("/", $path) as $dir) { + if (in_array($dir, EncodeExplorer::getConfig('hidden_dirs'))) + return false; + } + + return !in_array(basename($filepath), EncodeExplorer::getConfig('hidden_files')); } }