# Select docker image from https://hub.docker.com/_/php/
-image: php:7.3
+image: php:8.1
# Select what we should cache
cache:
- 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
- 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
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.
} else {
die("No command found. Should be admin.php <clean_expired|clean_async>.\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');
/* 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()) {
/* Show admin interface if not downloading a file. */
if (!(isset($_POST['action']) && strcmp($_POST['action'], 'download') == 0)) {
require(JIRAFEAU_ROOT . 'lib/template/header.php'); ?><h2><?php echo t('ADMIN_INTERFACE'); ?></h2><?php
- ?><h2>(version <?php echo JIRAFEAU_VERSION ?>)</h2><?php
+ ?><h2>(version <?php echo JIRAFEAU_VERSION ?>)</h2><?php
+
+ if ($cfg['enable_crypt'] && !(extension_loaded('sodium'))) {
+ echo '<div class="error"><p>'.t('SODIUM_UNAVAILABLE').'</p></div>';
+ }
- ?><div id = "admin">
+ ?><div id = "admin">
<fieldset><legend><?php echo t('ACTIONS'); ?></legend>
<table>
<form method="post">
}
require(JIRAFEAU_ROOT.'lib/template/footer.php');
+} else {
+ require(JIRAFEAU_ROOT . 'lib/template/header.php');
+ jirafeau_fatal_error(t('ACCESS_KO'), $cfg);
}
?>
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).
- `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.
- `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:
```
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;
}
}
-run_setup($cfg);
+run_setup($cfg);
\ No newline at end of file
server.port = 80
server.modules = (
"mod_access",
+# "mod_usertrack",
"mod_expire",
"mod_accesslog"
)
$_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 {
if ($link['onetime'] == 'O') {
jirafeau_delete_link($link_name);
}
+
+jirafeau_write_download_stats($link_name, get_ip_address($cfg));
+
exit;
?>
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');
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()) {
?>
<form method="post" class="form login">
<fieldset>
</tr>
<tr class = "nav">
<td class = "nav next">
- <input type = "submit" name = "key" value =
- "<?php echo t('LOGIN'); ?>" />
+ <input type = "submit" name = "key" value = "<?php echo t('LOGIN'); ?>" />
</td>
</tr>
</table>
</p>
</div>
- <?php if ($cfg['preview'] == true) {
+ <?php if ($cfg['download_password_requirement'] === "generated"){
?>
+ <div id="show_password">
+ <p><?php echo t('PSW') ?></p>
+
+ <div id="download_password">
+ <p>
+ <?php echo '<input id="output_key" value="' . $download_pass . '"/>'?>
+ <button id="password_copy_button">📋</button>
+ </p>
+ </div>
+ </div>
+ <?php
+ }?>
+
+ <?php if ($cfg['preview'] == true) {
+ ?>
<div id="upload_finished_preview">
<p>
<a id="preview_link" href=""><?php echo t('VIEW_LINK') ?></a>
</p>
</div>
<?php
-} ?>
+ } ?>
<div id="upload_direct_download">
<p>
</div>
<div id="upload">
-<fieldset>
+<form id="upload-form" onsubmit="
+ event.preventDefault();
+ document.getElementById('upload').style.display = 'none';
+ document.getElementById('uploading').style.display = '';
+ upload (<?php echo jirafeau_get_max_upload_chunk_size_bytes($cfg['max_upload_chunk_size_bytes']); ?>);
+ "><fieldset>
<legend>
<?php echo t('SEL_FILE'); ?>
</legend>
<p>
<input type="file" id="file_select" size="30"
onchange="control_selected_file_size(<?php echo $cfg['maximal_upload_size'] ?>, '<?php
- 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.";
- }
- ?>')"/>
+ 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.";
+ }
+?>')"/>
</p>
<div id="options">
echo '<tr><td>' . t('ONE_TIME_DL') . ':</td>';
echo '<td><input type="checkbox" id="one_time_download" /></td></tr>';
}
- ?>
- <tr>
- <td><label for="input_key"><?php echo t('PSW') . ':'; ?></label></td>
- <td><input type="password" name="key" id="input_key" autocomplete = "new-password"/></td>
- </tr>
+ if ($cfg['download_password_requirement'] === 'generated'){
+ echo '<input type="hidden" name="key" id="input_key" value="' . $download_pass .'"/>';
+ }else{
+ echo '<tr><td><label for="input_key">' . t('PSW') . ':' . '</label></td>';
+ echo '<td><input type="password" name="key" id="input_key" autocomplete = "new-password"';
+ if ($cfg['download_password_policy'] === 'regex'){
+ echo ' pattern="' . substr($cfg['download_password_policy_regex'], 1, strlen($cfg['download_password_policy_regex']) - 2) . '"'; //remove php delimiters
+ }
+ if ($cfg['download_password_requirement'] === 'required'){
+ echo ' required';
+ }
+ echo '/></td></tr>';
+ }?>
<tr>
<td><label for="select_time"><?php echo t('TIME_LIM') . ':'; ?></label></td>
<td><select name="time" id="select_time">
<?php
- $expirationTimeOptions = array(
- array(
- 'value' => 'minute',
- 'label' => '1_MIN'
- ),
- array(
- 'value' => 'hour',
- 'label' => '1_H'
- ),
- array(
- 'value' => 'day',
- 'label' => '1_D'
- ),
- array(
- 'value' => 'week',
- 'label' => '1_W'
- ),
- array(
- 'value' => 'fortnight',
- 'label' => '2_W'
- ),
- array(
- 'value' => 'month',
- 'label' => '1_M'
- ),
- array(
- 'value' => 'quarter',
- 'label' => '1_Q'
- ),
- array(
- 'value' => 'year',
- 'label' => '1_Y'
- ),
- array(
- 'value' => 'none',
- 'label' => 'NONE'
- )
- );
- foreach ($expirationTimeOptions as $expirationTimeOption) {
- $selected = ($expirationTimeOption['value'] === $cfg['availability_default'])? 'selected="selected"' : '';
- if (true === $cfg['availabilities'][$expirationTimeOption['value']]) {
- echo '<option value="' . $expirationTimeOption['value'] . '" ' .
+$expirationTimeOptions = array(
+ array(
+ 'value' => 'minute',
+ 'label' => '1_MIN'
+ ),
+ array(
+ 'value' => 'hour',
+ 'label' => '1_H'
+ ),
+ array(
+ 'value' => 'day',
+ 'label' => '1_D'
+ ),
+ array(
+ 'value' => 'week',
+ 'label' => '1_W'
+ ),
+ array(
+ 'value' => 'fortnight',
+ 'label' => '2_W'
+ ),
+ array(
+ 'value' => 'month',
+ 'label' => '1_M'
+ ),
+ array(
+ 'value' => 'quarter',
+ 'label' => '1_Q'
+ ),
+ array(
+ 'value' => 'year',
+ 'label' => '1_Y'
+ ),
+ array(
+ 'value' => 'none',
+ 'label' => 'NONE'
+ )
+);
+foreach ($expirationTimeOptions as $expirationTimeOption) {
+ $selected = ($expirationTimeOption['value'] === $cfg['availability_default'])? 'selected="selected"' : '';
+ if (true === $cfg['availabilities'][$expirationTimeOption['value']]) {
+ echo '<option value="' . $expirationTimeOption['value'] . '" ' .
$selected . '>' . t($expirationTimeOption['label']) . '</option>';
- }
- }
- ?>
+ }
+}
+?>
</select></td>
</tr>
<?php
- if ($cfg['maximal_upload_size'] >= 1024) {
- echo '<p class="config">' . t('FILE_LIM');
- echo " " . number_format($cfg['maximal_upload_size'] / 1024, 2) . " GB.</p>";
- } elseif ($cfg['maximal_upload_size'] > 0) {
- echo '<p class="config">' . t('FILE_LIM');
- echo " " . $cfg['maximal_upload_size'] . " MB.</p>";
- } else {
- echo '<p class="config"></p>';
- }
- ?>
+if ($cfg['maximal_upload_size'] >= 1024) {
+ echo '<p class="config">' . t('FILE_LIM');
+ echo " " . number_format($cfg['maximal_upload_size'] / 1024, 2) . " GB.</p>";
+} elseif ($cfg['maximal_upload_size'] > 0) {
+ echo '<p class="config">' . t('FILE_LIM');
+ echo " " . $cfg['maximal_upload_size'] . " MB.</p>";
+} else {
+ echo '<p class="config"></p>';
+}
+?>
<p id="max_file_size" class="config"></p>
<p>
- <?php
- if (jirafeau_has_upload_password($cfg) && $_SESSION['upload_auth']) {
- ?>
- <input type="hidden" id="upload_password" name="upload_password" value="<?php echo $_SESSION['user_upload_password'] ?>"/>
- <?php
- } else {
- ?>
- <input type="hidden" id="upload_password" name="upload_password" value=""/>
- <?php
- }
- ?>
- <input type="submit" id="send" value="<?php echo t('SEND'); ?>"
- onclick="
- document.getElementById('upload').style.display = 'none';
- document.getElementById('uploading').style.display = '';
- upload (<?php echo jirafeau_get_max_upload_chunk_size_bytes($cfg['max_upload_chunk_size_bytes']); ?>);
- "/>
+ <input type="submit" id="send" value="<?php echo t('SEND'); ?>"/>
</p>
</table>
- </div> </fieldset>
+ </div> </fieldset></form>
<?php
- if (jirafeau_has_upload_password($cfg)
- && false === jirafeau_challenge_upload_ip_without_password($cfg, get_ip_address($cfg))) {
+ if (jirafeau_user_session_logged()) {
?>
<form method="post" class="form logout">
<input type = "hidden" name = "action" value = "logout"/>
</form>
<?php
}
- ?>
+?>
</div>
document.getElementById('send').style.display = 'none';
if (!check_html5_file_api ())
document.getElementById('max_file_size').innerHTML = '<?php
- $max_size = jirafeau_get_max_upload_size();
- if ($max_size > 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
</script>
<?php require(JIRAFEAU_ROOT . 'lib/template/footer.php'); ?>
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;
}
}
}
switch ($current) {
-case 1:
-default:
- ?><h2><?php printf(t('JI_INSTALL') . ' - ' . t('STEP') .
- ' %d ' . t('OUT_OF') . ' %d', 1, 3);
- ?></h2> <div id = "install"> <form method="post"> <input type =
+ case 1:
+ default:
+ ?><h2><?php printf(t('JI_INSTALL') . ' - ' . t('STEP') .
+ ' %d ' . t('OUT_OF') . ' %d', 1, 3);
+ ?></h2> <div id = "install"> <form method="post"> <input type =
"hidden" name = "jirafeau" value =
"<?php echo JIRAFEAU_VERSION; ?>" /><input type = "hidden" name =
"step" value = "1" /><fieldset> <legend><?php
- echo t('ADMIN_PSW');
- ?></legend> <table> <tr> <td class = "info" colspan =
+ echo t('ADMIN_PSW');
+ ?></legend> <table> <tr> <td class = "info" colspan =
"2"><?php echo t('ADMIN_INTERFACE_INFO');
- ?></td> </tr> <tr> <td class = "label"><label for = "select_password"
+ ?></td> </tr> <tr> <td class = "label"><label for = "select_password"
><?php echo t('ADMIN_PSW') . ':';
- ?></label></td>
+ ?></label></td>
<td class = "field"><input type = "password" name = "admin_password"
id = "admin_password" size = "40" autocomplete = "new-password"/></td>
</tr>
<td class = "nav next">
<input type = "submit"
class = "navleft" name = "previous" value = "<?php
- echo t('PREV_STEP'); ?>" />
+ echo t('PREV_STEP'); ?>" />
<input type = "submit" name = "next" value =
"<?php echo t('NEXT_STEP'); ?>" /></td> </tr> </table>
</fieldset> </form> </div> <?php
break;
-case 2:
- ?><h2><?php printf(t('JI_INSTALL') . ' - ' . t('STEP') .
- ' %d ' . t('OUT_OF') . ' %d', 2, 3);
- ?></h2> <div id = "install"> <form method="post"> <input type =
+ case 2:
+ ?><h2><?php printf(t('JI_INSTALL') . ' - ' . t('STEP') .
+ ' %d ' . t('OUT_OF') . ' %d', 2, 3);
+ ?></h2> <div id = "install"> <form method="post"> <input type =
"hidden" name = "jirafeau" value =
"<?php echo JIRAFEAU_VERSION; ?>" /><input type = "hidden" name =
"step" value =
"2" /><fieldset> <legend><?php echo t('INFO');
- ?></legend> <table> <tr> <td class = "info" colspan =
+ ?></legend> <table> <tr> <td class = "info" colspan =
"2"><?php echo t('BASE_ADDR_INFO');
- ?></td> </tr> <tr> <td class = "label"><label for = "input_web_root"
+ ?></td> </tr> <tr> <td class = "label"><label for = "input_web_root"
><?php echo t('BASE_ADDR') . ':';
- ?></label></td>
+ ?></label></td>
<td class = "field"><input type = "text" name = "web_root"
id = "input_web_root" value = "<?php
- echo(empty($cfg['web_root']) ? jirafeau_default_web_root() : $cfg['web_root']);
- ?>" size = "40" /></td>
+ echo(empty($cfg['web_root']) ? jirafeau_default_web_root() : $cfg['web_root']);
+ ?>" size = "40" /></td>
</tr> <tr> <td class = "info" colspan = "2"><?php
- echo t('DATA_DIR_EXPLAINATION');
- ?></td> </tr> <tr> <td class = "label"><label for = "input_var_root"
+ echo t('DATA_DIR_EXPLAINATION');
+ ?></td> </tr> <tr> <td class = "label"><label for = "input_var_root"
><?php echo t('DATA_DIR') . ':';
- ?></label></td>
+ ?></label></td>
<td class = "field"><input type = "text" name = "var_root"
id = "input_var_root" value = "<?php
- if (empty($cfg['var_root'])) {
- $alphanum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' .
+ if (empty($cfg['var_root'])) {
+ $alphanum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' .
'abcdefghijklmnopqrstuvwxyz' . '0123456789';
- $len_alphanum = strlen($alphanum);
- $var = 'var-';
- for ($i = 0; $i <JIRAFEAU_VAR_RAND_LENGTH; $i++) {
- $var .= substr($alphanum, mt_rand(0, $len_alphanum - 1), 1);
+ $len_alphanum = strlen($alphanum);
+ $var = 'var-';
+ for ($i = 0; $i <JIRAFEAU_VAR_RAND_LENGTH; $i++) {
+ $var .= substr($alphanum, mt_rand(0, $len_alphanum - 1), 1);
+ }
+ echo JIRAFEAU_ROOT . $var . '/';
+ } else {
+ echo $cfg['var_root'];
}
- echo JIRAFEAU_ROOT . $var . '/';
- } else {
- echo $cfg['var_root'];
- }
- ?>" size = "40" /></td>
+ ?>" size = "40" /></td>
</tr> <tr> <td colspan = "2"><input type = "submit"
class = "navleft" name = "previous" value = "<?php
- echo t('PREV_STEP'); ?>" />
+ echo t('PREV_STEP'); ?>" />
<input type = "submit" class = "navright" name = "next" value =
"<?php echo t('NEXT_STEP'); ?>" />
</td> </tr> </table> </fieldset>
</form> </div> <?php
break;
-case 3:
- ?><h2><?php printf(t('JI_INSTALL') . ' - ' . t('STEP') .
- ' %d ' . t('OUT_OF') . ' %d', 3, 3);
- ?></h2> <div id = "install"> <form method="post"> <input type =
+ case 3:
+ ?><h2><?php printf(t('JI_INSTALL') . ' - ' . t('STEP') .
+ ' %d ' . t('OUT_OF') . ' %d', 3, 3);
+ ?></h2> <div id = "install"> <form method="post"> <input type =
"hidden" name = "jirafeau" value =
"<?php echo JIRAFEAU_VERSION; ?>" /><input type = "hidden" name =
"step" value =
"3" /><fieldset> <legend><?php echo t('FINALIZATION');
- ?></legend> <table> <tr> <td class = "info" colspan =
+ ?></legend> <table> <tr> <td class = "info" colspan =
"2"><?php echo t('SETTING_UP');
- ?></td> </tr> <tr> <td class = "nav previous"><input type =
+ ?></td> </tr> <tr> <td class = "nav previous"><input type =
"submit" name = "previous" value = " <?php echo t('PREV_STEP');
- ?>" /></td> <td></td> </tr>
+ ?>" /></td> <td></td> </tr>
</table> </fieldset> </form> </div>
<?php
- $err = jirafeau_check_var_dir($cfg['var_root']);
- if ($err['has_error']) {
- echo '<div class="error"><p>'.$err['why'].'<br />'.NL; ?><form method="post"> <input type = "hidden" name = "jirafeau" value =
+ $err = jirafeau_check_var_dir($cfg['var_root']);
+ if ($err['has_error']) {
+ echo '<div class="error"><p>'.$err['why'].'<br />'.NL; ?><form method="post"> <input type = "hidden" name = "jirafeau" value =
"<?php echo JIRAFEAU_VERSION; ?>" /><input type = "hidden" name =
"step" value = "3" /><input type = "submit" name =
"retry" value =
"<?php echo t('RETRY_STEP'); ?>" /></form>
<?php echo '</p></div>';
- } else {
- $cfg['installation_done'] = true;
- jirafeau_export_cfg($cfg);
- echo '<div class="message"><p>' .
- t('JI_FONCTIONAL') . ':' .
- '<br /><a href="./">' .
- $cfg['web_root'].'</a></p></div>';
- }
-break;
+ } else {
+ $cfg['installation_done'] = true;
+ jirafeau_export_cfg($cfg);
+ echo '<div class="message"><p>' .
+ t('JI_FONCTIONAL') . ':' .
+ '<br /><a href="./">' .
+ $cfg['web_root'].'</a></p></div>';
+ }
+ break;
}
require(JIRAFEAU_ROOT . 'lib/template/footer.php');
*/
$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
* 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'] = '/.*/';
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 = "<?php echo $cfg['web_root']; ?>";
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);
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);
}
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;
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);
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
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
);
}
}
}
}
+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 = "<?php echo 'media/' . $cfg['dark_style'] . '/style.css.php'; ?>";
let shortcut_icon = "<?php echo 'media/' . $cfg['dark_style'] . '/favicon.ico'; ?>";
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 = "<?php echo 'media/' . $cfg['style'] . '/style.css.php'; ?>";
let shortcut_icon = "<?php echo 'media/' . $cfg['style'] . '/favicon.ico'; ?>";
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 = "<?php echo 'media/' . $cfg['dark_style'] . '/style.css.php'; ?>"
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
set_dark_mode();
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'])) {
// Convert UTC timestamp to a datetime field
function jirafeau_get_datetimefield($timestamp)
{
- $content = '<span class="datetime" data-datetime="' . strftime('%Y-%m-%d %H:%M', $timestamp) . '">'
- . strftime('%Y-%m-%d %H:%M', $timestamp) . ' (GMT)</span>';
+
+ $ts = date_create("@" . $timestamp);
+ $content = '<span class="datetime" data-datetime="' . date_format($ts, 'Y-m-d H:i') . '">'
+ . date_format($ts, 'Y-m-d H:i') . ' (GMT)</span>';
+
return $content;
}
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)
$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;
}
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. ');
}
/* 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;
+ }
}
}
$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);
$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;
}
if (!count($l)) {
continue;
}
+ $ld = jirafeau_get_download_stats($node);
/* Filter. */
if (!empty($name) && !@preg_match("/$name/i", jirafeau_escape($l['file_name']))) {
if (strlen($l['ip']) > 0) {
echo t('ORIGIN') . ': ' . $l['ip'] . '<br/>';
}
+ echo t('DOWNLOAD_COUNT') . ': ' . $ld['count'] . '<br/>';
+ if ($ld['count'] > 0) {
+ echo t('DOWNLOAD_DATE') . ': ' . jirafeau_get_datetimefield($ld['date']) . '<br/>';
+ echo t('DOWNLOAD_IP') . ': ' . $ld['ip'] . '<br/>';
+ }
echo '</td><td>';
echo '<form method="post">' .
'<input type = "hidden" name = "action" value = "download"/>' .
$out .= "# PHP options<br/>";
$out .= "- php version: " . phpversion() . "<br/>";
+ $out .= "- sodium version: " . phpversion('sodium') . "<br/>";
$out .= "- mcrypt version: " . phpversion('mcrypt') . "<br/>";
$php_options = [
'post_max_size',
$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;
+ }
}
}
$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);
}
/**
- * 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) {
$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');
(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()
{
$_SESSION['admin_csrf'] = md5(uniqid(mt_rand(), true));
}
-function jirafeau_admin_session_end()
+function jirafeau_session_end()
{
$_SESSION = array();
session_destroy();
return "<input type='hidden' name='admin_csrf' value='". $_SESSION['admin_csrf'] . "'/>";
}
+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;
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);
}
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "Una quincena",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "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",
"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",
"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",
"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",
"CONF_SOLUTION_2": "Die lokale Konfiguration ist vom Webserver nicht schreibbar. Gib dem Webserver die Schreibberechtigung für die Datei <code>lib/config.local.php</code>.",
"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",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "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",
"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",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "Una quincena",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "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",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "Due settimane",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "To uker",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "Twee weken",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "Uma quinzena",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "Uma quinzena",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"REPORTING_AN_ISSUE": "",
"SIZE_DATA": "",
"INCOMPATIBLE_OPTIONS_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "Två veckor",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "İki hafta",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
{
+ "SODIUM_UNAVAILABLE": "",
"INSTALL_FILE_NOT_FOUND_TITLE": "",
"INSTALL_FILE_NOT_FOUND_DESC": "",
"2_W": "",
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');
<head>
<meta charset="utf-8">
<title><?php echo (true === empty($cfg['title']))? t('JI_WEB_RE') : $cfg['title']; ?></title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
<link id="shortcut_icon" rel="shortcut icon" href="<?php echo 'media/' . $cfg['style'] . '/favicon.ico'; ?>">
<link id="stylesheet" rel="stylesheet" href="<?php echo 'media/' . $cfg['style'] . '/style.css.php'; ?>" type="text/css" />
</head>
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.
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();
case 'year':
$time += JIRAFEAU_YEAR;
break;
- default:
+ default:
$time = JIRAFEAU_INFINITY;
break;
}
} else {
$ip = "";
}
-
+
$res = jirafeau_upload(
$_FILES['file'],
isset($_POST['one_time_download']),
$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'])) {
}
/* 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;
$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
} else {
$ip = "";
}
-
+
echo jirafeau_async_init(
$_POST['filename'],
$type,