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

140
README.md
View File

@ -1,31 +1,34 @@
# IFM - improved file manager # IFM - improved file manager
## contents
- [about](#about) ## Contents
- [features](#features)
- [requirements](#requirements) * [about](#about)
- [installation](#installation) * [features](#features)
- [security information](#security-information) * [requirements](#requirements)
- [keybindings](#keybindings) * [installation](#installation)
- [configuration](#configuration) * [security information](#security-information)
- [docker](#docker) * [keybindings](#keybindings)
- [screenshots](#screenshots) * [configuration](#configuration)
- [issues](#issues) * [docker](#docker)
* [screenshots](#screenshots)
* [issues](#issues)
## About ## 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: The IFM uses the following resources:
* [ACE Editor](https://ace.c9.io) * [ACE Editor](https://ace.c9.io)
* [Bootstrap v4](https://getbootstrap.com) * [Bootstrap v4](https://getbootstrap.com)
* custom icon set generated with [Fontello](http://fontello.com/) * custom icon set generated with [Fontello](http://fontello.com/)
* [jQuery](https://jquery.com) * [jQuery](https://jquery.com)
* [Mustache](https://mustache.github.io/) * [Mustache](https://mustache.github.io/)
## features ## Features
* create/edit files and directories * create/edit files and directories
* copy/move files and directories * copy/move files and directories
* download files and directories * download files and directories
@ -36,46 +39,40 @@ The IFM uses the following resources:
* simple authentication (LDAP via `ldap_bind` possible) * simple authentication (LDAP via `ldap_bind` possible)
## Requirements ## Requirements
* Client * Client
* HTML5 and CSS3 compatible browser + HTML5 and CSS3 compatible browser
* activated javascript + activated javascript
* Server * Server
* PHP >= 5.6 + PHP >= 5.6
* extensions + extensions
* bz2 - bz2
* curl (for remote upload) - curl (for remote upload)
* fileinfo - fileinfo
* json - json
* ldap (only if LDAP based authentication is used) - ldap (only if LDAP based authentication is used)
* mbstring - mbstring
* openssl (for remote uploads from https sources) - openssl (for remote uploads from https sources)
* phar - phar
* posix - posix
* zip - zip
* zlib - zlib
## Installation ## 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 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.
recommended; if the filesize of the IFM is an issue for you, consider using the
CDN versions. 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 ## 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 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).
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 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 configuration. [See also](https://github.com/misterunknown/ifm/wiki/Configuration).
also](https://github.com/misterunknown/ifm/wiki/Configuration).
## Keybindings ## Keybindings
* <kbd>e</kbd> - edit / extract current file * <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>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") * <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 * <kbd>Ctrl</kbd>-<kbd>Shift</kbd>-<kbd>f</kbd> - toggle fullscreen ace editor
## Configuration ## Configuration
See [configuration](https://github.com/misterunknown/ifm/wiki/Configuration). See [configuration](https://github.com/misterunknown/ifm/wiki/Configuration).
### authentication
### Authentication
See [authentication](https://github.com/misterunknown/ifm/wiki/Authentication). See [authentication](https://github.com/misterunknown/ifm/wiki/Authentication).
## Docker ## Docker
The docker image is based on the official php docker images (alpine version) The docker image is based on the official php docker images (alpine version)
and exposes port 80. and exposes port 80.
### Quickstart ### Quickstart
Build the image with this command in the top source dir: 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: 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` ```bash
docker run --rm -d --name ifm -p 8080:80 -v /path/to/data:/var/www ifm:latest
```
### Specify user/group ### 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` 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 ### 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 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:
The scripts configuration can be changed by adjusting the corresponding ```bash
environment variables. For example: docker run --rm -i -p "8080:80" -v "/var/www:/var/www" ifm
```
```docker run --rm -i -p "8080:80" -v /var/www:/var/www \ 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=1 -e IFM_AUTH \
-e IFM_AUTH_SOURCE="admin:$2y$05$LPdE7u/5da/TCE8ZhqQ1o.acuV50HqB3OrHhNwxbXYeWmmZKdQxrC" \ -e IFM_AUTH_SOURCE="admin:$2y$05$LPdE7u/5da/TCE8ZhqQ1o.acuV50HqB3OrHhNwxbXYeWmmZKdQxrC" \
ifm ifm
``` ```
You can get a complete list of environment variables You can get a complete list of environment variables [here](https://github.com/misterunknown/ifm/wiki/Configuration#configuration-options).
[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_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_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_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> <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 ## Issues
If you happen to find an error or miss a feature, you can create an issue on
Github. 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"]); $options = getopt(null, ["language::", "languages::", "lang::", "cdn"]);
// build CDN version? // build CDN version?
if (isset($options['cdn'])) if (isset($options['cdn'])) {
define("IFM_CDN", true); define("IFM_CDN", true);
else } else {
define("IFM_CDN", false); define("IFM_CDN", false);
}
// process languages // process languages
$langs = []; $langs = [];
foreach ($options as $key => $value) foreach ($options as $key => $value) {
if (substr($key, 0, 4) == "lang") if (substr($key, 0, 4) == "lang") {
$langs = array_merge($langs, explode(",", $value)); $langs = array_merge($langs, explode(",", $value));
}
}
$langs = array_unique($langs); $langs = array_unique($langs);
if (!empty($langs)) { if (!empty($langs)) {
@ -45,8 +48,9 @@ if (!empty($langs)) {
} }
// ensure english is available, as it gets merged with the other languages // ensure english is available, as it gets merged with the other languages
// in case of missing keys in 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"); array_push($langs, "en");
}
if (in_array("all", $langs)) if (in_array("all", $langs))
$langs = array_map( $langs = array_map(
@ -55,15 +59,17 @@ if (in_array("all", $langs))
); );
$vars['languageincludes'] = ""; $vars['languageincludes'] = "";
foreach ($langs as $l) foreach ($langs as $l) {
if (file_exists("src/i18n/".$l.".json")) if (file_exists("src/i18n/".$l.".json")) {
$vars['languageincludes'] .= $vars['languageincludes'] .=
'$i18n["'.$l.'"] = <<<\'f00bar\'' . "\n" '$i18n["'.$l.'"] = <<<\'f00bar\'' . "\n"
. file_get_contents( "src/i18n/".$l.".json" ) . "\n" . file_get_contents( "src/i18n/".$l.".json" ) . "\n"
. 'f00bar;' . "\n" . 'f00bar;' . "\n"
. '$i18n["'.$l.'"] = json_decode( $i18n["'.$l.'"], true );' . "\n" ; . '$i18n["'.$l.'"] = json_decode( $i18n["'.$l.'"], true );' . "\n" ;
else } else {
print "WARNING: Language file src/i18n/".$l.".json not found.\n"; print "WARNING: Language file src/i18n/".$l.".json not found.\n";
}
}
// Concat PHP Files // Concat PHP Files
$compiled = ["<?php"]; $compiled = ["<?php"];
@ -81,11 +87,12 @@ $compiled = str_replace("###ASSETS_JS###", file_get_contents("src/assets".(IFM_C
// Process file includes // Process file includes
$includes = NULL; $includes = NULL;
preg_match_all("/\#\#\#file:([^\#]+)\#\#\#/", $compiled, $includes, PREG_SET_ORDER); 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); $compiled = str_replace($file[0], file_get_contents($file[1]), $compiled);
}
// Process ace includes // Process ace includes
$includes = NULL; $includes = null;
$vars['ace_includes'] = ""; $vars['ace_includes'] = "";
preg_match_all("/\#\#\#acedir:([^\#]+)\#\#\#/", $compiled, $includes, PREG_SET_ORDER); preg_match_all("/\#\#\#acedir:([^\#]+)\#\#\#/", $compiled, $includes, PREG_SET_ORDER);
foreach ($includes as $dir) { foreach ($includes as $dir) {
@ -102,13 +109,15 @@ foreach ($includes as $dir) {
// Process variable includes // Process variable includes
$includes = NULL; $includes = NULL;
preg_match_all("/\#\#\#vars:([^\#]+)\#\#\#/", $compiled, $includes, PREG_SET_ORDER); 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($var[0], $vars[$var[1]], $compiled);
}
$compiled = str_replace('IFM_VERSION', IFM_VERSION, $compiled); $compiled = str_replace('IFM_VERSION', IFM_VERSION, $compiled);
if (!is_dir(IFM_RELEASE_DIR)) if (!is_dir(IFM_RELEASE_DIR)) {
mkdir(IFM_RELEASE_DIR); mkdir(IFM_RELEASE_DIR);
}
// build standalone ifm // build standalone ifm
file_put_contents(IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE, $compiled); file_put_contents(IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE, $compiled);

View File

@ -3,30 +3,30 @@ set -e
if [ ! -z $IFM_DOCKER_UID ]; then if [ ! -z $IFM_DOCKER_UID ]; then
# check if UID/GID are numeric # 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)" echo "FATAL: IFM_DOCKER_UID or IFM_DOCKER_GID are not numeric (UID: $IFM_DOCKER_UID, GID: $IFM_DOCKER_GID)"
exit 1 exit 1
fi fi
# get GID if not set # get GID if not set
if [ -z $IFM_DOCKER_GID ]; then if [ -z "$IFM_DOCKER_GID" ]; then
export IFM_DOCKER_GID=$IFM_DOCKER_UID export IFM_DOCKER_GID="$IFM_DOCKER_UID"
fi fi
# delete user if already exists # delete user if already exists
if getent passwd $IFM_DOCKER_UID >/dev/null 2>&1; then if getent passwd "$IFM_DOCKER_UID" >/dev/null 2>&1; then
deluser $(getent passwd $IFM_DOCKER_UID | sed "s/:.*//") deluser $(getent passwd "$IFM_DOCKER_UID" | sed "s/:.*//")
fi fi
# check if group already exists # check if group already exists
if ! getent group $IFM_DOCKER_GID >/dev/null 2>&1; then if ! getent group "$IFM_DOCKER_GID" >/dev/null 2>&1; then
addgroup -g $IFM_DOCKER_GID -S www-data addgroup -g "$IFM_DOCKER_GID" -S www-data
REAL_GROUP=www-data REAL_GROUP=www-data
else else
REAL_GROUP=$(getent group $IFM_DOCKER_GID | sed "s/:.*//") REAL_GROUP=$(getent group "$IFM_DOCKER_GID" | sed "s/:.*//")
fi fi
adduser -u $IFM_DOCKER_UID -SHDG $REAL_GROUP www-data adduser -u "$IFM_DOCKER_UID" -SHDG "$REAL_GROUP" www-data
else else
addgroup -g 33 -S www-data addgroup -g 33 -S www-data
adduser -SHD -u 33 -G www-data 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" 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.11.3/r-2.2.9/datatables.min.css"/> <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"> <style type="text/css">
###file:src/includes/bootstrap-treeview.min.css### ###file:src/includes/bootstrap-treeview.min.css###
###file:src/includes/fontello-embedded.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/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 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.11.3/r-2.2.9/datatables.min.js"></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 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/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/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/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.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/ace/1.14.0/ace.min.js" integrity="sha512-s57ywpCtz+4PU992Bg1rDtr6+1z38gO2mS92agz2nqQcuMQ6IvgLWoQ2SFpImvg1rbgqBKeSEq0d9bo9NtBY0w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer> <script defer>
###file:src/includes/bootstrap-treeview.min.js### ###file:src/includes/bootstrap-treeview.min.js###
###file:src/includes/BootstrapMenu.min.js### ###file:src/includes/BootstrapMenu.min.js###

View File

@ -7,9 +7,10 @@ class Htpasswd {
public $users = []; public $users = [];
public function __construct($filename="") { public function __construct($filename="") {
if( $filename ) if ($filename) {
$this->load($filename); $this->load($filename);
} }
}
/** /**
* Load a new htpasswd file * Load a new htpasswd file
@ -23,9 +24,10 @@ class Htpasswd {
$this->users[$user] = trim($pass); $this->users[$user] = trim($pass);
} }
return true; return true;
} else } else {
return false; return false;
} }
}
public function getUsers() { public function getUsers() {
return array_keys($this->users); return array_keys($this->users);
@ -50,7 +52,7 @@ class Htpasswd {
$apr1 = new APR1_MD5(); $apr1 = new APR1_MD5();
return $apr1->check($pass, $hash); return $apr1->check($pass, $hash);
} elseif (substr($hash, 0, 5) == '{SHA}') { } elseif (substr($hash, 0, 5) == '{SHA}') {
return base64_encode( sha1( $pass, TRUE ) ) == substr( $hash, 5 ); return base64_encode(sha1($pass, true)) == substr($hash, 5);
} else { // assume CRYPT } else { // assume CRYPT
return crypt($pass, $hash) == $hash; return crypt($pass, $hash) == $hash;
} }
@ -75,21 +77,28 @@ class APR1_MD5 {
// Wikipedia // Wikipedia
public static function hash($mdp, $salt = null) { public static function hash($mdp, $salt = null) {
if (is_null($salt)) if (is_null($salt)) {
$salt = self::salt(); $salt = self::salt();
}
$salt = substr($salt, 0, 8); $salt = substr($salt, 0, 8);
$max = strlen($mdp); $max = strlen($mdp);
$context = $mdp.'$apr1$'.$salt; $context = $mdp.'$apr1$'.$salt;
$binary = pack('H32', md5($mdp.$salt.$mdp)); $binary = pack('H32', md5($mdp.$salt.$mdp));
for($i=$max; $i>0; $i-=16) for ($i=$max; $i>0; $i-=16) {
$context .= substr($binary, 0, min(16, $i)); $context .= substr($binary, 0, min(16, $i));
for($i=$max; $i>0; $i>>=1) }
for ($i=$max; $i>0; $i>>=1) {
$context .= ($i & 1) ? chr(0) : $mdp[0]; $context .= ($i & 1) ? chr(0) : $mdp[0];
}
$binary = pack('H32', md5($context)); $binary = pack('H32', md5($context));
for ($i=0; $i<1000; $i++) { for ($i=0; $i<1000; $i++) {
$new = ($i & 1) ? $mdp : $binary; $new = ($i & 1) ? $mdp : $binary;
if($i % 3) $new .= $salt; if ($i % 3) {
if($i % 7) $new .= $mdp; $new .= $salt;
}
if ($i % 7) {
$new .= $mdp;
}
$new .= ($i & 1) ? $binary : $mdp; $new .= ($i & 1) ? $binary : $mdp;
$binary = pack('H32', md5($new)); $binary = pack('H32', md5($new));
} }
@ -97,7 +106,9 @@ class APR1_MD5 {
for ($i = 0; $i < 5; $i++) { for ($i = 0; $i < 5; $i++) {
$k = $i+6; $k = $i+6;
$j = $i+12; $j = $i+12;
if($j == 16) $j = 5; if ($j == 16) {
$j = 5;
}
$hash = $binary[$i].$binary[$k].$binary[$j].$hash; $hash = $binary[$i].$binary[$k].$binary[$j].$hash;
} }
$hash = chr(0).chr(0).$binary[11].$hash; $hash = chr(0).chr(0).$binary[11].$hash;

View File

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