diff --git a/TODO b/TODO index 253bf0b5..14ba2716 100644 --- a/TODO +++ b/TODO @@ -18,14 +18,21 @@ * Menus in templates * move highscores to twig * migrations: option to downgrade the database - * hooks: login + logout * create account: create character 1.0: + * mobile version + * switch do desktop/mobile version link + * inside templates/mobile + * using Mobile_Detect.php library * i18n support (issue #1 on github) * New Admin Panel layout and interface * most preferably: https://adminlte.io/ * move all pages administration to this panel (like faq, forum, newses) + * save plugin configuration in database + * table name: myaac_config_plugins, columns: plugin, name, type, default, required, extra (json data, like options for select) + * plugin auto-update and check-version + * needs support from my-aac.org (plugins database) * remove tibiacom template, and include it as a plugin 2.0 diff --git a/admin/index.php b/admin/index.php index 65a73a64..5293d374 100644 --- a/admin/index.php +++ b/admin/index.php @@ -23,6 +23,12 @@ define('PAGE', $page); require(SYSTEM . 'functions.php'); require(SYSTEM . 'init.php'); + +// event system +require_once(SYSTEM . 'hooks.php'); +$hooks = new Hooks(); +$hooks->load(); + require(SYSTEM . 'status.php'); require(SYSTEM . 'login.php'); require(ADMIN . 'includes/functions.php'); diff --git a/index.php b/index.php index 790d6e54..ca0ae389 100644 --- a/index.php +++ b/index.php @@ -165,6 +165,11 @@ define('PAGE', $page); $template_place_holders = array(); require_once(SYSTEM . 'init.php'); + +// event system +require_once(SYSTEM . 'hooks.php'); +$hooks = new Hooks(); +$hooks->load(); require_once(SYSTEM . 'template.php'); require_once(SYSTEM . 'login.php'); require_once(SYSTEM . 'status.php'); @@ -191,10 +196,6 @@ else { // register first version } } -// event system -require_once(SYSTEM . 'hooks.php'); -$hooks = new Hooks(); -$hooks->load(); $hooks->trigger(HOOK_STARTUP); // anonymous usage statistics diff --git a/system/functions.php b/system/functions.php index 53ebe1f5..4afe969b 100644 --- a/system/functions.php +++ b/system/functions.php @@ -931,6 +931,16 @@ function str_replace_first($search, $replace, $subject) { return $subject; } +function get_browser_real_ip() { + if(isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR'])) + return $_SERVER['REMOTE_ADDR']; + else if(isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP'])) + return $_SERVER['HTTP_CLIENT_IP']; + else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) + return $_SERVER['HTTP_X_FORWARDED_FOR']; + + return '0'; +} function setSession($key, $data) { global $config; $_SESSION[$config['session_prefix'] . $key] = $data; diff --git a/system/hooks.php b/system/hooks.php index 0a299e08..91efd2f5 100644 --- a/system/hooks.php +++ b/system/hooks.php @@ -21,8 +21,11 @@ define('HOOK_CHARACTERS_BEFORE_SIGNATURE', 9); define('HOOK_CHARACTERS_AFTER_SIGNATURE', 10); define('HOOK_CHARACTERS_AFTER_ACCOUNT', 11); define('HOOK_CHARACTERS_AFTER_CHARACTERS', 12); +define('HOOK_LOGIN', 13); +define('HOOK_LOGIN_ATTEMPT', 14); +define('HOOK_LOGOUT', 15); define('HOOK_FIRST', HOOK_STARTUP); -define('HOOK_LAST', HOOK_CHARACTERS_AFTER_CHARACTERS); +define('HOOK_LAST', HOOK_LOGOUT); class Hook { diff --git a/system/libs/plugins.php b/system/libs/plugins.php index 06651b40..ebdfa49f 100644 --- a/system/libs/plugins.php +++ b/system/libs/plugins.php @@ -195,8 +195,11 @@ class Plugins { if($continue) { if (isset($plugin['install'])) { - if (file_exists(BASE . $plugin['install'])) + if (file_exists(BASE . $plugin['install'])) { + $db->revalidateCache(); require(BASE . $plugin['install']); + $db->revalidateCache(); + } else self::$warnings[] = 'Cannot load install script. Your plugin might be not working correctly.'; } @@ -270,7 +273,7 @@ class Plugins { break; } - $file = BASE . $file; + $file = str_replace('/', '\\', BASE . $file); if(!is_sub_dir($file, BASE) || realpath(dirname($file)) != dirname($file)) { $success = false; self::$error = "You don't have rights to delete: " . $file; diff --git a/system/libs/pot/OTS_Account.php b/system/libs/pot/OTS_Account.php index 0ac36107..18a3e73c 100644 --- a/system/libs/pot/OTS_Account.php +++ b/system/libs/pot/OTS_Account.php @@ -879,14 +879,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable public function logAction($action) { - $ip = '0'; - if(isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR'])) - $ip = $_SERVER['REMOTE_ADDR']; - else if(isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP'])) - $ip = $_SERVER['HTTP_CLIENT_IP']; - else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) - $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; - + $ip = get_browser_real_ip(); if(strpos($ip, ":") === false) { $ipv6 = '0'; } diff --git a/system/libs/pot/OTS_DB_MySQL.php b/system/libs/pot/OTS_DB_MySQL.php index 0e51dc09..1a5a0190 100644 --- a/system/libs/pot/OTS_DB_MySQL.php +++ b/system/libs/pot/OTS_DB_MySQL.php @@ -180,6 +180,10 @@ class OTS_DB_MySQL extends OTS_Base_DB return $this->has_table_cache[$name]; } + return $this->hasTableInternal($name); + } + + private function hasTableInternal($name) { global $config; return ($this->has_table_cache[$name] = $this->query("SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = " . $this->quote($config['database_name']) . " AND `TABLE_NAME` = " . $this->quote($name) . " LIMIT 1;")->rowCount() > 0); } @@ -189,8 +193,25 @@ class OTS_DB_MySQL extends OTS_Base_DB return $this->has_column_cache[$table . '.' . $column]; } + return $this->hasColumnInternal($table, $column); + } + + private function hasColumnInternal($table, $column) { return ($this->has_column_cache[$table . '.' . $column] = count($this->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $column . "'")->fetchAll()) > 0); } + + public function revalidateCache() { + foreach($this->has_table_cache as $key => $value) { + $this->hasTableInternal($key); + } + + foreach($this->has_column_cache as $key => $value) { + $explode = explode('.', $key); + if(isset($this->has_table_cache[$explode[0]]) && $this->has_table_cache[$explode[0]]) {// first check if table exist + $this->hasColumnInternal($explode[0], $explode[1]); + } + } + } } /**#@-*/ diff --git a/system/login.php b/system/login.php index 9d256c2e..504434d8 100644 --- a/system/login.php +++ b/system/login.php @@ -14,16 +14,37 @@ $logged_flags = 0; $action = isset($_REQUEST['action']) ? strtolower($_REQUEST['action']) : ''; define('ACTION', $action); -if(ACTION == 'logout' && !isset($_REQUEST['account_login'])) +// stay-logged with sessions +$current_session = getSession('account'); +if($current_session !== false) { - unsetSession('account'); - unsetSession('password'); - unsetSession('remember_me'); + $account_logged = new OTS_Account(); + $account_logged->load($current_session); + if($account_logged->isLoaded() && $account_logged->getPassword() == getSession('password') + //&& (!isset($_SESSION['admin']) || admin()) + && (getSession('remember_me') !== false || getSession('last_visit') > time() - 15 * 60)) { // login for 15 minutes if "remember me" is not used + $logged = true; + } + else { + unsetSession('account'); + unset($account_logged); + } +} - if(isset($_REQUEST['redirect'])) - { - header('Location: ' . urldecode($_REQUEST['redirect'])); - exit; +if(ACTION == 'logout' && !isset($_REQUEST['account_login'])) { + if($hooks->trigger(HOOK_LOGOUT, array('logged' => $logged, 'account' => (isset($account_logged) ? $account_logged : new OTS_Account()), 'password' => getSession('password')))) { + unsetSession('account'); + unsetSession('password'); + unsetSession('remember_me'); + + $logged = false; + unset($account_logged); + + if(isset($_REQUEST['redirect'])) + { + header('Location: ' . urldecode($_REQUEST['redirect'])); + exit; + } } } else @@ -31,8 +52,9 @@ else // new login with data from form if(!$logged && isset($_POST['account_login']) && isset($_POST['password_login'])) { - $login_account = strtoupper($_POST['account_login']); + $login_account = $_POST['account_login']; $login_password = $_POST['password_login']; + $remember_me = isset($_POST['remember_me']); if(!empty($login_account) && !empty($login_password)) { if($cache->enabled()) @@ -71,8 +93,9 @@ else { setSession('account', $account_logged->getId()); setSession('password', encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $login_password)); - if(isset($_POST['remember_me'])) + if($remember_me) { setSession('remember_me', true); + } $logged = true; $logged_flags = $account_logged->getWebFlags(); @@ -87,9 +110,13 @@ else else { $account_logged->setCustomField('web_lastlogin', time()); } + + $hooks->trigger(HOOK_LOGIN, array('account' => $account_logged, 'password' => $login_password, 'remember_me' => $remember_me)); } else { + $hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me)); + // temporary solution for blocking failed login attempts if($cache->enabled()) { @@ -116,28 +143,11 @@ else } else { $errors[] = 'Please enter your account ' . (USE_ACCOUNT_NAME ? 'name' : 'password') . ' and password.'; + + $hooks->trigger(HOOK_LOGIN_ATTEMPT, array('account' => $login_account, 'password' => $login_password, 'remember_me' => $remember_me)); } } - // stay-logged with sessions - $current_session = getSession('account'); - if($current_session !== false) - { - $account_logged = new OTS_Account(); - $account_logged->load($current_session); - if($account_logged->isLoaded() && $account_logged->getPassword() == getSession('password') - //&& (!isset($_SESSION['admin']) || admin()) - && (getSession('remember_me') !== false || getSession('last_visit') > time() - 15 * 60)) { // login for 15 minutes if "remember me" is not used - $logged = true; - } - else - { - $logged = false; - unsetSession('account'); - unset($account_logged); - } - } - if($logged) { $logged_flags = $account_logged->getWebFlags(); $twig->addGlobal('logged', true); diff --git a/system/pages/accountmanagement.php b/system/pages/accountmanagement.php index 8f2bc7b8..f0ca51d8 100644 --- a/system/pages/accountmanagement.php +++ b/system/pages/accountmanagement.php @@ -18,27 +18,30 @@ $groups = new OTS_Groups_List(); $show_form = true; $config_salt_enabled = $db->hasColumn('accounts', 'salt'); -if(!$logged) -{ - if($action == "logout") { + +if(ACTION == "logout" && !isset($_REQUEST['account_login'])) { + if(!defined('HOOK_LOGOUT_DISPLAY') || HOOK_LOGOUT_DISPLAY) { // plugin will take care of this message echo $twig->render('account.logout.html.twig'); } - else - { - if($action == 'confirm_email') { - require(PAGES . 'account/' . $action . '.php'); - return; - } - - if(!empty($errors)) - echo $twig->render('error_box.html.twig', array('errors' => $errors)); - - echo $twig->render('account.login.html.twig', array( - 'redirect' => isset($_REQUEST['redirect']) ? $_REQUEST['redirect'] : null, - 'account' => USE_ACCOUNT_NAME ? 'Name' : 'Number', - 'error' => isset($errors[0]) ? $errors[0] : null - )); + + return; +} + +if(!$logged) +{ + if(ACTION == 'confirm_email') { + require(PAGES . 'account/' . ACTION . '.php'); + return; } + + if(!empty($errors)) + echo $twig->render('error_box.html.twig', array('errors' => $errors)); + + echo $twig->render('account.login.html.twig', array( + 'redirect' => isset($_REQUEST['redirect']) ? $_REQUEST['redirect'] : null, + 'account' => USE_ACCOUNT_NAME ? 'Name' : 'Number', + 'error' => isset($errors[0]) ? $errors[0] : null + )); return; } diff --git a/system/pages/admin/plugins.php b/system/pages/admin/plugins.php index 759d1788..416ab27f 100644 --- a/system/pages/admin/plugins.php +++ b/system/pages/admin/plugins.php @@ -10,7 +10,6 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Plugin manager'; -require(SYSTEM . 'hooks.php'); require(LIBS . 'plugins.php'); echo $twig->render('admin.plugins.form.html.twig');