run Form::processForm() when importing settings so the same validations apply if the import file has malicious content

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann
2023-02-07 13:02:11 +01:00
parent 802168cb5b
commit aa48ffca2b
4 changed files with 39 additions and 61 deletions

View File

@@ -89,7 +89,7 @@ final class Froxlor
* *
* @return bool true if version to check does not match, else false * @return bool true if version to check does not match, else false
*/ */
public static function hasUpdates(string $to_check): bool public static function hasUpdates(string $to_check = ''): bool
{ {
if (empty($to_check)) { if (empty($to_check)) {
$to_check = self::VERSION; $to_check = self::VERSION;
@@ -109,7 +109,7 @@ final class Froxlor
* *
* @return bool true if version to check does not match, else false * @return bool true if version to check does not match, else false
*/ */
public static function hasDbUpdates(string $to_check): bool public static function hasDbUpdates(string $to_check = ''): bool
{ {
if (empty($to_check)) { if (empty($to_check)) {
$to_check = self::DBVERSION; $to_check = self::DBVERSION;

View File

@@ -27,6 +27,7 @@ namespace Froxlor;
use Exception; use Exception;
use Froxlor\Database\Database; use Froxlor\Database\Database;
use Froxlor\UI\Form;
use PDO; use PDO;
/** /**
@@ -79,14 +80,16 @@ class SImExporter
$_data[$index] = $row['value']; $_data[$index] = $row['value'];
} }
if (array_key_exists($row['settinggroup'], $settings_definitions) && array_key_exists($row['varname'], $settings_definitions[$row['settinggroup']])) { if (array_key_exists($row['settinggroup'], $settings_definitions) && array_key_exists($row['varname'],
$settings_definitions[$row['settinggroup']])) {
// Export image file // Export image file
if ($settings_definitions[$row['settinggroup']][$row['varname']]['type'] === "image") { if ($settings_definitions[$row['settinggroup']][$row['varname']]['type'] === "image") {
if ($row['value'] === "") { if ($row['value'] === "") {
continue; continue;
} }
$_data[$index . '.image_data'] = base64_encode(file_get_contents(explode('?', $row['value'], 2)[0])); $_data[$index . '.image_data'] = base64_encode(file_get_contents(explode('?', $row['value'],
2)[0]));
} }
} }
} }
@@ -140,66 +143,35 @@ class SImExporter
$_data['system.le_froxlor_redirect'] = 0; $_data['system.le_froxlor_redirect'] = 0;
} }
} }
// store new data
foreach ($_data as $index => $value) {
$index_split = explode('.', $index, 3);
// Catch image_data and save it $form_data = [];
if (isset($index_split[2]) && $index_split[2] === 'image_data' && !empty($_data[$index_split[0] . '.' . $index_split[1]])) { // read in all current settings
$path = Froxlor::getInstallDir() . '/img/'; $current_settings = Settings::getAll();
if (!is_dir($path) && !mkdir($path, 0775)) { foreach ($current_settings as $setting_group => $setting) {
throw new Exception("img directory does not exist and cannot be created"); foreach ($setting as $varname => $value) {
// set all group/varname:values which are not in the import file
if (!isset($_data[$setting_group.'.'.$varname])) {
$_data[$setting_group.'.'.$varname] = $value;
} }
// Make sure we can write to the upload directory
if (!is_writable($path)) {
if (!chmod($path, 0775)) {
throw new Exception("Cannot write to img directory");
}
}
$img_data = base64_decode($value);
$img_filename = Froxlor::getInstallDir() . '/' . str_replace('../', '', explode('?', $_data[$index_split[0] . '.' . $index_split[1]], 2)[0]);
file_put_contents($img_filename, $img_data);
if (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $img_filename);
finfo_close($finfo);
} else {
$mimetype = mime_content_type($img_filename);
}
if (empty($mimetype)) {
$mimetype = 'application/octet-stream';
}
if (!in_array($mimetype, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
@unlink($img_filename);
throw new Exception("Uploaded file is not a valid image");
}
$spl = explode('.', $img_filename);
$file_extension = strtolower(array_pop($spl));
unset($spl);
if (!in_array($file_extension, [
'jpeg',
'jpg',
'png',
'gif'
])) {
@unlink($img_filename);
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
}
continue;
} }
Settings::Set($index, $value);
} }
// save to DB // re-format the array-key for Form::processForm
Settings::Flush(); foreach ($_data as $key => $value) {
// all good $form_data[str_replace(".", "_", $key)] = $value;
return true; }
// store new data
$settings_data = PhpHelper::loadConfigArrayDir(Froxlor::getInstallDir() . '/actions/admin/settings/');
Settings::loadSettingsInto($settings_data);
if (Form::processForm($settings_data, $form_data, [], null, true)) {
// save to DB
Settings::Flush();
// all good
return true;
} else {
throw new Exception("Importing settings failed");
}
} }
throw new Exception("Invalid JSON data: " . json_last_error_msg()); throw new Exception("Invalid JSON data: " . json_last_error_msg());
} }

View File

@@ -329,6 +329,12 @@ class Settings
} }
} }
public static function getAll() : array
{
self::init();
return self::$data;
}
/** /**
* get value from config by identifier * get value from config by identifier
*/ */

View File

@@ -203,7 +203,7 @@ class Form
return $returnvalue; return $returnvalue;
} }
public static function processForm(&$form, &$input, $url_params = [], $part = null, $settings_all = [], $settings_part = null, $only_enabledisable = false) public static function processForm(&$form, &$input, $url_params = [], $part = null, bool $settings_all = false, $settings_part = null, bool $only_enabledisable = false)
{ {
if (\Froxlor\Validate\Form::validateFormDefinition($form)) { if (\Froxlor\Validate\Form::validateFormDefinition($form)) {
$submitted_fields = []; $submitted_fields = [];