diff --git a/config/extAuth.php.in b/config/extAuth.php.in new file mode 100644 index 00000000..1181c946 --- /dev/null +++ b/config/extAuth.php.in @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/includes/ajaxHandler.class.php b/includes/ajaxHandler.class.php index 9ccf40ee..1463d15a 100644 --- a/includes/ajaxHandler.class.php +++ b/includes/ajaxHandler.class.php @@ -27,7 +27,7 @@ class AjaxHandler public function handle($what) { $f = 'handle'.ucFirst($what); - if (!method_exists($this, $f)) + if (!$what || !method_exists($this, $f)) return null; return $this->$f(); @@ -139,7 +139,7 @@ class AjaxHandler break; } } - + return $result; } @@ -253,9 +253,50 @@ class AjaxHandler private function handleLocale() // not sure if this should be here.. { User::setLocale($this->params[0]); - User::writeCookie(); + User::save(); + header('Location: '.(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '.')); } + + private function handleAccount() + { + if (!$this->params || !User::$id) + return null; + + switch ($this->params[0]) + { + case 'exclude': + // profiler completion exclude handler + // $this->post['groups'] = bitMask of excludeGroupIds when using .. excludeGroups .. duh + // should probably occur in g_user.excludegroups (dont forget to also set g_users.settings = {}) + return ''; + case 'weightscales': + if (isset($this->post['save'])) + { + if (!isset($this->post['id'])) + { + $res = DB::Aowow()->selectRow('SELECT max(id) as max, count(id) as num FROM ?_account_weightscales WHERE account = ?d', User::$id); + if ($res['num'] < 5) // more or less hard-defined in LANG.message_weightscalesaveerror + $this->post['id'] = ++$res['max']; + else + return 0; + } + + if (DB::Aowow()->query('REPLACE INTO ?_account_weightscales VALUES (?d, ?d, ?, ?)', intVal($this->post['id']), User::$id, $this->post['name'], $this->post['scale'])) + return $this->post['id']; + else + return 0; + } + else if (isset($this->post['delete']) && isset($this->post['id'])) + DB::Aowow()->query('DELETE FROM ?_account_weightscales WHERE id = ?d AND account = ?d', intVal($this->post['id']), User::$id); + else + return 0; + } + + + return null; + } + } ?> diff --git a/includes/defines.php b/includes/defines.php index acb47fb7..ffb1479b 100644 --- a/includes/defines.php +++ b/includes/defines.php @@ -43,15 +43,31 @@ define('DB_WORLD', 1); define('DB_AUTH', 2); define('DB_CHARACTERS', 3); +// Account Status +define('ACC_STATUS_OK', 0); // nothing special +define('ACC_STATUS_NEW', 1); // just created, awaiting confirmation +define('ACC_STATUS_RECOVER_USER', 2); // currently recovering username +define('ACC_STATUS_RECOVER_PASS', 3); // currently recovering password + +define('ACC_BAN_NONE', 0x00); // all clear +define('ACC_BAN_TEMP', 0x01); +define('ACC_BAN_PERM', 0x02); +define('ACC_BAN_RATE', 0x04); // cannot rate community items +define('ACC_BAN_COMMENT', 0x08); // cannot create comments +define('ACC_BAN_UPLOAD', 0x10); // cannot upload screenshots / suggest videos + // Auth Result define('AUTH_OK', 0); -define('AUTH_WRONGPASS', 1); -define('AUTH_TIMEDOUT', 2); +define('AUTH_WRONGUSER', 1); +define('AUTH_WRONGPASS', 2); define('AUTH_BANNED', 3); define('AUTH_IPBANNED', 4); +define('AUTH_ACC_INACTIVE', 5); +define('AUTH_INTERNAL_ERR', 6); -// Cookie Names -define('COOKIE_AUTH', 'aw_a'); +define('AUTH_MODE_SELF', 0); // uses ?_accounts +define('AUTH_MODE_REALM', 1); // uses given realm-table +define('AUTH_MODE_EXTERNAL', 2); // uses external script // Times define('MINUTE', 60); @@ -74,6 +90,11 @@ define('U_GROUP_BLOGGER', 0x0080); define('U_GROUP_PREMIUM', 0x0100); define('U_GROUP_LOCALIZER', 0x0200); define('U_GROUP_SALESAGENT', 0x0400); +define('U_GROUP_SCREENSHOT', 0x0800); +define('U_GROUP_VIDEO', 0x1000); +// define('U_GROUP_APIONLY, 0x2000); // the heck..? +// define('U_GROUP_PENDING, 0x4000); + define('U_GROUP_STAFF', (U_GROUP_ADMIN|U_GROUP_EDITOR|U_GROUP_MOD|U_GROUP_BUREAU|U_GROUP_DEV|U_GROUP_BLOGGER|U_GROUP_LOCALIZER|U_GROUP_SALESAGENT)); define('U_GROUP_EMPLOYEE', (U_GROUP_ADMIN|U_GROUP_BUREAU|U_GROUP_DEV)); define('U_GROUP_GREEN_TEXT', (U_GROUP_MOD|U_GROUP_BUREAU|U_GROUP_DEV)); diff --git a/includes/kernel.php b/includes/kernel.php index 7489bacc..c239b332 100644 --- a/includes/kernel.php +++ b/includes/kernel.php @@ -8,7 +8,6 @@ ini_set('serialize_precision', 4); require 'includes/defines.php'; require 'config/config.php'; -require 'includes/genericPage.class.php'; require 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using mysqli variant: https://bitbucket.org/brainreaver/dbsimple/src) require 'includes/utilities.php'; // misc™ data 'n func require 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests @@ -17,6 +16,7 @@ require 'includes/database.class.php'; // wrap DBSimple require 'includes/community.class.php'; // handle comments, screenshots and videos require 'includes/loot.class.php'; // build lv-tabs containing loot-information require 'localization/lang.class.php'; +require 'pages/genericPage.class.php'; // autoload List-classes, associated filters and pages @@ -63,10 +63,11 @@ foreach ($AoWoWconf['characters'] as $realm => $charDBInfo) unset($AoWoWconf); // link set up: delete passwords + // load config to constants $sets = DB::Aowow()->select('SELECT `key` AS ARRAY_KEY, intValue as i, strValue as s FROM ?_config'); foreach ($sets as $k => $v) - define('CFG_'.strtoupper($k), $v['s'] ? $v['s'] : intVal($v['i'])); + define('CFG_'.strtoupper($k), $v['s'] ?: intVal($v['i'])); define('STATIC_URL', substr('http://'.$_SERVER['SERVER_NAME'].strtr($_SERVER['SCRIPT_NAME'], ['index.php' => '']), 0, -1).'/static'); // points js to images & scripts (change here if you want to use a separate subdomain) define('HOST_URL', substr('http://'.$_SERVER['SERVER_NAME'].strtr($_SERVER['SCRIPT_NAME'], ['index.php' => '']), 0, -1)); // points js to executable files @@ -76,54 +77,25 @@ $e = CFG_DEBUG ? (E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT)) : 0; error_reporting($e); -// php session (used for profiler: g_dataKey) (todo (high): merge to user-class at some point) -session_start(); -if (empty($_SESSION['timeout']) || $_SESSION['timeout'] < time()) -{ - $seed = "abcdefghijklmnopqrstuvwxyz0123456789"; - $_SESSION['dataKey'] = ''; // just some random numbers for identifictaion purpose - for ($i = 0; $i < 40; $i++) - $_SESSION['dataKey'] .= substr($seed, mt_rand(0, 35), 1); -} -$_SESSION['timeout'] = time() + CFG_SESSION_TIMEOUT_DELAY; - - // debug: measure execution times Util::execTime(CFG_DEBUG); // Setup Session -if (isset($_COOKIE[COOKIE_AUTH])) -{ - $offset = intval($_COOKIE[COOKIE_AUTH][1]); +ini_set('session.cookie_httponly', true); +session_cache_limiter('private'); +session_start(); +if (User::init()) + User::save(); // save user-variables in session - if ($id = hexdec(substr($_COOKIE[COOKIE_AUTH], 2, $offset))) - { - User::init($id); - switch (User::Auth()) - { - case AUTH_OK: - case AUTH_BANNED: - User::writeCookie(); - break; - default: - User::destroy(); - } - } - else - User::init(0); -} -else - User::init(0); +// all strings attached.. +Lang::load(User::$localeString); -User::setLocale(); // parse page-parameters .. sanitize before use! @list($str, $trash) = explode('&', $_SERVER['QUERY_STRING'], 2); @list($pageCall, $pageParam) = explode('=', $str, 2); Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/'.$str; -$ajax = new AjaxHandler($pageParam); - ?> diff --git a/includes/types/basetype.class.php b/includes/types/basetype.class.php index b9a369bd..bf5271cf 100644 --- a/includes/types/basetype.class.php +++ b/includes/types/basetype.class.php @@ -320,9 +320,11 @@ abstract class BaseType public function getRandomId() { - // its not optimal, so if anyone has an alternative idea.. + // ORDER BY RAND() is not optimal, so if anyone has an alternative idea.. + $where = User::isInGroup(U_GROUP_EMPLOYEE) ? 'WHERE (cuFlags & '.CUSTOM_EXCLUDE_FOR_LISTVIEW.') = 0' : null; $pattern = '/SELECT .* (-?`?[\w_]*\`?.?`?(id|entry)`?) AS ARRAY_KEY,?.* FROM (\?[\w_-]+) (`?\w*`?)/i'; - $replace = 'SELECT $1 FROM $3 $4 WHERE (cuFlags & '.CUSTOM_EXCLUDE_FOR_LISTVIEW.') = 0 ORDER BY RAND() ASC LIMIT 1'; + $replace = 'SELECT $1 FROM $3 $4 '.$where.' ORDER BY RAND() ASC LIMIT 1'; + $query = preg_replace($pattern, $replace, $this->queryBase); return DB::Aowow()->selectCell($query); diff --git a/includes/types/item.class.php b/includes/types/item.class.php index baabc71c..8bb793af 100644 --- a/includes/types/item.class.php +++ b/includes/types/item.class.php @@ -655,7 +655,7 @@ class ItemList extends BaseType { $gems = DB::Aowow()->select('SELECT i.id AS ARRAY_KEY, i.iconString, ae.*, i.gemColorMask AS colorMask FROM ?_items i JOIN ?_itemenchantment ae ON ae.id = i.gemEnchantmentId WHERE i.id IN (?a)', $enhance['g']); foreach ($enhance['g'] as $k => $v) - if (!in_array(array_keys($gems), $v)) + if (!in_array($v, array_keys($gems))) unset($enhance['g'][$k]); } else diff --git a/includes/user.class.php b/includes/user.class.php index c9454f24..5d275610 100644 --- a/includes/user.class.php +++ b/includes/user.class.php @@ -3,148 +3,113 @@ if (!defined('AOWOW_REVISION')) die('illegal access'); -/* - Cookie-Content - W X Y [Z] : base64 - Z : passHash length: ? exampleValue: base64_encode('+RQGbSW7Yqyz6fTNAUrI3BE-Zt0FoiMh8ke1_sCmLDwOjgXda9JxH2KcPVu4l5vnp') - Y : X chars accId as hex length: X exampleValue: 0xF29 - X : [1-9] num chars of Y as int length: 1 exampleValue: 3 - W : locale [0, 2, 3, 6, 8] length: 1 exampleValue: 0 - - 03F29K1JRR2JTVzdZcXl6NmZUTkFVckkzQkUtWnQwRm9pTWg4a2UxX3NDbUxEd09qZ1hkYTlKeEgyS2NQVnU0bDV2bnA= -*/ class User { - public static $id; - public static $authId; - public static $displayName; - public static $email; + public static $id = 0; + public static $displayName = ''; + public static $banStatus = 0x0; // &1: banedIP; &2: banUser; &4: ratingBan; &8: commentBan; &16: disableUpload + public static $groups = 0x0; + public static $perms = 0; + public static $localeId = 0; + public static $localeString = 'enus'; - public static $user; - private static $passHash; - private static $timeout; + private static $dataKey = ''; + private static $expires = false; + private static $passHash = ''; - public static $lastIP; - public static $lastLogin; - public static $joindate; - - public static $groups; - public static $perms; - public static $localeId; - public static $localeString; - public static $profiles; - public static $characters; - public static $avatar; - public static $description; - - /* public static $ratingBan; */ - /* public static $commentBan; .. jeez.. banflags..? &1: banIP; &2: banUser; &4: disableRating; &8: disableComment; &16: disableUpload ?? */ - public static $bannedIP; - public static $banned; - public static $unbanDate; - public static $bannedBy; - public static $banReason; - - public static function init($userId) + public static function init() { - self::$id = $userId; + self::setLocale(); - $ipBan = DB::Aowow()->SelectRow('SELECT count, unbanDate AS unbanDateIP FROM ?_account_bannedIPs WHERE ip = ? AND type = 0', - $_SERVER['REMOTE_ADDR'] - ); - // explicit " > "; incremented first, checked after - self::$bannedIP = $ipBan && $ipBan['count'] > CFG_FAILED_AUTH_COUNT && $ipBan['unbanDateIP'] > time(); + // session have a dataKey to access the JScripts (yes, also the anons) + if (empty($_SESSION['dataKey'])) + $_SESSION['dataKey'] = Util::createHash(); // just some random numbers for identifictaion purpose - $query = !$userId ? null : DB::Aowow()->SelectRow(' - SELECT - a.id, a.authId, a.user, a.passHash, a.displayName, a.email, a.lastIP, a.lastLogin, a.joindate, a.locale, a.avatar, a.description, a.userGroups, a.userPerms, a.timeout, - ab.bannedBy, ab.banReason, ab.isActive, ab.unbanDate - FROM - ?_account a - LEFT JOIN - ?_account_banned ab ON a.id = ab.id AND ab.isActive = 1 - WHERE - a.id = ?d - ORDER - BY ab.banDate DESC - LIMIT - 1 - ', - $userId - ); + self::$dataKey = $_SESSION['dataKey']; - if ($query) + // check IP bans + if ($ipBan = DB::Aowow()->selectRow('SELECT count, unbanDate FROM ?_account_bannedIPs WHERE ip = ? AND type = 0', $_SERVER['REMOTE_ADDR'])) { - self::$authId = intval($query['authId']); - self::$user = $query['user']; - self::$passHash = $query['passHash']; - self::$email = $query['email']; - self::$lastIP = $query['lastIP']; - self::$lastLogin = intval($query['lastLogin']); - self::$joindate = intval($query['joindate']); - self::$localeId = intval($query['locale']); - self::$localeString = self::localeString(self::$localeId); - self::$timeout = intval($query['timeout']); - self::$groups = intval($query['userGroups']); - self::$perms = intval($query['userPerms']); - self::$banned = $query['isActive'] == 1 && $query['unbanDate'] > time(); - self::$unbanDate = intval($query['unbanDate']); - self::$bannedBy = intval($query['bannedBy']); - self::$banReason = $query['banReason']; - - self::$displayName = $query['displayName']; - self::$avatar = $query['avatar']; - self::$description = $query['description']; + if ($ipBan['count'] > CFG_FAILED_AUTH_COUNT && $ipBan['unbanDate'] > time()) + return false; + else if ($ipBan['unbanDate'] <= time()) + DB::Aowow()->query('DELETE FROM ?_account_bannedIPs WHERE ip = ?', $_SERVER['REMOTE_ADDR']); } - else - self::setLocale(); + + // try to restore session + if (empty($_SESSION['user'])) + return false; + + // timed out... + if (!empty($_SESSION['timeout']) && $_SESSION['timeout'] <= time()) + return false; + + $query = DB::Aowow()->SelectRow(' + SELECT a.id, a.passHash, a.displayName, a.locale, a.userGroups, a.userPerms, a.allowExpire, BIT_OR(ab.typeMask) AS bans + FROM ?_account a + LEFT JOIN ?_account_banned ab ON a.id = ab.userId AND ab.end > UNIX_TIMESTAMP() + WHERE a.id = ?d + GROUP BY a.id', + $_SESSION['user'] + ); + + if (!$query) + return false; + + // password changed, terminate session + if (AUTH_MODE_SELF && $query['passHash'] != $_SESSION['hash']) + { + self::destroy(); + return; + } + + self::$id = intval($query['id']); + self::$displayName = $query['displayName']; + self::$passHash = $query['passHash']; + self::$expires = (bool)$query['allowExpire']; + self::$banStatus = $query['bans']; + self::$groups = $query['bans'] & (ACC_BAN_TEMP | ACC_BAN_PERM) ? 0 : intval($query['userGroups']); + self::$perms = $query['bans'] & (ACC_BAN_TEMP | ACC_BAN_PERM) ? 0 : intval($query['userPerms']); + + self::setLocale(intVal($query['locale'])); // reset, if changed + + return true; } - // set and use until further notice + // set and save public static function setLocale($set = -1) { - if ($set != -1) + $loc = LOCALE_EN; + + // get + if ($set != -1 && isset(Util::$localeStrings[$set])) + $loc = $set; + else if (isset($_SESSION['locale']) && isset(Util::$localeStrings[$_SESSION['locale']])) + $loc = $_SESSION['locale']; + else if (!empty($_SERVER["HTTP_ACCEPT_LANGUAGE"])) { - $loc = isset(Util::$localeStrings[$set]) ? $set : 0; - if (self::$id) - { - DB::Aowow()->query('UPDATE ?_account SET locale = ? WHERE id = ?', - $loc, - self::$id - ); - } - } - else if (isset($_COOKIE[COOKIE_AUTH])) - { - $loc = intval(substr($_COOKIE[COOKIE_AUTH], 0, 1)); - $loc = isset(Util::$localeStrings[$loc]) ? $loc : 0; - } - else - { - if (empty($_SERVER["HTTP_ACCEPT_LANGUAGE"])) - $loc = 0; - else - { - $loc = strtolower(substr($_SERVER["HTTP_ACCEPT_LANGUAGE"], 0, 2)); - switch ($loc) { - case 'ru': $loc = 8; break; - case 'es': $loc = 6; break; - case 'de': $loc = 3; break; - case 'fr': $loc = 2; break; - default: $loc = 0; - } + $loc = strtolower(substr($_SERVER["HTTP_ACCEPT_LANGUAGE"], 0, 2)); + switch ($loc) { + case 'ru': $loc = LOCALE_RU; break; + case 'es': $loc = LOCALE_ES; break; + case 'de': $loc = LOCALE_DE; break; + case 'fr': $loc = LOCALE_FR; break; + default: $loc = LOCALE_EN; } } // set - self::$localeId = $loc; - self::$localeString = self::localeString($loc); + if ($loc != self::$localeId) + { + if (self::$id) + DB::Aowow()->query('UPDATE ?_account SET locale = ? WHERE id = ?', $loc, self::$id); - Lang::load(self::$localeString); + self::useLocale($loc); + } } - // only use this once + // only use once public static function useLocale($use) { self::$localeId = isset(Util::$localeStrings[$use]) ? $use : 0; @@ -156,50 +121,6 @@ class User return (self::$groups & $group) != 0; } - public static function Auth($pass = '') - { - if (self::$bannedIP) - return AUTH_IPBANNED; - - if (!$pass) // pass not set, check against cookie - { - $offset = intVal($_COOKIE[COOKIE_AUTH][1]) + 2; // value of second char in string + 1 for locale - $cookiePass = base64_decode(substr($_COOKIE[COOKIE_AUTH], $offset)); - if ($cookiePass != self::$passHash) - return AUTH_WRONGPASS; - - // "stay logged in" unchecked; kill session in time() + 5min - // if (self::$timeout > 0 && self::$timeout < time()) - // return AUTH_TIMEDOUT; - - if (self::$timeout > 0) - DB::Aowow()->query('UPDATE ?_account SET timeout = ?d WHERE id = ?d', - time() + CFG_SESSION_TIMEOUT_DELAY, - self::$id - ); - } - else - { - if (self::$passHash[0] == '$') // salted hash -> aowow-password - { - if (!self::verifyCrypt($pass)) - return AUTH_WRONGPASS; - } - else // assume sha1 hash; account got copied from wow database - { - if (self::verifySHA1($pass)) - self::convertAuthInfo($pass); // drop sha1 and generate with crypt - else - return AUTH_WRONGPASS; - } - } - - if (self::$banned) - return AUTH_BANNED; - - return AUTH_OK; - } - private static function localeString($loc = -1) { if (!isset(Util::$localeStrings[$loc])) @@ -208,77 +129,185 @@ class User return Util::$localeStrings[$loc]; } + public static function Auth($name, $pass) + { + $user = 0; + $hash = ''; + + switch (CFG_AUTH_MODE) + { + case AUTH_MODE_SELF: + { + // handle login try limitation + $ip = DB::Aowow()->selectRow('SELECT ip, count, unbanDate FROM ?_account_bannedIPs WHERE type = 0 AND ip = ?', $_SERVER['REMOTE_ADDR']); + if (!$ip || $ip['unbanDate'] < time()) // no entry exists or time expired; set count to 1 + DB::Aowow()->query('REPLACE INTO ?_account_bannedIPs (ip, type, count, unbanDate) VALUES (?, 0, 1, UNIX_TIMESTAMP() + ?d)', $_SERVER['REMOTE_ADDR'], CFG_FAILED_AUTH_EXCLUSION); + else // entry already exists; increment count + DB::Aowow()->query('UPDATE ?_account_bannedIPs SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ?', CFG_FAILED_AUTH_EXCLUSION, $_SERVER['REMOTE_ADDR']); + + if ($ip && $ip['count'] >= CFG_FAILED_AUTH_COUNT && $ip['unbanDate'] >= time()) + return AUTH_IPBANNED; + + $query = DB::Aowow()->SelectRow(' + SELECT a.id, a.passHash, BIT_OR(ab.typeMask) AS bans, status + FROM ?_account a + LEFT JOIN ?_account_banned ab ON a.id = ab.userId AND ab.end > UNIX_TIMESTAMP() + WHERE a.user = ? + GROUP BY a.id', + $name + ); + if (!$query) + return AUTH_WRONGUSER; + + self::$passHash = $query['passHash']; + if (!self::verifyCrypt($pass)) + return AUTH_WRONGPASS; + + if ($query['status'] & ACC_STATUS_NEW) + return AUTH_ACC_INACTIVE; + + // successfull auth; clear bans for this IP + DB::Aowow()->query('DELETE FROM ?_account_bannedIPs WHERE type = 0 AND ip = ?', $_SERVER['REMOTE_ADDR']); + + if ($query['bans'] & (ACC_BAN_PERM | ACC_BAN_TEMP)) + return AUTH_BANNED; + + $user = $query['id']; + $hash = $query['passHash']; + break; + } + case AUTH_MODE_REALM: + { + if (!DB::isConnected(DB_AUTH)) + return AUTH_INTERNAL_ERR; + + $wow = DB::Auth()->selectRow('SELECT a.id, a.sha_pass_hash, ab.active AS hasBan FROM account a LEFT JOIN account_banned ab ON ab.id = a.id WHERE username = ? AND ORDER BY ab.active DESC LIMIT 1', $name); + if (!$wow) + return AUTH_WRONGUSER; + + self::$passHash = $wow['sha_pass_hash']; + if (!self::verifySHA1($pass)) + return AUTH_WRONGPASS; + + if ($wow && !$wow['hasBan']) + if (!self::checkOrCreateInDB($wow['id'], $name)) + return AUTH_INTERNAL_ERR; + + else if ($wow['hasBan']) + return AUTH_BANNED; + + $user = $wow['id']; + break; + } + case AUTH_MODE_EXTERNAL: + { + if (!file_exists('/config/extAuth.php')) + return AUTH_INTERNAL_ERR; + + require '/config/extAuth.php'; + $result = extAuth($name, $pass, $extId); + + if ($result == AUTH_OK && $extId) + { + if (!self::checkOrCreateInDB($extId, $name)) + return AUTH_INTERNAL_ERR; + + $user = $extId; + break; + } + + return $result; + } + default: + return AUTH_INTERNAL_ERR; + } + + // kickstart session + session_unset(); + $_SESSION['user'] = $user; + $_SESSION['hash'] = $hash; + + return AUTH_OK; + } + + // create a linked account for our settings if nessecary + private static function checkOrCreateInDB($extId, $name) + { + if (DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE extId = ?d', $extId)) + return true; + + $ok = DB::Aowow()->query('INSERT INTO ?_account (extId, user, displayName, lastIP, locale, status) VALUES (?d, ?, ?, ?, ?d, ?d)', + $extId, + $name, + Util::ucFirst($name), + isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : '', + User::$localeId, + ACC_STATUS_OK + ); + + return $ok; + } + private static function createSalt() { - static $seed = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; $algo = '$2a'; $strength = '$09'; - $salt = '$'; - - for ($i = 0; $i < 22; $i++) - $salt .= substr($seed, mt_rand(0, 63), 1); + $salt = '$'.Util::createHash(22); return $algo.$strength.$salt; } - private static function hashCrypt($pass) + // crypt used by aowow + public static function hashCrypt($pass) { return crypt($pass, self::createSalt()); } + public static function verifyCrypt($pass, $hash = '') + { + $_ = $hash ?: self::$passHash; + return $_ == crypt($pass, $_); + } + + // sha1 used by TC / MaNGOS private static function hashSHA1($pass) { return sha1(strtoupper(self::$user).':'.strtoupper($pass)); } - private static function verifyCrypt($pass) - { - return self::$passHash == crypt($pass, self::$passHash); - } - private static function verifySHA1($pass) { return self::$passHash == self::hashSHA1($pass); } - private static function convertAuthInfo($pass) - { - self::$passHash = self::hashCrypt($pass); - - DB::Aowow()->query('UPDATE ?_account SET passHash = ? WHERE id = ?d', - self::$passHash, - self::$id - ); - } - public static function getUserGlobals() { - $set = array( - 'commentban' => false, // enforce this for now - 'ratingban' => false, // enforce this for now + $gUser = array( + 'commentban' => (bool)(self::$banStatus & ACC_BAN_COMMENT), + 'ratingban' => (bool)(self::$banStatus & ACC_BAN_RATE), 'id' => self::$id, - 'name' => self::$displayName ? self::$displayName : '', - 'roles' => self::$groups ? self::$groups : 0, - 'permissions' => self::$perms ? self::$perms : 0, + 'name' => self::$displayName, + 'roles' => self::$groups, + 'permissions' => self::$perms, 'cookies' => [] ); - if (!self::$id) - return $set; + if (!self::$id || self::$banStatus & (ACC_BAN_TEMP | ACC_BAN_PERM)) + return $gUser; if ($_ = self::getCharacters()) - $subSet['characters'] = $_; + $gUser['characters'] = $_; if ($_ = self::getProfiles()) - $subSet['profiles'] = $_; + $gUser['profiles'] = $_; if ($_ = self::getWeightScales()) - $subSet['weightscales'] = $_; + $gUser['weightscales'] = $_; if ($_ = self::getCookies()) - $subSet['cookies'] = $_; + $gUser['cookies'] = $_; - return array_merge($set, $subSet); + return $gUser; } public static function getWeightScales() @@ -312,43 +341,37 @@ class User public static function getCharacters($asJSON = true) { - if (empty(self::$characters)) - { - // todo: do after profiler - @include('datasets/ProfilerExampleChar'); + // todo: do after profiler + @include('datasets/ProfilerExampleChar'); - // existing chars on realm(s) - self::$characters = array( - array( - 'name' => $character['name'], - 'realmname' => $character['realm'][1], - 'region' => $character['region'][0], - 'realm' => $character['realm'][0], - 'race' => $character['race'], - 'classs' => $character['classs'], - 'level' => $character['level'], - 'gender' => $character['gender'], - 'pinned' => $character['pinned'] - ) - ); - } + // existing chars on realm(s) + $characters = array( + array( + 'name' => $character['name'], + 'realmname' => $character['realm'][1], + 'region' => $character['region'][0], + 'realm' => $character['realm'][0], + 'race' => $character['race'], + 'classs' => $character['classs'], + 'level' => $character['level'], + 'gender' => $character['gender'], + 'pinned' => $character['pinned'] + ) + ); - return self::$characters; + return $characters; } public static function getProfiles($asJSON = true) { - if (empty(self::$profiles)) - { - // todo => do after profiler - // chars build in profiler - self::$profiles = array( - array('id' => 21, 'name' => 'Example Profile 1', 'race' => 4, 'classs' => 5, 'level' => 72, 'gender' => 1, 'icon' => 'inv_axe_04'), - array('id' => 23, 'name' => 'Example Profile 2', 'race' => 11, 'classs' => 3, 'level' => 17, 'gender' => 0) - ); - } + // todo => do after profiler + // chars build in profiler + $profiles = array( + array('id' => 21, 'name' => 'Example Profile 1', 'race' => 4, 'classs' => 5, 'level' => 72, 'gender' => 1, 'icon' => 'inv_axe_04'), + array('id' => 23, 'name' => 'Example Profile 2', 'race' => 11, 'classs' => 3, 'level' => 17, 'gender' => 0) + ); - return self::$profiles; + return $profiles; } public static function getCookies() @@ -361,23 +384,25 @@ class User return $data; } - public static function writeCookie() + public static function save() { - $cookie = self::$localeId.count(dechex(self::$id)).dechex(self::$id).base64_encode(self::$passHash); - SetCookie(COOKIE_AUTH, $cookie, time() + YEAR); + $_SESSION['user'] = self::$id; + $_SESSION['hash'] = self::$passHash; + $_SESSION['locale'] = self::$localeId; + $_SESSION['timeout'] = self::$expires ? time() + CFG_SESSION_TIMEOUT_DELAY : 0; + // $_SESSION['dataKey'] does not depend on user login status and is set in User::init() } public static function destroy() { - $cookie = self::$localeId.'10'; // id = 0, length of this is 1, empty base64_encode is 0 - SetCookie(COOKIE_AUTH, $cookie, time() + YEAR); + session_unset(); + $_SESSION['locale'] = self::$localeId; // keep locale + $_SESSION['dataKey'] = self::$dataKey; // keep dataKey - self::$id = 0; - self::$displayName = ''; - self::$perms = 0; - self::$groups = 0; - self::$characters = NULL; - self::$profiles = NULL; + self::$id = 0; + self::$displayName = ''; + self::$perms = 0; + self::$groups = U_GROUP_NONE; } } diff --git a/includes/utilities.php b/includes/utilities.php index 06dc07e8..47efcb13 100644 --- a/includes/utilities.php +++ b/includes/utilities.php @@ -1339,6 +1339,11 @@ class Util return str; } + public static function isValidEmail($email) + { + return preg_match('/^([a-z0-9._-]+)(\+[a-z0-9._-]+)?(@[a-z0-9.-]+\.[a-z]{2,4})$/i', $email); + } + public static function loadStaticFile($file, &$result, $localized = false) { $success = true; @@ -1362,6 +1367,17 @@ class Util return $success; } + public static function createHash($length = 40) // just some random numbers for unsafe identifictaion purpose + { + static $seed = ".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + $hash = ''; + + for ($i = 0; $i < $length; $i++) + $hash .= substr($seed, mt_rand(0, 62), 1); + + return $hash; + } + public static function createShowOnMap() { /* diff --git a/index.php b/index.php index 9c297aca..864fb7d3 100644 --- a/index.php +++ b/index.php @@ -27,6 +27,11 @@ switch ($pageCall) case '': // no parameter given -> MainPage $altClass = 'main'; case 'account': // account management [nyi] + if (($_ = (new AjaxHandler($pageParam))->handle($pageCall)) !== null) + { + header('Content-type: application/x-javascript; charset=utf-8'); + die((string)$_); + } case 'achievement': case 'achievements': // case 'arena-team': @@ -72,7 +77,7 @@ switch ($pageCall) case 'talent': // tool: talent calculator case 'title': case 'titles': - case 'user': // tool: user profiles [nyi] + // case 'user': // tool: user profiles [nyi] case 'zone': case 'zones': $_ = ($altClass ?: $pageCall).'Page'; @@ -97,7 +102,7 @@ switch ($pageCall) case 'missing-screenshots': case 'most-comments': case 'random': - require 'pages/miscTools.php'; + (new UtilityPage($pageCall, $pageParam))->display(); break; /* called by script */ case 'data': // tool: dataset-loader @@ -105,10 +110,11 @@ switch ($pageCall) case 'contactus': case 'comment': case 'locale': // subdomain-workaround, change the language - header('Content-type: application/x-javascript; charset=utf-8'); - if (($_ = $ajax->handle($pageCall)) !== null) + if (($_ = (new AjaxHandler($pageParam))->handle($pageCall)) !== null) + { + header('Content-type: application/x-javascript; charset=utf-8'); die((string)$_); - + } break; /* setup */ case 'build': diff --git a/localization/lang.class.php b/localization/lang.class.php index d6902bd4..56cfa33e 100644 --- a/localization/lang.class.php +++ b/localization/lang.class.php @@ -5,6 +5,7 @@ class Lang public static $timeUnits; public static $main; public static $account; + public static $mail; public static $game; public static $search; @@ -99,10 +100,10 @@ class Lang $skill = 0; switch ($prop) { - case 1: $skill = 633; break; // Lockpicking - case 2: $skill = 182; break; // Herbing - case 3: $skill = 186; break; // Mining - case 20: $skill = 773; break; // Scribing + case 1: $skill = 633; break; // Lockpicking + case 2: $skill = 182; break; // Herbing + case 3: $skill = 186; break; // Mining + case 20: $skill = 773; break; // Scribing } if ($skill) diff --git a/localization/locale_dede.php b/localization/locale_dede.php index 22727d93..4de7322f 100644 --- a/localization/locale_dede.php +++ b/localization/locale_dede.php @@ -47,14 +47,6 @@ $lang = array( 'forum' => "Forum", 'n_a' => "n. v.", - // err_title = Fehler in AoWoW - // un_err = Gib bitte deinen Benutzernamen ein - // pwd_err = Gib bitte dein Passwort ein - // signin_msg = Gib bitte deinen Accountnamen ein - // c_pwd = Passwort wiederholen - // facts = Übersicht - // This_Object_cant_be_found = Der Standort dieses Objekts ist nicht bekannt. - // filter 'extSearch' => "Erweiterte Suche", 'addFilter' => "Weiteren Filter hinzufügen", @@ -197,12 +189,14 @@ $lang = array( 'expansions' => ["Classic", "The Burning Crusade", "Wrath of the Lich King"], 'stats' => ["Stärke", "Beweglichkeit", "Ausdauer", "Intelligenz", "Willenskraft"], 'sources' => array( - null, "Hergestellt", "Drop", "PvP", "Quest", "Händler", "Lehrer", "Entdeckung", - "Einlösung", "Talent", "Startausrüstung", "Ereignis", "Erfolg" + null, "Hergestellt", "Drop", "PvP", "Quest", "Händler", + "Lehrer", "Entdeckung", "Einlösung", "Talent", "Startausrüstung", "Ereignis", + "Erfolg" ), 'languages' => array( - 1 => "Orcisch", 2 => "Darnassisch", 3 => "Taurisch", 6 => "Zwergisch", 7 => "Gemeinsprache", 8 => "Dämonisch", 9 => "Titanisch", 10 => "Thalassisch", - 11 => "Drachisch", 12 => "Kalimagisch", 13 => "Gnomisch", 14 => "Trollisch", 33 => "Gossensprache", 35 => "Draeneiisch", 36 => "Zombie", 37 => "Gnomenbinär", 38 => "Goblinbinär" + 1 => "Orcisch", 2 => "Darnassisch", 3 => "Taurisch", 6 => "Zwergisch", 7 => "Gemeinsprache", 8 => "Dämonisch", + 9 => "Titanisch", 10 => "Thalassisch", 11 => "Drachisch", 12 => "Kalimagisch", 13 => "Gnomisch", 14 => "Trollisch", + 33 => "Gossensprache", 35 => "Draeneiisch", 36 => "Zombie", 37 => "Gnomenbinär", 38 => "Goblinbinär" ), 'gl' => [null, "Erhebliche", "Geringe"], 'si' => [1 => "Allianz", -1 => "Nur für Allianz", 2 => "Horde", -2 => "Nur für Horde", 3 => "Beide"], @@ -213,72 +207,118 @@ $lang = array( 'ra' => [-2 => "Horde", -1 => "Allianz", "Beide", "Mensch", "Orc", "Zwerg", "Nachtelf", "Untoter", "Tauren", "Gnom", "Troll", null, "Blutelf", "Draenei"], 'rep' => ["Hasserfüllt", "Feindselig", "Unfreundlich", "Neutral", "Freundlich", "Wohlwollend", "Respektvoll", "Ehrfürchtig"], 'st' => array( - "Vorgabe", "Katzengestalt", "Baum des Lebens", "Reisegestalt", "Wassergestalt", - "Bärengestalt", null, null, "Terrorbärengestalt", null, - null, null, null, "Schattentanz", null, - null, "Geisterwolf", "Kampfhaltung", "Verteidigungshaltung", "Berserkerhaltung", - null, null, "Metamorphosis", null, null, - null, null, "Schnelle Fluggestalt", "Schattengestalt", "Fluggestalt", - "Verstohlenheit", "Mondkingestalt", "Geist der Erlösung" + "Vorgabe", "Katzengestalt", "Baum des Lebens", "Reisegestalt", "Wassergestalt", "Bärengestalt", + null, null, "Terrorbärengestalt", null, null, null, + null, "Schattentanz", null, null, "Geisterwolf", "Kampfhaltung", + "Verteidigungshaltung", "Berserkerhaltung", null, null, "Metamorphosis", null, + null, null, null, "Schnelle Fluggestalt", "Schattengestalt", "Fluggestalt", + "Verstohlenheit", "Mondkingestalt", "Geist der Erlösung" ), 'me' => array( - null, "Bezaubert", "Desorientiert", "Entwaffnet", "Abgelenkt", "Flüchtend", "Ergriffen", "Unbeweglich", - "Befriedet", "Schweigend", "Schlafend", "Verlangsamt", "Betäubt", "Eingefroren", "Handlungsunfähig", "Blutend", - "Heilung", "Verwandelt", "Verbannt", "Abgeschirmt", "Gefesselt", "Reitend", "Verführt", "Vertrieben", - "Entsetzt", "Unverwundbar", "Unterbrochen", "Benommen", "Entdeckung", "Unverwundbar", "Kopfnuss", "Wütend" + null, "Bezaubert", "Desorientiert", "Entwaffnet", "Abgelenkt", "Flüchtend", + "Ergriffen", "Unbeweglich", "Befriedet", "Schweigend", "Schlafend", "Verlangsamt", + "Betäubt", "Eingefroren", "Handlungsunfähig", "Blutend", "Heilung", "Verwandelt", + "Verbannt", "Abgeschirmt", "Gefesselt", "Reitend", "Verführt", "Vertrieben", + "Entsetzt", "Unverwundbar", "Unterbrochen", "Benommen", "Entdeckung", "Unverwundbar", + "Kopfnuss", "Wütend" ), 'ct' => array( - "Nicht kategorisiert", "Wildtier", "Drachkin", "Dämon", "Elementar", "Riese", "Untoter", "Humanoid", - "Tier", "Mechanisch", "Nicht spezifiziert", "Totem", "Haustier", "Gaswolke" + "Nicht kategorisiert", "Wildtier", "Drachkin", "Dämon", "Elementar", "Riese", + "Untoter", "Humanoid", "Tier", "Mechanisch", "Nicht spezifiziert", "Totem", + "Haustier", "Gaswolke" ), 'fa' => array( - 1 => "Wolf", 2 => "Katze", 3 => "Spinne", 4 => "Bär", 5 => "Eber", 6 => "Krokilisk", 7 => "Aasvogel", 8 => "Krebs", - 9 => "Gorilla", 11 => "Raptor", 12 => "Weitschreiter", 20 => "Skorpid", 21 => "Schildkröte", 24 => "Fledermaus", 25 => "Hyäne", 26 => "Raubvogel", - 27 => "Windnatter", 30 => "Drachenfalke", 31 => "Felshetzer", 32 => "Sphärenjäger", 33 => "Sporensegler", 34 => "Netherrochen", 35 => "Schlange", 37 => "Motte", - 38 => "Schimäre", 39 => "Teufelssaurier", 41 => "Silithid", 42 => "Wurm", 43 => "Rhinozeros", 44 => "Wespe", 45 => "Kernhund", 46 => "Geisterbestie" + 1 => "Wolf", 2 => "Katze", 3 => "Spinne", 4 => "Bär", 5 => "Eber", 6 => "Krokilisk", + 7 => "Aasvogel", 8 => "Krebs", 9 => "Gorilla", 11 => "Raptor", 12 => "Weitschreiter", 20 => "Skorpid", + 21 => "Schildkröte", 24 => "Fledermaus", 25 => "Hyäne", 26 => "Raubvogel", 27 => "Windnatter", 30 => "Drachenfalke", + 31 => "Felshetzer", 32 => "Sphärenjäger", 33 => "Sporensegler", 34 => "Netherrochen", 35 => "Schlange", 37 => "Motte", + 38 => "Schimäre", 39 => "Teufelssaurier", 41 => "Silithid", 42 => "Wurm", 43 => "Rhinozeros", 44 => "Wespe", + 45 => "Kernhund", 46 => "Geisterbestie" ), 'pvpRank' => array( - null, "Gefreiter / Späher", "Fußknecht / Grunzer", - "Landsknecht / Waffenträger", "Feldwebel / Schlachtrufer", "Fähnrich / Rottenmeister", - "Leutnant / Steingardist", "Hauptmann / Blutgardist", "Kürassier / Zornbringer", - "Ritter der Allianz / Klinge der Horde", "Feldkomandant / Feldherr", "Rittmeister / Sturmreiter", - "Marschall / Kriegsherr", "Feldmarschall / Kriegsfürst", "Großmarschall / Oberster Kriegsfürst" + null, "Gefreiter / Späher", "Fußknecht / Grunzer", + "Landsknecht / Waffenträger", "Feldwebel / Schlachtrufer", "Fähnrich / Rottenmeister", + "Leutnant / Steingardist", "Hauptmann / Blutgardist", "Kürassier / Zornbringer", + "Ritter der Allianz / Klinge der Horde", "Feldkomandant / Feldherr", "Rittmeister / Sturmreiter", + "Marschall / Kriegsherr", "Feldmarschall / Kriegsfürst", "Großmarschall / Oberster Kriegsfürst" ), ), 'account' => array( + 'title' => "Aowow-Konto", + 'email' => "E-Mail-Adresse", + 'continue' => "Fortsetzen", + 'groups' => array( + -1 => "Keine", "Tester", "Administrator", "Editor", "Moderator", "Bürokrat", + "Entwickler", "VIP", "Blogger", "Premium", "Übersetzer", "Handelsvertreter", + "Screenshot-Verwalter", "Video-Verwalter" + ), + // signIn 'doSignIn' => "Mit Eurem AoWoW-Konto anmelden", + 'signIn' => "Anmelden", 'user' => "Benutzername", 'pass' => "Kennwort", 'rememberMe' => "Angemeldet bleiben", 'forgot' => "Vergessen", - 'accNoneYet' => "Noch kein Konto", - 'accCreateNow' => "Jetzt eins erstellen", - 'userNotFound' => "Ein Konto mit diesem Namen existiert nicht", - 'userBanned' => "Dieses Konto wurde geschlossen", - 'passMismatch' => "Die eingegebenen Passwörter stimmen nicht überein", - 'loginsExceeded'=> "Die maximale Anzahl an Login-Versuchen von dieser IP wurde überschritten. Bitte versuchen Sie es in %s Minuten noch einmal.", - 'nameInUse' => "Es existiert bereits ein Konto mit diesem Namen", - 'email' => "E-Mail-Adresse", - 'unkError' => "Unbekannter Fehler bei der Accounterstellung", - 'accCreate' => "Konto erstellen", - 'passConfirm' => "Passwort bestätigen", - 'signup' => "Anmelden", - 'requestName' => "Username Request", - 'resetPass' => "Password Reset", - 'emailInvalid' => "Diese E-Mail-Adresse ist ungültig.", - 'emailUnknown' => "Die E-Mail-Adresse, die Ihr eingegeben habt, ist mit keinem Konto verbunden.

Falls Ihr die E-Mail-Adresse vergessen habt, mit der Ihr Euer Konto erstellt habt, kontaktiert Ihr bitte feedback@aowow.com für Hilfestellung.", - 'passJustSend' => "Eine Nachricht mit einem neuen Passwort wurde soeben an %s versandt.", - 'nameJustSend' => "Eine Nachricht mit Eurem Benutzernamen wurde soeben an %s versandt.", - 'wrongPass' => "Falsches Passwort", + 'forgotUser' => "Benutzername", + 'forgotPass' => "Kennwort", + 'accCreate' => 'Noch kein Konto? Jetzt eins erstellen!', + + // recovery + 'recoverUser' => "Benutzernamenanfrage", + 'recoverPass' => "Kennwort zurücksetzen: Schritt %s von 2", + 'newPass' => "Neues Kennwort", + + // creation + 'register' => "Registrierung: Schritt %s von 2", + + // dashboard 'ipAddress' => "IP-Adresse", 'lastIP' => "Letzte bekannte IP", 'joinDate' => "Mitglied seit", 'lastLogin' => "Letzter Besuch", - 'userGroups' => "Role", + 'userGroups' => "Rolle", 'myAccount' => "Mein Account", 'editAccount' => "Benutze die folgenden Formulare um deine Account-Informationen zu aktualisieren", 'publicDesc' => "Öffentliche Beschreibung", 'viewPubDesc' => 'Die Beschreibung in deinem öffentlichen Profil ansehen', + + // bans + 'accBanned' => "Dieses Konto wurde geschlossen", + 'bannedBy' => "Gebannt durch", + 'ends' => "Endet am", + 'permanent' => "Der Bann ist permanent", + 'reason' => "Grund", + 'noReason' => "Es wurde kein Grund angegeben.", + + // form-text + 'emailInvalid' => "Diese E-Mail-Adresse ist ungültig.", // message_emailnotvalid + 'emailNotFound' => "Die E-Mail-Adresse, die Ihr eingegeben habt, ist mit keinem Konto verbunden.

Falls Ihr die E-Mail-Adresse vergessen habt, mit der Ihr Euer Konto erstellt habt, kontaktiert Ihr bitte ".CFG_CONTACT_EMAIL." für Hilfestellung.", + 'createAccSent' => "Eine Nachricht wurde soeben an %s versandt. Folgt den Anweisungen um euer Konto zu erstellen.", + 'recovUserSent' => "Eine Nachricht wurde soeben an %s versandt. Folgt den Anweisungen um euren Benutzernamen zu erhalten.", + 'recovPassSent' => "Eine Nachricht wurde soeben an %s versandt. Folgt den Anweisungen um euer Kennwort zurückzusetzen.", + 'accActivated' => 'Euer Konto wurde soeben aktiviert.
Ihr könnt euch nun anmelden', + 'userNotFound' => "Ein Konto mit diesem Namen existiert nicht.", + 'wrongPass' => "Dieses Kennwort ist ungültig.", + 'accInactive' => "Dieses Konto wurde bisher nicht aktiviert.", + 'loginExceeded' => "Die maximale Anzahl an Anmelde-Versuchen von dieser IP wurde überschritten. Bitte versucht es in %s erneut.", + 'signupExceeded'=> "Die maximale Anzahl an Regustrierungen von dieser IP wurde überschritten. Bitte versucht es in %s erneut.", + 'errNameLength' => "Euer Benutzername muss mindestens 4 Zeichen lang sein.", // message_usernamemin + 'errNameChars' => "Euer Benutzername kann nur aus Buchstaben und Zahlen bestehen.", // message_usernamenotvalid + 'errPassLength' => "Euer Kennwort muss mindestens 6 Zeichen lang sein.", // message_passwordmin + 'passMismatch' => "Die eingegebenen Kennworte stimmen nicht überein.", + 'nameInUse' => "Es existiert bereits ein Konto mit diesem Namen.", + 'mailInUse' => "Diese E-Mail-Adresse ist bereits mit einem Konto verbunden.", + 'intError' => "Ein interner Fehler ist aufgetreten.", + 'intError2' => "Ein interner Fehler ist aufgetreten. (%s)", + 'isRecovering' => "Dieses Konto wird bereits wiederhergestellt. Folgt den Anweisungen in der Nachricht oder wartet %s bis das Token verfällt.", + 'passCheckFail' => "Die Kennwörter stimmen nicht überein.", // message_passwordsdonotmatch + 'newPassDiff' => "Euer neues Kennwort muss sich von eurem alten Kennwort unterscheiden." // message_newpassdifferent + ), + 'mail' => array( + 'tokenExpires' => "Das Token wird in %s verfallen.", + 'accConfirm' => ["Kontobestätigung", "Willkommen bei ".CFG_NAME_SHORT."!\r\n\r\nKlicke auf den Link um euren Account zu aktivieren.\r\n\r\n".HOST_URL."?account=signup&token=%s\r\n\r\nFalls Ihr diese Mail nicht angefordert habt kann sie einfach ignoriert werden."], + 'recoverUser' => ["Benutzernamenanfrage", "Folgt diesem Link um euch anzumelden.\r\n\r\n".HOST_URL."?account=signin&token=%s\r\n\r\nFalls Ihr diese Mail nicht angefordert habt kann sie einfach ignoriert werden."], + 'resetPass' => ["Kennwortreset", "Folgt diesem Link um euer Kennwort zurückzusetzen.\r\n\r\n".HOST_URL."?account=forgotpassword&token=%s\r\n\r\nFalls Ihr diese Mail nicht angefordert habt kann sie einfach ignoriert werden."] ), 'gameObject' => array( 'cat' => [0 => "Anderes", 9 => "Bücher", 3 => "Behälter", -5 => "Truhen", 25 => "Fischschwärme", -3 => "Kräuter", -4 => "Erzadern", -2 => "Quest", -6 => "Werkzeuge"], diff --git a/localization/locale_enus.php b/localization/locale_enus.php index b18c3c98..a8d872c1 100644 --- a/localization/locale_enus.php +++ b/localization/locale_enus.php @@ -184,12 +184,14 @@ $lang = array( 'expansions' => ["Classic", "The Burning Crusade", "Wrath of the Lich King"], 'stats' => ["Strength", "Agility", "Stamina", "Intellect", "Spirit"], 'sources' => array( - null, "Crafted", "Drop", "PvP", "Quest", "Vendor", "Trainer", "Discovery", - "Redemption", "Talent", "Starter", "Event", "Achievement" + null, "Crafted", "Drop", "PvP", "Quest", "Vendor", + "Trainer", "Discovery", "Redemption", "Talent", "Starter", "Event", + "Achievement" ), 'languages' => array( - 1 => "Orcish", 2 => "Darnassian", 3 => "Taurahe", 6 => "Dwarvish", 7 => "Common", 8 => "Demonic", 9 => "Titan", 10 => "Thalassian", - 11 => "Draconic", 12 => "Kalimag", 13 => "Gnomish", 14 => "Troll", 33 => "Gutterspeak", 35 => "Draenei", 36 => "Zombie", 37 => "Gnomish Binary", 38 => "Goblin Binary" + 1 => "Orcish", 2 => "Darnassian", 3 => "Taurahe", 6 => "Dwarvish", 7 => "Common", 8 => "Demonic", + 9 => "Titan", 10 => "Thalassian", 11 => "Draconic", 12 => "Kalimag", 13 => "Gnomish", 14 => "Troll", + 33 => "Gutterspeak", 35 => "Draenei", 36 => "Zombie", 37 => "Gnomish Binary", 38 => "Goblin Binary" ), 'gl' => [null, "Major", "Minor"], 'si' => [1 => "Alliance", -1 => "Alliance only", 2 => "Horde", -2 => "Horde only", 3 => "Both"], @@ -200,72 +202,118 @@ $lang = array( 'ra' => [-2 => "Horde", -1 => "Alliance", "Both", "Human", "Orc", "Dwarf", "Night Elf", "Undead", "Tauren", "Gnome", "Troll", null, "Blood Elf", "Draenei"], 'rep' => ["Hated", "Hostile", "Unfriendly", "Neutral", "Friendly", "Honored", "Revered", "Exalted"], 'st' => array( - "Default", "Cat Form", "Tree of Life", "Travel Form", "Aquatic Form", - "Bear From", null, null, "Dire Bear Form", null, - null, null, null, "Shadowdance", null, - null, "Ghostwolf", "Battle Stance", "Defensive Stance", "Berserker Stance", - null, null, "Metamorphosis", null, null, - null, null, "Swift Flight Form", "Shadow Form", "Flight Form", - "Stealth", "Moonkin Form", "Spirit of Redemption" + "Default", "Cat Form", "Tree of Life", "Travel Form", "Aquatic Form", "Bear From", + null, null, "Dire Bear Form", null, null, null, + null, "Shadowdance", null, null, "Ghostwolf", "Battle Stance", + "Defensive Stance", "Berserker Stance", null, null, "Metamorphosis", null, + null, null, null, "Swift Flight Form", "Shadow Form", "Flight Form", + "Stealth", "Moonkin Form", "Spirit of Redemption" ), 'me' => array( - null, "Charmed", "Disoriented", "Disarmed", "Distracted", "Fleeing", "Gripped", "Rooted", - "Pacified", "Silenced", "Asleep", "Ensnared", "Stunned", "Frozen", "Incapacitated", "Bleeding", - "Healing", "Polymorphed", "Banished", "Shielded", "Shackled", "Mounted", "Seduced", "Turned", - "Horrified", "Invulnerable", "Interrupted", "Dazed", "Discovery", "Invulnerable", "Sapped", "Enraged" + null, "Charmed", "Disoriented", "Disarmed", "Distracted", "Fleeing", + "Gripped", "Rooted", "Pacified", "Silenced", "Asleep", "Ensnared", + "Stunned", "Frozen", "Incapacitated", "Bleeding", "Healing", "Polymorphed", + "Banished", "Shielded", "Shackled", "Mounted", "Seduced", "Turned", + "Horrified", "Invulnerable", "Interrupted", "Dazed", "Discovery", "Invulnerable", + "Sapped", "Enraged" ), 'ct' => array( - "Uncategorized", "Beast", "Dragonkin", "Demon", "Elemental", "Giant", "Undead", "Humanoid", - "Critter", "Mechanical", "Not specified", "Totem", "Non-combat Pet", "Gas Cloud" + "Uncategorized", "Beast", "Dragonkin", "Demon", "Elemental", "Giant", + "Undead", "Humanoid", "Critter", "Mechanical", "Not specified", "Totem", + "Non-combat Pet", "Gas Cloud" ), 'fa' => array( - 1 => "Wolf", 2 => "Cat", 3 => "Spider", 4 => "Bear", 5 => "Boar", 6 => "Crocolisk", 7 => "Carrion Bird", 8 => "Crab", - 9 => "Gorilla", 11 => "Raptor", 12 => "Tallstrider", 20 => "Scorpid", 21 => "Turtle", 24 => "Bat", 25 => "Hyena", 26 => "Bird of Prey", - 27 => "Wind Serpent", 30 => "Dragonhawk", 31 => "Ravager", 32 => "Warp Stalker", 33 => "Sporebat", 34 => "Nether Ray", 35 => "Serpent", 37 => "Moth", - 38 => "Chimaera", 39 => "Devilsaur", 41 => "Silithid", 42 => "Worm", 43 => "Rhino", 44 => "Wasp", 45 => "Core Hound", 46 => "Spirit Beast" + 1 => "Wolf", 2 => "Cat", 3 => "Spider", 4 => "Bear", 5 => "Boar", 6 => "Crocolisk", + 7 => "Carrion Bird", 8 => "Crab", 9 => "Gorilla", 11 => "Raptor", 12 => "Tallstrider", 20 => "Scorpid", + 21 => "Turtle", 24 => "Bat", 25 => "Hyena", 26 => "Bird of Prey", 27 => "Wind Serpent", 30 => "Dragonhawk", + 31 => "Ravager", 32 => "Warp Stalker", 33 => "Sporebat", 34 => "Nether Ray", 35 => "Serpent", 37 => "Moth", + 38 => "Chimaera", 39 => "Devilsaur", 41 => "Silithid", 42 => "Worm", 43 => "Rhino", 44 => "Wasp", + 45 => "Core Hound", 46 => "Spirit Beast" ), 'pvpRank' => array( - null, "Private / Scout", "Corporal / Grunt", - "Sergeant / Sergeant", "Master Sergeant / Senior Sergeant", "Sergeant Major / First Sergeant", - "Knight / Stone Guard", "Knight-Lieutenant / Blood Guard", "Knight-Captain / Legionnare", - "Knight-Champion / Centurion", "Lieutenant Commander / Champion", "Commander / Lieutenant General", - "Marshal / General", "Field Marshal / Warlord", "Grand Marshal / High Warlord" + null, "Private / Scout", "Corporal / Grunt", + "Sergeant / Sergeant", "Master Sergeant / Senior Sergeant", "Sergeant Major / First Sergeant", + "Knight / Stone Guard", "Knight-Lieutenant / Blood Guard", "Knight-Captain / Legionnare", + "Knight-Champion / Centurion", "Lieutenant Commander / Champion", "Commander / Lieutenant General", + "Marshal / General", "Field Marshal / Warlord", "Grand Marshal / High Warlord" ), ), 'account' => array( + 'title' => "Aowow Account", + 'email' => "Email address", + 'continue' => "Continue", + 'groups' => array( + -1 => "None", "Tester", "Administrator", "Editor", "Moderator", "Bureaucrat", + "Developer", "VIP", "Blogger", "Premium", "Localizer", "Sales agent", + "Screenshot manager", "Video manager" + ), + // signIn 'doSignIn' => "Log in to your AoWoW Account", + 'signIn' => "Log In", 'user' => "Username", 'pass' => "Password", 'rememberMe' => "Stay logged in", 'forgot' => "Forgot", - 'accNoneYet' => "Don't have an account", - 'accCreateNow' => "Create one now", - 'userNotFound' => "Such user does not exists", - 'userBanned' => "This Account was closed", - 'passMismatch' => "Entered passwords does not match", - 'loginsExceeded'=> "The maximum number of logins from this IP has been exceeded. Please try again in %s minutes.", - 'nameInUse' => "Such user already exists", - 'email' => "Email address", - 'unkError' => "Unknown error on account create", - 'accCreate' => "Create your account", - 'passConfirm' => "Confirm password", - 'signup' => "Signup", - 'requestName' => "Username Request", - 'resetPass' => "Password Reset", - 'emailInvalid' => "This email address is invalid.", - 'emailUnknown' => "The email address you entered is not associated with any account.

If you forgot the email you registered your account with email feedback@aowow.com for assistance.", - 'passJustSend' => "An email containing a new password was just sent to %s", - 'nameJustSend' => "An email containing your username was just sent to %s", - 'wrongPass' => "Wrong Password", + 'forgotUser' => "Username", + 'forgotPass' => "Password", + 'accCreate' => 'Don\'t have an account? Create one now!', + + // recovery + 'recoverUser' => "Username Request", + 'recoverPass' => "Password Reset: Step %s of 2", + 'newPass' => "New Password", + + // creation + 'register' => "Registration - Step %s of 2", + + // dashboard 'ipAddress' => "IP-Adress", 'lastIP' => "last used IP", 'joinDate' => "Joined", 'lastLogin' => "Last visit", - 'userGroups' => "Rolle", + 'userGroups' => "Role", 'myAccount' => "My Account", 'editAccount' => "Simply use the forms below to update your account information", 'publicDesc' => "Public Description", 'viewPubDesc' => 'View your Public Description in your Profile Page', + + // bans + 'accBanned' => "This Account was closed", + 'bannedBy' => "Banned by", + 'ends' => "Ends on", + 'permanent' => "The ban is permanent", + 'reason' => "Reason", + 'noReason' => "No reason was given.", + + // form-text + 'emailInvalid' => "That email address is not valid.", // message_emailnotvalid + 'emailNotFound' => "The email address you entered is not associated with any account.

If you forgot the email you registered your account with email ".CFG_CONTACT_EMAIL." for assistance.", + 'createAccSent' => "An email was sent to %s. Simply follow the instructions to create your account.", + 'recovUserSent' => "An email was sent to %s. Simply follow the instructions to recover your username.", + 'recovPassSent' => "An email was sent to %s. Simply follow the instructions to reset your password.", + 'accActivated' => 'Your account has been activated.
Proceed to sign in', + 'userNotFound' => "The username you entered does not exists.", + 'wrongPass' => "That password is not vaild.", + 'accInactive' => "That account has not yet been confirmed active.", + 'loginExceeded' => "The maximum number of logins from this IP has been exceeded. Please try again in %s.", + 'signupExceeded'=> "The maximum number of signups from this IP has been exceeded. Please try again in %s.", + 'errNameLength' => "Your username must be at least 4 characters long.", // message_usernamemin + 'errNameChars' => "Your username can only contain letters and numbers.", // message_usernamenotvalid + 'errPassLength' => "Your password must be at least 6 characters long.", // message_passwordmin + 'passMismatch' => "The passwords you entered do not match.", + 'nameInUse' => "That username is already taken.", + 'mailInUse' => "That email is already registered to an account.", + 'intError' => "An internal error occured.", + 'intError2' => "An internal error occured. (%s)", + 'isRecovering' => "This account is already recovering. Follow the instructions in your email or wait %s for the token to expire.", + 'passCheckFail' => "Passwords do not match.", // message_passwordsdonotmatch + 'newPassDiff' => "Your new password must be different than your previous one." // message_newpassdifferent + ), + 'mail' => array( + 'tokenExpires' => "This token expires in %s.", + 'accConfirm' => ["Account Confirmation", "Welcome to ".CFG_NAME_SHORT."!\r\n\r\nClick the Link below to activate your account.\r\n\r\n".HOST_URL."?account=signup&token=%s\r\n\r\nIf you did not request this mail simply ignore it."], + 'recoverUser' => ["User Recovery", "Follow this link to log in.\r\n\r\n".HOST_URL."?account=signin&token=%s\r\n\r\nIf you did not request this mail simply ignore it."], + 'resetPass' => ["Password Reset", "Follow this link to reset your password.\r\n\r\n".HOST_URL."?account=forgotpassword&token=%s\r\n\r\nIf you did not request this mail simply ignore it."] ), 'gameObject' => array( 'cat' => [0 => "Other", 9 => "Books", 3 => "Containers", -5 => "Chests", 25 => "Fishing Pools", -3 => "Herbs", -4 => "Mineral Veins", -2 => "Quest", -6 => "Tools"], diff --git a/localization/locale_eses.php b/localization/locale_eses.php index d2e63aed..51498214 100644 --- a/localization/locale_eses.php +++ b/localization/locale_eses.php @@ -237,7 +237,84 @@ $lang = array( "Marshal / General", "Field Marshal / Warlord", "Grand Marshal / High Warlord" ), ), - 'account' => [], + 'account' => array( + 'title' => "Cuenta de Aowow", + 'email' => "Dirección de correo electrónico", + 'continue' => "Continuar", + 'groups' => array( + -1 => "Ninguno", "Probador", "Administrador", "Editor", "Moderador", "Burócrata", + "Desarrollador", "VIP", "Bloggor", "Premium", "Traductor", "Agente de ventas", + "Gestor de Capturas de pantalla","Gestor de vídeos" + ), + + // signIn + 'doSignIn' => "Iniciar sesión con tu cuenta de Aowow", + 'signIn' => "Iniciar sesión", + 'user' => "Nombre de usuario", + 'pass' => "Contraseña", + 'rememberMe' => "Seguir conectado", + 'forgot' => "Se me olvidó mi", + 'forgotUser' => "Nombre de usuario", + 'forgotPass' => "Contraseña", + 'accCreate ' => '¿No tienes una cuenta? ¡Crea una ahora!', + + // recovery + 'recoverUser' => "Pedir nombre de usuario", + 'recoverPass' => "Reiniciar contraseña: Paso %s de 2", + 'newPass' => "New Password", + + // creation + 'register' => "Inscripción: Paso %s de 2", + + // dashboard + 'ipAddress' => "IP-Adress", + 'lastIP' => "last used IP", + 'joinDate' => "Joined", + 'lastLogin' => "Last visit", + 'userGroups' => "Role", + 'myAccount' => "My Account", + 'editAccount' => "Simply use the forms below to update your account information", + 'publicDesc' => "Public Description", + 'viewPubDesc' => 'View your Public Description in your Profile Page', + + // bans + 'accBanned' => "This Account was closed", + 'bannedBy' => "Banned by", + 'ends' => "Ends on", + 'permanent' => "The ban is permanent", + 'reason' => "Reason", + 'noReason' => "No reason was given.", + + // form-text + 'emailInvalid' => "Esa dirección de correo electrónico no es válida.", // message_emailnotvalid + 'emailNotFound' => "The email address you entered is not associated with any account.

If you forgot the email you registered your account with email ".CFG_CONTACT_EMAIL." for assistance.", + 'createAccSent' => "An email was sent to %s. Simply follow the instructions to create your account.", + 'recovUserSent' => "An email was sent to %s. Simply follow the instructions to recover your username.", + 'recovPassSent' => "An email was sent to %s. Simply follow the instructions to reset your password.", + 'accActivated' => 'Your account has been activated.
Proceed to sign in', + 'userNotFound' => "The username you entered does not exists.", + 'wrongPass' => "That password is not vaild.", + 'accInactive' => "That account has not yet been confirmed active.", + 'loginExceeded' => "The maximum number of logins from this IP has been exceeded. Please try again in %s.", + 'signupExceeded'=> "The maximum number of signups from this IP has been exceeded. Please try again in %s.", + 'errNameLength' => "Tu nombre de usuario tiene que tener por lo menos cuatro caracteres.", // message_usernamemin + 'errNameChars' => "Tu nombre de usuario solo puede contener números y letras.", // message_usernamenotvalid + 'errPassLength' => "Tu contraseña tiene que tener por lo menos seis caracteres.", // message_passwordmin + 'passMismatch' => "The passwords you entered do not match.", + 'nameInUse' => "That username is already taken.", + 'mailInUse' => "That email is already registered to an account.", + 'intError' => "An internal error occured.", + 'intError2' => "An internal error occured. (%s)", + 'isRecovering' => "This account is already recovering. Follow the instructions in your email or wait %s for the token to expire.", + 'passCheckFail' => "Las contraseñas no son iguales.", // message_passwordsdonotmatch + 'newPassDiff' => "Su nueva contraseña tiene que ser diferente a Su contraseña anterior." // message_newpassdifferent + ), + 'mail' => array( + 'tokenExpires' => "This token expires in %s.", + 'accConfirm' => ["Account Confirmation", "Welcome to ".CFG_NAME_SHORT."!\r\n\r\nClick the Link below to activate your account.\r\n\r\n".HOST_URL."?account=signup&token=%s\r\n\r\nIf you did not request this mail simply ignore it."], + 'recoverUser' => ["User Recovery", "Follow this link to log in.\r\n\r\n".HOST_URL."?account=signin&token=%s\r\n\r\nIf you did not request this mail simply ignore it."], + 'resetPass' => ["Password Reset", "Follow this link to reset your password.\r\n\r\n".HOST_URL."?account=forgotpassword&token=%s\r\n\r\nIf you did not request this mail simply ignore it."] + ), 'gameObject' => array( 'cat' => [0 => "Otros", 9 => "Libros", 3 => "Contenedores", -5 => "Cofres", 25 => "Bancos de peces", -3 => "Hierbas", -4 => "Venas de minerales", -2 => "Misiones", -6 => "Herramientas"], 'type' => [ 9 => "Libro", 3 => "Contenedore", -5 => "Cofre", 25 => "", -3 => "Hierba", -4 => "Filóne de mineral", -2 => "Misión", -6 => ""], diff --git a/localization/locale_frfr.php b/localization/locale_frfr.php index a77b470d..f35ed465 100644 --- a/localization/locale_frfr.php +++ b/localization/locale_frfr.php @@ -237,7 +237,83 @@ $lang = array( "Marshal / General", "Field Marshal / Warlord", "Grand Marshal / High Warlord" ), ), - 'account' => [], + 'account' => array( + 'title' => "Compte Aowow", + 'email' => "Courriel", + 'continue' => "Poursuivre", + 'groups' => array( + -1 => "None", "Testeur", "Administrateur", "Éditeur", "Modérateur", "Bureaucrate", + "Développeur", "VIP", "Bloggeur", "Premium", "Traducteur", "Agent de ventes", + "Gestionnaire de capture d'écran","Gestionnaire de vidéos" + ), + // signIn + 'doSignIn' => "Connexion à votre compte Aowow", + 'signIn' => "Connexion", + 'user' => "Nom d'utilisateur", + 'pass' => "Mot de passe", + 'rememberMe' => "Rester connecté", + 'forgot' => "Oublié", + 'forgotUser' => "Nom d'utilisateur", + 'forgotPass' => "Mot de passe", + 'accCreate' => 'Vous n\'avez pas encore de compte ? Créez-en un maintenant !', + + // recovery + 'recoverUser' => "Demande de nom d'utilisateur", + 'recoverPass' => "Changement de mot de passe : Étape %s de 2", + 'newPass' => "New Password", + + // creation + 'register' => "Enregistrement : Étape %s de 2", + + // dashboard + 'ipAddress' => "IP-Adress", + 'lastIP' => "last used IP", + 'joinDate' => "Joined", + 'lastLogin' => "Last visit", + 'userGroups' => "Role", + 'myAccount' => "My Account", + 'editAccount' => "Simply use the forms below to update your account information", + 'publicDesc' => "Public Description", + 'viewPubDesc' => 'View your Public Description in your Profile Page', + + // bans + 'accBanned' => "This Account was closed", + 'bannedBy' => "Banned by", + 'ends' => "Ends on", + 'permanent' => "The ban is permanent", + 'reason' => "Reason", + 'noReason' => "No reason was given.", + + // form-text + 'emailInvalid' => "Cette adresse courriel est invalide.", // message_emailnotvalid + 'emailNotFound' => "The email address you entered is not associated with any account.

If you forgot the email you registered your account with email ".CFG_CONTACT_EMAIL." for assistance.", + 'createAccSent' => "An email was sent to %s. Simply follow the instructions to create your account.", + 'recovUserSent' => "An email was sent to %s. Simply follow the instructions to recover your username.", + 'recovPassSent' => "An email was sent to %s. Simply follow the instructions to reset your password.", + 'accActivated' => 'Your account has been activated.
Proceed to sign in', + 'userNotFound' => "The username you entered does not exists.", + 'wrongPass' => "That password is not vaild.", + 'accInactive' => "That account has not yet been confirmed active.", + 'loginExceeded' => "The maximum number of logins from this IP has been exceeded. Please try again in %s.", + 'signupExceeded'=> "The maximum number of signups from this IP has been exceeded. Please try again in %s.", + 'errNameLength' => "Votre nom d'utilisateur doit faire au moins 4 caractères de long.", // message_usernamemin + 'errNameChars' => "Votre nom d'utilisateur doit contenir seulement des lettres et des chiffres.", // message_usernamenotvalid + 'errPassLength' => "Votre mot de passe doit faire au moins 6 caractères de long.", // message_passwordmin + 'passMismatch' => "The passwords you entered do not match.", + 'nameInUse' => "That username is already taken.", + 'mailInUse' => "That email is already registered to an account.", + 'intError' => "An internal error occured.", + 'intError2' => "An internal error occured. (%s)", + 'isRecovering' => "This account is already recovering. Follow the instructions in your email or wait %s for the token to expire.", + 'passCheckFail' => "Les mots de passe ne correspondent pas.", // message_passwordsdonotmatch + 'newPassDiff' => "Votre nouveau mot de passe doit être différent de l'ancien." // message_newpassdifferent + ), + 'mail' => array( + 'tokenExpires' => "This token expires in %s.", + 'accConfirm' => ["Account Confirmation", "Welcome to ".CFG_NAME_SHORT."!\r\n\r\nClick the Link below to activate your account.\r\n\r\n".HOST_URL."?account=signup&token=%s\r\n\r\nIf you did not request this mail simply ignore it."], + 'recoverUser' => ["User Recovery", "Follow this link to log in.\r\n\r\n".HOST_URL."?account=signin&token=%s\r\n\r\nIf you did not request this mail simply ignore it."], + 'resetPass' => ["Password Reset", "Follow this link to reset your password.\r\n\r\n".HOST_URL."?account=forgotpassword&token=%s\r\n\r\nIf you did not request this mail simply ignore it."] + ), 'gameObject' => array( 'cat' => [0 => "Autre", 9 => "Livres", 3 => "Conteneurs", -5 => "Coffres", 25 => "Bancs de poissons", -3 => "Herbes", -4 => "Filons de minerai", -2 => "Quêtes", -6 => "Outils"], 'type' => [ 9 => "Livre", 3 => "Conteneur", -5 => "Coffre", 25 => "", -3 => "Herbe", -4 => "Filon de minerai", -2 => "Quête", -6 => ""], diff --git a/localization/locale_ruru.php b/localization/locale_ruru.php index 8536ef8a..02af784e 100644 --- a/localization/locale_ruru.php +++ b/localization/locale_ruru.php @@ -189,12 +189,14 @@ $lang = array( 'expansions' => array("World of Warcraft", "The Burning Crusade", "Wrath of the Lich King"), 'stats' => array("к силе", "к ловкости", "к выносливости", "к интеллекту", "к духу"), 'sources' => array( - null, "Ремесло", "Добыча", "PvP", "Задание", "Продавец", "Тренер", "Открытие", - "Рекламная акция", "Талант", "Начальное заклинание", "Мероприятие", "Достижение" + null, "Ремесло", "Добыча", "PvP", "Задание", "Продавец", + "Тренер", "Открытие", "Рекламная акция", "Талант", "Начальное заклинание", "Мероприятие", + "Достижение" ), 'languages' => array( - 1 => "орочий", 2 => "дарнасский", 3 => "таурахэ", 6 => "дворфийский", 7 => "всеобщий", 8 => "язык демонов", 9 => "язык титанов", 10 => "талассийский", - 11 => "драконий", 12 => "калимаг", 13 => "гномский", 14 => "язык троллей", 33 => "наречие нежити", 35 => "дренейский", 36 => "наречие зомби", 37 => "машинный гномский", 38 => "машинный гоблинский" + 1 => "орочий", 2 => "дарнасский", 3 => "таурахэ", 6 => "дворфийский", 7 => "всеобщий", 8 => "язык демонов", + 9 => "язык титанов", 10 => "талассийский", 11 => "драконий", 12 => "калимаг", 13 => "гномский", 14 => "язык троллей", + 33 => "наречие нежити", 35 => "дренейский", 36 => "наречие зомби", 37 => "машинный гномский", 38 => "машинный гоблинский" ), 'gl' => array(null, "Большой", "Малый"), 'si' => array(1 => "Альянс", -1 => "Альянс только", 2 => "Орда", -2 => "Орда только", null, 3 => "Обе"), @@ -205,39 +207,119 @@ $lang = array( 'ra' => array(-2 => "Орда", -1 => "Альянс", "Обе", "Человек", "Орк", "Дворф", "Ночной эльф", "Нежить", "Таурен", "Гном", "Тролль", null, "Эльф крови", "Дреней"), 'rep' => array("Ненависть", "Враждебность", "Неприязнь", "Равнодушие", "Дружелюбие", "Уважение", "Почтение", "Превознесение"), 'st' => array( - "По-умолчанию", "Облик кошки", "TОблик Древа жизни", "Походный облик", "Водный облик", - "Облик медведя", null, null, "Облик лютого медведя", null, - null, null, null, "Танец теней", null, - null, "Призрачный волк", "Боевая стойка", "Оборонительная стойка", "Стойка берсерка", - null, null, "Метаморфоза", null, null, - null, null, "Облик стремительной птицы", "Облик Тьмы", "Облик птицы", - "Незаметность", "Облик лунного совуха", "Дух воздаяния" + "По-умолчанию", "Облик кошки", "TОблик Древа жизни", "Походный облик", "Водный облик", "Облик медведя", + null, null, "Облик лютого медведя", null, null, null, + null, "Танец теней", null, null, "Призрачный волк", "Боевая стойка", + "Оборонительная стойка", "Стойка берсерка", null, null, "Метаморфоза", null, + null, null, null, "Облик стремительной птицы", "Облик Тьмы", "Облик птицы", + "Незаметность", "Облик лунного совуха", "Дух воздаяния" ), 'me' => array( - null, "Подчинённый", "Дезориентирован", "Разоружённый", "Отвлечён", "Убегающий", "Неуклюжий", "Оплетён", - "Немота", "В покое", "Усыплён", "Пойманный в ловушку", "Оглушен", "Замороженный", "Бездейственный", "Кровоточащий", - "Целительное", "Превращён", "Изгнан", "Ограждён", "Скован", "Оседлавший", "Соблазнён", "Обращение", - "Испуганный", "Неуязвимый", "Прервано", "Замедленный", "Открытие", "Неуязвимый", "Ошеломлён", "Исступление" + null, "Подчинённый", "Дезориентирован", "Разоружённый", "Отвлечён", "Убегающий", + "Неуклюжий", "Оплетён", "Немота", "В покое", "Усыплён", "Пойманный в ловушку", + "Оглушен", "Замороженный", "Бездейственный", "Кровоточащий", "Целительное", "Превращён", + "Изгнан", "Ограждён", "Скован", "Оседлавший", "Соблазнён", "Обращение", + "Испуганный", "Неуязвимый", "Прервано", "Замедленный", "Открытие", "Неуязвимый", + "Ошеломлён", "Исступление" ), 'ct' => array( - "Разное", "Животное", "Дракон", "Демон", "Элементаль", "Великан", "Нежить", "Гуманоид", - "Существо", "Механизм", "Не указано", "Тотем", "Спутник", "Облако газа" + "Разное", "Животное", "Дракон", "Демон", "Элементаль", "Великан", + "Нежить", "Гуманоид", "Существо", "Механизм", "Не указано", "Тотем", + "Спутник", "Облако газа" ), 'fa' => array( - 1 => "Волк", 2 => "Кошка", 3 => "Паук", 4 => "Медведь", 5 => "Вепрь", 6 => "Кроколиск", 7 => "Падальщик", 8 => "Краб", - 9 => "Горилла", 11 => "Ящер", 12 => "Долгоног", 20 => "Скорпид", 21 => "Черепаха", 24 => "Летучая мышь", 25 => "Гиена", 26 => "Сова", - 27 => "Крылатый змей", 30 => "Дракондор", 31 => "Опустошитель", 32 => "Прыгуана", 33 => "Спороскат", 34 => "Скат Пустоты", 35 => "Змей", 37 => "Мотылек", - 38 => "Химера", 39 => "Дьявозавр", 41 => "Силитид", 42 => "Червь", 43 => "Люторог", 44 => "Оса", 45 => "Гончая Недр", 46 => "Дух зверя" + 1 => "Волк", 2 => "Кошка", 3 => "Паук", 4 => "Медведь", 5 => "Вепрь", 6 => "Кроколиск", + 7 => "Падальщик", 8 => "Краб", 9 => "Горилла", 11 => "Ящер", 12 => "Долгоног", 20 => "Скорпид", + 21 => "Черепаха", 24 => "Летучая мышь", 25 => "Гиена", 26 => "Сова", 27 => "Крылатый змей", 30 => "Дракондор", + 31 => "Опустошитель", 32 => "Прыгуана", 33 => "Спороскат", 34 => "Скат Пустоты", 35 => "Змей", 37 => "Мотылек", + 38 => "Химера", 39 => "Дьявозавр", 41 => "Силитид", 42 => "Червь", 43 => "Люторог", 44 => "Оса", + 45 => "Гончая Недр", 46 => "Дух зверя" ), 'pvpRank' => array( - null, "Private / Scout", "Corporal / Grunt", - "Sergeant / Sergeant", "Master Sergeant / Senior Sergeant", "Sergeant Major / First Sergeant", - "Knight / Stone Guard", "Knight-Lieutenant / Blood Guard", "Knight-Captain / Legionnare", - "Knight-Champion / Centurion", "Lieutenant Commander / Champion", "Commander / Lieutenant General", - "Marshal / General", "Field Marshal / Warlord", "Grand Marshal / High Warlord" + null, "Private / Scout", "Corporal / Grunt", + "Sergeant / Sergeant", "Master Sergeant / Senior Sergeant", "Sergeant Major / First Sergeant", + "Knight / Stone Guard", "Knight-Lieutenant / Blood Guard", "Knight-Captain / Legionnare", + "Knight-Champion / Centurion", "Lieutenant Commander / Champion", "Commander / Lieutenant General", + "Marshal / General", "Field Marshal / Warlord", "Grand Marshal / High Warlord" ), ), - 'account' => [], + 'account' => array( + 'title' => "Учетная запись Aowow", + 'email' => "Email", + 'continue' => "Продолжить", + 'groups' => array( + -1 => "Нет", "Тестер", "Администратор", "Редактор", "Модератор", "Бюрократ", + "Разработчик", "VIP", "Блогер", "Учетная запись Премиум", "Переводчик", "Агент по продажам", + "Менеджер изображений", "Менеджер видео" + ), + // signIn + 'doSignIn' => "Войти в вашу учетную запись Aowow", + 'signIn' => "Вход", + 'user' => "Логин", + 'pass' => "Пароль", + 'rememberMe' => "Запомнить меня на этом компьютере", + 'forgot' => "Забыл", + 'forgotUser' => "Имя пользователя", + 'forgotPass' => "Пароль", + 'accCreate' => 'У вас еще нет учетной записи? Зарегистрируйтесь прямо сейчас!', + + // recovery + 'recoverUser' => "Запрос имени пользователя", + 'recoverPass' => "Сброс пароля: Шаг %s из 2", + 'newPass' => "New Password", + + // creation + 'register' => "Регистрация: Шаг %s из 2", + + // dashboard + 'ipAddress' => "IP-Adress", + 'lastIP' => "last used IP", + 'joinDate' => "Joined", + 'lastLogin' => "Last visit", + 'userGroups' => "Role", + 'myAccount' => "My Account", + 'editAccount' => "Simply use the forms below to update your account information", + 'publicDesc' => "Public Description", + 'viewPubDesc' => 'View your Public Description in your Profile Page', + + // bans + 'accBanned' => "This Account was closed", + 'bannedBy' => "Banned by", + 'ends' => "Ends on", + 'permanent' => "The ban is permanent", + 'reason' => "Reason", + 'noReason' => "No reason was given.", + + // form-text + 'emailInvalid' => "Недопустимый адрес email.", // message_emailnotvalid + 'emailNotFound' => "The email address you entered is not associated with any account.

If you forgot the email you registered your account with email ".CFG_CONTACT_EMAIL." for assistance.", + 'createAccSent' => "An email was sent to %s. Simply follow the instructions to create your account.", + 'recovUserSent' => "An email was sent to %s. Simply follow the instructions to recover your username.", + 'recovPassSent' => "An email was sent to %s. Simply follow the instructions to reset your password.", + 'accActivated' => 'Your account has been activated.
Proceed to sign in', + 'userNotFound' => "The username you entered does not exists.", + 'wrongPass' => "That password is not vaild.", + 'accInactive' => "That account has not yet been confirmed active.", + 'loginExceeded' => "The maximum number of logins from this IP has been exceeded. Please try again in %s.", + 'signupExceeded'=> "The maximum number of signups from this IP has been exceeded. Please try again in %s.", + 'errNameLength' => "Имя пользователя не должно быть короче 4 символов.", // message_usernamemin + 'errNameChars' => "Имя пользователя может содержать только буквы и цифры.", // message_usernamenotvalid + 'errPassLength' => "Ваш пароль должен состоять минимум из 6 знаков.", // message_passwordmin + 'passMismatch' => "The passwords you entered do not match.", + 'nameInUse' => "That username is already taken.", + 'mailInUse' => "That email is already registered to an account.", + 'intError' => "An internal error occured.", + 'intError2' => "An internal error occured. (%s)", + 'isRecovering' => "This account is already recovering. Follow the instructions in your email or wait %s for the token to expire.", + 'passCheckFail' => "Пароли не совпадают.", // message_passwordsdonotmatch + 'newPassDiff' => "Прежний и новый пароли не должны совпадать." // message_newpassdifferent + ), + 'mail' => array( + 'tokenExpires' => "This token expires in %s.", + 'accConfirm' => ["Account Confirmation", "Welcome to ".CFG_NAME_SHORT."!\r\n\r\nClick the Link below to activate your account.\r\n\r\n".HOST_URL."?account=signup&token=%s\r\n\r\nIf you did not request this mail simply ignore it."], + 'recoverUser' => ["User Recovery", "Follow this link to log in.\r\n\r\n".HOST_URL."?account=signin&token=%s\r\n\r\nIf you did not request this mail simply ignore it."], + 'resetPass' => ["Password Reset", "Follow this link to reset your password.\r\n\r\n".HOST_URL."?account=forgotpassword&token=%s\r\n\r\nIf you did not request this mail simply ignore it."] + ), 'gameObject' => array( 'cat' => [0 => "Другое", 9 => "Книги", 3 => "Контейнеры", -5 => "Сундуки", 25 => "Рыболовные лунки",-3 => "Травы", -4 => "Полезные ископаемые", -2 => "Задания", -6 => "Инструменты"], 'type' => [ 9 => "Книга", 3 => "Контейнер", -5 => "Сундук", 25 => "", -3 => "Растение", -4 => "Полезное ископаемое", -2 => "Задание", -6 => ""], diff --git a/pages/account.php b/pages/account.php index 0e584f9f..7b826a96 100644 --- a/pages/account.php +++ b/pages/account.php @@ -1,4 +1,9 @@ 'activate_usernamelength', @@ -18,342 +23,448 @@ enum(array( // AcctError 'ACCT_INTERNAL_ERROR' => 'internal_error', )); -enum(array( // UserPropsLimits - 'USERNAME_LENGTH_MIN' => 4, - 'USERNAME_LENGTH_MAX' => 16, - 'PASSWORD_LENGTH_MIN' => 6, - 'PASSWORD_LENGTH_MAX' => 16, -)); +message_emailnotvalid: "That email address is not valid.", +message_newemaildifferent: "Your new email address must be different than your previous one.", +message_newpassdifferent: "Your new password must be different than your previous one.", +message_passwordmin: "Your password must be at least 6 characters long.", +message_passwordsdonotmatch: "Passwords do not match.", +message_usernamemin: "Your username must be at least 4 characters long.", +message_usernamenotvalid: "Your username can only contain letters and numbers.", + */ -function signin() +// exclude & weightscales are handled as Ajax +class AccountPage extends GenericPage { - if (!isset($_POST['username']) || !isset($_POST['password'])) - return Lang::$account['userNotFound']; - - $username = $_POST['username']; - $password = $_POST['password']; - $remember = $_POST['remember_me'] == 'yes'; - - // handle login try limitation - $ipBan = DB::Aowow()->selectRow('SELECT ip, count, UNIX_TIMESTAMP(unbanDate) as unbanDate FROM ?_account_bannedIPs WHERE type = 0 AND ip = ?', - $_SERVER['REMOTE_ADDR'] + protected $tpl = 'acc-dashboard'; + protected $js = ['user.js', 'profile.js']; + protected $css = [['path' => 'Profiler.css']]; + protected $mode = CACHETYPE_NONE; + protected $category = null; + protected $validCats = array( + 'signin' => [false], + 'signup' => [false], + 'signout' => [true], + 'forgotpassword' => [false], + 'forgotusername' => [false] ); - if (!$ipBan) // no entry exists; set count to 1 - DB::Aowow()->query('INSERT INTO ?_account_bannedIPs VALUES (?, 0, 1, FROM_UNIXTIME(?))', - $_SERVER['REMOTE_ADDR'], - time() + CFG_FAILED_AUTH_EXCLUSION - ); - else if ($ipBan['unbanDate'] < time()) // ip has accumulated counts but time expired; reset count to 1 - DB::Aowow()->query('INSERT IGNORE INTO ?_account_bannedIPs VALUES (?, 0, 1, ?)', - $_SERVER['REMOTE_ADDR'], - time() + CFG_FAILED_AUTH_EXCLUSION - ); - else // entry already exists; increment count - DB::Aowow()->query('UPDATE ?_account_bannedIPs SET count = count + 1, unbanDate = FROM_UNIXTIME(?) WHERE ip = ?', - time() + CFG_FAILED_AUTH_EXCLUSION, - $_SERVER['REMOTE_ADDR'] - ); + protected $user = ''; + protected $error = ''; + protected $next = ''; - $id = DB::Aowow()->SelectCell('SELECT id FROM ?_account WHERE user = ?', $username); - if (!$id) - return Lang::$account['userNotFound']; - - User::init($id); - - switch (User::Auth($password)) + public function __construct($pageCall, $pageParam) { - case AUTH_OK: - DB::Aowow()->query('DELETE FROM ?_account_bannedIPs WHERE type = 0 AND ip = ?', - $_SERVER['REMOTE_ADDR'] - ); - DB::Aowow()->query('UPDATE ?_account SET lastLogin = FROM_UNIXTIME(?), timeout = FROM_UNIXTIME(?) WHERE id = ?', - time(), - $remember ? 0 : time() + CFG_SESSION_TIMEOUT_DELAY, - $id - ); - User::writeCookie(); // overwrites the current user - return; - case AUTH_BANNED: - User::writeCookie(); - return Lang::$account['userBanned']; - case AUTH_WRONGPASS: - User::destroy(); - return Lang::$account['wrongPass']; - case AUTH_IPBANNED: - User::destroy(); - return sprintf(Lang::$account['loginsExceeded'], round(CFG_FAILED_AUTH_EXCLUSION / 60)); - default: - return; - } -} + if ($pageParam) + $this->category = [$pageParam]; -function signup() -{ - global $smarty; + parent::__construct($pageCall, $pageParam); -/* - $username = Get(GET_STRING, 'username', 'POST'); - $password = Get(GET_STRING, 'password', 'POST'); - $pwd2 = Get(GET_STRING, 'password2', 'POST'); - $email = Get(GET_STRING, 'email', 'POST'); - $remember = Get(GET_BOOL, 'remember_me', 'POST'); - - if($password != $pwd2) + if ($pageParam) { - $this->acct_error = ACCT_PASSWORDS_NOT_EQUAL; - $this->type = 'signup'; - return; - } - - // Check length - if(strlen($username) > USERNAME_LENGTH_MAX || strlen($username) < USERNAME_LENGTH_MIN) - { - $this->acct_error = ACCT_USERNAME_LENGTH; - $this->type = 'signup'; - return; - } - if(strlen($password) > PASSWORD_LENGTH_MAX || strlen($password) < PASSWORD_LENGTH_MIN) - { - $this->acct_error = ACCT_PASSWORD_LENGTH; - $this->type = 'signup'; - return; - } - - // Check symbols - if(preg_match('/[^\w\d]/i', $username)) - { - $this->acct_error = ACCT_USERNAME_SYMBOLS; - $this->type = 'signup'; - return; - } - if(preg_match('/[^\w\d!"#\$%]/', $password)) - { - $this->acct_error = ACCT_PASSWORD_SYMBOLS; - $this->type = 'signup'; - return; - } - if(!preg_match('/^([a-z0-9._-]+)(\+[a-z0-9._-]+)?(@[a-z0-9.-]+\.[a-z]{2,4})$/i', $email)) - { - $this->acct_error = ACCT_EMAIL_SYMBOLS; - $this->type = 'signup'; - return; - } - - // After 5 signup tries in a row, - // or after a single successful signup, - // the signup feature is blocked for 3 min - // and the time is expanded to full-time block. - - DB::Realm()->Query('DELETE FROM account_ip_signup WHERE ip = ? AND time <= ?d', $_SERVER['REMOTE_ADDR'], time() - 3*MINUTE); - DB::Realm()->Query('INSERT IGNORE INTO account_ip_signup (ip,time,tries) VALUES (?,?d,?d)', $_SERVER['REMOTE_ADDR'], time(), 0); - $tries = DB::Realm()->SelectCell('SELECT tries FROM account_ip_signup WHERE ip = ?', $_SERVER['REMOTE_ADDR']); - if($tries >= 5) - { - DB::Realm()->Query('UPDATE account_ip_signup SET time = ?d WHERE ip = ?', time(), $_SERVER['REMOTE_ADDR']); - $this->acct_error = ACCT_SIGNUP_BLOCKED; - $this->type = 'signup'; - return; - } - DB::Realm()->Query('UPDATE account_ip_signup SET tries = tries + 1 WHERE ip = ?', $_SERVER['REMOTE_ADDR']); - - $result = DB::Realm()->SelectCell('SELECT 1 FROM account WHERE username = ?', $username); - if($result) - { - $this->acct_error = ACCT_USERNAME_EXISTS; - $this->type = 'signup'; - return; - } - - DB::Realm()->Query('UPDATE account_ip_signup SET tries = tries + 5 WHERE ip = ?', $_SERVER['REMOTE_ADDR']); - $id = DB::Realm()->Query(' - INSERT INTO account (username,sha_pass_hash,email,joindate,expansion,last_ip) - VALUES (?,?,?,NOW(),?d,?) - ', - strtoupper($username), - $hash = AccountPage::CreateHash($username, $password), - strtolower($email), - 2, - $_SERVER['REMOTE_ADDR'] - ); - if($id) - { - DB::Realm()->Query('UPDATE account_ip_signup SET tries = tries + 5 WHERE ip = ?', $_SERVER['REMOTE_ADDR']); - DB::Realm()->Query('INSERT INTO account_aowow_extend (id,name) VALUES (?d,?)', $id, 'user-'.wn_create($id, WN_)); - - $us = new User($id); - if($us->Auth($hash) == AUTH_OK) - $us->SetAuthCookies($remember); - else - { - $this->acct_error = ACCT_INTERNAL_ERROR; - $this->type = 'signin'; - return; - } - } - else - { - $this->acct_error = ACCT_INTERNAL_ERROR; - $this->type = 'signup'; - return; - } -*/ - - // Account creation - if (isset($_POST['username']) && isset($_POST['password']) && isset($_POST['c_password']) && CFG_ALLOW_REGISTER) - { - // password mismatch - if ($_POST['password'] != $_POST['c_password']) - $smarty->assign('signup_error', Lang::$account['passMismatch']); - else - { - // AccName already in use - if (DB::Aowow()->selectCell('SELECT 1 FROM aowow_account WHERE user = ? LIMIT 1', $_POST['username'])) - $smarty->assign('signup_error', Lang::$account['nameInUse']); - else - { - $success = DB::Aowow()->query('INSERT INTO aowow_account (user, passHash, displayName, email, joindate, lastIP, locale) VALUES (?, ?, ?, ?, NOW(), ?, ?)', - $_POST['username'], - sha1(strtoupper($_POST['username']).':'.strtoupper($_POST['password'])), - Util::ucFirst($_POST['username']), - (isset($_POST['email']))? $_POST['email'] : '', - (isset($_SERVER["REMOTE_ADDR"]))? $_SERVER["REMOTE_ADDR"] : '', - 0 - ); - if ($success > 0) - // all fine, send to login - $_REQUEST['account']='signin'; - else - // something went wrong - $smarty->assign('signup_error', Lang::$account['unkError']); - } + // requires auth && not authed + if ($this->validCats[$pageParam][0] && !User::$id) + $this->forwardToSignIn('account='.$pageParam); + // doesn't require auth && authed + else if (!$this->validCats[$pageParam][0] && User::$id) + header('Location: ?account'); // goto dashboard } } -} -function dashboard() -{ - // cpmsg change pass messaeg class:failure|success, msg:blabla -} - -function recoverPass() -{ -} - -function recoverUser() -{ -} - -$smarty->updatePageVars(array( - 'reqCSS' => array( - ['path' => STATIC_URL.'/css/Profiler.css'], - ), - 'reqJS' => array( - STATIC_URL.'/js/user.js', - STATIC_URL.'/js/profile.js', - ), -)); - -$smarty->assign('lang', array_merge(Lang::$main, Lang::$account, ['colon' => Lang::$colon])); - -if (User::$id) -{ - switch ($pageParam) + protected function generateContent() { - case 'exclude': - // profiler completion exclude handler - // $_POST['groups'] = bitMask of excludeGroupIds when using .. excludeGroups .. duh - // should probably occur in g_user.excludegroups (dont forget to also set g_users.settings = {}) - die(); - break; - case 'signout': - User::destroy(); - $next = explode('?', $_SERVER['HTTP_REFERER']); - $next = !empty($next[1]) ? '?'.$next[1] : '.'; - header('Location: '.$next); - case 'weightscales': - if (isset($_POST['save'])) - { - if (!isset($_POST['id'])) + if (!$this->category) + { + $this->createDashboard(); + return; + } + + switch ($this->category[0]) + { + case 'forgotpassword': + if (CFG_AUTH_MODE != AUTH_MODE_SELF) // only recover own accounts + $this->error(); + + $this->tpl = 'acc-recover'; + $this->resetPass = false; + + if ($this->createRecoverPass($nStep)) // location-header after final step + header('Location: ?account=signin'); + + $this->head = sprintf(Lang::$account['recoverPass'], $nStep); + break; + case 'forgotusername': + if (CFG_AUTH_MODE != AUTH_MODE_SELF) // only recover own accounts + $this->error(); + + $this->tpl = 'acc-recover'; + if (isset($_POST['email'])) { - $res = DB::Aowow()->selectRow('SELECT max(id) as max, count(id) as num FROM ?_account_weightscales WHERE account = ?d', User::$id); - if ($res['num'] < 5) // more or less hard-defined in LANG.message_weightscalesaveerror - $_POST['id'] = ++$res['max']; + if (!Util::isValidEmail($_POST['email'])) + $this->error = Lang::$account['emailInvalid']; + else if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE email = ?', $_POST['email'])) + $this->error = Lang::$account['emailNotFound']; + else if ($err = $this->doRecoverUser($_POST['email'])) + $this->error = $err; else - die('0'); + $this->text = sprintf(Lang::$account['recovUserSent']. $_POST['email']); } - if (DB::Aowow()->query('REPLACE INTO ?_account_weightscales VALUES (?d, ?d, ?, ?)', intVal($_POST['id']), User::$id, $_POST['name'], $_POST['scale'])) - die((string)$_POST['id']); + $this->head = Lang::$account['recoverUser']; + break; + case 'signin': + $this->tpl = 'acc-signIn'; + if (isset($_POST['username']) || isset($_POST['password'])) + { + if ($err = $this->doSignIn()) + $this->error = $err; + else + header('Location: '.$this->getNext(true)); + } + else if (!empty($_GET['token']) && ($_ = DB::Aowow()->selectCell('SELECT user FROM ?_account WHERE status IN (?a) AND token = ? AND statusTimer > UNIX_TIMESTAMP()', [ACC_STATUS_RECOVER_USER, ACC_STATUS_OK], $_GET['token']))) + $this->user = $_; + + break; + case 'signup': + if (!CFG_ALLOW_REGISTER || CFG_AUTH_MODE != AUTH_MODE_SELF) + $this->error(); + + $this->tpl = 'acc-signUp'; + $nStep = 1; + if (isset($_POST['username']) || isset($_POST['password']) || isset($_POST['c_password']) || isset($_POST['email'])) + { + if ($err = $this->doSignUp()) + $this->error = $err; + else + { + $nStep = 1.5; + $this->text = sprintf(Lang::$account['createAccSent']. $_POST['email']); + } + } + else if (!empty($_GET['token']) && DB::Aowow()->query('SELECT 1 FROM ?_account WHERE status = ?d AND token = ?', ACC_STATUS_NEW, $_GET['token'])) + { + $nStep = 2; + DB::Aowow()->query('UPDATE ?_account SET status = ?d WHERE token = ?', ACC_STATUS_OK, $_GET['token']); + DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 1, ?d + 1, UNIX_TIMESTAMP() + ?d)', $_SERVER['REMOTE_ADDR'], CFG_FAILED_AUTH_COUNT, CFG_FAILED_AUTH_EXCLUSION); + $this->text = sprintf(Lang::$account['accActivated'], $_GET['token']); + } else - die('0'); - } - else if (isset($_POST['delete']) && isset($_POST['id']) && User::$id) - DB::Aowow()->query('DELETE FROM ?_account_weightscales WHERE id = ?d AND account = ?d', intVal($_POST['id']), User::$id); - else - die('0'); + $this->next = $this->getNext(); - break; - case ''; - dashboard(); - $smarty->display('dashboard.tpl'); - break; - default: - $smarty->error(); + $this->head = sprintf(Lang::$account['register'], $nStep); + break; + case 'signout': + User::destroy(); + default: + header('Location: '.$this->getNext(true)); + break; + } } -} -else -{ - switch ($pageParam) + + protected function generateTitle() { - case 'signin_do': - $error = signin(); - if ($error) - $smarty->assign('signinError', $error); - else - header('Location: '.$_GET['next']); - case 'signin': - if (!isset($_GET['next'])) - { - $next = isset($_SERVER['HTTP_REFERER']) ? explode('?', $_SERVER['HTTP_REFERER']) : '.'; - $smarty->assign('next', isset($next[1]) ? '?'.$next[1] : '.'); - } - else - $smarty->assign('next', $_GET['next']); + $this->title = [Lang::$account['title']]; + } - $smarty->assign('register', CFG_ALLOW_REGISTER); - $smarty->display('signin.tpl'); - break; - case 'signup_do': - $error = signup(); - if ($error) - $smarty->assign('signupError', $error); + protected function generatePath() { } + + private function createDashboard() + { + if (!User::$id) + $this->forwardToSignIn('account'); + + $user = DB::Aowow()->selectRow('SELECT * FROM ?_account WHERE id = ?d', User::$id); + $bans = DB::Aowow()->select('SELECT ab.*, a.displayName, ab.id AS ARRAY_KEY FROM ?_account_banned ab LEFT JOIN ?_account a ON a.id = ab.staffId WHERE ab.userId = ?d', User::$id); + + /***********/ + /* Infobox */ + /***********/ + + $infobox = []; + $infobox[] = Lang::$account['joinDate']. Lang::$main['colon'].'[tooltip name=joinDate]'. date('l, G:i:s', $user['joinDate']). '[/tooltip][span class=tip tooltip=joinDate]'. date(Lang::$main['dateFmtShort'], $user['joinDate']). '[/span]'; + $infobox[] = Lang::$account['lastLogin'].Lang::$main['colon'].'[tooltip name=lastLogin]'.date('l, G:i:s', $user['prevLogin']).'[/tooltip][span class=tip tooltip=lastLogin]'.date(Lang::$main['dateFmtShort'], $user['prevLogin']).'[/span]'; + $infobox[] = Lang::$account['lastIP']. Lang::$main['colon'].$user['prevIP']; + $infobox[] = Lang::$account['email']. Lang::$main['colon'].$user['email']; + + $groups = []; + foreach (Lang::$account['groups'] as $idx => $key) + if ($idx >= 0 && $user['userGroups'] & (1 << $idx)) + $groups[] = (!fMod(count($groups) + 1, 3) ? '[br]' : null).Lang::$account['groups'][$idx]; + + $infobox[] = Lang::$account['userGroups'].Lang::$main['colon'].($groups ? implode(', ', $groups) : Lang::$account['groups'][-1]); + + $this->infobox = '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]'; + + /*************/ + /* Ban Popup */ + /*************/ + + $this->banned = []; + foreach ($bans as $b) + { + if (!($b['typeMask'] & (ACC_BAN_TEMP | ACC_BAN_PERM)) || ($b['end'] && $b['end'] <= time())) + continue; + + $this->banned = array( + 'by' => [$b['staffId'], $b['displayName']], + 'end' => $b['end'], + 'reason' => $b['reason'] + ); + + break; // one is enough + } + + /************/ + /* Listview */ + /************/ + + // claimed characters + // profiles + // own screenshots + // own videos + // own comments (preview) + // articles guides..? + + $this->lvData = []; + + // cpmsg change pass messaeg class:failure|success, msg:blabla + } + + private function createRecoverPass(&$step) + { + $step = 1; + + if (isset($_POST['email'])) // step 1 + { + if (!Util::isValidEmail($_POST['email'])) + $this->error = Lang::$account['emailInvalid']; + else if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE email = ?', $_POST['email'])) + $this->error = Lang::$account['emailNotFound']; + else if ($err = $this->doRecoverPass($_POST['email'])) + $this->error = $err; else - header('Location: '.$_GET['next']); - break; - case 'signup': - if (!isset($_GET['next'])) { - $next = isset($_SERVER['HTTP_REFERER']) ? explode('?', $_SERVER['HTTP_REFERER']) : '.'; - $smarty->assign('next', isset($next[1]) ? '?'.$next[1] : '.'); + $step = 1.5; + $this->text = sprintf(Lang::$account['recovPassSent'], $_POST['email']); } + } + else if (isset($_GET['token'])) // step 2 + { + $step = 2; + $this->resetPass = true; + $this->token = $_GET['token']; + } + else if (isset($_POST['token']) && isset($_POST['email']) && isset($_POST['password']) && isset($_POST['c_password'])) + { + $step = 2; + $this->resetPass = true; + $this->token = $_GET['token']; // insecure source .. that sucks; but whats the worst that could happen .. this account cannot be recovered for some minutes + + if ($err = $this->doResetPass()) + $this->error = $err; else - $smarty->assign('next', $_GET['next']); - $smarty->display('signup.tpl'); - break; - case 'forgotpassword': - recoverPass(); - $smarty->display('recoverPass.tpl'); - break; - case 'forgotusername': - recoverUser(); - $smarty->display('recoverUser.tpl'); - break; - default: - header('Location: '.($_GET['next'] ? $_GET['next'] : '.')); - break; + return true; + } + + return false; + } + + private function doSignIn() + { + if (!isset($_POST['username']) || !isset($_POST['password'])) + return Lang::$account['userNotFound']; + + $username = $_POST['username']; + $password = $_POST['password']; + $doExpire = $_POST['remember_me'] != 'yes'; + + switch (User::Auth($username, $password)) + { + case AUTH_OK: + // reset account status, update expiration + DB::Aowow()->query('UPDATE ?_account SET prevLogin = curLogin, curLogin = UNIX_TIMESTAMP(), prevIP = curIP, curIP = ?, allowExpire = ?d, status = 0, statusTimer = 0, token = "" WHERE user = ?', + $_SERVER['REMOTE_ADDR'], + $doExpire, + $username + ); + if (User::init()) + User::save(); // overwrites the current user + return; + case AUTH_BANNED: + if (User::init()) + User::save(); + return Lang::$account['accBanned']; + case AUTH_WRONGUSER: + User::destroy(); + return Lang::$account['userNotFound']; + case AUTH_WRONGPASS: + User::destroy(); + return Lang::$account['wrongPass']; + case AUTH_ACC_INACTIVE: + User::destroy(); + return Lang::$account['accInactive']; + case AUTH_IPBANNED: + User::destroy(); + return sprintf(Lang::$account['loginExceeded'], Util::formatTime(CFG_FAILED_AUTH_EXCLUSION * 1000)); + default: + return; + } + } + + private function doSignUp() + { + $username = @$_POST['username']; + $password = @$_POST['password']; + $cPassword = @$_POST['c_password']; + $email = @$_POST['email']; + $doExpire = @$_POST['remember_me'] != 'yes'; + + // check username + if (strlen($username) > 4 || strlen($username) < 16) + return Lang::$account['errNameLength']; + + if (preg_match('/[^\w\d]/i', $username)) + return Lang::$account['errNameChars']; + + // check password + if (strlen($password) > 6 || strlen($password) < 16) + return Lang::$account['errPassLength']; + + // if (preg_match('/[^\w\d!"#\$%]/', $password)) // such things exist..? :o + // return Lang::$account['errPassChars']; + + if ($password != $cPassword) + return Lang::$account['passMismatch']; + + // check email + if (!Util::isValidEmail($email)) + return Lang::$account['emailInvalid']; + + // limit account creation + $ip = DB::Aowow()->selectRow('SELECT ip, count, unbanDate FROM ?_account_bannedIPs WHERE type = 1 AND ip = ?', $_SERVER['REMOTE_ADDR']); + if ($ip && $ip['count'] >= CFG_FAILED_AUTH_COUNT && $ip['unbanDate'] >= time()) + { + DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ? AND type = 1', CFG_FAILED_AUTH_EXCLUSION, $_SERVER['REMOTE_ADDR']); + return sprintf(Lang::$account['signupExceeded'], Util::formatTime(CFG_FAILED_AUTH_EXCLUSION * 1000)); + } + + // username taken + if ($_ = DB::Aowow()->SelectCell('SELECT user FROM ?_account WHERE (user = ? OR email = ?) AND (status <> ?d OR (status = ?d AND statusTimer > UNIX_TIMESTAMP()))', $username, $email, ACC_STATUS_NEW, ACC_STATUS_NEW)) + return $_ == $username ? Lang::$account['nameInUse'] : Lang::$account['mailInUse']; + + // create.. + $token = Util::createHash(); + $delay = 7 * DAY; + $id = DB::Aowow()->query('INSERT INTO ?_account (user, passHash, displayName, email, joindate, curIP, allowExpire, locale, status, statusTimer, token) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(), ?, ?d, ?d, ?d, UNIX_TIMESTAMP() + ?d, ?)', + $username, + User::hashCrypt($_POST['password']), + Util::ucFirst($username), + $email, + isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : '', + $doExpire, + User::$localeId, + ACC_STATUS_NEW, + $delay, + $token + ); + if (!$id) // something went wrong + return Lang::$account['intError']; + else if ($_ = $this->sendMail($email, Lang::$mail['accConfirm'][0], sprintf(Lang::$mail['accConfirm'][1], $token), $delay)) + { + // success:: update ip-bans + if (!$ip || $ip['unbanDate'] < time()) + DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 1, 1, UNIX_TIMESTAMP() + ?d)', $_SERVER['REMOTE_ADDR'], CFG_FAILED_AUTH_EXCLUSION); + else + DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ? AND type = 1', CFG_FAILED_AUTH_EXCLUSION, $_SERVER['REMOTE_ADDR']); + + return $_; + } + } + + private function doRecoverPass($target) + { + $delay = 5 * MINUTE; + if ($_ = $this->initRecovery(ACC_STATUS_RECOVER_PASS, $target, $delay, $token)) + return $_; + + // send recovery mail + return $this->sendMail($target, Lang::$mail['resetPass'][0], sprintf(Lang::$mail['resetPass'][1], $token), $delay); + } + + private function doResetPass() + { + $token = $_POST['token']; + $email = $_POST['email']; + $pass = $_POST['password']; + $cPass = $_POST['c_password']; + + if ($pass != $cPass) + return Lang::$account['passCheckFail']; + + $uRow = DB::Aowow()->selectRow('SELECT id, user, passHash FROM ?_account WHERE token = ? AND email = ? AND status = ?d AND statusTimer > UNIX_TIMESTAMP()', $token, $email, ACC_STATUS_RECOVER_PASS); + if (!$uRow) + return Lang::$account['emailNotFound']; // assume they didn't meddle with the token + + if (!User::verifyCrypt($newPass)) + return Lang::$account['newPassDiff']; + + if (!DB::Aowow()->query('UPDATE ?_account SET passHash = ?, status = ?d WHERE id = ?d', User::hashcrypt($newPass), ACC_STATUS_OK, $uRow['id'])) + return Lang::$account['intError']; + } + + private function doRecoverUser($target) + { + $delay = 5 * MINUTE; + if ($_ = $this->initRecovery(ACC_STATUS_RECOVER_USER, $target, $delay, $token)) + return $_; + + // send recovery mail + return $this->sendMail($target, Lang::$mail['recoverUser'][0], sprintf(Lang::$mail['recoverUser'][1], $token), $delay); + } + + private function initRecovery($type, $target, $delay, &$token) + { + if (!$type) + return Lang::$account['intError']; + + // check if already processing + if ($_ = DB::Aowow()->selectCell('SELECT statusTimer - UNIX_TIMESTAMP() FROM ?_account WHERE email = ? AND status <> ?d AND statusTimer > UNIX_TIMESTAMP()', $target, ACC_STATUS_OK)) + return sprintf(lang::$account['isRecovering'], Util::formatTime($_)); + + // create new token and write to db + $token = Util::createHash(); + if (!DB::Aowow()->query('UPDATE ?_account SET token = ?, status = ?d, statusTimer = UNIX_TIMESTAMP() + ?d WHERE email = ?', $token, $type, $delay, $target)) + return Lang::$account['intError']; + } + + private function sendMail($target, $subj, $msg, $delay = 300) + { + // send recovery mail + $subj = CFG_NAME_SHORT.Lang::$main['colon'] . $subj; + $msg .= "\r\n\r\n".sprintf(Lang::$mail['tokenExpires'], Util::formatTime($delay * 1000))."\r\n"; + $header = 'From: '.CFG_CONTACT_EMAIL . "\r\n" . + 'Reply-To: '.CFG_CONTACT_EMAIL . "\r\n" . + 'X-Mailer: PHP/' . phpversion(); + + if (!mail($target, $subj, $msg, $header)) + return sprintf(Lang::$account['intError2'], 'send mail'); + } + + private function getNext($forHeader = false) + { + $next = $forHeader ? '.' : ''; + if (isset($_GET['next'])) + $next = $_GET['next']; + else if (isset($_SERVER['HTTP_REFERER']) && strstr($_SERVER['HTTP_REFERER'], '?')) + $next = explode('?', $_SERVER['HTTP_REFERER'])[1]; + + if ($forHeader && !$next) + $next = '.'; + + return ($forHeader && $next != '.' ? '?' : '').$next; } } + + ?> diff --git a/includes/genericPage.class.php b/pages/genericPage.class.php similarity index 98% rename from includes/genericPage.class.php rename to pages/genericPage.class.php index 99a5c2e8..11679e3a 100644 --- a/includes/genericPage.class.php +++ b/pages/genericPage.class.php @@ -81,11 +81,6 @@ class GenericPage if ($this->restrictedGroups && !User::isInGroup($this->restrictedGroups)) $this->error(); - if (CFG_MAINTENANCE && !User::isInGroup(U_GROUP_EMPLOYEE)) - $this->maintenance(); - else if (CFG_MAINTENANCE && User::isInGroup(U_GROUP_EMPLOYEE)) - Util::addNote(U_GROUP_EMPLOYEE, 'Maintenance mode enabled!'); - // display modes if (isset($_GET['power']) && method_exists($this, 'generateTooltip')) $this->mode = CACHETYPE_TOOLTIP; @@ -102,6 +97,11 @@ class GenericPage if (!$this->isValidPage() || !$this->tpl) $this->error(); } + + if (CFG_MAINTENANCE && !User::isInGroup(U_GROUP_EMPLOYEE)) + $this->maintenance(); + else if (CFG_MAINTENANCE && User::isInGroup(U_GROUP_EMPLOYEE)) + Util::addNote(U_GROUP_EMPLOYEE, 'Maintenance mode enabled!'); } /**********/ @@ -311,6 +311,12 @@ class GenericPage $this->category = $params; } + protected function forwardToSignIn($next = '') + { + $next = $next ? '&next='.$next : ''; + header('Location: ?account=signin'.$next); + } + /*******************/ /* Special Display */ /*******************/ @@ -351,6 +357,8 @@ class GenericPage public function display($override = '') // load given template string or GenericPage::$tpl { + session_regenerate_id(true); // can only reagenerate for real pages, otherwise a simple tooltip would be fatal for the session + if ($override) { $this->addAnnouncements(); @@ -562,7 +570,7 @@ class GenericPage catch (ReflectionException $e) { } // shut up! } - $data .= serialize($cache); + $data .= gzcompress(serialize($cache), 9); } else $data .= (string)$saveString; @@ -594,7 +602,7 @@ class GenericPage if ($type == '0') { - $data = unserialize($cache[1]); + $data = unserialize(gzuncompress($cache[1])); foreach ($data as $k => $v) $this->$k = $v; diff --git a/pages/item.php b/pages/item.php index eca518dd..d4c33b72 100644 --- a/pages/item.php +++ b/pages/item.php @@ -66,8 +66,11 @@ class ItemPage extends genericPage $this->name = $this->subject->getField('name', true); - $jsg = $this->subject->getJSGlobals(GLOBALINFO_EXTRA | GLOBALINFO_SELF, $extra); - $this->extendGlobalData($jsg, $extra); + if ($this->mode == CACHETYPE_PAGE) + { + $jsg = $this->subject->getJSGlobals(GLOBALINFO_EXTRA | GLOBALINFO_SELF, $extra); + $this->extendGlobalData($jsg, $extra); + } } protected function generatePath() @@ -918,7 +921,7 @@ class ItemPage extends genericPage { $itemString = $this->typeId; foreach ($this->enhancedTT as $k => $val) - $itemString .= $k.(is_array($val) ? implode(':', $val) : $val); + $itemString .= $k.(is_array($val) ? implode(',', $val) : $val); if ($asError) return '$WowheadPower.registerItem(\''.$itemString.'\', '.User::$localeId.', {})'; diff --git a/pages/miscTools.php b/pages/miscTools.php deleted file mode 100644 index d5ce31a7..00000000 --- a/pages/miscTools.php +++ /dev/null @@ -1,164 +0,0 @@ -getRandomId(); - - header('Location: ?'.Util::$typeStrings[$type].'='.$typeId); - die(); - case 'latest-comments': - $menu = 2; - $lv = array( - array( - 'file' => 'commentpreview', - 'data' => [], - 'params' => [] - ) - ); - break; - case 'latest-screenshots': - $menu = 3; - $lv[] = array( - 'file' => 'screenshot', - 'data' => [], - 'params' => [] - ); - break; - case 'latest-videos': - $menu = 11; - $lv[] = array( - 'file' => 'video', - 'data' => [], - 'params' => [] - ); - break; - case 'latest-articles': - $menu = 1; - $lv = []; - break; - case 'latest-additions': - $menu = 0; - $extraText = ''; - break; - case 'unrated-comments': - $menu = 5; - $lv[] = array( - 'file' => 'commentpreview', - 'data' => [], - 'params' => [] - ); - break; - case 'missing-screenshots': - $menu = 13; - $cnd = [[['cuFlags', CUSTOM_HAS_SCREENSHOT, '&'], 0]]; - - if (!User::isInGroup(U_GROUP_STAFF)) - $cnd[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0]; - - foreach (Util::$typeClasses as $classStr) - { - $typeObj = new $classStr($cnd); - if (!$typeObj->error) - { - $typeObj->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_RELATED); - - $lv[] = array( - 'file' => (new ReflectionProperty($typeObj, 'brickFile'))->getValue(), - 'data' => $typeObj->getListviewData(), - 'params' => ['tabs' => '$myTabs'] - ); - } - } - break; - case 'most-comments': - if ($pageParam && !in_array($pageParam, [1, 7, 30])) - header('Location: ?most-comments=1'.($_rss ? '&rss' : null)); - - if (in_array($pageParam, [7, 30])) - { - $subMenu = $pageParam; - $_title = sprintf(Lang::$main['mostComments'][1], $pageParam); - } - else - { - $subMenu = 1; - $_title = Lang::$main['mostComments'][0]; - } - - $menu = 12; - $lv[] = array( - 'file' => 'commentpreview', - 'data' => [], - 'params' => [] - ); - break; - default: - $smarty->error(); -} - -if (strstr($pageCall, 'latest') || $pageCall == 'most-comments') -{ - if ($_rss) - { - header("Content-Type: application/rss+xml; charset=ISO-8859-1"); - - $xml = "\n". - "\n\t\n". - "\t\t".CFG_NAME_SHORT.' - '.Lang::$main['utilities'][$menu] . ($_title ? Lang::$colon . $_title : null)."\n". - "\t\t".HOST_URL.'?'.$pageCall . ($pageParam ? '='.$pageParam : null)."\n". - "\t\t".CFG_NAME."\n". - "\t\t".implode('-', str_split(User::$localeString, 2))."\n". - "\t\t".CFG_TTL_RSS."\n". - // Sat, 31 Aug 2013 15:33:16 -0500 - "\t\n"; - - /* - generate 's here - */ - - $xml .= ''; - - die($xml); - } - else - $h1Links = ''.Lang::$main['subscribe'].''; -} - -array_push($_path, $menu); -if ($subMenu) - array_push($_path, $subMenu); - - -// menuId 8: Utilities g_initPath() -// tabId 1: Tools g_initHeader() -$smarty->updatePageVars(array( - 'name' => Lang::$main['utilities'][$menu] . ($_title ? Lang::$colon . $_title : null), - 'h1Links' => $h1Links, - 'title' => Lang::$main['utilities'][$menu] . ($_title ? ' - ' . $_title : null), - 'path' => json_encode($_path, JSON_NUMERIC_CHECK), - 'tab' => 1 -)); -$smarty->assign('lang', Lang::$main); -$smarty->assign('lvData', $lv); - -// load the page -$smarty->display('list-page-generic.tpl'); - -?> diff --git a/pages/more.php b/pages/more.php index 0b31d34c..dfc082bb 100644 --- a/pages/more.php +++ b/pages/more.php @@ -40,8 +40,7 @@ class MorePage extends GenericPage if (($_[1] = array_search($subPage, $this->subPages[$_[0]])) === false) $this->error(); - // ye.. hack .. can for some reason not be defined in the array itself - if ($page == 'help') + if ($page == 'help') // ye.. hack .. class definitions only allow static values $_[2] = Lang::$main['helpTopics'][$_[1]]; } $this->type = $_[0]; diff --git a/pages/utility.php b/pages/utility.php new file mode 100644 index 00000000..2e9f1244 --- /dev/null +++ b/pages/utility.php @@ -0,0 +1,185 @@ + 'latest-videos', 12 => 'most-comments', 13 => 'missing-screenshots' + ); + private $page = ''; + private $rss = false; + + public function __construct($pageCall, $pageParam) + { + $this->getCategoryFromUrl($pageParam); + + parent::__construct($pageCall, $pageParam); + + $this->page = $pageCall; + $this->rss = isset($_GET['rss']); + $this->name = Lang::$main['utilities'][array_search($pageCall, $this->validPages)]; + + if ($this->page == 'most-comments') + { + if ($this->category && in_array($this->category[0], [7, 30])) + $this->name .= Lang::$main['colon'] . sprintf(Lang::$main['mostComments'][1], $this->category[0]); + else + $this->name .= Lang::$main['colon'] . Lang::$main['mostComments'][0]; + } + } + + public function display($override = '') + { + if ($this->rss) // this should not be cached + { + header('Content-Type: application/rss+xml; charset=ISO-8859-1'); + die($this->generateRSS()); + } + else + return parent::display($override); + } + + protected function generateContent() + { + /****************/ + /* Main Content */ + /****************/ + + if (in_array(array_search($this->page, $this->validPages), [0, 1, 2, 3, 11, 12])) + $this->h1Links = ''.Lang::$main['subscribe'].''; + + switch ($this->page) + { + case 'random': + $type = array_rand(array_filter(Util::$typeStrings)); + $typeId = (new Util::$typeClasses[$type](null))->getRandomId(); + + header('Location: ?'.Util::$typeStrings[$type].'='.$typeId); + die(); + case 'latest-comments': + $this->lvData[] = array( + 'file' => 'commentpreview', + 'data' => [], + 'params' => [] + ); + break; + case 'latest-screenshots': + $this->lvData[] = array( + 'file' => 'screenshot', + 'data' => [], + 'params' => [] + ); + break; + case 'latest-videos': + $this->lvData[] = array( + 'file' => 'video', + 'data' => [], + 'params' => [] + ); + break; + case 'latest-articles': + $this->lvData = []; + break; + case 'latest-additions': + $extraText = ''; + break; + case 'unrated-comments': + $this->lvData[] = array( + 'file' => 'commentpreview', + 'data' => [], + 'params' => [] + ); + break; + case 'missing-screenshots': + $cnd = [[['cuFlags', CUSTOM_HAS_SCREENSHOT, '&'], 0]]; + + if (!User::isInGroup(U_GROUP_EMPLOYEE)) + $cnd[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0]; + + foreach (Util::$typeClasses as $classStr) + { + if (!$classStr) + continue; + + $typeObj = new $classStr($cnd); + if (!$typeObj->error) + { + $this->extendGlobalData($typeObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED | GLOBALINFO_REWARDS)); + $this->lvData[] = array( + 'file' => $typeObj::$brickFile, + 'data' => $typeObj->getListviewData(), + 'params' => ['tabs' => '$myTabs'] + ); + } + } + break; + case 'most-comments': + if ($this->category && !in_array($this->category[0], [1, 7, 30])) + header('Location: ?most-comments=1'.($this->rss ? '&rss' : null)); + + $this->lvData[] = array( + 'file' => 'commentpreview', + 'data' => [], + 'params' => [] + ); + break; + } + } + + protected function generateRSS() + { + $xml = "\n". + "\n\t\n". + "\t\t".CFG_NAME_SHORT.' - '.$this->name."\n". + "\t\t".HOST_URL.'?'.$this->page . ($this->category ? '='.$this->category[0] : null)."\n". + "\t\t".CFG_NAME."\n". + "\t\t".implode('-', str_split(User::$localeString, 2))."\n". + "\t\t".CFG_TTL_RSS."\n". + "\t\t".date(DATE_RSS)."\n". + "\t\n"; + + # generate 's here + + $xml .= ''; + + return $xml; + } + + protected function generateTitle() + { + if ($this->page == 'most-comments') + { + if ($this->category && in_array($this->category[0], [7, 30])) + array_unshift($this->title, sprintf(Lang::$main['mostComments'][1], $this->category[0])); + else + array_unshift($this->title, Lang::$main['mostComments'][0]); + } + + array_unshift($this->title, Lang::$main['utilities'][array_search($this->page, $this->validPages)]); + } + + protected function generatePath() + { + $this->path[] = array_search($this->page, $this->validPages); + + if ($this->page == 'most-comments') + { + if ($this->category && in_array($this->category[0], [7, 30])) + $this->path[] = $this->category[0]; + else + $this->path[] = 1; + } + } +} + +?> diff --git a/setup/u1_account.sql b/setup/u1_account.sql new file mode 100644 index 00000000..4e78a2a2 --- /dev/null +++ b/setup/u1_account.sql @@ -0,0 +1,82 @@ +-- -------------------------------------------------------- +-- Host: 127.0.0.1 +-- Server Version: 5.6.16 - MySQL Community Server (GPL) +-- Server Betriebssystem: Win32 +-- HeidiSQL Version: 8.3.0.4792 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +-- Exportiere Struktur von Tabelle world.aowow_account +DROP TABLE IF EXISTS `aowow_account`; +CREATE TABLE IF NOT EXISTS `aowow_account` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `extId` int(10) unsigned NOT NULL COMMENT 'external user id', + `user` varchar(64) NOT NULL COMMENT 'login', + `passHash` varchar(128) NOT NULL, + `displayName` varchar(64) NOT NULL COMMENT 'nickname', + `email` varchar(64) NOT NULL, + `joinDate` int(10) unsigned NOT NULL COMMENT 'unixtime', + `allowExpire` tinyint(1) unsigned NOT NULL, + `curIP` varchar(15) NOT NULL, + `prevIP` varchar(15) NOT NULL, + `curLogin` int(10) unsigned NOT NULL COMMENT 'unixtime', + `prevLogin` int(10) unsigned NOT NULL, + `locale` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '0,2,3,6,8', + `userGroups` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'bitmask', + `avatar` varchar(16) NOT NULL COMMENT 'icon-string for internal or id for upload', + `description` text NOT NULL COMMENT 'markdown formated', + `userPerms` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'bool isAdmin', + `status` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT 'flag, see defines', + `statusTimer` int(10) unsigned NOT NULL DEFAULT '0', + `token` varchar(40) NOT NULL COMMENT 'creation & recovery', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- Daten Export vom Benutzer nicht ausgewählt + + +-- Exportiere Struktur von Tabelle world.aowow_account_banned +DROP TABLE IF EXISTS `aowow_account_banned`; +CREATE TABLE IF NOT EXISTS `aowow_account_banned` ( + `id` int(16) unsigned NOT NULL, + `userId` int(11) unsigned NOT NULL COMMENT 'affected accountId', + `staffId` int(11) unsigned NOT NULL COMMENT 'executive accountId', + `typeMask` tinyint(4) unsigned NOT NULL COMMENT 'ACC_BAN_*', + `start` int(10) unsigned NOT NULL COMMENT 'unixtime', + `end` int(10) unsigned NOT NULL COMMENT 'automatic unban @ unixtime', + `reason` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- Daten Export vom Benutzer nicht ausgewählt + +-- Exportiere Daten aus Tabelle world.aowow_config: 18 rows +DELETE FROM `aowow_config`; +/*!40000 ALTER TABLE `aowow_config` DISABLE KEYS */; +INSERT INTO `aowow_config` (`key`, `intValue`, `strValue`, `comment`) VALUES + ('sql_limit_search', 500, NULL, 'default: 500 - Limit of some SQL queries'), + ('sql_limit_default', 300, NULL, 'default: 300 - Limit of some SQL queries'), + ('sql_limit_quicksearch', 10, NULL, 'default: 10 - Limit of some SQL queries'), + ('sql_limit_none', 0, NULL, 'default: 0 - Limit of some SQL queries (yes, i\'m lazy)'), + ('ttl_rss', 60, NULL, 'default: 60 - time to live for RSS'), + ('cache_decay', 604800, NULL, 'default: 60 * 60 * 7 - Time to keep cache in seconds'), + ('session_timeout_delay', 3600, NULL, 'default: 60 * 60 - non-permanent session times out in time() + X'), + ('failed_auth_exclusion', 900, NULL, 'default: 15 * 60 - how long an account is closed after exceeding failed_auth_count'), + ('failed_auth_count', 5, NULL, 'default: 5 - how often invalid passwords are tolerated'), + ('name', NULL, 'Aowow Database Viewer (ADV)', 'website title'), + ('name_short', NULL, 'Aowow', 'feed title'), + ('board_url', NULL, 'http://www.wowhead.com/forums?board=', 'a javascript thing..'), + ('contact_email', NULL, 'feedback@aowow.org', 'ah well...'), + ('battlegroup', NULL, 'Pure Pwnage', 'pretend, we belong to a battlegroup to satisfy profiler-related Jscripts; region can be determined from realmlist.timezone'), + ('allow_register', 1, NULL, 'default: 1 - Allow/disallow account creation (requires auth_mode 0)'), + ('debug', 0, NULL, 'default: 0 - Disable cache, enable sql-errors, enable error_reporting'), + ('maintenance', 0, NULL, 'default: 0 - brb gnomes'), + ('auth_mode', 0, NULL, 'default: 0 - 0:aowow, 1:wow-auth, 2:external'); + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/static/js/Markup.js b/static/js/Markup.js index 65709bc6..ed45ee40 100644 --- a/static/js/Markup.js +++ b/static/js/Markup.js @@ -1858,7 +1858,7 @@ var Markup = { if(attr.url && Markup._isUrlSafe(attr.url)) str += '' + username + ''; else if(g_isUsernameValid(username)) - str += '' + username + ''; + str += '' + username + ''; else str += username; str += ' '+ LANG.markup_said + '
'; @@ -2125,7 +2125,7 @@ var Markup = { toHtml: function(attr) { return; - return ''; + return ''; } }, small: @@ -2913,7 +2913,7 @@ var Markup = { if(g_customColors[username]) postColor = 'comment-' + g_customColors[username]; - str += postColor + '">' + username + ' ' + LANG.markup_said + '
'; + str += postColor + '">' + username + ' ' + LANG.markup_said + '
'; return [str, '']; } }, diff --git a/static/js/locale_enus.js b/static/js/locale_enus.js index 419daa37..2a8b6cf3 100644 --- a/static/js/locale_enus.js +++ b/static/js/locale_enus.js @@ -925,7 +925,7 @@ var mn_more = [ ]], [7,"What's New","?whats-new"], [,"Goodies"], - [16, "Search Box","?searchbox"], + [16, "Search Box","?searchbox"], [8,"Search Plugins (FF, IE7, ...)","?searchplugins"], [10,"Tooltips","?tooltips"] ]; diff --git a/static/js/locale_eses.js b/static/js/locale_eses.js index ef8369fc..1c1f36b7 100644 --- a/static/js/locale_eses.js +++ b/static/js/locale_eses.js @@ -879,7 +879,7 @@ var mn_more = [ ]], [7,"Novedades","?whats-new"], [,"Extras para tu sitio"], - [16, "Caja de búsqueda", "?searchbox"], + [16, "Caja de búsqueda", "?searchbox"], [8,"Extensiones de búsqueda","?searchplugins"], [10,"Tooltips","?tooltips"] ]; diff --git a/static/js/locale_frfr.js b/static/js/locale_frfr.js index 3165666d..b493cec8 100644 --- a/static/js/locale_frfr.js +++ b/static/js/locale_frfr.js @@ -879,7 +879,7 @@ var mn_more = [ ]], [7,"Quoi de neuf?","?whats-new"], [,"Extras pour votre site"], - [16,"Boîte de recherche", "?searchbox"], + [16,"Boîte de recherche", "?searchbox"], [8,"Plug-ins de recherche","?searchplugins"], [10,"Tooltips","?tooltips"] ]; diff --git a/static/js/locale_ruru.js b/static/js/locale_ruru.js index 19592acd..d052fc4b 100644 --- a/static/js/locale_ruru.js +++ b/static/js/locale_ruru.js @@ -880,7 +880,7 @@ var mn_more = [ [7,"Новости","?whats-new"], [,"Для вашего сайта"], [8,"Дополнения для браузеров","?searchplugins"], - [16,"Окно поиска","?searchbox"], + [16,"Окно поиска","?searchbox"], [10,"Всплывающие подсказки","?tooltips"] ]; var mn_path = [ diff --git a/template/bricks/infobox.tpl.php b/template/bricks/infobox.tpl.php index de2a4b50..178308a7 100644 --- a/template/bricks/infobox.tpl.php +++ b/template/bricks/infobox.tpl.php @@ -6,11 +6,14 @@ if (!empty($this->infobox)):
series)): foreach ($this->series as $s): $this->brick('series', ['list' => $s[0], 'listTitle' => $s[1]]); endforeach; endif; + +if (!empty($this->type) && !empty($this->typeId)): ?>
@@ -20,6 +23,10 @@ endif; \n"; +endif; + if (!empty($this->infobox)): ?> - - - -
{$lang.quickFacts}
-
-
-
    -
  • {$lang.login}: {$user.login}
  • -
  • {$lang.joinDate}{$lang.colon}{'Y/m/d'|date:$user.joinDate}
  • -
  • {$lang.lastLogin}{$lang.colon}{'Y/m/d'|date:$user.lastLogin}
  • -
  • {$lang.userGroups}{$lang.colon}{$user.roles}
  • -
  • {$lang.email}: {$user.email}
  • -
  • {$lang.lastIP}: {$user.lastIP}
  • - -
-
+ +brick('announcement'); ?> + + + +brick('infobox'); ?>
+

-

{$lang.myAccount}

-{* BANNED POPUP *} -{if !empty($user.banned)} -
-

[Account banned]

+banned): +?> +
+

    -
  • [banner]: {$user.bannedBy}
  • -
  • [end]: {$user.unbanDate}
  • -
  • [reason]{$lang.colon}{if isset($user.banReason)}{$user.banReason}{else}[none given.]{/if}
  • +
  • '.Lang::$account['bannedBy'].''.Lang::$main['colon'].''.$b['by'][1].''; ?>
  • +
  • '.Lang::$account['ends'].''.Lang::$main['colon'].($b['end'] ? date(Lang::$main['dateFmtLong'], $b['end']) : Lang::$account['permanent']); ?>
  • +
  • '.Lang::$account['reason'].''.Lang::$main['colon'].''.($b['reason'] ?: Lang::$account['noReason']).''; ?>
-{/if} - {$lang.editAccount} + -{* USER-PROFILE EDITING *}

{$lang.publicDesc}

{$lang.Your_description_has_been_updated_successfully}.
@@ -61,7 +51,7 @@
@@ -110,23 +100,34 @@ + +
-{include file='footer.tpl'} \ No newline at end of file + +brick('footer'); ?> diff --git a/template/pages/acc-recover.tpl.php b/template/pages/acc-recover.tpl.php new file mode 100644 index 00000000..fe7e845c --- /dev/null +++ b/template/pages/acc-recover.tpl.php @@ -0,0 +1,127 @@ +brick('header'); ?> + +
+
+
+
+text)): ?> +
+

head; ?>

+
+
text; ?>
+
+resetPass): ?> + + +
+
+

head; ?>

+
error; ?>
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + + + +
+
+

head; ?>

+
error; ?>
+ +
+ +
+ + +
+ +
+
+ + +
+
+
+ +brick('footer'); ?> diff --git a/template/pages/signin.tpl b/template/pages/acc-signIn.tpl.php similarity index 56% rename from template/pages/signin.tpl rename to template/pages/acc-signIn.tpl.php index 514b791c..93074827 100644 --- a/template/pages/signin.tpl +++ b/template/pages/acc-signIn.tpl.php @@ -1,4 +1,4 @@ -{include file='header.tpl'} +brick('header'); ?>
@@ -6,58 +6,62 @@
-
+
-

{$lang.doSignIn}

-
{if isset($signinError)}{$signinError}{/if}
+

+
error; ?>
- - + + - +
{$lang.user}{$lang.colon}
{$lang.pass}{$lang.colon}
- +
- +

-
{$lang.forgot}{$lang.colon}{$lang.user} | {$lang.pass}
+
|
- {if $register}
{$lang.accNoneYet}? {$lang.accCreateNow}!
{/if} +'.Lang::$account['accCreate']."
\n"; +endif; +?>
-{include file='footer.tpl'} +brick('footer'); ?> diff --git a/template/pages/acc-signUp.tpl.php b/template/pages/acc-signUp.tpl.php new file mode 100644 index 00000000..18e41eee --- /dev/null +++ b/template/pages/acc-signUp.tpl.php @@ -0,0 +1,117 @@ +brick('header'); ?> + +
+
+
+
+text)): ?> +
+

head; ?>

+
+
text; ?>
+
+ + + +
+
+

head; ?>

+
error; ?>
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+ + + +
+
+
+ +brick('footer'); ?> diff --git a/template/pages/recoverPass.tpl b/template/pages/recoverPass.tpl deleted file mode 100644 index 8f01354e..00000000 --- a/template/pages/recoverPass.tpl +++ /dev/null @@ -1,32 +0,0 @@ -{include file='header.tpl'} - -
-
-
-
- -
-
-

[Password Reset: Step 1 of 2]

-
- -
- [Email address]{$lang.colon} -
- -
-
- - -
- -
-
- - -
-
- -
- -{include file='footer.tpl'} diff --git a/template/pages/recoverUser.tpl b/template/pages/recoverUser.tpl deleted file mode 100644 index 1fce5a46..00000000 --- a/template/pages/recoverUser.tpl +++ /dev/null @@ -1,31 +0,0 @@ -{include file='header.tpl'} - -
-
-
-
- -
-
-

[Username Request]

-
- -
- [Email address]{$lang.colon} -
- -
-
- - -
- -
-
- - -
-
-
- -{include file='footer.tpl'} diff --git a/template/pages/signup.tpl b/template/pages/signup.tpl deleted file mode 100644 index d9f9b5fe..00000000 --- a/template/pages/signup.tpl +++ /dev/null @@ -1,75 +0,0 @@ -{include file='header.tpl'} - -
-
-
-
- - -
-
-

{$lang.accCreate}

-
{if isset($signupError)}{$signupError}{/if}
- - - - - - - - - - - - - - - - - - - - - -
{$lang.user}{$lang.colon}
{$lang.pass}{$lang.colon}
{$lang.passConfirm}{$lang.colon}
{$lang.email}{$lang.colon}
- -
- -
-
-
- - -
-
- -
- -{include file='footer.tpl'}