refactor logout. cleanup
This commit is contained in:
		
							parent
							
								
									fea0e9eb53
								
							
						
					
					
						commit
						f635dd8724
					
				| @ -1,11 +1,22 @@ | ||||
| <?php | ||||
| 
 | ||||
| session_start(); | ||||
| 
 | ||||
| if (!isset($_SESSION['csrf_token'])) { | ||||
|     $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); | ||||
| // Start a session and create a csrf token if necessary
 | ||||
| // TODO - move these to an AuthController?
 | ||||
| function start_session(){ | ||||
|     if (session_status() === PHP_SESSION_NONE) { | ||||
|         session_start(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function generate_csrf_token(bool $regenerate = false){ | ||||
|     if (!isset($_SESSION['csrf_token']) || $regenerate) { | ||||
|         $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| start_session(); | ||||
| generate_csrf_token(); | ||||
| 
 | ||||
| define('APP_ROOT', dirname(dirname(__FILE__))); | ||||
| 
 | ||||
| define('SRC_DIR', APP_ROOT . '/src'); | ||||
| @ -94,11 +105,14 @@ header('Content-Type: text/html; charset=utf-8'); | ||||
| // routes
 | ||||
| $routes = [ | ||||
|     ['', 'HomeController'], | ||||
|     ['', 'HomeController@tick', ['POST']], | ||||
|     ['login', 'LoginController'], | ||||
|     ['login', 'LoginController@login', ['POST']], | ||||
|     ['', 'HomeController@handleTick', ['POST']], | ||||
|     ['admin', 'AdminController'], | ||||
|     ['admin', 'AdminController@save', ['POST']], | ||||
|     ['login', 'AuthController@showLogin'], | ||||
|     ['login', 'AuthController@handleLogin', ['POST']], | ||||
|     ['logout', 'AuthController@handleLogout', ['GET', 'POST']], | ||||
|     ['mood', 'MoodController'], | ||||
|     ['mood', 'MoodController@set_mood', ['POST']], | ||||
|     ['mood', 'MoodController@handleMood', ['POST']], | ||||
|      | ||||
| ]; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										114
									
								
								src/Controller/Admin/Admin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/Controller/Admin/Admin.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | ||||
| <?php | ||||
| class AdminController { | ||||
|     // GET handler
 | ||||
|     // render the admin page
 | ||||
|     public function index(){ | ||||
|         $config = Config::load(); | ||||
|         $user = USER::load(); | ||||
| 
 | ||||
|         $vars = [ | ||||
|             'user' => $user, | ||||
|             'config' => $config, | ||||
|         ]; | ||||
| 
 | ||||
| 
 | ||||
|         echo render_template(TEMPLATES_DIR . "/admin.php", $vars); | ||||
|     } | ||||
| 
 | ||||
|     // POST handler
 | ||||
|     // save updated settings
 | ||||
|     public function save(){ | ||||
|         $isLoggedIn = isset($_SESSION['user_id']); | ||||
|         if (!$isLoggedIn){ | ||||
|             header('Location: ' . $config->basePath . 'login.php'); | ||||
|             exit; | ||||
|         } | ||||
| 
 | ||||
|         $config = Config::load(); | ||||
|         $user = User::load(); | ||||
| 
 | ||||
|         // handle form submission
 | ||||
|         if ($_SERVER['REQUEST_METHOD'] === 'POST') { | ||||
|             $errors = []; | ||||
|          | ||||
|             // User profile
 | ||||
|             $username        = trim($_POST['username'] ?? ''); | ||||
|             $displayName     = trim($_POST['display_name'] ?? ''); | ||||
|             $about           = trim($_POST['about'] ?? ''); | ||||
|             $website         = trim($_POST['website'] ?? ''); | ||||
|          | ||||
|             // Site settings
 | ||||
|             $siteTitle       = trim($_POST['site_title']) ?? ''; | ||||
|             $siteDescription = trim($_POST['site_description']) ?? ''; | ||||
|             $basePath        = trim($_POST['base_path'] ?? '/'); | ||||
|             $itemsPerPage    = (int) ($_POST['items_per_page'] ?? 25); | ||||
|             // Password
 | ||||
|             // TODO - Make sure I really shouldn't trim these
 | ||||
|             //        (I'm assuming there may be people who end their password with a space character)
 | ||||
|             $password                = $_POST['password'] ?? ''; | ||||
|             $confirmPassword         = $_POST['confirm_password'] ?? ''; | ||||
|          | ||||
|             // Validate user profile
 | ||||
|             if (!$username) { | ||||
|                 $errors[] = "Username is required."; | ||||
|             } | ||||
|             if (!$displayName) { | ||||
|                 $errors[] = "Display name is required."; | ||||
|             } | ||||
|             // Make sure the website looks like a URL and starts with a protocol
 | ||||
|             if ($website) { | ||||
|                 if (!filter_var($website, FILTER_VALIDATE_URL)) { | ||||
|                     $errors[] = "Please enter a valid URL (including http:// or https://)."; | ||||
|                 } elseif (!preg_match('/^https?:\/\//i', $website)) { | ||||
|                     $errors[] = "URL must start with http:// or https://."; | ||||
|                 } | ||||
|             } | ||||
|          | ||||
|          | ||||
|             // Validate site settings
 | ||||
|             if (!$siteTitle) { | ||||
|                 $errors[] = "Site title is required."; | ||||
|             } | ||||
|             if (!preg_match('#^/[^?<>:"|\\*]*$#', $basePath)) { | ||||
|                 $errors[] = "Base path must look like a valid URL path (e.g. / or /tkr/)."; | ||||
|             } | ||||
|             if ($itemsPerPage < 1 || $itemsPerPage > 50) { | ||||
|                 $errors[] = "Items per page must be a number between 1 and 50."; | ||||
|             } | ||||
|          | ||||
|             // If a password was sent, make sure it matches the confirmation
 | ||||
|             if ($password && !($password = $confirmPassword)){ | ||||
|                 $errors[] = "Passwords do not match"; | ||||
|             } | ||||
|          | ||||
|             // TODO: Actually handle errors
 | ||||
|             if (empty($errors)) { | ||||
|                 // Update site settings
 | ||||
|                 $config->siteTitle = $siteTitle; | ||||
|                 $config->siteDescription = $siteDescription; | ||||
|                 $config->basePath = $basePath; | ||||
|                 $config->itemsPerPage = $itemsPerPage; | ||||
|              | ||||
|                 // Save site settings and reload config from database
 | ||||
|                 $config = $config->save(); | ||||
|              | ||||
|                 // Update user profile
 | ||||
|                 $user->username = $username; | ||||
|                 $user->displayName = $displayName; | ||||
|                 $user->about = $about; | ||||
|                 $user->website = $website; | ||||
|              | ||||
|                 // Save user profile and reload user from database
 | ||||
|                 $user = $user->save(); | ||||
|              | ||||
|                 // Update the password if one was sent
 | ||||
|                 if($password){ | ||||
|                     $user->set_password($password); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         header('Location: ' . $config->basePath . '/admin'); | ||||
|         exit; | ||||
|     } | ||||
| } | ||||
| @ -1,6 +1,6 @@ | ||||
| <?php | ||||
| class LoginController { | ||||
|     function index(?string $error = null){ | ||||
| class AuthController { | ||||
|     function showLogin(?string $error = null){ | ||||
|         $config = Config::load(); | ||||
|         $csrf_token = $_SESSION['csrf_token']; | ||||
| 
 | ||||
| @ -13,7 +13,7 @@ class LoginController { | ||||
|         echo render_template(TEMPLATES_DIR . '/login.php', $vars); | ||||
|     } | ||||
| 
 | ||||
|     function login(){ | ||||
|     function handleLogin(){ | ||||
|         $config = Config::load(); | ||||
| 
 | ||||
|         $error = ''; | ||||
| @ -36,13 +36,21 @@ class LoginController { | ||||
|                 session_regenerate_id(true); | ||||
|                 $_SESSION['user_id'] = $user['id']; | ||||
|                 $_SESSION['username'] = $user['username']; | ||||
|                 $_SESSION['csrf_token'] = generate_csrf_token(true); | ||||
|                 header('Location: ' . $config->basePath); | ||||
|                 exit; | ||||
|             } else { | ||||
|                 $error = 'Invalid username or password'; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|         $csrf_token = generateCsrfToken(); | ||||
|     function handleLogout(){ | ||||
|         $_SESSION = []; | ||||
|         session_destroy(); | ||||
| 
 | ||||
|         $config = Config::load(); | ||||
|         header('Location: ' . $config->basePath); | ||||
|         exit; | ||||
|     } | ||||
| } | ||||
| @ -27,7 +27,7 @@ class HomeController{ | ||||
| 
 | ||||
|     // POST handler
 | ||||
|     // Saves the tick and reloads the homepage
 | ||||
|     public function tick(){ | ||||
|     public function handleTick(){ | ||||
|         if ($_SERVER['REQUEST_METHOD'] === 'POST' and isset($_POST['tick'])) { | ||||
|             // ensure that the session is valid before proceeding
 | ||||
|             if (!validateCsrfToken($_POST['csrf_token'])) { | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
|             echo render_template(TEMPLATES_DIR . "/mood.php", $vars); | ||||
|         } | ||||
| 
 | ||||
|         public function set_mood(){ | ||||
|         public function handleMood(){ | ||||
|             if ($_SERVER['REQUEST_METHOD'] === 'POST' and isset($_POST['mood'])) { | ||||
|                 // ensure that the session is valid before proceeding
 | ||||
|                 if (!validateCsrfToken($_POST['csrf_token'])) { | ||||
| @ -33,7 +33,7 @@ | ||||
|              | ||||
|                 // go back to the index and show the updated mood
 | ||||
|                 header('Location: ' . $config->basePath); | ||||
|                 //exit;
 | ||||
|                 exit; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| <?php | ||||
| /* | ||||
| if (session_status() === PHP_SESSION_NONE) { | ||||
|     session_start(); | ||||
| } | ||||
| @ -9,7 +10,7 @@ function generateCsrfToken() { | ||||
|     } | ||||
|     return $_SESSION['csrf_token']; | ||||
| } | ||||
| 
 | ||||
| */ | ||||
| function validateCsrfToken($token) { | ||||
|     return hash_equals($_SESSION['csrf_token'], $token); | ||||
| } | ||||
|  | ||||
| @ -1,102 +1,5 @@ | ||||
| <?php | ||||
| #require_once __DIR__ . '/../bootstrap.php';
 | ||||
| 
 | ||||
| #confirm_setup();
 | ||||
| 
 | ||||
| #require_once CLASSES_DIR . '/Config.php';
 | ||||
| #require LIB_DIR . '/session.php';
 | ||||
| 
 | ||||
| if (!$isLoggedIn){ | ||||
|     header('Location: ' . $config->basePath . 'login.php'); | ||||
| } | ||||
| 
 | ||||
| require CLASSES_DIR . '/User.php'; | ||||
| 
 | ||||
| $config = Config::load(); | ||||
| $user = User::load(); | ||||
| 
 | ||||
| // handle form submission
 | ||||
| if ($_SERVER['REQUEST_METHOD'] === 'POST') { | ||||
|     $errors = []; | ||||
| 
 | ||||
|     // User profile
 | ||||
|     $username        = trim($_POST['username'] ?? ''); | ||||
|     $displayName     = trim($_POST['display_name'] ?? ''); | ||||
|     $about           = trim($_POST['about'] ?? ''); | ||||
|     $website         = trim($_POST['website'] ?? ''); | ||||
| 
 | ||||
|     // Site settings
 | ||||
|     $siteTitle       = trim($_POST['site_title']) ?? ''; | ||||
|     $siteDescription = trim($_POST['site_description']) ?? ''; | ||||
|     $basePath        = trim($_POST['base_path'] ?? '/'); | ||||
|     $itemsPerPage    = (int) ($_POST['items_per_page'] ?? 25); | ||||
|     // Password
 | ||||
|     // TODO - Make sure I really shouldn't trim these
 | ||||
|     //        (I'm assuming there may be people who end their password with a space character)
 | ||||
|     $password                = $_POST['password'] ?? ''; | ||||
|     $confirmPassword         = $_POST['confirm_password'] ?? ''; | ||||
| 
 | ||||
|     // Validate user profile
 | ||||
|     if (!$username) { | ||||
|         $errors[] = "Username is required."; | ||||
|     } | ||||
|     if (!$displayName) { | ||||
|         $errors[] = "Display name is required."; | ||||
|     } | ||||
|     // Make sure the website looks like a URL and starts with a protocol
 | ||||
|     if ($website) { | ||||
|         if (!filter_var($website, FILTER_VALIDATE_URL)) { | ||||
|             $errors[] = "Please enter a valid URL (including http:// or https://)."; | ||||
|         } elseif (!preg_match('/^https?:\/\//i', $website)) { | ||||
|             $errors[] = "URL must start with http:// or https://."; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     // Validate site settings
 | ||||
|     if (!$siteTitle) { | ||||
|         $errors[] = "Site title is required."; | ||||
|     } | ||||
|     if (!preg_match('#^/[^?<>:"|\\*]*$#', $basePath)) { | ||||
|         $errors[] = "Base path must look like a valid URL path (e.g. / or /tkr/)."; | ||||
|     } | ||||
|     if ($itemsPerPage < 1 || $itemsPerPage > 50) { | ||||
|         $errors[] = "Items per page must be a number between 1 and 50."; | ||||
|     } | ||||
| 
 | ||||
|     // If a password was sent, make sure it matches the confirmation
 | ||||
|     if ($password && !($password = $confirmPassword)){ | ||||
|         $errors[] = "Passwords do not match"; | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Actually handle errors
 | ||||
|     if (empty($errors)) { | ||||
|         // Update site settings
 | ||||
|         $config->siteTitle = $siteTitle; | ||||
|         $config->siteDescription = $siteDescription; | ||||
|         $config->basePath = $basePath; | ||||
|         $config->itemsPerPage = $itemsPerPage; | ||||
| 
 | ||||
|         // Save site settings and reload config from database
 | ||||
|         $config = $config->save(); | ||||
| 
 | ||||
|         // Update user profile
 | ||||
|         $user->username = $username; | ||||
|         $user->displayName = $displayName; | ||||
|         $user->about = $about; | ||||
|         $user->website = $website; | ||||
| 
 | ||||
|         // Save user profile and reload user from database
 | ||||
|         $user = $user->save(); | ||||
| 
 | ||||
|         // Update the password if one was sent
 | ||||
|         if($password){ | ||||
|             $user->set_password($password); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
| <?php /** @var Config $config */ ?>
 | ||||
| <?php /** @var User $user */ ?>
 | ||||
| 
 | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| @ -111,6 +14,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { | ||||
|         <div><a href="<?= $config->basePath ?>">Back to home</a></div> | ||||
|         <div> | ||||
|             <form method="post"> | ||||
|                 <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>"> | ||||
|                 <fieldset id="user_settings" class="admin-settings-group"> | ||||
|                     <legend>User settings</legend> | ||||
|                     <label class="admin-option">Username: <input type="text" name="username" value="<?= $user->username ?>" required></label><br> | ||||
|  | ||||
| @ -1,14 +1,8 @@ | ||||
| <?php | ||||
| #require_once __DIR__ . '/../bootstrap.php';
 | ||||
| 
 | ||||
| #confirm_setup();
 | ||||
| 
 | ||||
| #require_once CLASSES_DIR . '/Config.php';
 | ||||
| #require LIB_DIR . '/session.php';
 | ||||
| 
 | ||||
| $config = Config::load(); | ||||
| $_SESSION = []; | ||||
| session_destroy(); | ||||
| 
 | ||||
| $config = Config::load(); | ||||
| header('Location: ' . $config->basePath); | ||||
| exit; | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user