Browse Source

Working custom session code

Alan Hardman 4 years ago
parent
commit
63cf1810fb

+ 11 - 34
app/controller/admin.php

@@ -11,7 +11,7 @@ class Admin extends \Controller {
 		\Base::instance()->set("menuitem", "admin");
 	}
 
-	public function index($f3, $params) {
+	public function index($f3) {
 		$f3->set("title", "Administration");
 		$f3->set("menuitem", "admin");
 
@@ -22,17 +22,6 @@ class Admin extends \Controller {
 
 		$db = $f3->get("db.instance");
 
-		if($f3->get("POST.action") == "updatedb") {
-			if(file_exists("db/".$f3->get("POST.version").".sql")) {
-				$update_db = file_get_contents("db/".$f3->get("POST.version").".sql");
-				$db->exec(explode(";", $update_db));
-				\Cache::instance()->reset();
-				$f3->set("success", " Database updated to version: ". $f3->get("POST.version"));
-			} else {
-				$f3->set("error", " Database file not found for version: ". $f3->get("POST.version"));
-			}
-		}
-
 		// Gather some stats
 		$result = $db->exec("SELECT COUNT(id) AS `count` FROM user WHERE deleted_date IS NULL AND role != 'group'");
 		$f3->set("count_user", $result[0]["count"]);
@@ -43,19 +32,7 @@ class Admin extends \Controller {
 		$result = $db->exec("SELECT COUNT(id) AS `count` FROM issue_comment");
 		$f3->set("count_issue_comment", $result[0]["count"]);
 		$result = $db->exec("SELECT value as version FROM config WHERE attribute = 'version'");
-		if(!empty($result)) {
-			$f3->set("version", $result[0]["version"]);
-		} else {
-			$f3->set("version", '1.0.0');
-		}
-		$db_files = scandir("db");
-		foreach ($db_files as $file) {
-			$file = substr($file, 0, -4);
-			if(version_compare($file, $f3->get('version')) >0) {
-				$f3->set("newer_version", $file);
-				break;
-			}
-		}
+		$f3->set("version", $result[0]["version"]);
 
 		if($f3->get("CACHE") == "apc") {
 			$f3->set("apc_stats", apc_cache_info("user", true));
@@ -64,7 +41,7 @@ class Admin extends \Controller {
 		$this->_render("admin/index.html");
 	}
 
-	public function plugins($f3, $params) {
+	public function plugins($f3) {
 		$f3->set("title", "Plugins");
 		$this->_render("admin/plugins.html");
 	}
@@ -80,7 +57,7 @@ class Admin extends \Controller {
 		}
 	}
 
-	public function users($f3, $params) {
+	public function users($f3) {
 		$f3->set("title", "Manage Users");
 
 		$users = new \Model\User();
@@ -105,14 +82,14 @@ class Admin extends \Controller {
 
 	}
 
-	public function user_new($f3, $params) {
+	public function user_new($f3) {
 		$f3->set("title", "New User");
 
 		$f3->set("rand_color", sprintf("#%02X%02X%02X", mt_rand(0, 0xFF), mt_rand(0, 0xFF), mt_rand(0, 0xFF)));
 		$this->_render("admin/users/edit.html");
 	}
 
-	public function user_save($f3, $params) {
+	public function user_save($f3) {
 
 		$security = \Helper\Security::instance();
 		$user = new \Model\User;
@@ -200,7 +177,7 @@ class Admin extends \Controller {
 		}
 	}
 
-	public function groups($f3, $params) {
+	public function groups($f3) {
 		$f3->set("title", "Manage Groups");
 
 		$group = new \Model\User();
@@ -223,7 +200,7 @@ class Admin extends \Controller {
 		$this->_render("admin/groups.html");
 	}
 
-	public function group_new($f3, $params) {
+	public function group_new($f3) {
 		$f3->set("title", "New Group");
 
 		if($f3->get("POST")) {
@@ -267,7 +244,7 @@ class Admin extends \Controller {
 		}
 	}
 
-	public function group_ajax($f3, $params) {
+	public function group_ajax($f3) {
 		if(!$f3->get("AJAX")) {
 			$f3->error(400);
 		}
@@ -327,7 +304,7 @@ class Admin extends \Controller {
 		$f3->reroute("/admin/groups/" . $group->id);
 	}
 
-	public function sprints($f3, $params) {
+	public function sprints($f3) {
 		$f3->set("title", "Manage Sprints");
 
 		$sprints = new \Model\Sprint();
@@ -336,7 +313,7 @@ class Admin extends \Controller {
 		$this->_render("admin/sprints.html");
 	}
 
-	public function sprint_new($f3, $params) {
+	public function sprint_new($f3) {
 		$f3->set("title", "New Sprint");
 
 		if($post = $f3->get("POST")) {

+ 2 - 2
app/controller/api/issues.php

@@ -61,7 +61,7 @@ class Issues extends \Controller\Api {
 	}
 
 	// Get a list of issues
-	public function get($f3, $params) {
+	public function get($f3) {
 		$issue = new \Model\Issue\Detail();
 		$result = $issue->paginate(
 			$f3->get("GET.offset") / ($f3->get("GET.limit") ?: 30),
@@ -82,7 +82,7 @@ class Issues extends \Controller\Api {
 	}
 
 	// Create a new issue
-	public function post($f3, $params) {
+	public function post($f3) {
 		if($_REQUEST) {
 			// By default, use standard HTTP POST fields
 			$post = $_REQUEST;

+ 2 - 2
app/controller/api/user.php

@@ -50,7 +50,7 @@ class User extends \Controller\Api {
 
 
 	// Gets a List of uers
-	public function get($f3, $params) {
+	public function get($f3) {
 		$pagLimit = $f3->get("GET.limit") ?: 30;
 		if($pagLimit == -1) {
 			$pagLimit = 100000;
@@ -80,7 +80,7 @@ class User extends \Controller\Api {
 
 
 	// Gets a list of Uers
-	public function get_group($f3, $params) {
+	public function get_group($f3) {
 
 		$pagLimit = $f3->get("GET.limit") ?: 30;
 

+ 1 - 1
app/controller/backlog.php

@@ -89,7 +89,7 @@ class Backlog extends \Controller {
 
 
 
-	public function edit($f3, $params) {
+	public function edit($f3) {
 		$post = $f3->get("POST");
 		$issue = new \Model\Issue();
 		$issue->load($post["itemId"]);

+ 16 - 13
app/controller/index.php

@@ -17,7 +17,7 @@ class Index extends \Controller {
 					$user->load($f3->get("site.demo"));
 					if($user->id) {
 						$session = new \Model\Session($user->id);
-						$f3->set("COOKIE.phproj_key", $session->key);
+						$f3->set("COOKIE.phproj_token", $session->token);
 						$f3->reroute("/");
 						return;
 					} else {
@@ -57,18 +57,22 @@ class Index extends \Controller {
 		// Verify password
 		$security = \Helper\Security::instance();
 		if($security->hash($f3->get("POST.password"), $user->salt ?: "") == $user->password) {
+
+			// Create a session and use it
+			$session = new \Model\Session($user->id);
+			$session->setCurrent();
+
 			if($user->salt) {
-				$f3->set("SESSION.phproject_user_id", $user->id);
 				if(!$f3->get("POST.to")) {
 					$f3->reroute("/");
 				} else {
 					$f3->reroute($f3->get("POST.to"));
 				}
 			} else {
-				$f3->set("SESSION.phproject_temp_user_id", $user->id);
 				$f3->set("user", $user->cast());
 				$this->_render("index/reset_forced.html");
 			}
+
 		} else {
 			if($f3->get("POST.to")) {
 				$f3->set("to", $f3->get("POST.to"));
@@ -128,7 +132,11 @@ class Index extends \Controller {
 			$user->salt = $salt;
 			$user->task_color = sprintf("#%02X%02X%02X", mt_rand(0, 0xFF), mt_rand(0, 0xFF), mt_rand(0, 0xFF));
 			$user->save();
-			$f3->set("SESSION.phproject_user_id", $user->id);
+
+			// Create a session and use it
+			$session = new \Model\Session($user->id);
+			$session->setCurrent();
+
 			$f3->reroute("/");
 		}
 	}
@@ -186,12 +194,9 @@ class Index extends \Controller {
 	}
 
 	public function reset_forced($f3) {
-		if(!$f3->get("SESSION.phproject_temp_user_id")) {
-			$f3->error(403);
-			return;
-		}
 		$user = new \Model\User;
-		$user->load($f3->get("SESSION.phproject_temp_user_id"));
+		$user->loadCurrent();
+
 		if($f3->get("POST.password1") != $f3->get("POST.password2")) {
 			$f3->set("reset.error", "The given passwords don't match.");
 		} elseif(strlen($f3->get("POST.password1")) < 6) {
@@ -202,8 +207,6 @@ class Index extends \Controller {
 			$user->salt = $security->salt();
 			$user->password = $security->hash($f3->get("POST.password1"), $user->salt);
 			$user->save();
-			$f3->set("SESSION.phproject_user_id", $user->id);
-			$f3->set("SESSION.phproject_temp_user_id", null);
 			$f3->reroute("/");
 			return;
 		}
@@ -211,8 +214,8 @@ class Index extends \Controller {
 	}
 
 	public function logout($f3) {
-		$f3->clear("SESSION.phproject_user_id");
-		session_destroy();
+		$session = new \Model\Session;
+		$session->delete();
 		$f3->reroute("/");
 	}
 

+ 1 - 1
app/controller/user.php

@@ -19,7 +19,7 @@ class User extends \Controller {
 		);
 	}
 
-	public function index($f3, $params) {
+	public function index($f3) {
 		$f3->reroute("/user");
 	}
 

+ 42 - 2
app/helper/security.php

@@ -39,10 +39,11 @@ class Security extends \Prefab {
 	}
 
 	/**
-	 * Generate a secure SHA256-SHA512 salt
+	 * Generate a secure SHA-256/384/512 salt
+	 * @param  integer $size 256, 384, or 512
 	 * @return string
 	 */
-	public function salt_sha2($size = 512) {
+	public function salt_sha2($size = 256) {
 		$allSizes = array(256, 384, 512);
 		if(!in_array($size, $allSizes)) {
 			throw new Exception("Hash size must be one of: " . implode(", ", $allSizes));
@@ -114,4 +115,43 @@ class Security extends \Prefab {
 		return (binary)$rnd;
 	}
 
+	/**
+	 * Check if the database is the latest version
+	 * @return bool|string TRUE if up-to-date, next version otherwise.
+	 */
+	public function checkDatabaseVersion() {
+
+		// Get current version
+		$db = \Base::instance()->get("db.instance");
+		$result = $db->exec("SELECT value as version FROM config WHERE attribute = 'version'");
+
+		// Check available versions
+		$db_files = scandir("db");
+		foreach ($db_files as $file) {
+			$file = substr($file, 0, -4);
+			if(version_compare($file, $result[0]["version"]) > 0) {
+				return $file;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Install latest core database updates
+	 * @param string $version
+	 */
+	public function updateDatabase($version) {
+		$f3 = \Base::instance();
+		if(file_exists("db/{$version}.sql")) {
+			$update_db = file_get_contents("db/{$version}.sql");
+			$db = $f3->get("db.instance");
+			$db->exec(explode(";", $update_db));
+			\Cache::instance()->reset();
+			$f3->set("success", " Database updated to version: {$version}");
+		} else {
+			$f3->set("error", " Database file not found for version: {$version}");
+		}
+	}
+
 }

+ 50 - 2
app/model/session.php

@@ -4,7 +4,9 @@ namespace Model;
 
 class Session extends \Model {
 
-	protected $_table_name = "session";
+	protected
+		$_table_name = "session",
+		$cookie_name = "phproj_token";
 
 	/**
 	 * Create a new session
@@ -18,7 +20,8 @@ class Session extends \Model {
 
 		if($user_id !== null) {
 			$this->user_id = $user_id;
-			$this->key = \Helper\Security::instance()->salt_sha2(512);
+			$this->token = \Helper\Security::instance()->salt_sha2();
+			$this->created = date("Y-m-d H:i:s");
 			if($auto_save) {
 				$this->save();
 			}
@@ -26,5 +29,50 @@ class Session extends \Model {
 
 	}
 
+	/**
+	 * Load the current session
+	 * @return Session
+	 */
+	public function loadCurrent() {
+		$f3 = \Base::instance();
+		$token = $f3->get("COOKIE.{$this->cookie_name}");
+		if($token) {
+			$this->load(array("token = ?", $token));
+			$expire = $f3->get("JAR.expire");
+			if(time() - $expire > strtotime($this->created)) {
+				$this->delete();
+			}
+		}
+		return $this;
+	}
+
+	/**
+	 * Set the user's cookie to the current session
+	 * @return Session
+	 */
+	public function setCurrent() {
+		$f3 = \Base::instance();
+		$f3->set("COOKIE.{$this->cookie_name}", $this->token, $f3->get("JAR.expire"));
+		return $this;
+	}
+
+	/**
+	 * Delete the session
+	 * @return Session
+	 */
+	public function delete() {
+
+		// Empty the session cookie if it matches the current token
+		$f3 = \Base::instance();
+		if($this->token = $f3->get("COOKIE.{$this->cookie_name}")) {
+			$f3->set("COOKIE.{$this->cookie_name}", "");
+		}
+
+		// Delete the session row
+		parent::delete();
+
+		return $this;
+	}
+
 }
 

+ 1 - 1
app/model/user.php

@@ -17,7 +17,7 @@ class User extends \Model {
 
 		// Load current session
 		$session = new \Model\Session;
-		$session->load(array("key = ?", $f3->get("COOKIE.phproj_key")));
+		$session->loadCurrent();
 
 		// Load user
 		if($session->user_id) {

+ 3 - 1
db/15.03.20.sql

@@ -1,10 +1,12 @@
 DROP TABLE IF EXISTS `session`;
 CREATE TABLE `session`(
 	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
-	`key` VARCHAR(128) NOT NULL,
+	`token` VARBINARY(64) NOT NULL,
 	`user_id` INT UNSIGNED NOT NULL,
 	`created` DATETIME NOT NULL,
 	PRIMARY KEY (`id`),
+	UNIQUE KEY `session_token` (`token`),
+	KEY `session_user_id` (`user_id`),
 	CONSTRAINT `session_user_id` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE
 ) ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_unicode_ci;
 

+ 12 - 0
index.php

@@ -36,6 +36,12 @@ $f3->config("config.ini");
 // Load routes
 $f3->config("app/routes.ini");
 
+// Set cookie properties
+$f3->mset(array(
+	"JAR.path" => parse_url($f3->get("site.url"), PHP_URL_PATH),
+	"JAR.domain" => parse_url($f3->get("site.url"), PHP_URL_HOST),
+));
+
 // Set up error handling
 $f3->set("ONERROR", function(Base $f3) {
 	switch($f3->get("ERROR.code")) {
@@ -63,6 +69,12 @@ $f3->set("db.instance", new DB\SQL(
 	$f3->get("db.pass")
 ));
 
+// Ensure database is up to date
+$version = \Helper\Security::instance()->checkDatabaseVersion();
+if($version !== true) {
+	\Helper\Security::instance()->updateDatabase($version);
+}
+
 // Minify static resources
 // Cache for 1 week
 $f3->route("GET /minify/@type/@files", function(Base $f3, $args) {