Merge branch 'master' of github.com:novashdima/ifm into novashdima-master

This commit is contained in:
Marco Dickert 2023-12-05 15:23:52 +01:00
commit f57ef6a469
17 changed files with 304 additions and 519 deletions

164
README.md
View File

@ -1,31 +1,34 @@
# IFM - improved file manager
## contents
- [about](#about)
- [features](#features)
- [requirements](#requirements)
- [installation](#installation)
- [security information](#security-information)
- [keybindings](#keybindings)
- [configuration](#configuration)
- [docker](#docker)
- [screenshots](#screenshots)
- [issues](#issues)
## Contents
* [about](#about)
* [features](#features)
* [requirements](#requirements)
* [installation](#installation)
* [security information](#security-information)
* [keybindings](#keybindings)
* [configuration](#configuration)
* [docker](#docker)
* [screenshots](#screenshots)
* [issues](#issues)
## About
The IFM is a web-based filemanager, which comes as a single file solution using
HTML5, CSS3, JavaScript and PHP. You can test a [demo
here](https://ifmdemo.gitea.de/).
<a href="https://youtu.be/owJepSas19Y"><img src="https://img.youtube.com/vi/owJepSas19Y/hqdefault.jpg"></a>
The IFM is a web-based filemanager, which comes as a single file solution using HTML5, CSS3, JavaScript and PHP. You can test a [demo here](https://ifmdemo.gitea.de/).
[![IFM](https://img.youtube.com/vi/owJepSas19Y/hqdefault.jpg)](https://youtu.be/owJepSas19Y)
The IFM uses the following resources:
* [ACE Editor](https://ace.c9.io)
* [Bootstrap v4](https://getbootstrap.com)
* custom icon set generated with [Fontello](http://fontello.com/)
* [jQuery](https://jquery.com)
* [Mustache](https://mustache.github.io/)
## features
## Features
* create/edit files and directories
* copy/move files and directories
* download files and directories
@ -36,46 +39,40 @@ The IFM uses the following resources:
* simple authentication (LDAP via `ldap_bind` possible)
## Requirements
* Client
* HTML5 and CSS3 compatible browser
* activated javascript
+ HTML5 and CSS3 compatible browser
+ activated javascript
* Server
* PHP >= 5.6
* extensions
* bz2
* curl (for remote upload)
* fileinfo
* json
* ldap (only if LDAP based authentication is used)
* mbstring
* openssl (for remote uploads from https sources)
* phar
* posix
* zip
* zlib
+ PHP >= 5.6
+ extensions
- bz2
- curl (for remote upload)
- fileinfo
- json
- ldap (only if LDAP based authentication is used)
- mbstring
- openssl (for remote uploads from https sources)
- phar
- posix
- zip
- zlib
## Installation
Just download the latest release of the IFM. You can find it
[here](https://github.com/misterunknown/ifm/releases/latest). You can choose
between the CDN version (dependencies like bootstrap, jquery etc. are loaded
via CDN) or the "simple" version, which bundles all these dependencies.
The minified versions (`*.min.php`) are zipped via gzip. These versions are not
recommended; if the filesize of the IFM is an issue for you, consider using the
CDN versions.
Just download the latest release of the IFM. You can find it [here](https://github.com/misterunknown/ifm/releases/latest). You can choose between the CDN version (dependencies like bootstrap, jquery etc. are loaded via CDN) or the "simple" version, which bundles all these dependencies.
The minified versions (`*.min.php`) are zipped via gzip. These versions are not recommended; if the filesize of the IFM is an issue for you, consider using the CDN versions.
## Security information
The IFM is usually locked to it's own directory, so you are not able to go
above. You can change that by setting the `root_dir` in the scripts
[configuration](https://github.com/misterunknown/ifm/wiki/Configuration).
By default, it is not allowed to show or edit the `.htaccess` file. This is
because you can configure the IFM via environment variables. Thus if anyone has
the ability to edit the `.htaccess` file, he could overwrite the active
configuration. [See
also](https://github.com/misterunknown/ifm/wiki/Configuration).
The IFM is usually locked to it's own directory, so you are not able to go above. You can change that by setting the `root_dir` in the scripts [configuration](https://github.com/misterunknown/ifm/wiki/Configuration).
By default, it is not allowed to show or edit the `.htaccess` file. This is because you can configure the IFM via environment variables. Thus if anyone has the ability to edit the `.htaccess` file, he could overwrite the active
configuration. [See also](https://github.com/misterunknown/ifm/wiki/Configuration).
## Keybindings
## Key bindings
* <kbd>e</kbd> - edit / extract current file
* <kbd>h</kbd><kbd>j</kbd><kbd>k</kbd><kbd>l</kbd> - vim-style navigation (alternative to arrow keys)
* <kbd>g</kbd> - focus the path input field (i.e. "goto")
@ -95,55 +92,66 @@ also](https://github.com/misterunknown/ifm/wiki/Configuration).
* <kbd>Ctrl</kbd>-<kbd>Shift</kbd>-<kbd>f</kbd> - toggle fullscreen ace editor
## Configuration
See [configuration](https://github.com/misterunknown/ifm/wiki/Configuration).
### authentication
### Authentication
See [authentication](https://github.com/misterunknown/ifm/wiki/Authentication).
## Docker
The docker image is based on the official php docker images (alpine version)
and exposes port 80.
### Quickstart
Build the image with this command in the top source dir:
`docker build -t ifm .`
```bash
docker build -t ifm .
```
Afterwards you can start the docker container as follows:
`docker run --rm -d --name ifm -p 8080:80 -v /path/to/data:/var/www ifm:latest`
### Specify user/group
By default IFM runs as user www-data (uid/gid 33). If you need to change that,
you can set the UID and GID with the following environment variables:
`docker run ... -e IFM_DOCKER_UID=1000 -e IFM_DOCKER_GID=100 ifm:latest`
### Other configuration
The script is located at `/usr/local/share/webapps/ifm/index.php`. By default
the `root_dir` is set to /var/www, so you can mount any directory at this
location. If you want to bind the corresponding host directory, you can do the
following:
`docker run --rm -i -p "8080:80" -v "/var/www:/var/www" ifm`
The scripts configuration can be changed by adjusting the corresponding
environment variables. For example:
```docker run --rm -i -p "8080:80" -v /var/www:/var/www \
-e IFM_AUTH=1 -e IFM_AUTH \
-e IFM_AUTH_SOURCE="admin:$2y$05$LPdE7u/5da/TCE8ZhqQ1o.acuV50HqB3OrHhNwxbXYeWmmZKdQxrC" \
ifm
```bash
docker run --rm -d --name ifm -p 8080:80 -v /path/to/data:/var/www ifm:latest
```
You can get a complete list of environment variables
[here](https://github.com/misterunknown/ifm/wiki/Configuration#configuration-options).
### Specify user/group
By default IFM runs as user www-data (uid/gid 33). If you need to change that, you can set the UID and GID with the following environment variables:
```bash
docker run ... -e IFM_DOCKER_UID=1000 -e IFM_DOCKER_GID=100 ifm:latest
```
### Other configuration
The script is located at `/usr/local/share/webapps/ifm/index.php`. By default the `root_dir` is set to /var/www, so you can mount any directory at this location. If you want to bind the corresponding host directory, you can do the following:
```bash
docker run --rm -i -p "8080:80" -v "/var/www:/var/www" ifm
```
The scripts configuration can be changed by adjusting the corresponding environment variables. For example:
```bash
docker run --rm -i -p "8080:80" -v /var/www:/var/www \
-e IFM_AUTH=1 -e IFM_AUTH \
-e IFM_AUTH_SOURCE="admin:$2y$05$LPdE7u/5da/TCE8ZhqQ1o.acuV50HqB3OrHhNwxbXYeWmmZKdQxrC" \
ifm
```
You can get a complete list of environment variables [here](https://github.com/misterunknown/ifm/wiki/Configuration#configuration-options).
## Screenshots
## screenshots
<a href="https://misterunknown.de/static/ifm_screenshot_desktop_filelist.png"><img src="https://misterunknown.de/static/ifm_screenshot_desktop_filelist.png" height="300px"></a>
<a href="https://misterunknown.de/static/ifm_screenshot_mobile_filelist.png"><img src="https://misterunknown.de/static/ifm_screenshot_mobile_filelist.png" height="300px"></a>
<a href="https://misterunknown.de/static/ifm_screenshot_desktop_remote_upload.png"><img src="https://misterunknown.de/static/ifm_screenshot_desktop_remote_upload.png" height="300px"></a>
<a href="https://misterunknown.de/static/ifm_screenshot_mobile_editfile.png"><img src="https://misterunknown.de/static/ifm_screenshot_mobile_editfile.png" height="300px"></a>
## issues
If you happen to find an error or miss a feature, you can create an issue on
Github.
## Issues
If you happen to find an error or miss a feature, you can create an issue on Github.

View File

@ -26,16 +26,19 @@ $IFM_SRC_PHP = [
$options = getopt(null, ["language::", "languages::", "lang::", "cdn"]);
// build CDN version?
if (isset($options['cdn']))
if (isset($options['cdn'])) {
define("IFM_CDN", true);
else
} else {
define("IFM_CDN", false);
}
// process languages
$langs = [];
foreach ($options as $key => $value)
if (substr($key, 0, 4) == "lang")
foreach ($options as $key => $value) {
if (substr($key, 0, 4) == "lang") {
$langs = array_merge($langs, explode(",", $value));
}
}
$langs = array_unique($langs);
if (!empty($langs)) {
@ -45,25 +48,28 @@ if (!empty($langs)) {
}
// ensure english is available, as it gets merged with the other languages
// in case of missing keys in other languages.
if (!in_array("all", $langs) || !in_array("en", $langs))
if (!in_array("all", $langs) || !in_array("en", $langs)) {
array_push($langs, "en");
}
if (in_array("all", $langs))
$langs = array_map(
function($lang_file) {return pathinfo($lang_file)['filename']; },
function ($lang_file) { return pathinfo($lang_file)['filename']; },
glob("src/i18n/*.json")
);
$vars['languageincludes'] = "";
foreach ($langs as $l)
if (file_exists("src/i18n/".$l.".json"))
foreach ($langs as $l) {
if (file_exists("src/i18n/".$l.".json")) {
$vars['languageincludes'] .=
'$i18n["'.$l.'"] = <<<\'f00bar\'' . "\n"
. file_get_contents( "src/i18n/".$l.".json" ) . "\n"
. 'f00bar;' . "\n"
. '$i18n["'.$l.'"] = json_decode( $i18n["'.$l.'"], true );' . "\n" ;
else
} else {
print "WARNING: Language file src/i18n/".$l.".json not found.\n";
}
}
// Concat PHP Files
$compiled = ["<?php"];
@ -81,11 +87,12 @@ $compiled = str_replace("###ASSETS_JS###", file_get_contents("src/assets".(IFM_C
// Process file includes
$includes = NULL;
preg_match_all("/\#\#\#file:([^\#]+)\#\#\#/", $compiled, $includes, PREG_SET_ORDER);
foreach ($includes as $file)
foreach ($includes as $file) {
$compiled = str_replace($file[0], file_get_contents($file[1]), $compiled);
}
// Process ace includes
$includes = NULL;
$includes = null;
$vars['ace_includes'] = "";
preg_match_all("/\#\#\#acedir:([^\#]+)\#\#\#/", $compiled, $includes, PREG_SET_ORDER);
foreach ($includes as $dir) {
@ -102,13 +109,15 @@ foreach ($includes as $dir) {
// Process variable includes
$includes = NULL;
preg_match_all("/\#\#\#vars:([^\#]+)\#\#\#/", $compiled, $includes, PREG_SET_ORDER);
foreach( $includes as $var )
foreach( $includes as $var ) {
$compiled = str_replace($var[0], $vars[$var[1]], $compiled);
}
$compiled = str_replace('IFM_VERSION', IFM_VERSION, $compiled);
if (!is_dir(IFM_RELEASE_DIR))
mkdir(IFM_RELEASE_DIR);
if (!is_dir(IFM_RELEASE_DIR)) {
mkdir(IFM_RELEASE_DIR);
}
// build standalone ifm
file_put_contents(IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE, $compiled);
@ -123,7 +132,7 @@ $ifm->run();
// build compressed ifm
file_put_contents(
IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE_GZ,
'<?php eval( gzdecode( file_get_contents( __FILE__, false, null, 85 ) ) ); exit(0); ?>'
'<?php eval(gzdecode(file_get_contents(__FILE__, false, null, 85))); exit(0); ?>'
. gzencode(file_get_contents(IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE, false, null, 5))
);
// build lib

View File

@ -3,30 +3,30 @@ set -e
if [ ! -z $IFM_DOCKER_UID ]; then
# check if UID/GID are numeric
if ! echo "$IFM_DOCKER_UID$IFM_DOCKER_GID" | egrep "^[0-9]+$" >/dev/null 2>&1; then
if ! echo "$IFM_DOCKER_UID$IFM_DOCKER_GID" | grep -E "^[0-9]+$" >/dev/null 2>&1; then
echo "FATAL: IFM_DOCKER_UID or IFM_DOCKER_GID are not numeric (UID: $IFM_DOCKER_UID, GID: $IFM_DOCKER_GID)"
exit 1
fi
# get GID if not set
if [ -z $IFM_DOCKER_GID ]; then
export IFM_DOCKER_GID=$IFM_DOCKER_UID
if [ -z "$IFM_DOCKER_GID" ]; then
export IFM_DOCKER_GID="$IFM_DOCKER_UID"
fi
# delete user if already exists
if getent passwd $IFM_DOCKER_UID >/dev/null 2>&1; then
deluser $(getent passwd $IFM_DOCKER_UID | sed "s/:.*//")
if getent passwd "$IFM_DOCKER_UID" >/dev/null 2>&1; then
deluser $(getent passwd "$IFM_DOCKER_UID" | sed "s/:.*//")
fi
# check if group already exists
if ! getent group $IFM_DOCKER_GID >/dev/null 2>&1; then
addgroup -g $IFM_DOCKER_GID -S www-data
if ! getent group "$IFM_DOCKER_GID" >/dev/null 2>&1; then
addgroup -g "$IFM_DOCKER_GID" -S www-data
REAL_GROUP=www-data
else
REAL_GROUP=$(getent group $IFM_DOCKER_GID | sed "s/:.*//")
REAL_GROUP=$(getent group "$IFM_DOCKER_GID" | sed "s/:.*//")
fi
adduser -u $IFM_DOCKER_UID -SHDG $REAL_GROUP www-data
adduser -u "$IFM_DOCKER_UID" -SHDG "$REAL_GROUP" www-data
else
addgroup -g 33 -S www-data
adduser -SHD -u 33 -G www-data www-data

View File

@ -1,5 +1,5 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/css/bootstrap.min.css" integrity="sha512-T584yQ/tdRR5QwOpfvDfVQUidzfgc2339Lc8uBDtcp/wYu80d7jwBgAxbyMh0a9YM9F8N3tdErpFI8iaGx6x5g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.11.3/r-2.2.9/datatables.min.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.2/css/bootstrap.min.css" integrity="sha512-rt/SrQ4UNIaGfDyEXZtNcyWvQeOq0QLygHluFQcSjaGB04IxWhal71tKuzP6K8eYXYB6vJV4pHkXcmFGGQ1/0w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.13.1/r-2.4.0/datatables.min.css"/>
<style type="text/css">
###file:src/includes/bootstrap-treeview.min.css###
###file:src/includes/fontello-embedded.css###

View File

@ -1,13 +1,13 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.1/umd/popper.min.js" integrity="sha512-ubuT8Z88WxezgSqf3RLuNi5lmjstiJcyezx34yIU2gAHonIi27Na7atqzUZCOoY4CExaoFumzOsFQ2Ch+I/HCw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.min.js" integrity="sha512-UR25UO94eTnCVwjbXozyeVd6ZqpaAE9naiEUBK/A+QDbfSTQFhPGj5lOR6d8tsgbBk84Ggb5A3EkjsOgPRPcKA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.11.3/r-2.2.9/datatables.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.2/js/bootstrap.min.js" integrity="sha512-7rusk8kGPFynZWu26OKbTeI+QPoYchtxsmPeBqkHIEXJxeun4yJ4ISYe7C6sz9wdxeE1Gk3VxsIWgCZTc+vX3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.13.1/r-2.4.0/datatables.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script async src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.3.1/index.min.js" integrity="sha512-6Wf/IjsSjLaFTYco3pXM+49kC5M7jtbHzxMcdmYvwDskjv7cMcBPmJX2053aoQ+LRi8Po4ZsCtkNMf+NhXhNyQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script async src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.3.2/index.min.js" integrity="sha512-GqhSAi+WYQlHmNWiE4TQsVa7HVKctQMdgUMA+1RogjxOPdv9Kj59/no5BEvJgpvuMTYw2JRQu/szumfVXdowag==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/3.2.1/mustache.min.js" integrity="sha512-Qjrukx28QnvFWISw9y4wCB0kTB/ISnWXPz5/RME5o8OlZqllWygc1AB64dOBlngeTeStmYmNTNcM6kfEjUdnnQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/mouse0270-bootstrap-notify/3.1.7/bootstrap-notify.min.js" integrity="sha512-BUaP7iu0aHqAISI8LphJT07Rv/MOiPI+mmq0h1rckNbzuKAW+UqmwEANqLPqanKNU331yApBM+40pZIkwkWAEQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.13/ace.min.js" integrity="sha512-jB1NOQkR0yLnWmEZQTUW4REqirbskxoYNltZE+8KzXqs9gHG5mrxLR5w3TwUn6AylXkhZZWTPP894xcX/X8Kbg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js" integrity="sha512-57oZ/vW8ANMjR/KQ6Be9v/+/h6bq9/l3f0Oc7vn6qMqyhvPd1cvKBRWWpzu0QoneImqr2SkmO4MSqU+RpHom3Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.14.0/ace.min.js" integrity="sha512-s57ywpCtz+4PU992Bg1rDtr6+1z38gO2mS92agz2nqQcuMQ6IvgLWoQ2SFpImvg1rbgqBKeSEq0d9bo9NtBY0w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer>
###file:src/includes/bootstrap-treeview.min.js###
###file:src/includes/BootstrapMenu.min.js###

View File

@ -6,53 +6,55 @@
class Htpasswd {
public $users = [];
public function __construct( $filename="" ) {
if( $filename )
$this->load( $filename );
public function __construct($filename="") {
if ($filename) {
$this->load($filename);
}
}
/**
* Load a new htpasswd file
*/
public function load( $filename ) {
unset( $this->users );
if( file_exists( $filename ) && is_readable( $filename ) ) {
public function load($filename) {
unset($this->users);
if (file_exists($filename) && is_readable($filename)) {
$lines = file( $filename );
foreach( $lines as $line ) {
list( $user, $pass ) = explode( ":", $line );
$this->users[$user] = trim( $pass );
foreach ($lines as $line) {
list($user, $pass) = explode(":", $line);
$this->users[$user] = trim($pass);
}
return true;
} else
return false;
}
public function getUsers() {
return array_keys( $this->users );
}
public function userExist( $user ) {
return isset( $this->users[ $user ] );
}
public function verify( $user, $pass ) {
if( isset( $this->users[$user] ) ) {
return $this->verifyPassword( $pass, $this->users[$user] );
} else {
return false;
}
}
public function verifyPassword( $pass, $hash ) {
if( substr( $hash, 0, 4 ) == '$2y$' ) {
return password_verify( $pass, $hash );
} elseif( substr( $hash, 0, 6 ) == '$apr1$' ) {
public function getUsers() {
return array_keys($this->users);
}
public function userExist($user) {
return isset($this->users[$user]);
}
public function verify($user, $pass) {
if (isset($this->users[$user])) {
return $this->verifyPassword($pass, $this->users[$user]);
} else {
return false;
}
}
public function verifyPassword($pass, $hash) {
if (substr($hash, 0, 4) == '$2y$') {
return password_verify($pass, $hash);
} elseif (substr($hash, 0, 6) == '$apr1$') {
$apr1 = new APR1_MD5();
return $apr1->check( $pass, $hash );
} elseif( substr( $hash, 0, 5 ) == '{SHA}' ) {
return base64_encode( sha1( $pass, TRUE ) ) == substr( $hash, 5 );
return $apr1->check($pass, $hash);
} elseif (substr($hash, 0, 5) == '{SHA}') {
return base64_encode(sha1($pass, true)) == substr($hash, 5);
} else { // assume CRYPT
return crypt( $pass, $hash ) == $hash;
return crypt($pass, $hash) == $hash;
}
}
}
@ -64,64 +66,73 @@ class Htpasswd {
*/
class APR1_MD5 {
const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const APRMD5_ALPHABET = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const APRMD5_ALPHABET = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
// Source/References for core algorithm:
// http://www.cryptologie.net/article/126/bruteforce-apr1-hashes/
// http://svn.apache.org/viewvc/apr/apr-util/branches/1.3.x/crypto/apr_md5.c?view=co
// http://www.php.net/manual/en/function.crypt.php#73619
// http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
// Wikipedia
// Source/References for core algorithm:
// http://www.cryptologie.net/article/126/bruteforce-apr1-hashes/
// http://svn.apache.org/viewvc/apr/apr-util/branches/1.3.x/crypto/apr_md5.c?view=co
// http://www.php.net/manual/en/function.crypt.php#73619
// http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
// Wikipedia
public static function hash($mdp, $salt = null) {
if (is_null($salt))
$salt = self::salt();
$salt = substr($salt, 0, 8);
$max = strlen($mdp);
$context = $mdp.'$apr1$'.$salt;
$binary = pack('H32', md5($mdp.$salt.$mdp));
for($i=$max; $i>0; $i-=16)
$context .= substr($binary, 0, min(16, $i));
for($i=$max; $i>0; $i>>=1)
$context .= ($i & 1) ? chr(0) : $mdp[0];
$binary = pack('H32', md5($context));
for($i=0; $i<1000; $i++) {
$new = ($i & 1) ? $mdp : $binary;
if($i % 3) $new .= $salt;
if($i % 7) $new .= $mdp;
$new .= ($i & 1) ? $binary : $mdp;
$binary = pack('H32', md5($new));
}
$hash = '';
for ($i = 0; $i < 5; $i++) {
$k = $i+6;
$j = $i+12;
if($j == 16) $j = 5;
$hash = $binary[$i].$binary[$k].$binary[$j].$hash;
}
$hash = chr(0).chr(0).$binary[11].$hash;
$hash = strtr(
strrev(substr(base64_encode($hash), 2)),
self::BASE64_ALPHABET,
self::APRMD5_ALPHABET
);
return '$apr1$'.$salt.'$'.$hash;
}
public static function hash($mdp, $salt = null) {
if (is_null($salt)) {
$salt = self::salt();
}
$salt = substr($salt, 0, 8);
$max = strlen($mdp);
$context = $mdp.'$apr1$'.$salt;
$binary = pack('H32', md5($mdp.$salt.$mdp));
for ($i=$max; $i>0; $i-=16) {
$context .= substr($binary, 0, min(16, $i));
}
for ($i=$max; $i>0; $i>>=1) {
$context .= ($i & 1) ? chr(0) : $mdp[0];
}
$binary = pack('H32', md5($context));
for ($i=0; $i<1000; $i++) {
$new = ($i & 1) ? $mdp : $binary;
if ($i % 3) {
$new .= $salt;
}
if ($i % 7) {
$new .= $mdp;
}
$new .= ($i & 1) ? $binary : $mdp;
$binary = pack('H32', md5($new));
}
$hash = '';
for ($i = 0; $i < 5; $i++) {
$k = $i+6;
$j = $i+12;
if ($j == 16) {
$j = 5;
}
$hash = $binary[$i].$binary[$k].$binary[$j].$hash;
}
$hash = chr(0).chr(0).$binary[11].$hash;
$hash = strtr(
strrev(substr(base64_encode($hash), 2)),
self::BASE64_ALPHABET,
self::APRMD5_ALPHABET
);
return '$apr1$'.$salt.'$'.$hash;
}
// 8 character salts are the best. Don't encourage anything but the best.
public static function salt() {
$alphabet = self::APRMD5_ALPHABET;
$salt = '';
for($i=0; $i<8; $i++) {
$offset = hexdec(bin2hex(openssl_random_pseudo_bytes(1))) % 64;
$salt .= $alphabet[$offset];
}
return $salt;
}
// 8 character salts are the best. Don't encourage anything but the best.
public static function salt() {
$alphabet = self::APRMD5_ALPHABET;
$salt = '';
for ($i=0; $i<8; $i++) {
$offset = hexdec(bin2hex(openssl_random_pseudo_bytes(1))) % 64;
$salt .= $alphabet[$offset];
}
return $salt;
}
public static function check($plain, $hash) {
$parts = explode('$', $hash);
return self::hash($plain, $parts[2]) === $hash;
}
public static function check($plain, $hash) {
$parts = explode('$', $hash);
return self::hash($plain, $parts[2]) === $hash;
}
}

View File

@ -1399,7 +1399,7 @@ function IFM(params) {
* @returns {boolean}
*/
this.inArray = function(needle, haystack) {
for( let i = 0; i < haystack.length; i++ )
for ( let i = 0; i < haystack.length; i++ )
if( haystack[i] == needle )
return true;
return false;
@ -1575,7 +1575,7 @@ function IFM(params) {
this.generateGuid = function() {
let result, i, j;
result = '';
for( j = 0; j < 20; j++ ) {
for ( j = 0; j < 20; j++ ) {
i = Math.floor( Math.random() * 16 ).toString( 16 ).toUpperCase();
result = result + i;
}

View File

@ -24,8 +24,9 @@ class IFMArchive {
* Add a folder to an archive
*/
private static function addFolder(&$archive, $folder, $offset=0, $exclude_callback=null) {
if ($offset == 0)
if ($offset == 0) {
$offset = strlen(dirname($folder)) + 1;
}
$archive->addEmptyDir(substr($folder, $offset));
$handle = opendir($folder);
while (false !== $f = readdir($handle)) {
@ -33,13 +34,15 @@ class IFMArchive {
$filePath = $folder . '/' . $f;
if (file_exists($filePath) && is_readable($filePath)) {
if (is_file($filePath)) {
if (!is_callable($exclude_callback) || $exclude_callback($f))
$archive->addFile( $filePath, substr( $filePath, $offset ) );
if (!is_callable($exclude_callback) || $exclude_callback($f)) {
$archive->addFile($filePath, substr($filePath, $offset));
}
} elseif (is_dir($filePath)) {
if (is_callable($exclude_callback))
if (is_callable($exclude_callback)) {
self::addFolder($archive, $filePath, $offset, $exclude_callback);
else
} else {
self::addFolder($archive, $filePath, $offset);
}
}
}
}
@ -54,18 +57,22 @@ class IFMArchive {
$a = new ZipArchive();
$a->open($archivename, ZIPARCHIVE::CREATE);
if (!is_array($filenames))
if (!is_array($filenames)) {
$filenames = array($filenames);
}
foreach ($filenames as $f)
if (is_dir($f))
if (is_callable($exclude_callback))
self::addFolder( $a, $f, null, $exclude_callback );
else
self::addFolder( $a, $f );
elseif (is_file($f))
if (!is_callable($exclude_callback) || $exclude_callback($f))
if (is_dir($f)) {
if (is_callable($exclude_callback)) {
self::addFolder($a, $f, null, $exclude_callback);
} else {
self::addFolder($a, $f);
}
} elseif (is_file($f)) {
if (!is_callable($exclude_callback) || $exclude_callback($f)) {
$a->addFile($f, pathinfo($f, PATHINFO_BASENAME));
}
}
try {
return $a->close();
@ -78,16 +85,18 @@ class IFMArchive {
* Unzip a zip file
*/
public static function extractZip($file, $destination="./") {
if (!file_exists($file))
if (!file_exists($file)) {
return false;
}
$zip = new ZipArchive;
$res = $zip->open($file);
if ($res === true) {
$zip->extractTo($destination);
$zip->close();
return true;
} else
} else {
return false;
}
}
/**
@ -98,14 +107,17 @@ class IFMArchive {
$a = new PharData($tmpf);
try {
if (!is_array($filenames))
if (!is_array($filenames)) {
$filenames = array($filenames);
}
foreach ($filenames as $f)
if (is_dir($f))
foreach ($filenames as $f) {
if (is_dir($f)) {
self::addFolder($a, $f);
elseif (is_file($f))
} elseif (is_file($f)) {
$a->addFile($f, pathinfo($f, PATHINFO_BASENAME));
}
}
switch ($format) {
case "tar.gz":
$a->compress(Phar::GZ);
@ -127,8 +139,9 @@ class IFMArchive {
* Extracts a tar archive
*/
public static function extractTar($file, $destination="./") {
if (!file_exists($file))
if (!file_exists($file)) {
return false;
}
$tar = new PharData($file);
try {
$tar->extractTo($destination, null, true);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
!function(){"use strict";var f={}.hasOwnProperty;function s(){for(var e=[],t=0;t<arguments.length;t++){var n=arguments[t];if(n){var r,o=typeof n;if("string"==o||"number"==o)e.push(n);else if(Array.isArray(n))!n.length||(r=s.apply(null,n))&&e.push(r);else if("object"==o)if(n.toString===Object.prototype.toString)for(var i in n)f.call(n,i)&&n[i]&&e.push(i);else e.push(n.toString())}}return e.join(" ")}"undefined"!=typeof module&&module.exports?(s.default=s,module.exports=s):"function"==typeof define&&"object"==typeof define.amd&&define.amd?define("classnames",[],function(){return s}):window.classNames=s}();
!function(){"use strict";var f={}.hasOwnProperty;function s(){for(var e=[],t=0;t<arguments.length;t++){var n=arguments[t];if(n){var o,r=typeof n;if("string"==r||"number"==r)e.push(n);else if(Array.isArray(n))!n.length||(o=s.apply(null,n))&&e.push(o);else if("object"==r)if(n.toString===Object.prototype.toString||n.toString.toString().includes("[native code]"))for(var i in n)f.call(n,i)&&n[i]&&e.push(i);else e.push(n.toString())}}return e.join(" ")}"undefined"!=typeof module&&module.exports?module.exports=s.default=s:"function"==typeof define&&"object"==typeof define.amd&&define.amd?define("classnames",[],function(){return s}):window.classNames=s}();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -220,7 +220,7 @@ f00bar;
case "getFolders":
return $this->getFolders($_REQUEST);
}
// checking working directory
if (!isset($_REQUEST["dir"]) || !$this->isPathValid($_REQUEST["dir"]))
throw new IFMException($this->l("invalid_dir"));
@ -580,7 +580,7 @@ f00bar;
if (isset($d['filename']) && $this->isFilenameValid($d['filename'])) {
if (isset($d['content'])) {
// work around magic quotes
if((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc())
if ((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc())
|| (ini_get('magic_quotes_sybase') && (strtolower(ini_get('magic_quotes_sybase'))!="off")) ) {
$content = stripslashes($d['content']);
} else {
@ -1025,7 +1025,7 @@ f00bar;
if ($login_failed === true)
throw new IFMException("Authentication failed: Wrong credentials", true);
else
throw new IFMException("Not authenticated" , true);
throw new IFMException("Not authenticated", true);
}
}
@ -1058,7 +1058,7 @@ f00bar;
}
$u = $uuid . "=" . $user . "," . $basedn;
if (!$ds = ldap_connect($ldap_server)) {
throw new IFMException("Could not reach the ldap server." , true);
throw new IFMException("Could not reach the ldap server.", true);
//trigger_error("Could not reach the ldap server.", E_USER_ERROR);
return false;
}
@ -1070,14 +1070,14 @@ f00bar;
if (ldap_count_entries($ds, ldap_search($ds, $u, $ufilter)) == 1) {
$authenticated = true;
} else {
throw new IFMException("User not allowed." , true);
throw new IFMException("User not allowed.", true);
//trigger_error("User not allowed.", E_USER_ERROR);
$authenticated = false;
}
} else
$authenticated = true;
} else {
throw new IFMException(ldap_error($ds) , true);
throw new IFMException(ldap_error($ds), true);
//trigger_error(ldap_error($ds), E_USER_ERROR);
$authenticated = false;
}
@ -1105,7 +1105,7 @@ f00bar;
private function isAbsolutePath($path) {
if ($path === null || $path === '')
return false;
return $path[0] === DIRECTORY_SEPARATOR || preg_match('~^[A-Z]:(?![^/\\\\])~i',$path) > 0;
return $path[0] === DIRECTORY_SEPARATOR || preg_match('~^[A-Z]:(?![^/\\\\])~i', $path) > 0;
}
private function getRootDir() {
@ -1247,7 +1247,7 @@ f00bar;
$ret = "";
foreach ($parts as $part)
if (trim($part) != "")
$ret .= (empty($ret) ? rtrim($part,"/") : trim($part, '/'))."/";
$ret .= (empty($ret) ? rtrim($part, "/") : trim($part, '/'))."/";
return rtrim($ret, "/");
}