diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..69c1c71 --- /dev/null +++ b/.htaccess @@ -0,0 +1,10 @@ +IndexIgnore * +Order Deny,Allow +Deny from all + + + Allow from all + + + Allow from all + diff --git a/README.md b/README.md index e77d265..c64b067 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@ 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) +is available and must be adjusted to the webserver. + License ---------------------------------- diff --git a/index.php b/index.php index a2ffe79..6f28446 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; @@ -787,7 +791,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 +800,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", @@ -1728,6 +1732,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. */ @@ -1926,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); } @@ -1950,6 +1962,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,6 +1981,18 @@ 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); + } + } } // @@ -2097,6 +2129,18 @@ public static function showLoginBox(){ return true; return false; } + + + public static function isAccessAllowedOnFile($filepath) { + $path = str_replace(basename($filepath), "", $filepath); + + foreach(explode("/", $path) as $dir) { + if (in_array($dir, EncodeExplorer::getConfig('hidden_dirs'))) + return false; + } + + return !in_array(basename($filepath), EncodeExplorer::getConfig('hidden_files')); + } } // @@ -2208,6 +2252,56 @@ 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' ); + 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 (strpos($filepath, '../') !== false) + return; // Not allowed + 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); @@ -2221,12 +2315,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); } } @@ -2265,6 +2363,11 @@ function run($location) FileManager::delete_file($path); } } + + 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']); } } @@ -2626,7 +2729,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 +2829,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 +2839,7 @@ function sort() usort($this->files, array('EncodeExplorer', 'cmp_'.$sort_by)); if($this->sort_as == "desc") { $this->files = array_reverse($this->files); - } + } } } @@ -2979,7 +3082,7 @@ function outputHtml() }); logging == true) + if($this->logging == true && !GateKeeper::isLoginRequired()) { ?> function logFileClick(path) @@ -2994,7 +3097,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"); }, @@ -3107,13 +3210,14 @@ function(){ mobile == false && GateKeeper::isDeleteAllowed()){?> + DL dir - + .. @@ -3146,6 +3250,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; } @@ -3162,8 +3267,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"; @@ -3190,6 +3297,14 @@ function(){ "; } + + print ""; + 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"; + print "\n"; $row =! $row; } @@ -3230,7 +3345,7 @@ function(){ { ?> -
+' : ''?>>