From 14a52539c98ec04ff35f3876f5f0ff1ff715ab7b Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 10:04:48 +0100 Subject: [PATCH 01/11] feat[installer]: added error logging to data validation --- install/includes/core/core_class.php | 48 ++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/install/includes/core/core_class.php b/install/includes/core/core_class.php index a62ecce27..c04219c10 100644 --- a/install/includes/core/core_class.php +++ b/install/includes/core/core_class.php @@ -8,22 +8,34 @@ class Core { // Counter variable $counter = 0; + $errors = []; // Validate the hostname if (isset($data['db_hostname']) and !empty($data['db_hostname'])) { $counter++; + } else { + $errors[] = "DB Hostname is missing."; } + // Validate the username if (isset($data['db_username']) and !empty($data['db_username'])) { $counter++; + } else { + $errors[] = "DB Username is missing."; } + // Validate the password if (isset($data['db_password']) and !empty($data['db_password'])) { - // pass + $counter++; + } else { + $errors[] = "DB Password is missing."; } + // Validate the database if (isset($data['db_name']) and !empty($data['db_name'])) { $counter++; + } else { + $errors[] = "DB Name is missing."; } if ($data['directory'] ?? '' != "") { @@ -31,36 +43,46 @@ class Core //pass folders real $counter++; } else { - echo "Directory " . $data['directory'] . " cannot be found"; - exit; + $errors[] = "Directory " . $data['directory'] . " does not exist."; } } else { + // directory is not set so nothing to check here $counter++; } // Validate First Name if (isset($data['firstname']) && !empty($data['firstname'])) { $counter++; + } else { + $errors[] = "First Name is missing."; } // Validate Last Name if (isset($data['lastname']) && !empty($data['lastname'])) { $counter++; + } else { + $errors[] = "Last Name is missing."; } // Validate Username if (isset($data['username']) && !empty($data['username'])) { $counter++; + } else { + $errors[] = "Username is missing."; } // Validate Callsign if (isset($data['callsign']) && !empty($data['callsign'])) { $counter++; + } else { + $errors[] = "Callsign is missing."; } // Validate Password if (isset($data['password']) && !empty($data['password'])) { $counter++; + } else { + $errors[] = "User Password is missing."; } // Validate Locator @@ -72,12 +94,14 @@ class Core $errors[] = "Invalid Maidenhead Locator format."; } } else { - $errors[] = "Locator is required."; + $errors[] = "Locator is missing."; } // Validate Confirm Password if (isset($data['cnfm_password']) && !empty($data['cnfm_password'])) { $counter++; + } else { + $errors[] = "Confirm Password is missing."; } // Validate Email Address @@ -90,18 +114,24 @@ class Core // Validate Timezone if (isset($data['timezone']) && is_numeric($data['timezone'])) { $counter++; + } else { + $errors[] = "Invalid Timezone."; } // Check if all the required fields have been entered - if ($counter == '13') { + if ($counter == '14') { + log_message('info', 'Data validation passed.'); return true; } else { - log_message('error', 'Failed to validate POST data'); + log_message('error', 'Data validation failed.'); + foreach ($errors as $error) { + log_message('error', $error); + } return false; } } - // Function to write the config file + // Function to write the database config file function write_config($data) { $template_path = 'config/database.php'; @@ -114,8 +144,8 @@ class Core $database_file = file_get_contents($template_path); // Sanitize DB Password from single quotes - $sanitized_db_pwd = preg_replace("/\\\\/i",'\\\\\\\\',$data['db_password']); // Escape the Escape char ( '\' becomes '\\' ) - $sanitized_db_pwd = preg_replace("/\'/i",'\\\\\'',$sanitized_db_pwd); // Escape the ' ( ' becomes \' ) + $sanitized_db_pwd = preg_replace("/\\\\/i",'\\\\\\\\',$data['db_password']); // Escape the Escape char ( '\' becomes '\\' ) + $sanitized_db_pwd = preg_replace("/\'/i",'\\\\\'',$sanitized_db_pwd); // Escape the ' ( ' becomes \' ) $new = str_replace("%HOSTNAME%", $data['db_hostname'], $database_file); $new = str_replace("%USERNAME%", $data['db_username'], $new); From 79c9559f4fd331a13de2ecc6a2312664e08b15b9 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 10:05:53 +0100 Subject: [PATCH 02/11] fix[installer]: remove potential security issue with chmod --- install/includes/core/core_class.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/install/includes/core/core_class.php b/install/includes/core/core_class.php index c04219c10..7a0c61446 100644 --- a/install/includes/core/core_class.php +++ b/install/includes/core/core_class.php @@ -155,9 +155,6 @@ class Core // Write the new database.php file $handle = fopen($output_path, 'w+'); - // Chmod the file, in case the user forgot - @chmod($output_path, 0777); - // Verify file permissions if (is_writable($output_path)) { From 6e7f852c268c92a07033599f378622630766e4d7 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 10:15:14 +0100 Subject: [PATCH 03/11] feat[installer]: enhance database configuration process with detailed logging --- install/includes/core/core_class.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/install/includes/core/core_class.php b/install/includes/core/core_class.php index 7a0c61446..917805c47 100644 --- a/install/includes/core/core_class.php +++ b/install/includes/core/core_class.php @@ -138,10 +138,23 @@ class Core $output_path = $_SERVER['DOCUMENT_ROOT'] . '/' . $data['directory'] . '/application/config/database.php'; if (isset($_ENV['CI_ENV'])) { $output_path = $_SERVER['DOCUMENT_ROOT'] . '/' . $data['directory'] . '/application/config/'.$_ENV['CI_ENV'].'/database.php'; + log_message('info', 'CI_ENV is set to ' . $_ENV['CI_ENV'] . '. Using ' . $_ENV['CI_ENV'] . ' database.php config path.'); + } else { + log_message('info', 'CI_ENV is not set. Using default database.php config path.'); + } + + if (!file_exists($template_path)) { + log_message('error', 'database.php template file not found.'); + return false; } // Open the file $database_file = file_get_contents($template_path); + if ($database_file === false) { + log_message('error', 'Failed to read database.php template file.'); + return false; + } + log_message('info', 'database.php template file read successfully.'); // Sanitize DB Password from single quotes $sanitized_db_pwd = preg_replace("/\\\\/i",'\\\\\\\\',$data['db_password']); // Escape the Escape char ( '\' becomes '\\' ) @@ -151,24 +164,31 @@ class Core $new = str_replace("%USERNAME%", $data['db_username'], $new); $new = str_replace("%PASSWORD%", $sanitized_db_pwd, $new); $new = str_replace("%DATABASE%", $data['db_name'], $new); + log_message('info', 'Database config file created successfully.'); // Write the new database.php file $handle = fopen($output_path, 'w+'); + if ($handle === false) { + log_message('error', 'Failed to open newly created database.php file for writing check.'); + return false; + } // Verify file permissions if (is_writable($output_path)) { - // Write the file if (fwrite($handle, $new)) { if(file_exists($output_path)) { + log_message('info', 'database.php file written successfully.'); return true; } else { + log_message('error', 'database.php file not found after writing.'); return false; } } else { return false; } } else { + log_message('error', 'database.php file is not writable.'); return false; } } From e904a0d8dff33dbebdc33f6b5bf83080e5b0c203 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 10:22:22 +0100 Subject: [PATCH 04/11] feat[installer]: improve logging messages for config file operations --- install/includes/core/core_class.php | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/install/includes/core/core_class.php b/install/includes/core/core_class.php index 917805c47..a9c80a215 100644 --- a/install/includes/core/core_class.php +++ b/install/includes/core/core_class.php @@ -164,12 +164,12 @@ class Core $new = str_replace("%USERNAME%", $data['db_username'], $new); $new = str_replace("%PASSWORD%", $sanitized_db_pwd, $new); $new = str_replace("%DATABASE%", $data['db_name'], $new); - log_message('info', 'Database config file created successfully.'); + log_message('info', 'Database config file prepared successfully. Writing to file...'); // Write the new database.php file $handle = fopen($output_path, 'w+'); if ($handle === false) { - log_message('error', 'Failed to open newly created database.php file for writing check.'); + log_message('error', 'Failed to open target path for writing the database.php file.'); return false; } @@ -188,7 +188,7 @@ class Core return false; } } else { - log_message('error', 'database.php file is not writable.'); + log_message('error', 'database.php path is not writable.'); return false; } } @@ -200,15 +200,23 @@ class Core $output_path = '../application/config/config.php'; if (isset($_ENV['CI_ENV'])) { $output_path = '../application/config/'.$_ENV['CI_ENV'].'/config.php'; + log_message('info', 'CI_ENV is set to ' . $_ENV['CI_ENV'] . '. Using ' . $_ENV['CI_ENV'] . ' config.php config path.'); + } else { + log_message('info', 'CI_ENV is not set. Using default config.php config path.'); } // Open the file - $database_file = file_get_contents($template_path); + $config_file = file_get_contents($template_path); + if ($config_file === false) { + log_message('error', 'Failed to read config.php template file.'); + return false; + } + log_message('info', 'config.php template file read successfully.'); // creating a unique encryption key $encryptionkey = uniqid(bin2hex(random_bytes(8)), false); - $new = str_replace("%baselocator%", strtoupper($data['userlocator']), $database_file); + $new = str_replace("%baselocator%", strtoupper($data['userlocator']), $config_file); $new = str_replace("%websiteurl%", $data['websiteurl'], $new); $new = str_replace("%directory%", $data['directory'], $new); $new = str_replace("%callbook%", $data['global_call_lookup'], $new); @@ -237,24 +245,31 @@ class Core $new = str_replace("%encryptionkey%", $encryptionkey, $new); $new = str_replace("'%log_threshold%'", $data['log_threshold'], $new); + log_message('info', 'Config.php file prepared successfully. Writing to file...'); // Write the new config.php file $handle = fopen($output_path, 'w+'); + if ($handle === false) { + log_message('error', 'Failed to open target path for writing the config.php file.'); + return false; + } // Verify file permissions if (is_writable($output_path)) { - // Write the file if (fwrite($handle, $new)) { if(file_exists($output_path)) { + log_message('info', 'config.php file written successfully.'); return true; } else { + log_message('error', 'config.php file not found after writing.'); return false; } } else { return false; } } else { + log_message('error', 'config.php path is not writable.'); return false; } } From c13f1b2af38a76bbbff0bbd905e5970ef1e7fa34 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 10:42:02 +0100 Subject: [PATCH 05/11] feat[installer]: enhance error logging for AJAX operations with status details --- install/run.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/install/run.php b/install/run.php index 339e08ec8..273e5d19f 100644 --- a/install/run.php +++ b/install/run.php @@ -148,7 +148,7 @@ } }, error: async function(error) { - await log_message('error', "Install Lock Check went wrong..."); + await log_message('error', "Install Lock Check went wrong... Ajax failed. Error: " + error.status); reject(error); window.location.href = "" + "index.php/user/login"; } @@ -183,7 +183,7 @@ } }, error: async function(error) { - await log_message('error', 'File: Could not write file. Ajax failed.'); + await log_message('error', 'File: Could not write file. Ajax failed. Status: ' + error.status + ' Status Text: ' + error.statusText); running(field, false, true); reject(error); } @@ -201,7 +201,7 @@ return new Promise((resolve, reject) => { $.ajax({ type: 'POST', - url: 'ajax.php', + url: 'ajaxx.php', data: { data: _POST, run_database_file: 1 @@ -218,7 +218,7 @@ } }, error: async function(error) { - await log_message('error', 'File: Could not write file. Ajax failed.'); + await log_message('error', 'File: Could not write file. Ajax failed. Status: ' + error.status + ' Status Text: ' + error.statusText); running(field, false, true); reject(error); } @@ -253,7 +253,7 @@ }, error: async function(error) { running(field, false, true); - await log_message('error', 'Creating database tables failed. Ajax crashed.'); + await log_message('error', 'Creating database tables failed. Ajax crashed. Status: ' + error.status + ' Status Text: ' + error.statusText); reject(error); } }); @@ -283,7 +283,7 @@ }, error: async function(error) { running(field, false, true); - await log_message('error', 'Could not migrate database. Ajax crashed.'); + await log_message('error', 'Could not migrate database. Ajax crashed. Status: ' + error.status + ' Status Text: ' + error.statusText); reject(error); } }); @@ -311,7 +311,7 @@ }, error: async function(error) { running(field, false, true); - await log_message('error', 'Could not update DXCC data. Ajax crashed.'); + await log_message('error', 'Could not update DXCC data. Ajax crashed. Status: ' + error.status + ' Status Text: ' + error.statusText); reject(error); } }); @@ -343,7 +343,7 @@ }, error: async function(error) { running(field, false, true); - await log_message('error', 'Could not create .lock file. Ajax crashed'); + await log_message('error', 'Could not create .lock file. Ajax crashed. Status: ' + error.status + ' Status Text: ' + error.statusText); reject(error); } }); From 029c53e65b0471cd3c995c708f1a47ff02bee3f5 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 10:52:07 +0100 Subject: [PATCH 06/11] feat[installer]: enhance database error logging --- install/includes/core/database_class.php | 43 +++++++++++++++++------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/install/includes/core/database_class.php b/install/includes/core/database_class.php index fe37dd9f2..c4d930d44 100644 --- a/install/includes/core/database_class.php +++ b/install/includes/core/database_class.php @@ -8,11 +8,16 @@ class Database { $mysqli = new mysqli($data['db_hostname'], $data['db_username'], $data['db_password'], $data['db_name']); // Check for errors - if (mysqli_connect_errno()) + if (mysqli_connect_errno()) { + log_message('error', 'Database connection error: ' . mysqli_connect_error()); return false; + } // Open the default SQL file - $query = file_get_contents('assets/install.sql'); + if (!$query = file_get_contents('assets/install.sql')) { + log_message('error', 'Failed to read install.sql file.'); + return false; + } $newpw = password_hash($data['password'], PASSWORD_DEFAULT); $newquery = str_replace("%%FIRSTUSER_NAME%%", str_replace("'", "\\'", $data['username']), $query); @@ -26,24 +31,37 @@ class Database { $newquery = str_replace("%%FIRSTUSER_DXCC%%", $data['dxcc'], $newquery); $newquery = str_replace("%%FIRSTUSER_CITY%%", str_replace("'", "\\'", $data['city']), $newquery); $newquery = str_replace("%%FIRSTUSER_USERLANGUAGE%%", $data['userlanguage'], $newquery); + log_message('info', 'SQL queries prepared successfully. Writing to database...'); mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); - // Execute a multi query - $mysqli->multi_query($newquery); + try { + // Execute a multi query + $mysqli->multi_query($newquery); - // MultiQuery is NON-Blocking,so wait until everything is done - do { - null; - } while ($mysqli->next_result()); + // MultiQuery is NON-Blocking,so wait until everything is done + do { + null; + } while ($mysqli->next_result()); - $result = $mysqli->store_result(); + $mysqli->store_result(); - // Close the connection - $mysqli->close(); + // Close the connection + $mysqli->close(); - return true; + log_message('info', 'Database tables created successfully.'); + return true; + + } catch (mysqli_sql_exception $e) { + log_message('error', 'Database Error: ' . $e->getMessage()); + + if ($mysqli->ping()) { + $mysqli->close(); + } + + return false; + } } function database_check($data) { @@ -80,6 +98,7 @@ class Database { return $mysql_version; } catch (Exception $e) { + log_message('error', 'Database Check Error: ' . $e->getMessage()); return 'Error: ' . $e->getMessage(); } } From b95cd1afd62adcd7bbee4363f3028f7c8d84b8e0 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 11:02:50 +0100 Subject: [PATCH 07/11] fix[installer]: database version check was hard fence. should be soft fence --- install/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/index.php b/install/index.php index 52384055f..ae4b6917f 100644 --- a/install/index.php +++ b/install/index.php @@ -1557,7 +1557,7 @@ if (!file_exists('.lock')) { } else { db_connection_results.addClass('alert-warning'); $('#db_connection_test_button').html(originalButtonText).prop('disabled', false); - db_connection_results.html(" " + "

' . $mysql_version . '', '' . $mariadb_version . ''); ?>"); + db_connection_results.html(" " + "

' . $mysql_version . '', '' . $mariadb_version . ''); ?>"); } resolve(true); } @@ -1857,7 +1857,7 @@ if (!file_exists('.lock')) { if ((checklistPrechecks.hasClass('fa-check-circle') || checklistPrechecks.hasClass('fa-exclamation-triangle')) && checklistConfiguration.hasClass('fa-check-circle') && - checklistDatabase.hasClass('fa-check-circle') && + (checklistDatabase.hasClass('fa-check-circle') || checklistDatabase.hasClass('fa-exclamation-triangle')) && (checklistFirstUser.hasClass('fa-check-circle') || checklistFirstUser.hasClass('fa-exclamation-triangle'))) { install_possible = true; } From 3460318e8559206b256a949c3abf98885f287f46 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 11:11:04 +0100 Subject: [PATCH 08/11] feat[update]: add a hint for dxcc update failure --- application/controllers/Update.php | 3 ++- install/run.php | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/application/controllers/Update.php b/application/controllers/Update.php index 5c6937735..b3b3ef253 100644 --- a/application/controllers/Update.php +++ b/application/controllers/Update.php @@ -211,7 +211,7 @@ class Update extends CI_Controller { $gz = gzopen($url, 'r'); if ($gz === FALSE) { $this->update_status("FAILED: Could not download from clublog.org"); - log_message('error', 'FAILED: Could not download exceptions from clublog.org'); + log_message('error', 'FAILED: Could not download data from clublog.org'); exit(); } @@ -223,6 +223,7 @@ class Update extends CI_Controller { if (file_put_contents($this->paths->make_update_path("cty.xml"), $data) === FALSE) { $this->update_status("FAILED: Could not write to cty.xml file"); + log_message('error', 'DXCC UPDATE FAILED: Could not write to cty.xml file'); exit(); } diff --git a/install/run.php b/install/run.php index 273e5d19f..6cb1879d3 100644 --- a/install/run.php +++ b/install/run.php @@ -201,7 +201,7 @@ return new Promise((resolve, reject) => { $.ajax({ type: 'POST', - url: 'ajaxx.php', + url: 'ajax.php', data: { data: _POST, run_database_file: 1 @@ -305,7 +305,7 @@ resolve(); } else { running(field, false, true); - await log_message('error', 'Could not update DXCC data.'); + await log_message('error', 'Could not update DXCC data. Check application/logs for any error messages.'); reject(""); } }, From bfd1a540dd65d145bd292ecad7ce07627a89def2 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Tue, 3 Dec 2024 12:17:26 +0100 Subject: [PATCH 09/11] fix[installer]: improve database version retrieval to avoid incorrect information --- install/includes/core/database_class.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/install/includes/core/database_class.php b/install/includes/core/database_class.php index c4d930d44..23d835c79 100644 --- a/install/includes/core/database_class.php +++ b/install/includes/core/database_class.php @@ -92,7 +92,15 @@ class Database { throw new Exception(__("Database is not empty.")); } - $mysql_version = $link->server_info; + $version_query = $link->query("SELECT VERSION() as version")->fetch_assoc(); // $link->server_info sometimes returns wrong version or additional (in this case unnecessary) information, e.g. 5.5.5-10.3.29-MariaDB-0+deb10u1 + if (!$version_query) { + throw new Exception(__("Unable to get Database version: ") . $link->error); + } + if (!isset($version_query['version'])) { + throw new Exception(__("Database version could not be retrieved.")); + } + $mysql_version = $version_query['version']; + $link->close(); From a0aa67a81ff614fd1b2665b3f3d02b72f93b471d Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Wed, 4 Dec 2024 16:23:15 +0100 Subject: [PATCH 10/11] fix[installer]: Remove migration lockfile if existent from a previous attempt to avoid unnecessary delay --- install/includes/core/database_class.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/install/includes/core/database_class.php b/install/includes/core/database_class.php index 23d835c79..5795b19cc 100644 --- a/install/includes/core/database_class.php +++ b/install/includes/core/database_class.php @@ -81,7 +81,6 @@ class Database { throw new Exception(__("Unable to create database: ") . $link->error); } - // Wählen Sie die Datenbank aus if (!$link->select_db($data['db_name'])) { throw new Exception(__("Unable to select database: ") . $link->error); } @@ -101,10 +100,19 @@ class Database { } $mysql_version = $version_query['version']; - + // in case of a previous failed installation it can happen that still the migration lockfile is existent + // this would prevent the migration from running or at least would cause a unnecessary delay + // so we delete it here + $lockfile = sys_get_temp_dir() . '/.migration_running'; + if (file_exists($lockfile)) { + log_message('info', 'Removing migration lockfile. Not expected to be present at this point.'); + unlink($lockfile); + } + $link->close(); return $mysql_version; + } catch (Exception $e) { log_message('error', 'Database Check Error: ' . $e->getMessage()); return 'Error: ' . $e->getMessage(); From 38a9c10c59d50774f34dd8d2d274298f17cfad6d Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Wed, 4 Dec 2024 17:20:53 +0100 Subject: [PATCH 11/11] fix[installer]: only delete the migration lockfile if it really exists --- system/libraries/Migration.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php index 256748747..e27ade116 100644 --- a/system/libraries/Migration.php +++ b/system/libraries/Migration.php @@ -348,8 +348,10 @@ class CI_Migration { log_message('debug', 'Finished migrating to '.$current_version); // After the migrations we can remove the lockfile - unlink($this->_migration_lockfile); - log_message('debug', 'Deleted migration lockfile'); + if (file_exists($this->_migration_lockfile)) { + unlink($this->_migration_lockfile); + log_message('debug', 'Deleted migration lockfile'); + } } else { log_message('error', 'Failed to create Migration Lockfile. Check directory permissions.');