From 608946ddee0245ac7aa66b80051c252f95ff7d77 Mon Sep 17 00:00:00 2001 From: Yasen Pramatarov Date: Sat, 4 Jan 2025 14:22:53 +0200 Subject: [PATCH] Adds new message system with dismissible messages --- app/classes/messages.php | 137 +++++++++++++++++++++++++++++++++++++ app/pages/security.php | 70 +++++++++++-------- app/templates/security.php | 15 +--- 3 files changed, 180 insertions(+), 42 deletions(-) create mode 100644 app/classes/messages.php diff --git a/app/classes/messages.php b/app/classes/messages.php new file mode 100644 index 0000000..a336820 --- /dev/null +++ b/app/classes/messages.php @@ -0,0 +1,137 @@ + [ + 'message' => 'IP address successfully added to whitelist.', + 'type' => self::TYPE_SUCCESS, + 'dismissible' => true + ], + 'WHITELIST_ADD_ERROR' => [ + 'message' => 'Failed to add IP to whitelist. Please check the IP format.', + 'type' => self::TYPE_ERROR, + 'dismissible' => true + ], + 'WHITELIST_REMOVE_SUCCESS' => [ + 'message' => 'IP address successfully removed from whitelist.', + 'type' => self::TYPE_SUCCESS, + 'dismissible' => true + ], + 'WHITELIST_REMOVE_ERROR' => [ + 'message' => 'Failed to remove IP from whitelist.', + 'type' => self::TYPE_ERROR, + 'dismissible' => true + ], + 'BLACKLIST_ADD_SUCCESS' => [ + 'message' => 'IP address successfully added to blacklist.', + 'type' => self::TYPE_SUCCESS, + 'dismissible' => true + ], + 'BLACKLIST_ADD_ERROR' => [ + 'message' => 'Failed to add IP to blacklist. Please check the IP format.', + 'type' => self::TYPE_ERROR, + 'dismissible' => true + ], + 'BLACKLIST_REMOVE_SUCCESS' => [ + 'message' => 'IP address successfully removed from blacklist.', + 'type' => self::TYPE_SUCCESS, + 'dismissible' => true + ], + 'BLACKLIST_REMOVE_ERROR' => [ + 'message' => 'Failed to remove IP from blacklist.', + 'type' => self::TYPE_ERROR, + 'dismissible' => true + ], + 'IP_REQUIRED' => [ + 'message' => 'IP address is required.', + 'type' => self::TYPE_ERROR, + 'dismissible' => true + ], + 'PERMISSION_DENIED' => [ + 'message' => 'You do not have permission to perform this action.', + 'type' => self::TYPE_ERROR, + 'dismissible' => false + ], + 'RATE_LIMIT_INFO' => [ + 'message' => 'Rate limiting is active. This helps protect against brute force attacks.', + 'type' => self::TYPE_INFO, + 'dismissible' => false + ] + ]; + + const LOGIN = [ + 'LOGIN_FAILED' => [ + 'message' => 'Invalid username or password.', + 'type' => self::TYPE_ERROR, + 'dismissible' => true + ], + 'LOGIN_BLOCKED' => [ + 'message' => 'Too many failed attempts. Please try again later.', + 'type' => self::TYPE_ERROR, + 'dismissible' => false + ], + 'IP_BLACKLISTED' => [ + 'message' => 'Access denied. Your IP address is blacklisted.', + 'type' => self::TYPE_ERROR, + 'dismissible' => false + ] + ]; + + /** + * Get message configuration by key + */ + public static function get($category, $key) { + $messages = constant("self::$category"); + return $messages[$key] ?? null; + } + + /** + * Render message HTML + */ + public static function render($category, $key, $customMessage = null) { + $config = self::get($category, $key); + if (!$config) return ''; + + $message = $customMessage ?? $config['message']; + $dismissible = $config['dismissible'] ? ' alert-dismissible fade show' : ''; + $dismissButton = $config['dismissible'] ? '' : ''; + + return sprintf( + '', + $config['type'], + $dismissible, + htmlspecialchars($message), + $dismissButton + ); + } + + /** + * Store message in session for display after redirect + */ + public static function flash($category, $key, $customMessage = null) { + if (!isset($_SESSION['flash_messages'])) { + $_SESSION['flash_messages'] = []; + } + $_SESSION['flash_messages'][] = [ + 'category' => $category, + 'key' => $key, + 'custom_message' => $customMessage + ]; + } + + /** + * Get and clear all flash messages + */ + public static function getFlash() { + $messages = $_SESSION['flash_messages'] ?? []; + unset($_SESSION['flash_messages']); + return $messages; + } +} diff --git a/app/pages/security.php b/app/pages/security.php index c9cf76f..6146b80 100644 --- a/app/pages/security.php +++ b/app/pages/security.php @@ -9,96 +9,106 @@ if (!($userObject->hasRight($user_id, 'superuser') || exit; } +// Include Messages class +require_once '../app/classes/messages.php'; + // Initialize variables for feedback messages -$error_message = ''; -$success_message = ''; +$messages = []; + +// Get current section +$section = isset($_POST['section']) ? $_POST['section'] : (isset($_GET['section']) ? $_GET['section'] : 'whitelist'); // Handle form submissions if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $action = $_POST['action']; - $section = isset($_POST['section']) ? $_POST['section'] : (isset($_GET['section']) ? $_GET['section'] : 'whitelist'); try { switch ($action) { case 'add_whitelist': if (!$userObject->hasRight($user_id, 'superuser') && !$userObject->hasRight($user_id, 'edit whitelist')) { - throw new Exception('You do not have permission to modify the whitelist.'); + throw new Exception(Messages::get('SECURITY', 'PERMISSION_DENIED')['message']); } if (empty($_POST['ip_address'])) { - throw new Exception('IP address is required.'); + throw new Exception(Messages::get('SECURITY', 'IP_REQUIRED')['message']); } $is_network = isset($_POST['is_network']) ? 1 : 0; if (!$rateLimiter->addToWhitelist($_POST['ip_address'], $is_network, $_POST['description'] ?? '', $currentUser, $user_id)) { - throw new Exception('Failed to add IP to whitelist. Please check the IP format.'); + throw new Exception(Messages::get('SECURITY', 'WHITELIST_ADD_ERROR')['message']); } - $success_message = 'IP address successfully added to whitelist.'; + Messages::flash('SECURITY', 'WHITELIST_ADD_SUCCESS'); break; case 'remove_whitelist': if (!$userObject->hasRight($user_id, 'superuser') && !$userObject->hasRight($user_id, 'edit whitelist')) { - throw new Exception('You do not have permission to modify the whitelist.'); + throw new Exception(Messages::get('SECURITY', 'PERMISSION_DENIED')['message']); } if (empty($_POST['ip_address'])) { - throw new Exception('IP address is required.'); + throw new Exception(Messages::get('SECURITY', 'IP_REQUIRED')['message']); } if (!$rateLimiter->removeFromWhitelist($_POST['ip_address'], $currentUser, $user_id)) { - throw new Exception('Failed to remove IP from whitelist.'); + throw new Exception(Messages::get('SECURITY', 'WHITELIST_REMOVE_ERROR')['message']); } - $success_message = 'IP address successfully removed from whitelist.'; + Messages::flash('SECURITY', 'WHITELIST_REMOVE_SUCCESS'); break; case 'add_blacklist': if (!$userObject->hasRight($user_id, 'superuser') && !$userObject->hasRight($user_id, 'edit blacklist')) { - throw new Exception('You do not have permission to modify the blacklist.'); + throw new Exception(Messages::get('SECURITY', 'PERMISSION_DENIED')['message']); } if (empty($_POST['ip_address'])) { - throw new Exception('IP address is required.'); + throw new Exception(Messages::get('SECURITY', 'IP_REQUIRED')['message']); } $is_network = isset($_POST['is_network']) ? 1 : 0; $expiry_hours = !empty($_POST['expiry_hours']) ? intval($_POST['expiry_hours']) : null; if (!$rateLimiter->addToBlacklist($_POST['ip_address'], $is_network, $_POST['reason'] ?? '', $currentUser, $user_id, $expiry_hours)) { - throw new Exception('Failed to add IP to blacklist. Please check the IP format.'); + throw new Exception(Messages::get('SECURITY', 'BLACKLIST_ADD_ERROR')['message']); } - $success_message = 'IP address successfully added to blacklist.'; + Messages::flash('SECURITY', 'BLACKLIST_ADD_SUCCESS'); break; case 'remove_blacklist': if (!$userObject->hasRight($user_id, 'superuser') && !$userObject->hasRight($user_id, 'edit blacklist')) { - throw new Exception('You do not have permission to modify the blacklist.'); + throw new Exception(Messages::get('SECURITY', 'PERMISSION_DENIED')['message']); } if (empty($_POST['ip_address'])) { - throw new Exception('IP address is required.'); + throw new Exception(Messages::get('SECURITY', 'IP_REQUIRED')['message']); } if (!$rateLimiter->removeFromBlacklist($_POST['ip_address'], $currentUser, $user_id)) { - throw new Exception('Failed to remove IP from blacklist.'); + throw new Exception(Messages::get('SECURITY', 'BLACKLIST_REMOVE_ERROR')['message']); } - $success_message = 'IP address successfully removed from blacklist.'; + Messages::flash('SECURITY', 'BLACKLIST_REMOVE_SUCCESS'); break; } } catch (Exception $e) { - $error_message = $e->getMessage(); + $messages[] = ['category' => 'SECURITY', 'key' => 'CUSTOM_ERROR', 'custom_message' => $e->getMessage()]; } - if (empty($error_message)) { - // Only redirect if there was no error - header("Location: {$app_root}?page=security§ion={$section}" . - ($success_message ? '&success=' . urlencode($success_message) : '')); + if (empty($messages)) { + // Only redirect if there were no errors + header("Location: {$app_root}?page=security§ion={$section}"); exit; } } -// Get success message from URL if redirected after successful action -if (isset($_GET['success'])) { - $success_message = $_GET['success']; +// Get flash messages from previous request +$flash_messages = Messages::getFlash(); +$messages = array_merge($messages, array_map(function($flash) { + return [ + 'category' => $flash['category'], + 'key' => $flash['key'], + 'custom_message' => $flash['custom_message'] + ]; +}, $flash_messages)); + +// Always show rate limit info message for rate limiting section +if ($section === 'ratelimit') { + $messages[] = ['category' => 'SECURITY', 'key' => 'RATE_LIMIT_INFO']; } // Get current lists $whitelisted = $rateLimiter->getWhitelistedIps(); $blacklisted = $rateLimiter->getBlacklistedIps(); -// Get current section -$section = isset($_GET['section']) ? $_GET['section'] : 'whitelist'; - // Include template include '../app/templates/security.php'; diff --git a/app/templates/security.php b/app/templates/security.php index f6e461c..faba804 100644 --- a/app/templates/security.php +++ b/app/templates/security.php @@ -3,18 +3,9 @@

Security Settings

- - - - - - + + +