235 lines
6.7 KiB
PHP
235 lines
6.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Initializes core constants used across the ip2nginx project.
|
|
*
|
|
* This script is **only** intended to be included by other scripts.
|
|
* It prevents direct execution and ensures all key configuration constants are defined.
|
|
*/
|
|
|
|
// If the script is included and the FILE_IS_INCLUDED flag is defined,
|
|
// proceed to define the required constants.
|
|
if (defined('FILE_IS_INCLUDED')) {
|
|
|
|
// === Core data paths ===
|
|
|
|
// Define DATA_DIR if not already defined (used to store data files)
|
|
if (!defined('DATA_DIR')) {
|
|
define('DATA_DIR', __DIR__ . '/data'); // Directory where data files are stored
|
|
}
|
|
|
|
// Define METAFILE if not already defined (path to meta.json file)
|
|
if (!defined('METAFILE')) {
|
|
define('METAFILE', DATA_DIR . '/meta.json'); // Central file for domain metadata
|
|
}
|
|
|
|
// === Nginx configuration settings ===
|
|
|
|
// Define VHOST_BASE if not already defined
|
|
if (!defined('VHOST_BASE')) {
|
|
define('VHOST_BASE', '/var/www/vhosts/system'); // Base path to vhost configs (Plesk)
|
|
}
|
|
|
|
// Define NGINX_CONF_NAME if not already defined
|
|
if (!defined('NGINX_CONF_NAME')) {
|
|
define('NGINX_CONF_NAME', 'nginx.conf'); // Target file to modify inside each vhost
|
|
}
|
|
|
|
// === Additional configuration ===
|
|
|
|
// Define blocklist file
|
|
if (!defined('BLOCKLIST_FILE')) {
|
|
define('BLOCKLIST_FILE', DATA_DIR . '/blocklist.json'); // File storing blocked IPs
|
|
}
|
|
|
|
// Define authentication failure tracking file
|
|
if (!defined('FAILURESFILE')) {
|
|
define('FAILURESFILE', DATA_DIR . '/failures.json'); // Tracks failed login attempts
|
|
}
|
|
|
|
// Define general log file
|
|
if (!defined('LOGFILE')) {
|
|
define('LOGFILE', DATA_DIR . '/log.json'); // Change log
|
|
}
|
|
|
|
// Define API token file
|
|
if (!defined('TOKENFILE')) {
|
|
define('TOKENFILE', DATA_DIR . '/token.json'); // Token registry
|
|
}
|
|
|
|
// Define default location block used if none is set
|
|
if (!defined('DEF_LOCATION')) {
|
|
define('DEF_LOCATION', '/'); // Default nginx location path
|
|
}
|
|
|
|
// Define default example block for meta.json
|
|
if (!defined('DEF_EXAMPLE')) {
|
|
define('DEF_EXAMPLE', ["example.com" => "SECRET_EXAMPLE"]);
|
|
}
|
|
|
|
// === Security settings ===
|
|
|
|
// Block duration in seconds (48 hours by default)
|
|
if (!defined('BLOCK_DURATION_SECONDS')) {
|
|
define('BLOCK_DURATION_SECONDS', 48 * 3600); // Duration of IP block after failures
|
|
}
|
|
|
|
} else {
|
|
// If the file was accessed directly, deny access
|
|
error_deny();
|
|
}
|
|
|
|
/**
|
|
* Sends a standard 403 Forbidden HTTP response with an HTML message
|
|
* and terminates the script.
|
|
*/
|
|
function error_deny() : void {
|
|
// Set HTTP response status code to 403
|
|
http_response_code(403);
|
|
|
|
// Explicitly send HTTP headers for 403 Forbidden and HTML content type
|
|
header('HTTP/1.1 403 Forbidden');
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
|
|
// Output a simple HTML page explaining the forbidden access
|
|
echo "<HTML>\n";
|
|
echo "<HEAD>\n";
|
|
echo "<TITLE>403 Forbidden</TITLE>\n";
|
|
echo "</HEAD>\n";
|
|
echo "<BODY>\n";
|
|
echo "<H1>Forbidden</H1>\n";
|
|
echo "You do not have permission to access this document.\n";
|
|
echo "<P>\n";
|
|
echo "<HR>\n";
|
|
echo "<ADDRESS>\n";
|
|
echo "Web Server at " . $_SERVER['SERVER_NAME'] . "\n";
|
|
echo "</ADDRESS>\n";
|
|
echo "</BODY>\n";
|
|
echo "</HTML>\n";
|
|
|
|
// Exit the script with status code 403
|
|
exit(403);
|
|
}
|
|
|
|
/**
|
|
* Retrieves a request parameter from POST or GET with fallback to default.
|
|
*
|
|
* @param string $name The name of the parameter to retrieve.
|
|
* @param mixed $def The default value if the parameter is not found or empty.
|
|
* @return mixed The parameter value or the default.
|
|
*/
|
|
function getQuery(string $name, mixed $def): mixed {
|
|
// Check POST first, then GET, fallback to default
|
|
$val = $_POST[$name] ?? $_GET[$name] ?? $def;
|
|
|
|
// Return default if value is empty (including trimmed empty strings)
|
|
return isEmpty($val) ? $def : $val;
|
|
}
|
|
|
|
/**
|
|
* Checks if a given value is considered "empty".
|
|
* - Returns true for null, empty strings, empty arrays, 0, "0", etc. (like PHP's `empty()`)
|
|
* - Additionally, for strings, also trims whitespace before checking emptiness
|
|
*
|
|
* @param mixed $val The value to evaluate
|
|
* @return bool True if the value is empty or whitespace-only, false otherwise
|
|
*/
|
|
function isEmpty(mixed $val): bool {
|
|
// Handle typical empty values (null, "", 0, [], false, etc.)
|
|
if (empty($val)) {
|
|
return true;
|
|
}
|
|
|
|
// If it's a string, trim and check again
|
|
if (is_string($val)) {
|
|
if (trim($val) === '') {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Loads and parses a JSON file into an associative array.
|
|
*
|
|
* Checks if the file exists and is readable before attempting to decode it.
|
|
* If the JSON is invalid, an error message is printed.
|
|
* If decoding fails or the result is not an array, an empty array is returned.
|
|
*
|
|
* @param string $filename Path to the JSON file
|
|
* @return array Parsed associative array or empty array on error
|
|
*/
|
|
function loadJson(string $filename): array {
|
|
$result = [];
|
|
|
|
// Attempt to read and decode the file if it exists and is readable
|
|
if (file_exists($filename) && is_readable($filename)) {
|
|
$result = json_decode(file_get_contents($filename), true);
|
|
|
|
// Log an error if JSON is invalid
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
echo "Invalid JSON in $filename: " . json_last_error_msg() . "\n";
|
|
}
|
|
}
|
|
|
|
// Ensure the result is an array
|
|
if (!is_array($result)) {
|
|
$result = [];
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Saves a PHP array to a JSON file in pretty format.
|
|
*
|
|
* - Ensures the target file is writable if it already exists.
|
|
* - Automatically replaces null or empty input with an empty array.
|
|
* - Returns true on success, false on any failure.
|
|
*
|
|
* @param string $filename The path to the JSON file to write
|
|
* @param array|null $val The data to save (null or empty → [])
|
|
* @return bool True if saved successfully, false otherwise
|
|
*/
|
|
function saveJson(string $filename, ?array $val): bool {
|
|
// Default to empty array if null or empty
|
|
if (isEmpty($val)) {
|
|
$val = [];
|
|
}
|
|
|
|
// Encode to JSON
|
|
$encoded = json_encode($val, JSON_PRETTY_PRINT);
|
|
if ($encoded === false) {
|
|
echo "Failed to encode $filename: " . json_last_error_msg() . "\n";
|
|
return false;
|
|
}
|
|
|
|
// If file exists, check for write permissions
|
|
if (file_exists($filename)) {
|
|
if (!is_writable($filename)) {
|
|
echo "No access to write in $filename\n";
|
|
return false;
|
|
}
|
|
}
|
|
-+
|
|
// Try writing up to 10 times with 250ms delay
|
|
$success = false;
|
|
$attempt = 0;
|
|
for ($attempt = 1; $attempt <= 10; $attempt++) {
|
|
if (@file_put_contents($filename, $encoded) !== false) {
|
|
$success = true;
|
|
break;
|
|
}
|
|
usleep(250 * 1000); // 250 ms delay
|
|
}
|
|
|
|
if (!$success) {
|
|
echo "Failed to write to $filename after $attempt attempts\n";
|
|
}
|
|
|
|
return $success;
|
|
}
|
|
|
|
|