X-Git-Url: https://git.p6c8.net/jirafeau.git/blobdiff_plain/b1c96930b34b47dd1c8f6321d62beeceb87afb00..463c260d3cf16d2fa2fbcba04bac446165d1a618:/lib/functions.php?ds=inline diff --git a/lib/functions.php b/lib/functions.php index fff8c44..f70e0de 100644 --- a/lib/functions.php +++ b/lib/functions.php @@ -3,7 +3,7 @@ * Jirafeau, your web file repository * Copyright (C) 2008 Julien "axolotl" BERNARD * Copyright (C) 2015 Jerome Jutteau - * Copyright (C) 2015 Nicola Spanti (RyDroid) + * Copyright (C) 2024 Jirafeau project (see AUTHORS.md) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -143,7 +143,6 @@ function jirafeau_human_size($octets) // Convert UTC timestamp to a datetime field function jirafeau_get_datetimefield($timestamp) { - $ts = date_create("@" . $timestamp); $content = '' . date_format($ts, 'Y-m-d H:i') . ' (GMT)'; @@ -447,25 +446,62 @@ function jirafeau_upload($file, $one_time_download, $key, $time, $ip, $crypt, $l 'link' => '', 'delete_link' => '')); } + jirafeau_add_file($file, $one_time_download, $key, $time, $ip, $crypt, $link_name_length, $file_hash_method); +} - /* array representing no error */ - $noerr = array('has_error' => false, 'why' => ''); - +/** + * + * @param bool $crypt_module_enabled + * @param string $file_path + * @return array [bool, string] + */ +function jirafeau_handle_add_file_encryption($crypt_module_enabled, $file_path) { /* Crypt file if option is enabled. */ $crypted = false; $crypt_key = ''; - if ($crypt == true && !(extension_loaded('sodium') == true)) { + if ($crypt_module_enabled == true && !(extension_loaded('sodium') == true)) { error_log("PHP extension sodium not loaded, won't encrypt in Jirafeau"); } - if ($crypt == true && extension_loaded('sodium') == true) { - $crypt_key = jirafeau_encrypt_file($file['tmp_name'], $file['tmp_name'].'crypt'); + if ($crypt_module_enabled == true && extension_loaded('sodium') == true) { + $crypt_key = jirafeau_encrypt_file($file_path, $file_path.'crypt'); if (strlen($crypt_key) > 0) { - if (rename($file['tmp_name'].'crypt', $file['tmp_name']) === true) { + if (rename($file_path.'crypt', $file_path) === true) { $crypted = true; } } } + return [$crypted, $crypt_key]; +} + +/** + * adds an uploaded or copy/linked local file + * @param $file the file struct given by $_FILE[] + * @param $one_time_download is the file a one time download ? + * @param $key if not empty, protect the file with this key + * @param $time the time of validity of the file + * @param $ip uploader's ip + * @param $crypt boolean asking to crypt or not + * @param $link_name_length size of the link name + * @param $is_upload, determines if the file is uploaded or local - it controls which file-functions are used + * @return array an array containing some information + * 'error' => information on possible errors + * 'link' => the link name of the uploaded file + * 'delete_link' => the link code to delete file + */ +function jirafeau_add_file($file, $one_time_download, $key, $time, $ip, $crypt, $link_name_length, $file_hash_method, $is_upload = true) +{ + // TODO needs to be adapted + $move_operation = $is_upload ? 'move_uploaded_file' : 'symlink'; + + /* array representing no error */ + $noerr = array('has_error' => false, 'why' => ''); + + $crypted = false; + $crypt_key = ''; + list($crypted, $crypt_key) = jirafeau_handle_add_file_encryption($crypt, $file['tmp_name']); + + /* file information */ $hash = jirafeau_hash_file($file_hash_method, $file['tmp_name']); $name = str_replace(NL, '', trim($file['name'])); @@ -478,7 +514,11 @@ function jirafeau_upload($file, $one_time_download, $key, $time, $ip, $crypt, $l if (file_exists(VAR_FILES . $p . $hash)) { $rc = unlink($file['tmp_name']); } elseif ((file_exists(VAR_FILES . $p) || @mkdir(VAR_FILES . $p, 0755, true)) - && move_uploaded_file($file['tmp_name'], VAR_FILES . $p . $hash)) { + && + //move_uploaded_file($file['tmp_name'], VAR_FILES . $p . $hash)) + $move_operation($file['tmp_name'], VAR_FILES . $p . $hash)) + { + $rc = true; } if (!$rc) { @@ -517,7 +557,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 ? 'C2' : 'O') + NL . $ip . NL. $delete_link_code . NL . ($crypted ? 'C' : 'O') ); fclose($handle); $hash_link = substr(base_16_to_64(md5_file($link_tmp_name)), 0, $link_name_length); @@ -549,6 +589,37 @@ function jirafeau_upload($file, $one_time_download, $key, $time, $ip, $crypt, $l 'crypt_key' => $crypt_key); } + +function jirafeau_admin_list_table ($name, $file_hash, $link_hash, $visitor_function = null) { + echo '
'; + if (!empty($name)) { + echo t('FILENAME') . ": " . jirafeau_escape($name); + } + if (!empty($file_hash)) { + echo t('FILE') . ": " . jirafeau_escape($file_hash); + } + if (!empty($link_hash)) { + echo t('LINK') . ": " . jirafeau_escape($link_hash); + } + if (empty($name) && empty($file_hash) && empty($link_hash)) { + echo t('LS_FILES'); + } + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + if ($visitor_function != null) { + $visitor_function($name, $file_hash, $link_hash); + } + echo '
' . t('ACTION') . '
'; +} + + + + + /** * Tells if a mime-type is viewable in a browser * @param $mime the mime type @@ -677,99 +748,89 @@ function jirafeau_get_link($hash) */ function jirafeau_admin_list($name, $file_hash, $link_hash) { - echo '
'; - if (!empty($name)) { - echo t('FILENAME') . ": " . jirafeau_escape($name); - } - if (!empty($file_hash)) { - echo t('FILE') . ": " . jirafeau_escape($file_hash); - } - if (!empty($link_hash)) { - echo t('LINK') . ": " . jirafeau_escape($link_hash); - } - if (empty($name) && empty($file_hash) && empty($link_hash)) { - echo t('LS_FILES'); - } - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - /* Get all links files. */ - $stack = array(VAR_LINKS); - while (($d = array_shift($stack)) && $d != null) { - $dir = scandir($d); - foreach ($dir as $node) { - if (strcmp($node, '.') == 0 || strcmp($node, '..') == 0 || - preg_match('/\.tmp/i', "$node")) { - continue; - } - if (is_dir($d . $node)) { - /* Push new found directory. */ - $stack[] = $d . $node . '/'; - } elseif (is_file($d . $node)) { - /* Read link information. */ - $l = jirafeau_get_link($node); - if (!count($l)) { + $function = function($name, $file_hash, $link_hash) { + /* Get all links files. */ + $stack = array(VAR_LINKS); + while (($d = array_shift($stack)) && $d != null) { + $dir = scandir($d); + foreach ($dir as $node) { + if (strcmp($node, '.') == 0 || strcmp($node, '..') == 0 || + preg_match('/\.tmp/i', "$node")) { continue; } - $ld = jirafeau_get_download_stats($node); - - /* Filter. */ - if (!empty($name) && !@preg_match("/$name/i", jirafeau_escape($l['file_name']))) { - continue; + if (is_dir($d . $node)) { + /* Push new found directory. */ + $stack[] = $d . $node . '/'; + } elseif (is_file($d . $node)) { + /* Read link information. */ + $l = jirafeau_get_link($node); + if (!count($l)) { + continue; + } + + /* Filter. */ + if (!empty($name) && !@preg_match("/$name/i", jirafeau_escape($l['file_name']))) { + continue; + } + if (!empty($file_hash) && $file_hash != $l['hash']) { + continue; + } + if (!empty($link_hash) && $link_hash != $node) { + continue; + } + /* Print link information. */ + echo ''; + echo ''; + echo ''; } - if (!empty($file_hash) && $file_hash != $l['hash']) { - continue; - } - if (!empty($link_hash) && $link_hash != $node) { - continue; - } - /* Print link information. */ - echo ''; - echo ''; - echo ''; } } - } - echo '
' . t('ACTION') . '
'; + + if (!$l['crypted'] && !$l['crypted_legacy']) { + echo'' . jirafeau_escape($l['file_name']) . ''; + } + else { + echo jirafeau_escape($l['file_name']); + } + + echo '
'; + + echo t('TYPE') . ': ' . jirafeau_escape($l['mime_type']) . '
'; + echo t('SIZE') . ': ' . jirafeau_human_size($l['file_size']) . '
'; + echo t('EXPIRE') . ': ' . ($l['time'] == -1 ? '∞' : jirafeau_get_datetimefield($l['time'])) . '
'; + echo t('ONETIME') . ': ' . ($l['onetime'] == 'O' ? t('YES') : t('NO')) . '
'; + echo t('ENCRYPTED') . ': ' . (($l['crypted'] || $l['crypted_legacy']) ? t('YES') : t('NO')) . '
'; + echo t('UPLOAD_DATE') . ': ' . jirafeau_get_datetimefield($l['upload_date']) . '
'; + if (strlen($l['ip']) > 0) { + echo t('ORIGIN') . ': ' . $l['ip'] . '
'; + } + echo '
'; + + if (!$l['crypted'] && !$l['crypted_legacy']) { + echo '
' . + '' . + '' . + jirafeau_admin_csrf_field() . + '' . + '
'; + } + + echo '
' . + '' . + '' . + jirafeau_admin_csrf_field() . + '' . + '
' . + '
' . + '' . + '' . + jirafeau_admin_csrf_field() . + '' . + '
' . + '
' . - '' . jirafeau_escape($l['file_name']) . '
'; - echo t('TYPE') . ': ' . jirafeau_escape($l['mime_type']) . '
'; - echo t('SIZE') . ': ' . jirafeau_human_size($l['file_size']) . '
'; - echo t('EXPIRE') . ': ' . ($l['time'] == -1 ? '∞' : jirafeau_get_datetimefield($l['time'])) . '
'; - echo t('ONETIME') . ': ' . ($l['onetime'] == 'O' ? 'Yes' : 'No') . '
'; - echo t('UPLOAD_DATE') . ': ' . jirafeau_get_datetimefield($l['upload_date']) . '
'; - 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 '
' . - '' . - '' . - jirafeau_admin_csrf_field() . - '' . - '
' . - '
' . - '' . - '' . - jirafeau_admin_csrf_field() . - '' . - '
' . - '
' . - '' . - '' . - jirafeau_admin_csrf_field() . - '' . - '
' . - '
'; + }; + jirafeau_admin_list_table($name, $file_hash, $link_hash, $function); } /** @@ -879,7 +940,7 @@ function jirafeau_fileperms($path) function jirafeau_admin_bug_report($cfg) { $out = "
" . t('REPORTING_AN_ISSUE') . ""; - $out .= "If you have a problem related to Jirafeau, please open an issue, explain your problem in english and copy-paste the following content:

"; + $out .= "If you have a problem related to Jirafeau, please open an issue, explain your problem in english and copy-paste the following content:

"; $out .= "# Jirafeau
"; $out .= "- version: " . JIRAFEAU_VERSION . "
"; @@ -1010,8 +1071,8 @@ function jirafeau_async_delete($ref) function jirafeau_async_init($filename, $type, $one_time, $key, $time, $ip) { /* Create temporary folder. */ - $ref; - $p; + $ref = ''; + $p = ''; $code = jirafeau_gen_random(4); do { $ref = jirafeau_gen_random(32); @@ -1216,7 +1277,7 @@ function jirafeau_crypt_create_iv($base, $size) * 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 (must not be the same). - * @return decrypt key composed of the key and the iv separated by a point ('.') + * @return key used to encrypt the file */ function jirafeau_encrypt_file($fp_src, $fp_dst) { @@ -1239,7 +1300,7 @@ function jirafeau_encrypt_file($fp_src, $fp_dst) $enc = sodium_crypto_secretstream_xchacha20poly1305_push($crypt_state, $to_enc); if (fwrite($w, $enc) === false) { - return ''; + return ''; } } @@ -1256,8 +1317,8 @@ function jirafeau_encrypt_file($fp_src, $fp_dst) * 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 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. + * @param $k decryption key + * @return true if decryption succeeded, false otherwise */ function jirafeau_decrypt_file($fp_src, $fp_dst, $k) { @@ -1267,22 +1328,27 @@ function jirafeau_decrypt_file($fp_src, $fp_dst, $k) } /* Decrypt file. */ - $r = fopen(VAR_FILES . $p . $link['hash'], 'rb'); + $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, $crypt_key); + $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); - echo $dec; + + if (fwrite($w, $dec) === false) { + return false; + } } fclose($r); + fclose($w); /* Cleanup. */ sodium_memzero($crypt_state); @@ -1295,7 +1361,7 @@ function jirafeau_decrypt_file($fp_src, $fp_dst, $k) * @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_legacy($fp_src, $fp_dst, $k) { @@ -1310,6 +1376,8 @@ function jirafeau_decrypt_file_legacy($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'); @@ -1713,3 +1781,229 @@ function jirafeau_write_download_stats($hash, $ip) fwrite($handle, $count . NL . time() . NL . $ip); fclose($handle); } + +function jirafeau_create_upload_finished_box($preview = true) { + ?> + +
+

+ +
+

+ + +

+ + +

+
+ + +
+

+ +

+ + +

+
+ + +
+

+ +

+ + +

+
+ +
+

+ +

+ + +

+
+ +
+

:

+

+
+
+ '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' + ) + ); +} + + + + /** + * + * creates the time selection field + * @param mixed $cfg + * @return void + */ + function jirafeau_create_selection_array($cfg) { + echo + ''; + } + + function jirafeau_datestr_to_int ($time_str) { + $time = time(); + switch ($time_str) { + case 'minute': + $time += JIRAFEAU_MINUTE; + break; + case 'hour': + $time += JIRAFEAU_HOUR; + break; + case 'day': + $time += JIRAFEAU_DAY; + break; + case 'week': + $time += JIRAFEAU_WEEK; + break; + case 'fortnight': + $time += JIRAFEAU_FORTNIGHT; + break; + case 'month': + $time += JIRAFEAU_MONTH; + break; + case 'quarter': + $time += JIRAFEAU_QUARTER; + break; + case 'year': + $time += JIRAFEAU_YEAR; + break; + default: + $time = JIRAFEAU_INFINITY; + break; + } + return $time; +} + + + + +/** + * links or copy a local file + * TODO: boolean in config for linking + * @param string $filepath + * @param $one_time_download is the file a one time download ? + * @param $key if not empty, protect the file with this key + * @param $time the time of validity of the file + * @param $ip uploader's ip + * @param $crypt boolean asking to crypt or not + * @param $link_name_length size of the link name + * @returns an array containing some information + * 'error' => information on possible errors + * 'link' => the link name of the uploaded file + * 'delete_link' => the link code to delete file + */ +function jirafeau_copy_local_file($local_file_path, $one_time_download, $key, $time, $ip, $crypt, $link_name_length, $file_hash_method) { + + if (!file_exists($local_file_path)) { + return (array( + 'error' => + array('has_error' => true, + 'why' => t('INTERNAL_ERROR_FILE_NOT_EXIST')), + 'link' =>'', + 'delete_link' => '')); + } + if( + // sanity check if file can be opened + $file = fopen($local_file_path, "r") + ) + { + // close file pointer - it's not needed here + fclose($file); + $time_in_int = jirafeau_datestr_to_int($time); + return jirafeau_add_file( + jirafeau_create_file_array($local_file_path), + $one_time_download, + $key, + $time_in_int, + $ip, + $crypt, + $link_name_length, + $file_hash_method, + false + ); + } + else { + return (array( + 'error' => + array('has_error' => true, + 'why' => t('INTERNAL_ERROR_FP_OPEN_LOCAL')), + 'link' =>'', + 'delete_link' => '')); + } + +} + + +function jirafeau_create_file_array($file_path) { + return + [ + 'type' => mime_content_type($file_path), + 'tmp_name' => $file_path, + 'name' => basename($file_path), + 'size' => filesize($file_path), + ]; +}