diff --git a/.gitignore b/.gitignore index 7a241261..e248f3dd 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ migrates.ini /MythicalDash /MythicalDash.zip /mythicaldash_backup.sql -/caches/notifications.json \ No newline at end of file +/caches/notifications.json +/.mono/ \ No newline at end of file diff --git a/app/CSRF.php b/app/CSRF.php deleted file mode 100644 index 105c185a..00000000 --- a/app/CSRF.php +++ /dev/null @@ -1,361 +0,0 @@ -, - * - * ); - * // Generate an input for a form with a token - * // Tokens on the list are binded on a group so that - * // they can only be matched on that group - * // You can use as a group name the form name - * echo $csrf_tokens->input(); - */ - -namespace MythicalDash; - - -class CSRF -{ - - private $name; - private $hashes; - private $hashTime2Live; - private $hashSize; - private $inputName; - - /** - * Initialize a CSRF instance - * @param string $session_name Session name - * @param string $input_name Form name - * @param integer $hashTime2Live Default seconds hash before expiration - * @param integer $hashSize Default hash size in chars - */ - function __construct($session_name = 'csrf-lib', $input_name = 'key-awesome', $hashTime2Live = 0, $hashSize = 64) - { - // Session mods - $this->name = $session_name; - // Form input name - $this->inputName = $input_name; - // Default time before expire for hashes - $this->hashTime2Live = $hashTime2Live; - // Default hash size - $this->hashSize = $hashSize; - // Load hash list - $this->_load(); - } - - /** - * Generate a CSRF_Hash - * @param string $context Name of the form - * @param integer $time2Live Seconds before expiration - * @param integer $max_hashes Clear old context hashes if more than this number - * @return CSRF_Hash - */ - private function generateHash($context = '', $time2Live = -1, $max_hashes = 5) - { - // If no time2live (or invalid) use default - if ($time2Live < 0) - $time2Live = $this->hashTime2Live; - // Generate new hash - $hash = new CSRF_Hash($context, $time2Live, $this->hashSize); - // Save it - array_push($this->hashes, $hash); - if ($this->clearHashes($context, $max_hashes) === 0) { - $this->_save(); - } - - // Return hash info - return $hash; - } - - /** - * Get the hashes of a context - * @param string $context the group to clean - * @param integer $max_hashes max hashes to get - * @return array array of hashes as strings - */ - public function getHashes($context = '', $max_hashes = -1) - { - $len = count($this->hashes); - $hashes = array(); - // Check in the hash list - for ($i = $len - 1; $i >= 0 && $len > 0; $i--) { - if ($this->hashes[$i]->inContext($context)) { - array_push($hashes, $this->hashes[$i]->get()); - $len--; - } - } - return $hashes; - } - - /** - * Clear the hashes of a context - * @param string $context the group to clean - * @param integer $max_hashes ignore first x hashes - * @return integer number of deleted hashes - */ - public function clearHashes($context = '', $max_hashes = 0) - { - $ignore = $max_hashes; - $deleted = 0; - // Check in the hash list - for ($i = count($this->hashes) - 1; $i >= 0; $i--) { - if ($this->hashes[$i]->inContext($context) && $ignore-- <= 0) { - array_splice($this->hashes, $i, 1); - $deleted++; - } - } - if ($deleted > 0) { - $this->_save(); - } - return $deleted; - } - - /** - * Generate an input html element - * @param string $context Name of the form - * @param integer $time2Live Seconds before expire - * @param integer $max_hashes Clear old context hashes if more than this number - * @return integer html input element code as a string - */ - public function input($context = '', $time2Live = -1, $max_hashes = 5): string - { - // Generate hash - $hash = $this->generateHash($context, $time2Live, $max_hashes); - // Generate html input string - return ''; - } - - /** - * Generate a script html element with the hash variable - * @param string $context Name of the form - * @param string $name The name for the variable - * @param integer $time2Live Seconds before expire - * @param integer $max_hashes Clear old context hashes if more than this number - * @return integer html script element code as a string - */ - public function script($context = '', $name = '', $declaration = 'var', $time2Live = -1, $max_hashes = 5): string - { - // Generate hash - $hash = $this->generateHash($context, $time2Live, $max_hashes); - // Variable name - if (strlen($name) === 0) { - $name = $this->inputName; - } - // Generate html input string - return ''; - } - - /** - * Generate a javascript variable with the hash - * @param string $context Name of the form - * @param string $name The name for the variable - * @param integer $time2Live Seconds before expire - * @param integer $max_hashes Clear old context hashes if more than this number - * @return integer html script element code as a string - */ - public function javascript($context = '', $name = '', $declaration = 'var', $time2Live = -1, $max_hashes = 5): string - { - // Generate hash - $hash = $this->generateHash($context, $time2Live, $max_hashes); - // Variable name - if (strlen($name) === 0) { - $name = $this->inputName; - } - // Generate html input string - return $declaration . ' ' . $name . ' = ' . json_encode($hash->get()) . ';'; - } - - /** - * Generate a string hash - * @param string $context Name of the form - * @param integer $time2Live Seconds before expire - * @param integer $max_hashes Clear old context hashes if more than this number - * @return integer hash as a string - */ - public function string($context = '', $time2Live = -1, $max_hashes = 5): string - { - // Generate hash - $hash = $this->generateHash($context, $time2Live, $max_hashes); - // Generate html input string - return $hash->get(); - } - - /** - * Validate by context - * @param string $context Name of the form - * @return boolean Valid or not - */ - public function validate($context = '', $hash = null) - { - // If hash was not given, find hash - if (is_null($hash)) { - if (isset($_POST[$this->inputName])) { - $hash = $_POST[$this->inputName]; - } else if (isset($_GET[$this->inputName])) { - $hash = $_GET[$this->inputName]; - } else { - return false; - } - } - - // Check in the hash list - for ($i = count($this->hashes) - 1; $i >= 0; $i--) { - if ($this->hashes[$i]->verify($hash, $context)) { - array_splice($this->hashes, $i, 1); - return true; - } - } - return false; - } - - - /** - * Load hash list - */ - private function _load() - { - $this->hashes = array(); - // If there are hashes on the session - if (isset($_SESSION[$this->name])) { - // Load session hashes - $session_hashes = unserialize($_SESSION[$this->name]); - // Ignore expired - for ($i = count($session_hashes) - 1; $i >= 0; $i--) { - // If an expired found, the rest will be expired - if ($session_hashes[$i]->hasExpire()) { - break; - } - array_unshift($this->hashes, $session_hashes[$i]); - } - if (count($this->hashes) != count($session_hashes)) { - $this->_save(); - } - } - } - - /** - * Save hash list - */ - private function _save() - { - $_SESSION[$this->name] = serialize($this->hashes); - } -} - -class CSRF_Hash -{ - - private $hash; - private $context; - private $expire; - - /** - * [__construct description] - * @param string $context [description] - * @param integer $time2Live Number of seconds before expiration - */ - function __construct($context, $time2Live = 0, $hashSize = 64) - { - // Save context name - $this->context = $context; - - // Generate hash - $this->hash = $this->_generateHash($hashSize); - - // Set expiration time - if ($time2Live > 0) { - $this->expire = time() + $time2Live; - } else { - $this->expire = 0; - } - } - - /** - * The hash function to use - * @param int $n Size in bytes - * @return string The generated hash - */ - private function _generateHash($n) - { - return bin2hex(openssl_random_pseudo_bytes($n / 2)); - } - - /** - * Check if hash has expired - * @return boolean - */ - public function hasExpire() - { - if ($this->expire === 0 || $this->expire > time()) { - return false; - } - return true; - } - - /** - * Verify hash - * @return boolean - */ - public function verify($hash, $context = '') - { - if (strcmp($context, $this->context) === 0 && !$this->hasExpire() && strcmp($hash, $this->hash) === 0) { - return true; - } - return false; - } - - /** - * Check Context - * @return boolean - */ - public function inContext($context = '') - { - if (strcmp($context, $this->context) === 0) { - return true; - } - return false; - } - - /** - * Get hash - * @return string - */ - public function get() - { - return $this->hash; - } -} \ No newline at end of file diff --git a/app/CloudFlare/Captcha.php b/app/CloudFlare/Captcha.php deleted file mode 100644 index 99d16016..00000000 --- a/app/CloudFlare/Captcha.php +++ /dev/null @@ -1,36 +0,0 @@ - $cf_secret_key, - "response" => $cf_turnstile_response, - "remoteip" => $cf_connecting_ip - ); - - $url = "https://challenges.cloudflare.com/turnstile/v0/siteverify"; - - $options = array( - "http" => array( - "header" => "Content-Type: application/x-www-form-urlencoded\r\n", - "method" => "POST", - "content" => http_build_query($data) - ) - ); - $context = stream_context_create($options); - $result = file_get_contents($url, false, $context); - - if ($result == false) { - return false; - } - - $result = json_decode($result, true); - - return $result["success"]; - } - -} -?> \ No newline at end of file diff --git a/app/Encryption.php b/app/Encryption.php index 3d23039a..85a4bf3e 100644 --- a/app/Encryption.php +++ b/app/Encryption.php @@ -1,4 +1,4 @@ -dbConnection,$_COOKIE['token']); + if (!Cookie::getCookie('token') == null) { + $session_id = mysqli_real_escape_string($this->dbConnection,Cookie::getCookie('token')); $query = "SELECT * FROM mythicaldash_users WHERE api_key='" . $session_id . "'"; $result = mysqli_query($this->dbConnection, $query); @@ -36,7 +37,7 @@ public function authenticateUser() public function getUserInfo($info) { - $session_id = mysqli_real_escape_string($this->dbConnection, $_COOKIE["token"]); + $session_id = mysqli_real_escape_string($this->dbConnection, Cookie::getCookie('token')); $safeInfo = $this->dbConnection->real_escape_string($info); $query = "SELECT `$safeInfo` FROM mythicaldash_users WHERE api_key='$session_id' LIMIT 1"; $result = $this->dbConnection->query($query); @@ -51,42 +52,14 @@ public function getUserInfo($info) private function redirectToLogin($fullUrl) { - $this->deleteCookies(); + Cookie::deleteAllCookies(); header('location: /auth/login?r=' . $fullUrl); die(); } - private function deleteCookies() - { - if (isset($_SERVER['HTTP_COOKIE'])) { - $cookies = explode(';', $_SERVER['HTTP_COOKIE']); - foreach ($cookies as $cookie) { - $parts = explode('=', $cookie); - $name = trim($parts[0]); - setcookie($name, '', time() - 1000); - setcookie($name, '', time() - 1000, '/'); - } - } - } public function getIP() { - if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) { - $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"]; - $_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"]; - } - $client = @$_SERVER['HTTP_CLIENT_IP']; - $forward = @$_SERVER['HTTP_X_FORWARDED_FOR']; - $remote = $_SERVER['REMOTE_ADDR']; - - if (filter_var($client, FILTER_VALIDATE_IP)) { - $ip = $client; - } elseif (filter_var($forward, FILTER_VALIDATE_IP)) { - $ip = $forward; - } else { - $ip = $remote; - } - - return mysqli_real_escape_string($this->dbConnection, $ip); + return mysqli_real_escape_string($this->dbConnection, CloudFlare::getRealUserIP()); } private function getFullUrl() { diff --git a/app/SettingsManager.php b/app/SettingsManager.php index 67f827c2..ccd9682c 100644 --- a/app/SettingsManager.php +++ b/app/SettingsManager.php @@ -4,12 +4,21 @@ use MythicalDash\Database\Connect; -class SettingsManager { - public static function getSetting($settingName) { +class SettingsManager +{ + /** + * Get a setting from the settings table + * + * @param string $settingName The value of the database you looking for + * + * @return string|null + */ + public static function getSetting(string $settingName): string|null + { $connect = new Connect(); $conn = $connect->connectToDatabase(); $safeSettingName = $conn->real_escape_string($settingName); - + $query = "SELECT `$safeSettingName` FROM mythicaldash_settings LIMIT 1"; $result = $conn->query($query); @@ -19,24 +28,33 @@ public static function getSetting($settingName) { return $row[$settingName]; } else { $conn->close(); - return null; + return null; } } - public static function updateSetting($settingName, $settingValue) { + /** + * Update the settings table + * + * @param string $settingName The name of the colum + * @param string $settingValue The new value you want to set + * + * @return bool The status! + */ + public static function updateSetting(string $settingName, string $settingValue) + { $connect = new Connect(); $conn = $connect->connectToDatabase(); $safeSettingName = $conn->real_escape_string($settingName); $safeSettingValue = $conn->real_escape_string($settingValue); - + $query = "UPDATE mythicaldash_settings SET `$safeSettingName` = '$safeSettingValue'"; - + if ($conn->query($query)) { $conn->close(); - return true; + return true; } else { $conn->close(); - return false; + return false; } } - + } \ No newline at end of file diff --git a/composer.json b/composer.json index 07d05627..646dc417 100644 --- a/composer.json +++ b/composer.json @@ -18,12 +18,12 @@ "minimum-stability": "stable", "require": { "php": ">=8.0.0", - "mythicalsystems/php-router": "^1.0", "symfony/yaml": "^6.3", "phpmailer/phpmailer": "^6.8", "atakde/discord-webhook-php": "^2.0", "stripe/stripe-php": "^13.2.0", - "guzzlehttp/guzzle": "^7.8" + "guzzlehttp/guzzle": "^7.8", + "mythicalsystems/core": "^1.0" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 12b4f675..f09d720b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1d0cd79a02ff50d5d6518b42672be713", + "content-hash": "e14cbfce46cd5a13403edf766788410d", "packages": [ { "name": "atakde/discord-webhook-php", @@ -381,21 +381,30 @@ "time": "2023-12-03T20:05:35+00:00" }, { - "name": "mythicalsystems/php-router", - "version": "1.0.3", + "name": "mythicalsystems/core", + "version": "1.0.0.1", "source": { "type": "git", - "url": "https://github.com/MythicalLTD/php-router.git", - "reference": "8190321cf094124e92eebf4945e001820858e10c" + "url": "https://github.com/MythicalLTD/MythicalCore.git", + "reference": "7ad45f0fdd509b5731eda069f3188db987280aad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MythicalLTD/php-router/zipball/8190321cf094124e92eebf4945e001820858e10c", - "reference": "8190321cf094124e92eebf4945e001820858e10c", + "url": "https://api.github.com/repos/MythicalLTD/MythicalCore/zipball/7ad45f0fdd509b5731eda069f3188db987280aad", + "reference": "7ad45f0fdd509b5731eda069f3188db987280aad", "shasum": "" }, "require": { - "php": ">=6.0.0" + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=8.1.0" + }, + "replace": { + "ecoal95/php-router": "*", + "mythicalsystems/php-router": "*" + }, + "suggest": { + "guzzlehttp/guzzle": "^7.0" }, "type": "library", "autoload": { @@ -403,7 +412,8 @@ "src/php-6.0-support.php" ], "psr-0": { - "Router": "src" + "Router": "src", + "MythicalSystems": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -414,28 +424,39 @@ { "name": "NaysKutzu", "email": "nayskutzu@mythicalsystems.me", - "homepage": "https://nayskutzu.xyz", - "role": "Developer" - }, - { - "name": "Emilio Cobos Álvarez", - "email": "emiliocobos@usal.es", - "homepage": "http://emiliocobos.net", - "role": "Old Developer" + "homepage": "https://mythicalsystems.me", + "role": "Owner" } ], - "description": "Minimal routing library", - "homepage": "https://github.com/MythicalLTD/php-router", + "description": "The core composer packages for all MythicalSystems projects!", + "homepage": "https://github.com/mythicalltd/mythicalcore", "keywords": [ + "kosmapanel", + "mythicalclient", + "mythicalcore", + "mythicaldash", + "mythicalltd", "mythicalsystems", "nayskutzu", "php-router", + "phprouter", "router" ], "support": { - "source": "https://github.com/MythicalLTD/php-router/tree/1.0.3" + "chat": "https://discord.gg/Tswkrhreu3", + "docs": "https://docs.mythicalsystems.me", + "forum": "https://discord.gg/Tswkrhreu3", + "issues": "https://github.com/mythicalltd/mythicalcore/issues", + "source": "https://github.com/MythicalLTD/MythicalCore/tree/1.0.0.1", + "wiki": "https://docs.mythicalsystems.me" }, - "time": "2023-08-27T16:23:31+00:00" + "funding": [ + { + "url": "https://github.com/sponsors/nayskutzu", + "type": "GitHub" + } + ], + "time": "2024-03-20T19:35:32+00:00" }, { "name": "phpmailer/phpmailer", @@ -724,16 +745,16 @@ }, { "name": "stripe/stripe-php", - "version": "v13.12.0", + "version": "v13.14.0", "source": { "type": "git", "url": "https://github.com/stripe/stripe-php.git", - "reference": "8052da9058caae10c7297f85821f652b38e31d85" + "reference": "d569265e79dc82329dadea1b1088a0a29c7a8a76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stripe/stripe-php/zipball/8052da9058caae10c7297f85821f652b38e31d85", - "reference": "8052da9058caae10c7297f85821f652b38e31d85", + "url": "https://api.github.com/repos/stripe/stripe-php/zipball/d569265e79dc82329dadea1b1088a0a29c7a8a76", + "reference": "d569265e79dc82329dadea1b1088a0a29c7a8a76", "shasum": "" }, "require": { @@ -777,9 +798,9 @@ ], "support": { "issues": "https://github.com/stripe/stripe-php/issues", - "source": "https://github.com/stripe/stripe-php/tree/v13.12.0" + "source": "https://github.com/stripe/stripe-php/tree/v13.14.0" }, - "time": "2024-02-22T22:19:58+00:00" + "time": "2024-03-14T21:12:02+00:00" }, { "name": "symfony/deprecation-contracts", diff --git a/public/wp-admin.php b/public/wp-admin.php new file mode 100644 index 00000000..1f59eedd --- /dev/null +++ b/public/wp-admin.php @@ -0,0 +1,17 @@ +composer install --no-dev --optimize-autoloader". Please run that and refresh the page'); + } +} catch (Exception $e) { + die('Hello, it looks like you did not run: composer install --no-dev --optimize-autoloader Please run that and refresh'); +} +use MythicalSystems\Api\ResponseHandler; + +ResponseHandler::NotFound("Nice try :)"); +?> \ No newline at end of file diff --git a/public/wp-login.php b/public/wp-login.php new file mode 100644 index 00000000..1f59eedd --- /dev/null +++ b/public/wp-login.php @@ -0,0 +1,17 @@ +composer install --no-dev --optimize-autoloader". Please run that and refresh the page'); + } +} catch (Exception $e) { + die('Hello, it looks like you did not run: composer install --no-dev --optimize-autoloader Please run that and refresh'); +} +use MythicalSystems\Api\ResponseHandler; + +ResponseHandler::NotFound("Nice try :)"); +?> \ No newline at end of file diff --git a/view/auth/forgot-password.php b/view/auth/forgot-password.php index e9bee404..76626eae 100644 --- a/view/auth/forgot-password.php +++ b/view/auth/forgot-password.php @@ -11,7 +11,6 @@ $conn = new Connect(); $conn = $conn->connectToDatabase(); $session = new SessionManager(); - $csrf = new MythicalDash\CSRF(); if (SettingsManager::getSetting("enable_smtp") == "false") { header('location: /auth/login?e='.$lang['login_mail_server_not_setup']); die(); @@ -19,7 +18,6 @@ session_start(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_POST['reset_password'])) { - if ($csrf->validate('forgot-password-form')) { if (SettingsManager::getSetting("enable_smtp") == "true") { $email = mysqli_real_escape_string($conn, $_POST['email']); $check_query = "SELECT * FROM mythicaldash_users WHERE email = '$email'"; @@ -234,10 +232,6 @@ header('location: /auth/forgot-password?e='.$lang['login_mail_server_not_setup']); die(); } - } else { - header('location: /auth/forgot-password?e='.$lang['csrf_failed']); - die(); - } } else { header("location: /auth/forgot-password?e=".$lang['login_error_unknown']); die(); @@ -295,7 +289,7 @@ if (isset($_GET['e'])) { ?> - input('forgot-password-form'); ?>
diff --git a/view/auth/login.php b/view/auth/login.php index 0656dd88..dfcbdd08 100644 --- a/view/auth/login.php +++ b/view/auth/login.php @@ -1,23 +1,21 @@ connectToDatabase(); $session = new SessionManager(); session_start(); - $csrf = new MythicalDash\CSRF(); + $csrf = new MythicalSystems\Utils\CSRFHandler; if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($csrf->validate('login-form')) { if (isset($_POST['login'])) { if (SettingsManager::getSetting("enable_turnstile") == "false") { $captcha_success = 1; } else { - $captcha_success = Captcha::validate_captcha($_POST["cf-turnstile-response"], $session->getIP(), SettingsManager::getSetting("turnstile_secretkey")); + $captcha_success = TurnStile::validate($_POST["cf-turnstile-response"], $session->getIP(), SettingsManager::getSetting("turnstile_secretkey")); } if ($captcha_success) { $email = mysqli_real_escape_string($conn, $_POST['email']); @@ -147,7 +145,7 @@ if (isset($_GET['e'])) { ?> connectToDatabase(); $session = new SessionManager(); session_start(); - $csrf = new MythicalDash\CSRF(); + $csrf = new MythicalSystems\Utils\CSRFHandler; if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($csrf->validate('register-form')) { @@ -23,7 +22,7 @@ if (SettingsManager::getSetting("enable_turnstile") == "false") { $captcha_success = 1; } else { - $captcha_success = Captcha::validate_captcha($_POST["cf-turnstile-response"], $session->getIP(), SettingsManager::getSetting("turnstile_secretkey")); + $captcha_success = TurnStile::validate($_POST["cf-turnstile-response"], $session->getIP(), SettingsManager::getSetting("turnstile_secretkey")); } if ($captcha_success) { if (!SettingsManager::getSetting("PterodactylURL") == "" && !SettingsManager::getSetting("PterodactylAPIKey") == "") { @@ -274,7 +273,7 @@ class="text-primary" data-bs-toggle="modal" data-bs-target="#pp"> connectToDatabase(); session_start(); -$csrf = new MythicalDash\CSRF(); +$csrf = new MythicalSystems\Utils\CSRFHandler; if ($_SERVER['REQUEST_METHOD'] === 'GET') { if (isset($_GET['code'])) { if (!$_GET['code'] == "") { diff --git a/view/components/alert.php b/view/components/alert.php index 1e87a690..d5cbf498 100644 --- a/view/components/alert.php +++ b/view/components/alert.php @@ -2,7 +2,7 @@ if (isset($_GET['e'])) { ?> validate('profile-form')) {