diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | inc/menu.inc.php | 10 | ||||
-rw-r--r-- | inc/message.inc.php | 29 | ||||
-rw-r--r-- | inc/session.inc.php | 123 | ||||
-rw-r--r-- | inc/user.inc.php | 26 | ||||
-rw-r--r-- | inc/util.inc.php | 10 | ||||
-rw-r--r-- | index.php | 3 | ||||
-rw-r--r-- | modules/main.inc.php | 2 | ||||
-rw-r--r-- | modules/session.inc.php | 17 | ||||
-rw-r--r-- | templates/menu-logout.html | 2 |
10 files changed, 153 insertions, 70 deletions
@@ -1,4 +1,5 @@ *~ *.bak *.tmp +*.swp diff --git a/inc/menu.inc.php b/inc/menu.inc.php index 7b2502b9..90bc4ebd 100644 --- a/inc/menu.inc.php +++ b/inc/menu.inc.php @@ -9,12 +9,10 @@ class Menu public function loginPanel() { if (User::getName() === false) return Render::parse('menu-login'); - return Render::parse('menu-logout', array('user' => User::getName())); - } - - public function token() - { - return 123; + return Render::parse('menu-logout', array( + 'user' => User::getName(), + 'token' => Session::get('token') + )); } } diff --git a/inc/message.inc.php b/inc/message.inc.php new file mode 100644 index 00000000..9409db95 --- /dev/null +++ b/inc/message.inc.php @@ -0,0 +1,29 @@ +<?php + +// TODO: Move to extra file +$error_text = array( + 'loginfail' => 'Benutzername oder Kennwort falsch', + 'token' => 'Ungültiges Token. CSRF Angriff?', +); + +class Message +{ + private static $list = array(); + + public static function addError($id) + { + self::$list[] = array( + 'type' => 'error', + 'id' => $id + ); + } + + public static function renderList() + { + foreach (self::$list as $item) { + Render::addTemplate('messagebox-' . $item['type'], array('message' => $error_text[$item['id']])); + } + } + +} + diff --git a/inc/session.inc.php b/inc/session.inc.php index a62c5cd3..4b4d4139 100644 --- a/inc/session.inc.php +++ b/inc/session.inc.php @@ -4,46 +4,101 @@ require_once('config.php'); @mkdir(CONFIG_SESSION_DIR, 0700); @chmod(CONFIG_SESSION_DIR, 0700); +if (!is_writable(CONFIG_SESSION_DIR)) die('Config error: Session Path not writable!'); -session_set_save_handler('sh_open', 'sh_close', 'sh_read', 'sh_write', 'sh_destroy', 'sh_gc'); - -// Pretty much a reimplementation of the default session handler: Plain files -// Needs to be switched to db later - -function sh_open($path, $name) +class Session { - return true; -} + private static $sid = false; + private static $data = false; + + private static function generateSessionId() + { + if (self::$sid !== false) Util::traceError('Error: Asked to generate session id when already set.'); + self::$sid = sha1( + mt_rand(0, 65535) + . $_SERVER['REMOTE_ADDR'] + . mt_rand(0, 65535) + . $_SERVER['REMOTE_PORT'] + . $_SERVER['HTTP_USER_AGENT'] + . microtime(true) + . mt_rand(0, 65535) + ); + } -function sh_close() -{ - return true; -} + public static function createSession() + { + self::generateSessionId(); + self::$data = array(); + } -function sh_read($id) -{ - return (string)@file_get_contents(CONFIG_SESSION_DIR . '/slx-session-' . $id); -} + public static function loadSession() + { + // Try to load session id from cookie + if (!self::loadSessionId()) return false; + // Succeded, now try to load session data. If successful, job is done + if (self::readSessionData()) return true; + // Loading session data failed + self::delete(); + } -function sh_write($id, $data) -{ - return @file_put_contents(CONFIG_SESSION_DIR . '/slx-session-' . $id, $data); -} + public static function get($key) + { + if (!isset(self::$data[$key])) return false; + return self::$data[$key]; + } -function sh_destroy($id) -{ - return @unlink(CONFIG_SESSION_DIR . '/slx-session-' . $id); -} + public static function set($key, $value) + { + if (self::$data === false) Util::traceError('Tried to set session data with no active session'); + self::$data[$key] = $value; + } + + private static function loadSessionId() + { + if (self::$sid !== false) die('Error: Asked to load session id when already set.'); + if (empty($_COOKIE['sid'])) return false; + $id = preg_replace('/[^a-zA-Z0-9]/', '', $_COOKIE['sid']); + if (empty($id)) return false; + self::$sid = $id; + return true; + } + + public static function delete() + { + if (self::$sid === false) return; + @unlink(self::getSessionFile()); + @setcookie('sid', '', time() - 8640000, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); + self::$sid = false; + self::$data = false; + } + + private static function getSessionFile() + { + if (self::$sid === false) Util::traceError('Error: Tried to access session file when no session id was set.'); + return CONFIG_SESSION_DIR . '/' . self::$sid; + } -function sh_gc($maxAgeSeconds) -{ - $files = @glob(CONFIG_SESSION_DIR . '/slx-session-*'); - if (!is_array($files)) return false; - foreach ($files as $file) { - if (filemtime($file) + $maxAgeSeconds < time()) { - @unlink($file); - } - } - return true; + private static function readSessionData() + { + if (self::$data !== false) Util::traceError('Tried to call read session data twice'); + $sessionfile = self::getSessionFile(); + if (!is_readable($sessionfile) || filemtime($sessionfile) + CONFIG_SESSION_TIMEOUT < time()) { + @unlink($sessionfile); + return false; + } + self::$data = @unserialize(@file_get_contents($sessionfile)); + if (self::$data === false) return false; + return true; + } + + public static function save() + { + if (self::$sid === false || self::$data === false) return; //Util::traceError('Called saveSession with no active session'); + $sessionfile = self::getSessionFile(); + $ret = @file_put_contents($sessionfile, @serialize(self::$data)); + if (!$ret) Util::traceError('Storing session data in ' . $sessionfile . ' failed.'); + $ret = @setcookie('sid', self::$sid, time() + CONFIG_SESSION_TIMEOUT, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); + if (!$ret) Util::traceError('Error: Could not set Cookie for Client (headers already sent)'); + } } diff --git a/inc/user.inc.php b/inc/user.inc.php index de615932..f10a4f65 100644 --- a/inc/user.inc.php +++ b/inc/user.inc.php @@ -5,7 +5,6 @@ require_once('inc/session.inc.php'); class User { private static $user = false; - private static $session = false; public static function isLoggedIn() { @@ -20,14 +19,8 @@ class User public static function load() { - if (isset($_REQUEST['PHPSESSID']) || isset($_COOKIE['PHPSESSID'])) { - session_start(); - if (!isset($_SESSION['uid']) || !is_numeric($_SESSION['uid'])) { - self::logout(); - return false; - } - // TODO: Query user db for persistent data - $user['name'] = 'Hans'; + if (Session::loadSession()) { + self::$user['name'] = 'Hans'; return true; } return false; @@ -36,10 +29,10 @@ class User public static function login($user, $pass) { if ($user == 'test' && $pass == 'test') { - session_start(); - $_SESSION['uid'] = 1; - $_SESSION['token'] = md5(rand() . time() . rand() . $_SERVER['REMOTE_ADDR'] . rand() . $_SERVER['REMOTE_PORT'] . rand() . $_SERVER['HTTP_USER_AGENT']); - session_write_close(); + Session::createSession();; + Session::set('uid', 1); + Session::set('token', md5(rand() . time() . rand() . $_SERVER['REMOTE_ADDR'] . rand() . $_SERVER['REMOTE_PORT'] . rand() . $_SERVER['HTTP_USER_AGENT'])); + Session::save(); return true; } return false; @@ -47,11 +40,8 @@ class User public static function logout() { - session_unset(); - session_destroy(); - if (setcookie('PHPSESSID', '', time() - 86400)) { - Header('Location: ?do=main&fromlogout'); - } + Session::delete(); + Header('Location: ?do=main&fromlogout'); exit(0); } diff --git a/inc/util.inc.php b/inc/util.inc.php index 793902ec..b4a0036e 100644 --- a/inc/util.inc.php +++ b/inc/util.inc.php @@ -20,9 +20,17 @@ class Util public static function redirect($location) { - session_write_close(); + Session::save(); Header('Location: ' . $location); exit(0); } + + public static function verifyToken() + { + if (Session::get('token') === false) return true; + if (isset($_REQUEST['token']) && Session::get('token') === $_REQUEST['token']) return true; + Message::addError('token'); + return false; + } } @@ -6,6 +6,7 @@ require_once('inc/user.inc.php'); require_once('inc/render.inc.php'); require_once('inc/menu.inc.php'); require_once('inc/util.inc.php'); +require_once('inc/message.inc.php'); if (empty($_REQUEST['do'])) { // No specific module - set default @@ -26,6 +27,8 @@ unset($module); $menu = new Menu; Render::addTemplate('main-menu', $menu); +Message::renderList(); + render_module(); Render::output(); diff --git a/modules/main.inc.php b/modules/main.inc.php index ef83f1c4..fc6a9fac 100644 --- a/modules/main.inc.php +++ b/modules/main.inc.php @@ -1,5 +1,7 @@ <?php +User::load(); + function render_module() { Render::setTitle('Wurstgesicht'); diff --git a/modules/session.inc.php b/modules/session.inc.php index 5b8c5f4d..456ff6b8 100644 --- a/modules/session.inc.php +++ b/modules/session.inc.php @@ -14,26 +14,23 @@ if (isset($_POST['action']) && $_POST['action'] === 'login') { Util::redirect('?do=main'); } // Login credentials wrong - Util::redirect('?do=session&action=fail'); + Message::addError('loginfail'); } if ($_REQUEST['action'] === 'logout') { - // Log user out (or do nothing if not logged in) - exit(0); + if (Util::verifyToken()) { + // Log user out (or do nothing if not logged in) + User::logout(); + Util::redirect('?do=main'); + } } function render_module() { - if (!isset($_GET['action'])) Util::traceError('No action on render'); - if ($_GET['action'] === 'login') { + if ($_REQUEST['action'] === 'login') { Render::setTitle('Anmelden'); Render::addTemplate('page-login'); return; } - if ($_GET['action'] === 'fail') { - Render::setTitle('Fehler'); - Render::addError('Benutzer oder Passwort falsch'); - return; - } } diff --git a/templates/menu-logout.html b/templates/menu-logout.html index d99fac58..68cf4671 100644 --- a/templates/menu-logout.html +++ b/templates/menu-logout.html @@ -1 +1 @@ -<li><a href="?do=session&action=logout&token={{{token}}}">{{user}} abmelden</a></li> +<li><a href="?do=session&action=logout&token={{{token}}}"><b>{{user}}</b> (abmelden)</a></li> |