From: Patrick Canterino Date: Thu, 27 Jun 2024 10:15:52 +0000 (+0200) Subject: Merged next-release into master X-Git-Tag: 4.6.0~16 X-Git-Url: https://git.p6c8.net/jirafeau_project.git/commitdiff_plain/93d7dffa6e851ee8e2c1c0708c78caff3fa35dd7?hp=9d5347af02b932d084082320dc14271d19040879 Merged next-release into master --- diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cddf940..0d2d9c4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,5 @@ # Select docker image from https://hub.docker.com/_/php/ -image: php:7.3 +image: php:8.1 # Select what we should cache cache: @@ -17,44 +17,19 @@ before_script: - curl -sS https://getcomposer.org/installer | php # Create composer.json file manually, since this is a project without any non-dev dependencies yet - php composer.phar require --dev php-parallel-lint/php-parallel-lint - - php composer.phar require --dev friendsofphp/php-cs-fixer + - php composer.phar require --dev friendsofphp/php-cs-fixer:3.10.0 # Install all project dependencies - php composer.phar install # Run tests -test_app_phpdefaultversion: +job_lint_app_81: + image: php:8.1 script: - ./vendor/bin/parallel-lint --exclude vendor . - - ./vendor/bin/php-cs-fixer -vvv fix . --dry-run --diff --using-cache=no --rules=@PSR2 + - ./vendor/bin/php-cs-fixer -vvv fix . --dry-run --using-cache=no --rules=@PSR2 -job_lint_app_phpnextversion: +job_lint_app_74: image: php:7.4 script: - ./vendor/bin/parallel-lint --exclude vendor . - - ./vendor/bin/php-cs-fixer -vvv fix . --dry-run --diff --using-cache=no --rules=@PSR2 - allow_failure: true - -# Run same tests with older supported versions -test_app_php72: - image: php:7.2 - script: - - ./vendor/bin/parallel-lint --exclude vendor . - - ./vendor/bin/php-cs-fixer -vvv fix . --dry-run --diff --using-cache=no --rules=@PSR2 - -test_app_php71: - image: php:7.1 - script: - - ./vendor/bin/parallel-lint --exclude vendor . - - ./vendor/bin/php-cs-fixer -vvv fix . --dry-run --diff --using-cache=no --rules=@PSR2 - -test_app_php70: - image: php:7.0 - script: - - ./vendor/bin/parallel-lint --exclude vendor . - - ./vendor/bin/php-cs-fixer -vvv fix . --dry-run --diff --using-cache=no --rules=@PSR2 - -test_app_php56: - image: php:5.6 - script: - - ./vendor/bin/parallel-lint --exclude vendor . - - ./vendor/bin/php-cs-fixer -vvv fix . --dry-run --diff --using-cache=no --rules=@PSR2 + - ./vendor/bin/php-cs-fixer -vvv fix . --dry-run --using-cache=no --rules=@PSR2 diff --git a/README.md b/README.md index 3e9a177..765b5bd 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ See [jirafeau.net](https://jirafeau.net/) for a demo. - Shows progression: speed, percentage and remaining upload time - Preview content in browser (if possible) - Optional password protection (for uploading or downloading) +- option to require, check or generate file download passwords - Set expiration time for downloads - Option to self-destruct after first download - Shortened URLs using base 64 encoding @@ -127,13 +128,13 @@ An other obvious basic security is to let access users to the site by HTTPS (mak Data encryption can be activated in options. This feature makes the server encrypt data and send the decryt key to the user (inside download URL). The decrypt key is not stored on the server so if you loose an url, you won't be able to retrieve file content. -Encryption is configured to use AES256 in OFB mode. +Encryption is configured to use [XChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305). In case of security troubles on the server, attacker won't be able to access files. By activating this feature, you have to be aware of few things: - Data encryption has a cost (cpu) and it takes more time for downloads to complete once file sent. - During the download, the server will decrypt on the fly (and use resource). -- This feature needs to have the mcrypt php module. +- This feature needs to have the Sodium php module. - File de-duplication will stop to work (as we can't compare two encrypted files). - Be sure your server do not log client's requests. - Don't forget to enable https. diff --git a/admin.php b/admin.php index d05ce35..0f8967f 100644 --- a/admin.php +++ b/admin.php @@ -44,7 +44,8 @@ if (php_sapi_name() == "cli") { } else { die("No command found. Should be admin.php .\n"); } -} else { +// Second check: Challenge by IP +} elseif (true === jirafeau_challenge_admin_ip($cfg, get_ip_address($cfg))) { /* Disable admin interface if we have a empty admin password. */ if (empty($cfg['admin_password']) && empty($cfg['admin_http_auth_user'])) { require(JIRAFEAU_ROOT . 'lib/template/header.php'); @@ -57,7 +58,7 @@ if (php_sapi_name() == "cli") { /* Logout if requested. */ if (jirafeau_admin_session_logged() && isset($_POST['action']) && (strcmp($_POST['action'], 'logout') == 0)) { - jirafeau_admin_session_end(); + jirafeau_session_end(); } if (!jirafeau_admin_session_logged()) { @@ -117,9 +118,13 @@ if (php_sapi_name() == "cli") { /* Show admin interface if not downloading a file. */ if (!(isset($_POST['action']) && strcmp($_POST['action'], 'download') == 0)) { require(JIRAFEAU_ROOT . 'lib/template/header.php'); ?>

(version )

(version )

'.t('SODIUM_UNAVAILABLE').'

'; + } - ?>
+ ?>
@@ -301,5 +306,8 @@ if (php_sapi_name() == "cli") { } require(JIRAFEAU_ROOT.'lib/template/footer.php'); +} else { + require(JIRAFEAU_ROOT . 'lib/template/header.php'); + jirafeau_fatal_error(t('ACCESS_KO'), $cfg); } ?> diff --git a/docker/README.md b/docker/README.md index daf5302..5f9dce3 100644 --- a/docker/README.md +++ b/docker/README.md @@ -34,6 +34,7 @@ More details about options in `lib/config.original.php`. Available options: - `ADMIN_PASSWORD`: setup a specific admin password. If not set, a random password will be generated. +- `ADMIN_IP`: set one or more ip allowed to access admin interface (separated by comma). - `WEB_ROOT`: setup a specific domain to point at when generating links (e.g. 'jirafeau.mydomain.com/'). - `VAR_ROOT`: setup a specific path where to place files. default: '/data'. - `FILE_HASH`: can be set to `md5`, `partial_md5` or `random` (default). @@ -41,7 +42,8 @@ Available options: - `TITLE`: set Jirafeau instance title. - `ORGANISATION`: set organisation (in ToS). - `CONTACTPERSON`: set contact person (in ToS). -- `STYLE`: apply a specific style. +- `STYLE`: apply a specific style from the media folder. +- `DARK_STYLE`: apply a specific style for browsers in dark mode. - `AVAILABILITY_DEFAULT`: setup which availability shows by default. - `ONE_TIME_DOWNLOAD`: set to 1 or 0 to enable or disable one time downloads. - `ENABLE_CRYPT`: set to 1 or 0 to enable or disable server side encryption. @@ -52,6 +54,11 @@ Available options: - `UPLOAD_IP_NO_PASSWORD`: set one or more ip allowed to upload files without password (separated by comma). - `PROXY_IP`: set one or more proxy ip (separated by comma). - `STORE_UPLOADER_IP`: set to 1 or 0 to enable or disable keeping sender's IP with the _link_ file. +- `DOWNLOAD_PASSWORD_REQUIREMENT`: set to 'optional' (default), 'required' or 'generated' to make a password for downloading optional, required or generated +- `DOWNLOAD_PASSWORD_GEN_LEN`: set length of generated download passwords +- `DOWNLOAD_PASSWORD_GEN_CHARS`: set characters used for generated download passwords +- `DOWNLOAD_PASSWORD_POLICY`: set to 'regex' to use a regular expression to check user provided download passwords for complexity constraints +- `DOWNLOAD_PASSWORD_POLICY_REGEX`: regex to check against if password policy is set to regex Example: ``` diff --git a/docker/docker_config.php b/docker/docker_config.php index 6a03b73..634d58b 100644 --- a/docker/docker_config.php +++ b/docker/docker_config.php @@ -161,20 +161,27 @@ function run_setup(&$cfg) setup_webroot($cfg); env_2_cfg_string($cfg, 'file_hash'); env_2_cfg_bool($cfg, 'preview'); - env_2_cfg_bool($cfg, 'title'); + env_2_cfg_string($cfg, 'title', false); env_2_cfg_string($cfg, 'organisation'); env_2_cfg_string($cfg, 'contactperson'); env_2_cfg_string($cfg, 'style'); env_2_cfg_string($cfg, 'availability_default'); + env_2_cfg_string($cfg, 'dark_style'); env_2_cfg_bool($cfg, 'one_time_download'); env_2_cfg_bool($cfg, 'enable_crypt'); env_2_cfg_bool($cfg, 'debug'); env_2_cfg_int($cfg, 'maximal_upload_size'); env_2_cfg_string_array($cfg, 'upload_password'); env_2_cfg_string_array($cfg, 'upload_ip'); + env_2_cfg_string_array($cfg, 'admin_ip'); env_2_cfg_string_array($cfg, 'upload_ip_nopassword'); env_2_cfg_string_array($cfg, 'proxy_ip'); env_2_cfg_bool($cfg, 'store_uploader_ip'); + env_2_cfg_string($cfg, 'download_password_requirement'); + env_2_cfg_int($cfg, 'download_password_gen_len'); + env_2_cfg_string($cfg, 'download_password_gen_chars'); + env_2_cfg_string($cfg, 'download_password_policy'); + env_2_cfg_string($cfg, 'download_password_policy_regex'); if ($setup_ok) { $cfg['installation_done'] = true; @@ -187,4 +194,4 @@ function run_setup(&$cfg) } } -run_setup($cfg); +run_setup($cfg); \ No newline at end of file diff --git a/docker/lighttpd.conf b/docker/lighttpd.conf index a137097..680280f 100644 --- a/docker/lighttpd.conf +++ b/docker/lighttpd.conf @@ -5,6 +5,7 @@ var.statedir = "/var/lib/lighttpd" server.port = 80 server.modules = ( "mod_access", +# "mod_usertrack", "mod_expire", "mod_accesslog" ) diff --git a/f.php b/f.php index 5555523..543fc10 100644 --- a/f.php +++ b/f.php @@ -248,25 +248,13 @@ if ($cfg['litespeed_workaround']) { $_SERVER['QUERY_STRING'] . '&litespeed_workaround=phase2'); } } -/* Read encrypted file. */ +/* Read encrypted file (Sodium mode). */ elseif ($link['crypted']) { - /* Init module */ - $m = mcrypt_module_open('rijndael-256', '', 'ofb', ''); - /* Extract key and iv. */ - $hash_key = md5($crypt_key); - $iv = jirafeau_crypt_create_iv($hash_key, mcrypt_enc_get_iv_size($m)); - /* Init module. */ - mcrypt_generic_init($m, $hash_key, $iv); - /* Decrypt file. */ - $r = fopen(VAR_FILES . $p . $link['hash'], 'r'); - while (!feof($r)) { - $dec = mdecrypt_generic($m, fread($r, 1024)); - print $dec; - } - fclose($r); - /* Cleanup. */ - mcrypt_generic_deinit($m); - mcrypt_module_close($m); + jirafeau_decrypt_file(VAR_FILES . $p . $link['hash'], 'php://output', $crypt_key); +} +/* Read encrypted file (legacy mode using mcrypt). */ +elseif ($link['crypted_legacy']) { + jirafeau_decrypt_file_legacy(VAR_FILES . $p . $link['hash'], 'php://output', $crypt_key); } /* Read file. */ else { @@ -285,6 +273,9 @@ else { if ($link['onetime'] == 'O') { jirafeau_delete_link($link_name); } + +jirafeau_write_download_stats($link_name, get_ip_address($cfg)); + exit; ?> diff --git a/index.php b/index.php index 33bb83e..24565bd 100644 --- a/index.php +++ b/index.php @@ -25,6 +25,10 @@ require(JIRAFEAU_ROOT . 'lib/settings.php'); require(JIRAFEAU_ROOT . 'lib/functions.php'); require(JIRAFEAU_ROOT . 'lib/lang.php'); +if ($cfg['download_password_requirement'] === "generated"){ + $download_pass = jirafeau_gen_download_pass($cfg['download_password_gen_len'], $cfg['download_password_gen_chars']); +} + check_errors($cfg); if (has_error()) { require(JIRAFEAU_ROOT . 'lib/template/header.php'); @@ -32,39 +36,37 @@ if (has_error()) { require(JIRAFEAU_ROOT . 'lib/template/footer.php'); exit; } - require(JIRAFEAU_ROOT . 'lib/template/header.php'); +// Logout action +if (isset($_POST['action']) && (strcmp($_POST['action'], 'logout') == 0)) { + jirafeau_session_end(); +} + /* Check if user is allowed to upload. */ -// First check: Challenge by IP NO PASSWORD -if (true === jirafeau_challenge_upload_ip_without_password($cfg, get_ip_address($cfg))) { - $_SESSION['upload_auth'] = true; - $_POST['upload_password'] = ''; - $_SESSION['user_upload_password'] = $_POST['upload_password']; +// First check: Is user already logged +if (jirafeau_user_session_logged()) { +} +// Second check: Challenge by IP NO PASSWORD +elseif (true === jirafeau_challenge_upload_ip_without_password($cfg, get_ip_address($cfg))) { + jirafeau_user_session_start(); } -// Second check: Challenge by IP +// Third check: Challenge by IP elseif (true === jirafeau_challenge_upload_ip($cfg, get_ip_address($cfg))) { // Is an upload password required? if (jirafeau_has_upload_password($cfg)) { - // Logout action - if (isset($_POST['action']) && (strcmp($_POST['action'], 'logout') == 0)) { - session_unset(); - } - // Challenge by password - // …save successful logins in session if (isset($_POST['upload_password'])) { if (jirafeau_challenge_upload_password($cfg, $_POST['upload_password'])) { - $_SESSION['upload_auth'] = true; - $_SESSION['user_upload_password'] = $_POST['upload_password']; + jirafeau_user_session_start(); } else { - $_SESSION['admin_auth'] = false; + jirafeau_session_end(); jirafeau_fatal_error(t('BAD_PSW'), $cfg); } } // Show login form if user session is not authorized yet - if (true === empty($_SESSION['upload_auth'])) { + if (!jirafeau_user_session_logged()) { ?>
@@ -81,8 +83,7 @@ elseif (true === jirafeau_challenge_upload_ip($cfg, get_ip_address($cfg))) {
@@ -111,8 +112,23 @@ elseif (true === jirafeau_challenge_upload_ip($cfg, get_ip_address($cfg))) {

- +
+

+ +
+

+ '?> + +

+
+
+ + +

@@ -122,7 +138,7 @@ elseif (true === jirafeau_challenge_upload_ip($cfg, get_ip_address($cfg))) {

+ } ?>

@@ -161,19 +177,24 @@ elseif (true === jirafeau_challenge_upload_ip($cfg, get_ip_address($cfg))) {

-
+

0) { - echo t('2_BIG') . ', ' . t('FILE_LIM') . " " . $cfg['maximal_upload_size'] . " MB."; - } - ?>')"/> + if ($cfg['maximal_upload_size'] >= 1024) { + echo t('2_BIG') . ', ' . t('FILE_LIM') . " " . number_format($cfg['maximal_upload_size']/1024, 2) . " GB."; + } elseif ($cfg['maximal_upload_size'] > 0) { + echo t('2_BIG') . ', ' . t('FILE_LIM') . " " . $cfg['maximal_upload_size'] . " MB."; + } +?>')"/>

@@ -183,102 +204,93 @@ elseif (true === jirafeau_challenge_upload_ip($cfg, get_ip_address($cfg))) { echo '' . t('ONE_TIME_DL') . ':'; echo ''; } - ?> - - - - + if ($cfg['download_password_requirement'] === 'generated'){ + echo ''; + }else{ + echo ''; + echo ''; + }?> = 1024) { - echo '

' . t('FILE_LIM'); - echo " " . number_format($cfg['maximal_upload_size'] / 1024, 2) . " GB.

"; - } elseif ($cfg['maximal_upload_size'] > 0) { - echo '

' . t('FILE_LIM'); - echo " " . $cfg['maximal_upload_size'] . " MB.

"; - } else { - echo '

'; - } - ?> +if ($cfg['maximal_upload_size'] >= 1024) { + echo '

' . t('FILE_LIM'); + echo " " . number_format($cfg['maximal_upload_size'] / 1024, 2) . " GB.

"; +} elseif ($cfg['maximal_upload_size'] > 0) { + echo '

' . t('FILE_LIM'); + echo " " . $cfg['maximal_upload_size'] . " MB.

"; +} else { + echo '

'; +} +?>

- - - - - - +

-
+
@@ -286,7 +298,7 @@ elseif (true === jirafeau_challenge_upload_ip($cfg, get_ip_address($cfg))) {
+?>
@@ -299,16 +311,17 @@ elseif (true === jirafeau_challenge_upload_ip($cfg, get_ip_address($cfg))) { document.getElementById('send').style.display = 'none'; if (!check_html5_file_api ()) document.getElementById('max_file_size').innerHTML = ' 0) { - echo t('NO_BROWSER_SUPPORT') . $max_size; - } - ?>'; + $max_size = jirafeau_get_max_upload_size(); +if ($max_size > 0) { + echo t('NO_BROWSER_SUPPORT') . $max_size; +} +?>'; addCopyListener('upload_link_button', 'upload_link'); addCopyListener('preview_link_button', 'preview_link'); addCopyListener('direct_link_button', 'direct_link'); addCopyListener('delete_link_button', 'delete_link'); + addTextCopyListener('password_copy_button', 'output_key'); // @license-end diff --git a/install.php b/install.php index 6dbefb5..ed99b19 100644 --- a/install.php +++ b/install.php @@ -62,26 +62,26 @@ if (!is_writable(JIRAFEAU_CFG) && !@chmod(JIRAFEAU_CFG, '0666')) { if (isset($_POST['step']) && isset($_POST['next'])) { switch ($_POST['step']) { - case 1: - if (strlen($_POST['admin_password'])) { - $cfg['admin_password'] = hash('sha256', $_POST['admin_password']); - } else { - $cfg['admin_password'] = ''; - } - jirafeau_export_cfg($cfg); - break; - - case 2: - $cfg['web_root'] = jirafeau_add_ending_slash($_POST['web_root']); - $cfg['var_root'] = jirafeau_add_ending_slash($_POST['var_root']); - jirafeau_export_cfg($cfg); - break; - - case 3: - $cfg['web_root'] = jirafeau_add_ending_slash($_POST['web_root']); - $cfg['var_root'] = jirafeau_add_ending_slash($_POST['var_root']); - jirafeau_export_cfg($cfg); - break; + case 1: + if (strlen($_POST['admin_password'])) { + $cfg['admin_password'] = hash('sha256', $_POST['admin_password']); + } else { + $cfg['admin_password'] = ''; + } + jirafeau_export_cfg($cfg); + break; + + case 2: + $cfg['web_root'] = jirafeau_add_ending_slash($_POST['web_root']); + $cfg['var_root'] = jirafeau_add_ending_slash($_POST['var_root']); + jirafeau_export_cfg($cfg); + break; + + case 3: + $cfg['web_root'] = jirafeau_add_ending_slash($_POST['web_root']); + $cfg['var_root'] = jirafeau_add_ending_slash($_POST['var_root']); + jirafeau_export_cfg($cfg); + break; } } @@ -95,20 +95,20 @@ if (isset($_POST['next'])) { } switch ($current) { -case 1: -default: - ?>

+ ?> @@ -117,90 +117,90 @@ default:

+ ?> + echo(empty($cfg['web_root']) ? jirafeau_default_web_root() : $cfg['web_root']); + ?>" size = "40" /> + ?> + ?>" size = "40" />
+ echo t('PREV_STEP'); ?>" />

+ ?>" />

'.$err['why'].'
'.NL; ?>

'.$err['why'].'
'.NL; ?>

'; - } else { - $cfg['installation_done'] = true; - jirafeau_export_cfg($cfg); - echo '

' . - t('JI_FONCTIONAL') . ':' . - '
' . - $cfg['web_root'].'

'; - } -break; + } else { + $cfg['installation_done'] = true; + jirafeau_export_cfg($cfg); + echo '

' . + t('JI_FONCTIONAL') . ':' . + '
' . + $cfg['web_root'].'

'; + } + break; } require(JIRAFEAU_ROOT . 'lib/template/footer.php'); diff --git a/lib/config.original.php b/lib/config.original.php index 1f2e8b7..1543089 100644 --- a/lib/config.original.php +++ b/lib/config.original.php @@ -108,6 +108,14 @@ $cfg['admin_password'] = ''; */ $cfg['admin_http_auth_user'] = ''; +/* List of IP allowed to access the admin interface. + * If the list is empty, then there is no admin interface restriction based on IP. + * Elements of the list can be a single IP (e.g. "123.45.67.89") or + * an IP range (e.g. "123.45.0.0/16"). + * Note that CIDR notation is available for IPv4 only for the moment. + */ +$cfg['admin_ip'] = array(); + /* Allow user to select different options for file expiration time. * Possible values in array: * 'minute': file is available for one minute @@ -222,3 +230,29 @@ $cfg['debug'] = false; * Set to 0 to remove limitation. */ $cfg['max_upload_chunk_size_bytes'] = 100000000; // 100MB + +/* Set password requirement policy for downloading files + * Possible values: + * optional (default): Password may be set by the uploader, but is not mandatory + * required: Setting a password is mandatory to upload a file. + * generated: Passwords are automatically generated and shown to the uploader, when uploading a file + */ +$cfg['download_password_requirement'] = 'optional'; + +/* Set length of generated passwords + */ +$cfg['download_password_gen_len'] = 10; + +/* Set allowed chars for password generation + */ +$cfg['download_password_gen_chars'] = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&*()_-=+;:,.?'; +/* Set password complexity policy for downloading files + * possible values: + * none (default): Passwords for downloading files can be of arbitrary complexity + * regex: Passwords are checked with a regex for complexity constraints + */ +$cfg['download_password_policy'] = 'none'; +/* Set the regex for regex download password policy + * Delimiters are need, but modifiers should not be used + */ +$cfg['download_password_policy_regex'] = '/.*/'; diff --git a/lib/functions.js.php b/lib/functions.js.php index e7bc339..3052bf0 100644 --- a/lib/functions.js.php +++ b/lib/functions.js.php @@ -24,6 +24,7 @@ define('JIRAFEAU_ROOT', dirname(__FILE__) . '/../'); require(JIRAFEAU_ROOT . 'lib/settings.php'); require(JIRAFEAU_ROOT . 'lib/functions.php'); require(JIRAFEAU_ROOT . 'lib/lang.php'); + ?> // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later var web_root = ""; @@ -344,7 +345,7 @@ function add_time_string_to_date(d, time) return false; } -function classic_upload (file, time, password, one_time, upload_password) +function classic_upload (file, time, password, one_time) { // Delay time estimation init as we can't have file size upload_time_estimation_init(0); @@ -397,9 +398,6 @@ function classic_upload (file, time, password, one_time, upload_password) form.append ("key", password); if (one_time) form.append ("one_time_download", '1'); - if (upload_password.length > 0) - form.append ("upload_password", upload_password); - req.send (form); } @@ -416,7 +414,7 @@ var async_global_time; var async_global_transfering = 0; var async_global_last_code; -function async_upload_start (max_size, file, time, password, one_time, upload_password) +function async_upload_start (max_size, file, time, password, one_time) { async_global_transfered = 0; async_global_file = file; @@ -455,8 +453,6 @@ function async_upload_start (max_size, file, time, password, one_time, upload_pa form.append ("key", password); if (one_time) form.append ("one_time_download", '1'); - if (upload_password.length > 0) - form.append ("upload_password", upload_password); // Start time estimation upload_time_estimation_init(async_global_file.size); @@ -607,8 +603,7 @@ function upload (max_chunk_size) document.getElementById('file_select').files[0], document.getElementById('select_time').value, document.getElementById('input_key').value, - one_time, - document.getElementById('upload_password').value + one_time ); } else @@ -617,8 +612,7 @@ function upload (max_chunk_size) document.getElementById('file_select').files[0], document.getElementById('select_time').value, document.getElementById('input_key').value, - one_time, - document.getElementById('upload_password').value + one_time ); } } @@ -792,22 +786,37 @@ function addCopyListener(button_id, link_id) { } } +function copyTextToClipboard(text_id){ + var copyText = document.getElementById(text_id); + copyText.select(); + copyText.setSelectionRange(0, 99999); + navigator.clipboard.writeText(copyText.value); +} + +function addTextCopyListener(button_id, text_id) { + if(document.getElementById(button_id)){ + document.getElementById(button_id) + .addEventListener("click", function() { + copyTextToClipboard(text_id);}); + } +} + function set_dark_mode() { let steel_sheet = ""; let shortcut_icon = ""; document.getElementById('stylesheet').href = steel_sheet; - document.getElementById('shortcut_icon').href = steel_sheet; + document.getElementById('shortcut_icon').href = shortcut_icon; } function set_light_mode() { let steel_sheet = ""; let shortcut_icon = ""; document.getElementById('stylesheet').href = steel_sheet; - document.getElementById('shortcut_icon').href = steel_sheet; + document.getElementById('shortcut_icon').href = shortcut_icon; } function color_scheme_preferences() { - + let dark_mode_steel_sheet = "" if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { set_dark_mode(); diff --git a/lib/functions.php b/lib/functions.php index 1e084fb..b6672fb 100644 --- a/lib/functions.php +++ b/lib/functions.php @@ -101,6 +101,19 @@ function jirafeau_gen_random($l) return $code; } +function jirafeau_gen_download_pass($length, $allowed_chars) +{ + if ($length <= 0) { + return false; + } + $pass=""; + for ($i = 0; $i < $length; $i++) { + $pass .= $allowed_chars[rand(0, strlen($allowed_chars) - 1)]; + } + + return $pass; +} + function is_ssl() { if (isset($_SERVER['HTTPS'])) { @@ -130,8 +143,11 @@ function jirafeau_human_size($octets) // Convert UTC timestamp to a datetime field function jirafeau_get_datetimefield($timestamp) { - $content = '' - . strftime('%Y-%m-%d %H:%M', $timestamp) . ' (GMT)'; + + $ts = date_create("@" . $timestamp); + $content = '' + . date_format($ts, 'Y-m-d H:i') . ' (GMT)'; + return $content; } @@ -148,6 +164,9 @@ function jirafeau_clean_rm_link($link) if (file_exists(VAR_LINKS . $p . $link)) { unlink(VAR_LINKS . $p . $link); } + if (file_exists(VAR_LINKS . $p . $link . '_download')) { + unlink(VAR_LINKS . $p . $link . '_download'); + } $parse = VAR_LINKS . $p; $scan = array(); while (file_exists($parse) @@ -190,23 +209,23 @@ function jirafeau_ini_to_bytes($value) $modifier = substr($value, -1); $bytes = substr($value, 0, -1); switch (strtoupper($modifier)) { - default: - return intval($value); - break; - case 'P': - $bytes *= 1024; - // no break - case 'T': - $bytes *= 1024; - // no break - case 'G': - $bytes *= 1024; - // no break - case 'M': - $bytes *= 1024; - // no break - case 'K': - $bytes *= 1024; + default: + return intval($value); + break; + case 'P': + $bytes *= 1024; + // no break + case 'T': + $bytes *= 1024; + // no break + case 'G': + $bytes *= 1024; + // no break + case 'M': + $bytes *= 1024; + // no break + case 'K': + $bytes *= 1024; } return $bytes; } @@ -264,19 +283,19 @@ function jirafeau_get_max_upload_chunk_size_bytes($max_upload_chunk_size_bytes = function jirafeau_upload_errstr($code) { switch ($code) { - case UPLOAD_ERR_INI_SIZE: - case UPLOAD_ERR_FORM_SIZE: - return t('Your file exceeds the maximum authorized file size. '); + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: + return t('Your file exceeds the maximum authorized file size. '); - case UPLOAD_ERR_PARTIAL: - case UPLOAD_ERR_NO_FILE: - return - t('Your file was not uploaded correctly. You may succeed in retrying. '); + case UPLOAD_ERR_PARTIAL: + case UPLOAD_ERR_NO_FILE: + return + t('Your file was not uploaded correctly. You may succeed in retrying. '); - case UPLOAD_ERR_NO_TMP_DIR: - case UPLOAD_ERR_CANT_WRITE: - case UPLOAD_ERR_EXTENSION: - return t('Internal error. You may not succeed in retrying. '); + case UPLOAD_ERR_NO_TMP_DIR: + case UPLOAD_ERR_CANT_WRITE: + case UPLOAD_ERR_EXTENSION: + return t('Internal error. You may not succeed in retrying. '); } return t('Unknown error. '); } @@ -435,13 +454,15 @@ function jirafeau_upload($file, $one_time_download, $key, $time, $ip, $crypt, $l /* Crypt file if option is enabled. */ $crypted = false; $crypt_key = ''; - if ($crypt == true && !(extension_loaded('mcrypt') == true)) { - error_log("PHP extension mcrypt not loaded, won't encrypt in Jirafeau"); + if ($crypt == true && !(extension_loaded('sodium') == true)) { + error_log("PHP extension sodium not loaded, won't encrypt in Jirafeau"); } - if ($crypt == true && extension_loaded('mcrypt') == true) { - $crypt_key = jirafeau_encrypt_file($file['tmp_name'], $file['tmp_name']); + if ($crypt == true && extension_loaded('sodium') == true) { + $crypt_key = jirafeau_encrypt_file($file['tmp_name'], $file['tmp_name'].'crypt'); if (strlen($crypt_key) > 0) { - $crypted = true; + if (rename($file['tmp_name'].'crypt', $file['tmp_name']) === true) { + $crypted = true; + } } } @@ -496,7 +517,7 @@ function jirafeau_upload($file, $one_time_download, $key, $time, $ip, $crypt, $l $handle, $name . NL. $mime_type . NL. $size . NL. $password . NL. $time . NL . $hash. NL . ($one_time_download ? 'O' : 'R') . NL . time() . - NL . $ip . NL. $delete_link_code . NL . ($crypted ? 'C' : 'O') + NL . $ip . NL. $delete_link_code . NL . ($crypted ? 'C2' : 'O') ); fclose($handle); $hash_link = substr(base_16_to_64(md5_file($link_tmp_name)), 0, $link_name_length); @@ -645,7 +666,8 @@ function jirafeau_get_link($hash) $out['upload_date'] = trim($c[7]); $out['ip'] = trim($c[8]); $out['link_code'] = trim($c[9]); - $out['crypted'] = trim($c[10]) == 'C'; + $out['crypted'] = trim($c[10]) == 'C2'; + $out['crypted_legacy'] = trim($c[10]) == 'C'; return $out; } @@ -693,6 +715,7 @@ function jirafeau_admin_list($name, $file_hash, $link_hash) if (!count($l)) { continue; } + $ld = jirafeau_get_download_stats($node); /* Filter. */ if (!empty($name) && !@preg_match("/$name/i", jirafeau_escape($l['file_name']))) { @@ -717,6 +740,11 @@ function jirafeau_admin_list($name, $file_hash, $link_hash) if (strlen($l['ip']) > 0) { echo t('ORIGIN') . ': ' . $l['ip'] . '
'; } + echo t('DOWNLOAD_COUNT') . ': ' . $ld['count'] . '
'; + if ($ld['count'] > 0) { + echo t('DOWNLOAD_DATE') . ': ' . jirafeau_get_datetimefield($ld['date']) . '
'; + echo t('DOWNLOAD_IP') . ': ' . $ld['ip'] . '
'; + } echo '
'; echo '
' . '' . @@ -875,6 +903,7 @@ function jirafeau_admin_bug_report($cfg) $out .= "# PHP options
"; $out .= "- php version: " . phpversion() . "
"; + $out .= "- sodium version: " . phpversion('sodium') . "
"; $out .= "- mcrypt version: " . phpversion('mcrypt') . "
"; $php_options = [ 'post_max_size', @@ -1116,10 +1145,12 @@ function jirafeau_async_end($ref, $code, $crypt, $link_name_length, $file_hash_m $crypted = false; $crypt_key = ''; - if ($crypt == true && extension_loaded('mcrypt') == true) { - $crypt_key = jirafeau_encrypt_file($p, $p); + if ($crypt == true && extension_loaded('sodium') == true) { + $crypt_key = jirafeau_encrypt_file($p, $p.'.crypt'); if (strlen($crypt_key) > 0) { - $crypted = true; + if (rename($p.'.crypt', $p) === true) { + $crypted = true; + } } } @@ -1154,7 +1185,7 @@ function jirafeau_async_end($ref, $code, $crypt, $link_name_length, $file_hash_m $handle, $a['file_name'] . NL . $a['mime_type'] . NL . $size . NL . $a['key'] . NL . $a['time'] . NL . $hash . NL . $a['onetime'] . NL . - time() . NL . $a['ip'] . NL . $delete_link_code . NL . ($crypted ? 'C' : 'O') + time() . NL . $a['ip'] . NL . $delete_link_code . NL . ($crypted ? 'C2' : 'O') ); fclose($handle); $hash_link = substr(base_16_to_64(md5_file($link_tmp_name)), 0, $link_name_length); @@ -1182,51 +1213,96 @@ function jirafeau_crypt_create_iv($base, $size) } /** - * Crypt file and returns decrypt key. + * Crypt file using Sodium and returns decrypt key. * @param $fp_src file path to the file to crypt. - * @param $fp_dst file path to the file to write crypted file (could be the same). - * @return decrypt key composed of the key and the iv separated by a point ('.') + * @param $fp_dst file path to the file to write crypted file (must not be the same). + * @return key used to encrypt the file */ function jirafeau_encrypt_file($fp_src, $fp_dst) { $fs = filesize($fp_src); - if ($fs === false || $fs == 0 || !(extension_loaded('mcrypt') == true)) { + if ($fs === false || $fs == 0 || extension_loaded('sodium') == false || $fp_src == $fp_dst) { return ''; } - /* Prepare module. */ - $m = mcrypt_module_open('rijndael-256', '', 'ofb', ''); /* Generate key. */ - $crypt_key = jirafeau_gen_random(10); - $hash_key = md5($crypt_key); - $iv = jirafeau_crypt_create_iv($hash_key, mcrypt_enc_get_iv_size($m)); + $crypt_key = bin2hex(random_bytes(SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES / 2)); /* Init module. */ - mcrypt_generic_init($m, $hash_key, $iv); + [$crypt_state, $crypt_header] = sodium_crypto_secretstream_xchacha20poly1305_init_push($crypt_key); /* Crypt file. */ - $r = fopen($fp_src, 'r'); - $w = fopen($fp_dst, 'c'); - while (!feof($r)) { - $enc = mcrypt_generic($m, fread($r, 1024)); + $r = fopen($fp_src, 'rb'); + $w = fopen($fp_dst, 'wb'); + fwrite($w, $crypt_header); + + for ($i = 0; $i < $fs; $i += JIRAFEAU_SODIUM_CHUNKSIZE) { + $to_enc = fread($r, JIRAFEAU_SODIUM_CHUNKSIZE); + $enc = sodium_crypto_secretstream_xchacha20poly1305_push($crypt_state, $to_enc); + if (fwrite($w, $enc) === false) { - return ''; + return ''; } } + fclose($r); fclose($w); + /* Cleanup. */ - mcrypt_generic_deinit($m); - mcrypt_module_close($m); + sodium_memzero($crypt_state); + return $crypt_key; } /** - * Decrypt file. + * Decrypt file using Sodium. + * @param $fp_src file path to the file to decrypt. + * @param $fp_dst file path to the file to write decrypted file (must not be the same). + * @param $k decryption key + * @return true if decryption succeeded, false otherwise + */ +function jirafeau_decrypt_file($fp_src, $fp_dst, $k) +{ + $fs = filesize($fp_src); + if ($fs === false || $fs == 0 || extension_loaded('sodium') == false || $fp_src == $fp_dst) { + return false; + } + + /* Decrypt file. */ + $r = fopen($fp_src, 'rb'); + $w = fopen($fp_dst, 'wb'); + + $crypt_header = fread($r, SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES); + + /* Init module. */ + $crypt_state = sodium_crypto_secretstream_xchacha20poly1305_init_pull($crypt_header, $k); + + /* Decrypt file. */ + + for ($i = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES; $i < $fs; $i += JIRAFEAU_SODIUM_CHUNKSIZE + SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES) { + $to_dec = fread($r, JIRAFEAU_SODIUM_CHUNKSIZE + SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES); + [$dec, $crypt_tag] = sodium_crypto_secretstream_xchacha20poly1305_pull($crypt_state, $to_dec); + + if (fwrite($w, $dec) === false) { + return false; + } + } + + fclose($r); + fclose($w); + + /* Cleanup. */ + sodium_memzero($crypt_state); + + return true; +} + +/** + * Decrypt file using mcrypt. * @param $fp_src file path to the file to decrypt. * @param $fp_dst file path to the file to write decrypted file (could be the same). * @param $k string composed of the key and the iv separated by a point ('.') - * @return key used to decrypt. a string of length 0 is returned if failed. + * @return true if decryption succeeded, false otherwise */ -function jirafeau_decrypt_file($fp_src, $fp_dst, $k) +function jirafeau_decrypt_file_legacy($fp_src, $fp_dst, $k) { $fs = filesize($fp_src); if ($fs === false || $fs == 0 || extension_loaded('mcrypt') == false) { @@ -1239,6 +1315,8 @@ function jirafeau_decrypt_file($fp_src, $fp_dst, $k) $crypt_key = $k; $hash_key = md5($crypt_key); $iv = jirafeau_crypt_create_iv($hash_key, mcrypt_enc_get_iv_size($m)); + /* Init module. */ + mcrypt_generic_init($m, $hash_key, $iv); /* Decrypt file. */ $r = fopen($fp_src, 'r'); $w = fopen($fp_dst, 'c'); @@ -1357,6 +1435,31 @@ function jirafeau_challenge_upload($cfg, $ip, $password) (jirafeau_challenge_upload_password($cfg, $password) && jirafeau_challenge_upload_ip($cfg, $ip)); } +/** + * Check if Jirafeau has a restriction on the IP address for accessing the admin interface. + * @return true if admin interface is IP restricted, false otherwise. + */ +function jirafeau_admin_has_ip_restriction($cfg) +{ + return count($cfg['admin_ip']) > 0; +} + +/** + * Test if visitor's IP is authorized to access the admin interface. + * + * @param $cfg configuration + * @param $challengedIp IP to be challenged + * @return true if IP is authorized, false otherwise. + */ +function jirafeau_challenge_admin_ip($cfg, $challengedIp) +{ + // If no IP address have been listed, allow upload from any IP + if (!jirafeau_admin_has_ip_restriction($cfg)) { + return true; + } + return jirafeau_challenge_ip($cfg['admin_ip'], $challengedIp); +} + /** Tell if we have some HTTP headers generated by a proxy */ function has_http_forwarded() { @@ -1476,7 +1579,7 @@ function jirafeau_admin_session_start() $_SESSION['admin_csrf'] = md5(uniqid(mt_rand(), true)); } -function jirafeau_admin_session_end() +function jirafeau_session_end() { $_SESSION = array(); session_destroy(); @@ -1496,6 +1599,17 @@ function jirafeau_admin_csrf_field() return ""; } +function jirafeau_user_session_start() +{ + $_SESSION['user_auth'] = true; +} + +function jirafeau_user_session_logged() +{ + return isset($_SESSION['user_auth']) && + $_SESSION['user_auth'] === true; +} + function jirafeau_dir_size($dir) { $size = 0; @@ -1574,5 +1688,35 @@ function jirafeau_add_ending_slash($path) function jirafeau_default_web_root() { - return $_SERVER['HTTP_HOST'] . str_replace('install.php', '', $_SERVER['REQUEST_URI']); + $url_scheme = (isset($_SERVER['HTTPS'])) ? 'https://' : 'http://'; + return $url_scheme . $_SERVER['HTTP_HOST'] . str_replace('install.php', '', $_SERVER['REQUEST_URI']); +} + +function jirafeau_get_download_stats($hash) +{ + $filename = VAR_LINKS . s2p("$hash") . $hash . '_download'; + + if (!file_exists($filename)) { + return array('count'=>0); + } + + $c = file($filename); + $data['count'] = trim($c[0]); + $data['date'] = trim($c[1]); + $data['ip'] = trim($c[2]); + + return $data; +} + +function jirafeau_write_download_stats($hash, $ip) +{ + $data = jirafeau_get_download_stats($hash); + $count = $data['count']; + $count++; + + $filename = VAR_LINKS . s2p("$hash") . $hash . '_download'; + + $handle = fopen($filename, 'w'); + fwrite($handle, $count . NL . time() . NL . $ip); + fclose($handle); } diff --git a/lib/locales/ar.json b/lib/locales/ar.json index 771da14..a048c2b 100644 --- a/lib/locales/ar.json +++ b/lib/locales/ar.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/be.json b/lib/locales/be.json index 4c7218a..7f38ca9 100644 --- a/lib/locales/be.json +++ b/lib/locales/be.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/bn_IN.json b/lib/locales/bn_IN.json index da6831a..796ceaa 100644 --- a/lib/locales/bn_IN.json +++ b/lib/locales/bn_IN.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/bo.json b/lib/locales/bo.json index 58a6845..0a94967 100644 --- a/lib/locales/bo.json +++ b/lib/locales/bo.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/ca.json b/lib/locales/ca.json index fdcaa45..9fa8499 100644 --- a/lib/locales/ca.json +++ b/lib/locales/ca.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "Una quincena", diff --git a/lib/locales/ckb.json b/lib/locales/ckb.json index 6bca483..6277346 100644 --- a/lib/locales/ckb.json +++ b/lib/locales/ckb.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/cs.json b/lib/locales/cs.json index 2803a33..8aee626 100644 --- a/lib/locales/cs.json +++ b/lib/locales/cs.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/da.json b/lib/locales/da.json index 9fa7145..a08c46f 100644 --- a/lib/locales/da.json +++ b/lib/locales/da.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/de.json b/lib/locales/de.json index 3b6d96f..24f3e0c 100644 --- a/lib/locales/de.json +++ b/lib/locales/de.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "Verschlüsselung ist in der Konfiguration aktiviert, aber das PHP-Modul \"Sodium\" ist nicht verfügbar! Verschlüsselung ist nicht verfügbar!", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "Zwei Wochen", @@ -14,7 +15,7 @@ "ADMIN_PSW": "Admin-Passwort", "ERR_OCC": "Ein Fehler ist aufgetreten.", "BASE_ADDR": "Basisadresse", - "USING_SERVICE": "Durch die Nutzung unserer Dienste, akzeptierest du unsere", + "USING_SERVICE": "Durch die Nutzung unserer Dienste akzeptierest du unsere", "CLEAN": "Aufräumen", "CLEAN_EXPIRED": "Abgelaufene Dateien löschen", "CLEAN_INCOMPLETE": "Alte unfertige Übertragungen löschen", @@ -43,7 +44,7 @@ "INSTALL_SCRIPT_HERE": "Installer-Skript noch vorhanden", "INTERNAL_ERROR_DEL": "Interner Fehler während der Dateierstellung.", "JI_PROJECT": "Jirafeau-Projekt", - "ADMIN_INTERFACE_INFO": "Jirafeau hat eine Admin-Oberfläche (durch admin.php). Für den Zugriff auf die Schnittstelle kann ein Kennwort festlegt. werden. Um die Schnittstelle zu deaktivieren, Kennwort einfach leer lassen.", + "ADMIN_INTERFACE_INFO": "Jirafeau hat eine Admin-Oberfläche (durch admin.php). Für den Zugriff auf die Schnittstelle kann ein Passwort festlegt werden. Um die Schnittstelle zu deaktivieren, Passwort einfach leer lassen.", "JI_FONCTIONAL": "Jirafeau ist nun voll funktionsfähig", "SETTING_UP": "Jirafeau richtet die Webseite entsprechend der angegebenen Konfiguration ein.", "JI_WEB_RE": "Jirafeau, dein Web-Speicher für Dateien", @@ -84,8 +85,8 @@ "NO_ADMIN_AUTH": "Leider bist du nicht auf der Admin-Oberfläche angemeldet.", "TOS": "Allgemeine Geschäftsbedingungen", "ASYNC_DIR_W": "Das Async-Verzeichnis ist nicht beschreibbar.", - "BASE_ADDR_INFO": "Die Basisadresse von Jirafeau ist der erste Teil der URL, bis (einschließlich) dem letzten Schrägstrich. Zum Beispiel: „http://www.example.com/“. Abschließenden Schrägstrich nichrt vergessen!", - "DATA_DIR_EXPLAINATION": "Das Datenverzeichnis ist, wo deine Dateien und Informationen über deine Dateien gespeichert werden. Dieses Verzeichnis sollte sich außerhalb der Webseite befinden, oder zumindest beschränkten Zugriff haben. Abschließenden Schrägstrich nichrt vergessen!", + "BASE_ADDR_INFO": "Die Basisadresse von Jirafeau ist der erste Teil der URL, bis einschließlich dem letzten Schrägstrich, zum Beispiel: „http://www.example.com/“. Abschließenden Schrägstrich nicht vergessen!", + "DATA_DIR_EXPLAINATION": "Im Datenverzeichnis werden deine Dateien und zugehörige Informationen gespeichert. Dieses Verzeichnis sollte sich außerhalb der Webseite befinden oder zumindest beschränkten Zugriff haben. Abschließenden Schrägstrich nicht vergessen!", "FILE_DIR_W": "Das Dateiverzeichnis ist nicht beschreibbar.", "CANNOT_CREATE_DIR": "Der folgende Ordner konnte nicht erstellt werden", "DIR_NOT_W": "Das folgende Verzeichnis ist nicht beschreibbar", @@ -94,14 +95,14 @@ "CONF_SOLUTION_2": "Die lokale Konfiguration ist vom Webserver nicht schreibbar. Gib dem Webserver die Schreibberechtigung für die Datei lib/config.local.php.", "FILE_EXPIRED": "Die zeitliche Begrenzung dieser Datei ist abgelaufen.", "VALID_UNTIL": "Diese Datei ist gültig bis", - "CONF_AUTOGEN_COMMENT": "Diese Datei wurde vom Installationsprozess erezugt. Du kannst sie bearbeiten. Siehe config.original.php, um die Konfigurationsparameter zu verstehen.", + "CONF_AUTOGEN_COMMENT": "Diese Datei wurde vom Installationsprozess erzeugt. Du kannst sie bearbeiten. Siehe config.original.php, um die Konfigurationsparameter zu verstehen.", "TIME_LIM": "Ablauffrist", "TYPE": "Typ", "UPLOAD_DATE": "Datum", "UP_PSW": "Passwort", "UP": "Lädt hoch …", "VIEW_LINK": "Verknüpfung zeigen", - "AUTO_DESTRUCT": "Achtung, diese Datei wird automatisch gelöscht, nachdem diese gelesen wird", + "AUTO_DESTRUCT": "Achtung: Diese Datei wird automatisch gelöscht, nachdem sie heruntergeladen oder gelesen wurde!", "BAD_PSW": "Falsches Passwort.", "GONNA_DEL": "Du löschst", "NOW_DOWNLOADING": "Du lädst herunter", diff --git a/lib/locales/el.json b/lib/locales/el.json index 1e8248a..a0da96f 100644 --- a/lib/locales/el.json +++ b/lib/locales/el.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/en.json b/lib/locales/en.json index b3de22c..092980a 100644 --- a/lib/locales/en.json +++ b/lib/locales/en.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "Encryption is enabled in configuration, but the Sodium PHP module is not loaded! Encryption is not available!", "INSTALL_FILE_NOT_FOUND_TITLE": "Installation file not found", "INSTALL_FILE_NOT_FOUND_DESC": "Installation is not complete and install.php file does not seem to exist", "REPORTING_AN_ISSUE": "Reporting an issue", @@ -109,6 +110,9 @@ "ONETIME": "One-time", "UPLOAD_DATE": "Upload date", "ORIGIN": "Origin", + "DOWNLOAD_COUNT": "Downloads", + "DOWNLOAD_DATE": "Last download", + "DOWNLOAD_IP": "Downloaded from", "ACTION": "Action", "DEL_LINK": "Del link", "DEL_FILE_LINKS": "Del file and links", diff --git a/lib/locales/es.json b/lib/locales/es.json index 6ea0619..5053041 100644 --- a/lib/locales/es.json +++ b/lib/locales/es.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "Una quincena", diff --git a/lib/locales/et.json b/lib/locales/et.json index 6bca483..6277346 100644 --- a/lib/locales/et.json +++ b/lib/locales/et.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/fi.json b/lib/locales/fi.json index 5bd1613..db7eecf 100644 --- a/lib/locales/fi.json +++ b/lib/locales/fi.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/fr.json b/lib/locales/fr.json index 5c5d766..a9162ab 100644 --- a/lib/locales/fr.json +++ b/lib/locales/fr.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "Fichier d'installation non-trouvé", "INSTALL_FILE_NOT_FOUND_DESC": "L'installation est incomplète et le ficher install.php est introuvable", "2_W": "Deux semaines", diff --git a/lib/locales/he.json b/lib/locales/he.json index 21a4464..3e40020 100644 --- a/lib/locales/he.json +++ b/lib/locales/he.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/hi.json b/lib/locales/hi.json index 1c8538f..5c19acc 100644 --- a/lib/locales/hi.json +++ b/lib/locales/hi.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/hr.json b/lib/locales/hr.json index 3a9ccb1..788ce9e 100644 --- a/lib/locales/hr.json +++ b/lib/locales/hr.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/hu.json b/lib/locales/hu.json index 129c3e5..4d3b8e0 100644 --- a/lib/locales/hu.json +++ b/lib/locales/hu.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/id.json b/lib/locales/id.json index 9551163..74fc276 100644 --- a/lib/locales/id.json +++ b/lib/locales/id.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/it.json b/lib/locales/it.json index 94a3abb..c4e53b5 100644 --- a/lib/locales/it.json +++ b/lib/locales/it.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "Due settimane", diff --git a/lib/locales/ja.json b/lib/locales/ja.json index 4d32118..ee6a2e8 100644 --- a/lib/locales/ja.json +++ b/lib/locales/ja.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/ko.json b/lib/locales/ko.json index 1c8538f..5c19acc 100644 --- a/lib/locales/ko.json +++ b/lib/locales/ko.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/la.json b/lib/locales/la.json index 846f564..45aeaaa 100644 --- a/lib/locales/la.json +++ b/lib/locales/la.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/mfe.json b/lib/locales/mfe.json index 6bca483..6277346 100644 --- a/lib/locales/mfe.json +++ b/lib/locales/mfe.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/ms.json b/lib/locales/ms.json index 066ecd8..c01c93d 100644 --- a/lib/locales/ms.json +++ b/lib/locales/ms.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/nb_NO.json b/lib/locales/nb_NO.json index cacbca1..ce80c40 100644 --- a/lib/locales/nb_NO.json +++ b/lib/locales/nb_NO.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "To uker", diff --git a/lib/locales/nl.json b/lib/locales/nl.json index 36243f9..1855d0b 100644 --- a/lib/locales/nl.json +++ b/lib/locales/nl.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "Twee weken", diff --git a/lib/locales/pl.json b/lib/locales/pl.json index eea531b..07a814a 100644 --- a/lib/locales/pl.json +++ b/lib/locales/pl.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/ps.json b/lib/locales/ps.json index 6bca483..6277346 100644 --- a/lib/locales/ps.json +++ b/lib/locales/ps.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/pt.json b/lib/locales/pt.json index 782b63e..9ec79a9 100644 --- a/lib/locales/pt.json +++ b/lib/locales/pt.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "Uma quinzena", diff --git a/lib/locales/pt_BR.json b/lib/locales/pt_BR.json index 08d4104..c902a9c 100644 --- a/lib/locales/pt_BR.json +++ b/lib/locales/pt_BR.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "Uma quinzena", diff --git a/lib/locales/ro.json b/lib/locales/ro.json index f3d9841..dbe2046 100644 --- a/lib/locales/ro.json +++ b/lib/locales/ro.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/ru.json b/lib/locales/ru.json index aba71f5..6452559 100644 --- a/lib/locales/ru.json +++ b/lib/locales/ru.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/sh.json b/lib/locales/sh.json index 6bca483..6277346 100644 --- a/lib/locales/sh.json +++ b/lib/locales/sh.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/si.json b/lib/locales/si.json index 786a8bf..54401df 100644 --- a/lib/locales/si.json +++ b/lib/locales/si.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "REPORTING_AN_ISSUE": "", "SIZE_DATA": "", "INCOMPATIBLE_OPTIONS_W": "", diff --git a/lib/locales/sk.json b/lib/locales/sk.json index bbf21ea..e40d2b9 100644 --- a/lib/locales/sk.json +++ b/lib/locales/sk.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/sl.json b/lib/locales/sl.json index aca3a2d..7f06388 100644 --- a/lib/locales/sl.json +++ b/lib/locales/sl.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/sq.json b/lib/locales/sq.json index 6bca483..6277346 100644 --- a/lib/locales/sq.json +++ b/lib/locales/sq.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/sr.json b/lib/locales/sr.json index 2149291..53f23a2 100644 --- a/lib/locales/sr.json +++ b/lib/locales/sr.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/sv.json b/lib/locales/sv.json index 134763f..0145206 100644 --- a/lib/locales/sv.json +++ b/lib/locales/sv.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "Två veckor", diff --git a/lib/locales/ta.json b/lib/locales/ta.json index 16ee6fc..d6e0c1d 100644 --- a/lib/locales/ta.json +++ b/lib/locales/ta.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/template.json b/lib/locales/template.json index 5a55190..cfaefff 100644 --- a/lib/locales/template.json +++ b/lib/locales/template.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/th.json b/lib/locales/th.json index 6bca483..6277346 100644 --- a/lib/locales/th.json +++ b/lib/locales/th.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/tr.json b/lib/locales/tr.json index 6cfe69e..239a432 100644 --- a/lib/locales/tr.json +++ b/lib/locales/tr.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "İki hafta", diff --git a/lib/locales/uk.json b/lib/locales/uk.json index a933434..6b9e17e 100644 --- a/lib/locales/uk.json +++ b/lib/locales/uk.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/vi.json b/lib/locales/vi.json index cf36cc7..bcfad0a 100644 --- a/lib/locales/vi.json +++ b/lib/locales/vi.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/zh.json b/lib/locales/zh.json index c3e89b4..cf65cc5 100644 --- a/lib/locales/zh.json +++ b/lib/locales/zh.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/locales/zh_TW.json b/lib/locales/zh_TW.json index b243155..a571dcb 100644 --- a/lib/locales/zh_TW.json +++ b/lib/locales/zh_TW.json @@ -1,4 +1,5 @@ { + "SODIUM_UNAVAILABLE": "", "INSTALL_FILE_NOT_FOUND_TITLE": "", "INSTALL_FILE_NOT_FOUND_DESC": "", "2_W": "", diff --git a/lib/settings.php b/lib/settings.php index e2173bd..e3399fd 100644 --- a/lib/settings.php +++ b/lib/settings.php @@ -75,5 +75,23 @@ define('JIRAFEAU_MONTH', 2592000); // JIRAFEAU_DAY * 30 define('JIRAFEAU_QUARTER', 7776000); // JIRAFEAU_DAY * 90 define('JIRAFEAU_YEAR', 31536000); // JIRAFEAU_DAY * 365 +define('JIRAFEAU_SODIUM_CHUNKSIZE', 1024); + +// Define some Sodium constants from newer PHP versions if they are not available + +if (extension_loaded('sodium')) { + if (!defined('SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES')) { + define('SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES', 32); + } + + if (!defined('SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES')) { + define('SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES', 24); + } + + if (!defined('SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES')) { + define('SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES', 17); + } +} + // set UTC as default timezone for all date/time functions date_default_timezone_set('UTC'); diff --git a/lib/template/header.php b/lib/template/header.php index 71b8857..8be36c7 100644 --- a/lib/template/header.php +++ b/lib/template/header.php @@ -7,6 +7,7 @@ header('x-ua-compatible: ie=edge'); <?php echo (true === empty($cfg['title']))? t('JI_WEB_RE') : $cfg['title']; ?> + diff --git a/script.php b/script.php index 0d4aeab..600b1d5 100644 --- a/script.php +++ b/script.php @@ -25,8 +25,8 @@ require(JIRAFEAU_ROOT . 'lib/settings.php'); require(JIRAFEAU_ROOT . 'lib/functions.php'); require(JIRAFEAU_ROOT . 'lib/lang.php'); - global $script_langages; - $script_langages = array('bash' => 'Bash'); +global $script_langages; +$script_langages = array('bash' => 'Bash'); /* Operations may take a long time. * Be sure PHP's safe mode is off. @@ -62,23 +62,34 @@ if (has_error()) { exit; } +session_start(); + /* Upload file */ if (isset($_FILES['file']) && is_writable(VAR_FILES) && is_writable(VAR_LINKS)) { - if (isset($_POST['upload_password'])) { - if (!jirafeau_challenge_upload($cfg, get_ip_address($cfg), $_POST['upload_password'])) { + if (!jirafeau_user_session_logged()) { + if (isset($_POST['upload_password']) && + !jirafeau_challenge_upload($cfg, get_ip_address($cfg), $_POST['upload_password'])) { echo 'Error 3: Invalid password'; exit; - } - } else { - if (!jirafeau_challenge_upload($cfg, get_ip_address($cfg), null)) { + } elseif (!jirafeau_challenge_upload($cfg, get_ip_address($cfg), null)) { echo 'Error 2: No password nor allowed IP'; exit; } } + $key = ''; if (isset($_POST['key'])) { $key = $_POST['key']; + if ($cfg['download_password_requirement'] !== 'generated' && $cfg['download_password_policy'] === 'regex'){ + if (!preg_match($cfg['download_password_policy_regex'], $key)){ + echo 'Error 14: The download password is not complying to the security standards.'; + exit; + } + } + }elseif ($cfg['download_password_requirement'] !== 'optional'){ + echo 'Error 13: The parameter password is required.'; + exit; } $time = time(); @@ -111,7 +122,7 @@ if (isset($_FILES['file']) && is_writable(VAR_FILES) case 'year': $time += JIRAFEAU_YEAR; break; - default: + default: $time = JIRAFEAU_INFINITY; break; } @@ -135,7 +146,7 @@ if (isset($_FILES['file']) && is_writable(VAR_FILES) } else { $ip = ""; } - + $res = jirafeau_upload( $_FILES['file'], isset($_POST['one_time_download']), @@ -164,6 +175,15 @@ if (isset($_FILES['file']) && is_writable(VAR_FILES) $key = ''; if (isset($_POST['key'])) { $key = $_POST['key']; + if ($cfg['download_password_requirement'] !== 'generated' && $cfg['download_password_policy'] === 'regex'){ + if (!preg_match($cfg['download_password_policy_regex'], $key)){ + echo 'Error 14: The download password is not complying to the security standards.'; + exit; + } + } + }elseif ($cfg['download_password_requirement'] !== 'optional'){ + echo 'Error 13: The parameter password is required.'; + exit; } $d = ''; if (isset($_GET['d'])) { @@ -405,7 +425,8 @@ fi } /* Initialize an asynchronous upload. */ elseif (isset($_GET['init_async'])) { - if (isset($_POST['upload_password'])) { + if (jirafeau_user_session_logged()) { + } elseif (isset($_POST['upload_password'])) { if (!jirafeau_challenge_upload($cfg, get_ip_address($cfg), $_POST['upload_password'])) { echo 'Error 20: Invalid password'; exit; @@ -430,6 +451,15 @@ elseif (isset($_GET['init_async'])) { $key = ''; if (isset($_POST['key'])) { $key = $_POST['key']; + if ($cfg['download_password_requirement'] !== 'generated' && $cfg['download_password_policy'] === 'regex'){ + if (!preg_match($cfg['download_password_policy_regex'], $key)){ + echo 'Error 14: The download password is not complying to the security standards.'; + exit; + } + } + }elseif ($cfg['download_password_requirement'] !== 'optional'){ + echo 'Error 13: The parameter password is required.'; + exit; } // Check if one time download is enabled @@ -479,7 +509,7 @@ elseif (isset($_GET['init_async'])) { } else { $ip = ""; } - + echo jirafeau_async_init( $_POST['filename'], $type,