Compare commits

..

13 Commits

Author SHA1 Message Date
slawkens
abee4b3962 Add spomky-labs/otphp 2025-09-14 13:01:51 +02:00
slawkens
fbdb6890b9 Working two factor email authentication 2025-09-14 11:38:01 +02:00
slawkens
041f58ed11 Merge branch 'main' into feature/2fa 2025-09-14 09:53:34 +02:00
slawkens
03c7dd0002 Merge branch 'main' into feature/2fa 2025-08-12 14:36:29 +02:00
slawkens
e435062025 [WIP] 2fa 2025-07-05 08:20:58 +02:00
slawkens
ecc9bd4042 Merge branch 'main' into feature/2fa 2025-07-01 14:18:38 +02:00
slawkens
797377e428 Replace TwoFactorAuth with self 2025-06-22 22:34:36 +02:00
slawkens
96b5df9d74 Merge branch 'main' into feature/2fa 2025-06-22 18:51:32 +02:00
slawkens
b3dfc56c96 [WIP] Working 2fa email auth 2025-06-22 18:50:54 +02:00
slawkens
96d6e04bd2 Update 46-account_email_codes.sql 2025-06-22 13:19:29 +02:00
slawkens
9146eee327 Move 2025-06-22 11:55:34 +02:00
slawkens
3d97fa0719 Merge branch 'main' into feature/2fa 2025-06-22 11:45:21 +02:00
slawkens
a66cafceab 2fa: first draft 2025-06-22 08:34:30 +02:00
82 changed files with 1650 additions and 1147 deletions

View File

@@ -1,46 +1,5 @@
# Changelog # Changelog
## [1.8.3 - 21.10.2025]
### Added
* Feature: resend email verify (https://github.com/slawkens/myaac/commit/fe821c58085483e70491dcf76376ad5b96de3fdd)
* New config: hooks_debug (To view where hooks are located in .twig files) (https://github.com/slawkens/myaac/commit/8c3cb0e06f9709c1de3398b48221241e7cbdd310)
* Functions: Add db->getColumnInfo(table, column) (https://github.com/slawkens/myaac/commit/c898fe25efff6793a01d11c26fc153cb23fcb858)
* Plugins: Add option to use ?subtopic=x for plugins pages (https://github.com/slawkens/myaac/commit/97f9d3d6f6c28aef6d824973058d7133f56e09c4)
* getTopPlayers() Function - Add lookmount & promotion (https://github.com/slawkens/myaac/commit/2da0024c68f1cedc38a16ebbc6f52ffa55e65f7a, https://github.com/slawkens/myaac/commit/901df48d134079d648a18f9d82b60182e818ac02)
* New hooks for account/change-password (https://github.com/slawkens/myaac/commit/470555f2687809a0c12491bbb27597e64b8929c1)
### Changed
* Feature: show vip days in account management (https://github.com/slawkens/myaac/commit/c88b08eb1ec1f560cbfdaaa16b24e3a0f26da7b3, by @andreoam)
* Allow links in error_box.html.twig (https://github.com/slawkens/myaac/commit/9acad15451071639acf7a7d4e81619b0a9742b12)
* Canary - Comment code to update lastday in login.php (https://github.com/slawkens/myaac/commit/38902c30d114fdbce259467f5820f97037b393e9)
* Cache::remember $ttl = -1 = infinite (https://github.com/slawkens/myaac/commit/64acf70d3854182d88aaf0b67f77cea2a254f179)
### Fixed
* Online - Allow for html code (example - img) in online_datacenter (https://github.com/slawkens/myaac/commit/3bb272ebbbd2eb7769d174b7082061d14a17bd44)
* Guilds - Fix guild create with freePremium enabled (https://github.com/slawkens/myaac/commit/c91bb5d4097647dca2196d3dea87bc90c89181d2)
* Canary - Fix premDays count (https://github.com/slawkens/myaac/commit/3e61692780d4add93b7b0e9f12f7a283bd8f4b7a)
* Template Change: Ignore set last visit for AJAX pages - Fixes template change redirect (https://github.com/slawkens/myaac/commit/89fae38caa7e4f645957fcf1a9330a36358ac04f)
* Admin Panel - Accounts: Fix lastip v6 (TFS master) (https://github.com/slawkens/myaac/commit/f54b1bdd2af4c16c64ddff0e87a6c96bc4cf9eeb)
* Functions - Prevent injection in $db->hasColumn (https://github.com/slawkens/myaac/commit/56bd7ec5ed904666074492f2e4f13e4fce226bee)
* Compat Config: Add missing config: email_lai_sec_interval (https://github.com/slawkens/myaac/commit/2eae44e0755e624a91be68b4d1ec26d01eb4d9a1)
## [1.8.2 - 26.09.2025]
### Added
* Routes: Possibility to override routes with plugins pages, like characters.php - No need to define routes in plugin.json anymore (https://github.com/slawkens/myaac/commit/3f24f961b1cdeff5c60387e837ae454448bc5e1b)
### Changed
* Style: Better look for myaac-table (https://github.com/slawkens/myaac/commit/a6032093b21e5bb3f0e75d2704da87d6dea6469d, https://github.com/slawkens/myaac/commit/5aa9bbf1c8e580d973ec82ac012489f8e7bc437e)
### Fixed
* Install: Fix when config.local.php cannot be saved (https://github.com/slawkens/myaac/commit/4eab805d26d8c5562b29ed699769919d77dabced)
* Create Account: Fix an exception when email cannot be sent (https://github.com/slawkens/myaac/commit/d0112d1a67e8b854b65ad131f0375b79305df8d3)
* Login Page: Add missing csrf() - fix create account button (https://github.com/slawkens/myaac/commit/3c0cb53e17dd0b85394cfa0fdc9cf9ad8d4551df)
* tibiacom template: Fix account lost menu (https://github.com/slawkens/myaac/commit/ed9beaf2b6ca069e304e569c52e5b9188b58f05c)
* tibiacom template: Fix Menu div wrong tag/closing (#329) (https://github.com/slawkens/myaac/commit/85e7005fd3f0be51466151a3c122b96085fdfe68)
* tibiacom template: Replace firstChild with firstElementChild (Thanks to @un000000) (https://github.com/slawkens/myaac/commit/df7b6e29fb8875da97f431468c81ee99116271d9)
## [1.8.1 - 05.09.2025] ## [1.8.1 - 05.09.2025]
### Added ### Added

4
aac
View File

@@ -25,9 +25,7 @@ foreach ($commandsGlob as $item) {
} }
$commandPre = '\\MyAAC\Commands\\'; $commandPre = '\\MyAAC\Commands\\';
if (!trait_exists($class = $commandPre . $name)) { $application->add(new ($commandPre . $name));
$application->add(new $class);
}
} }
$pluginCommands = Plugins::getCommands(); $pluginCommands = Plugins::getCommands();

View File

@@ -669,18 +669,12 @@ else if (isset($_REQUEST['search'])) {
<div class="col-12 col-sm-12 col-lg-6"> <div class="col-12 col-sm-12 col-lg-6">
<label for="lastip" class="control-label">Last IP:</label> <label for="lastip" class="control-label">Last IP:</label>
<input type="text" class="form-control" id="lastip" name="lastip" autocomplete="off" maxlength="10" value="<?php <input type="text" class="form-control" id="lastip" name="lastip" autocomplete="off" maxlength="10" value="<?php
$lastIPColumnInfo = $db->getColumnInfo('players', 'lastip'); if (strlen($player->getLastIP()) > 11) {
if ($lastIPColumnInfo && is_array($lastIPColumnInfo)) {
if (str_contains($lastIPColumnInfo['type'], 'varbinary')) {
echo inet_ntop($player->getLastIP()); echo inet_ntop($player->getLastIP());
} }
else { else {
echo longToIp($player->getLastIP()); echo longToIp($player->getLastIP());
} }
}
else {
echo 'Error';
}
?>" readonly/> ?>" readonly/>
</div> </div>
</div> </div>

View File

@@ -1,6 +1,5 @@
<?php <?php
const MYAAC_ADMIN = true; define('MYAAC_ADMIN', true);
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -26,7 +26,6 @@
use MyAAC\DataLoader; use MyAAC\DataLoader;
const MYAAC_ADMIN = true; const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -3,7 +3,6 @@
use MyAAC\Settings; use MyAAC\Settings;
const MYAAC_ADMIN = true; const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -1,6 +1,5 @@
<?php <?php
const MYAAC_ADMIN = true; define('MYAAC_ADMIN', true);
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'init.php'; require SYSTEM . 'init.php';

View File

@@ -1,6 +1,5 @@
<?php <?php
const MYAAC_ADMIN = true; define('MYAAC_ADMIN', true);
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php'; require '../../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -26,7 +26,7 @@
if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.'); if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.');
const MYAAC = true; const MYAAC = true;
const MYAAC_VERSION = '1.8.3'; const MYAAC_VERSION = '1.8.2-dev';
const DATABASE_VERSION = 46; const DATABASE_VERSION = 46;
const TABLE_PREFIX = 'myaac_'; const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true)); define('START_TIME', microtime(true));

View File

@@ -19,7 +19,8 @@
"symfony/var-dumper": "^6.4", "symfony/var-dumper": "^6.4",
"filp/whoops": "^2.15", "filp/whoops": "^2.15",
"maximebf/debugbar": "1.*", "maximebf/debugbar": "1.*",
"guzzlehttp/guzzle": "7.9.3" "guzzlehttp/guzzle": "7.9.3",
"spomky-labs/otphp": "^11.3"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "^1.10" "phpstan/phpstan": "^1.10"

151
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "5317e97a5025ebc2a977214bd3fa964c", "content-hash": "07419f6fe133f9bebc99557f3df843c8",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@@ -1556,6 +1556,73 @@
}, },
"time": "2018-02-13T20:26:39+00:00" "time": "2018-02-13T20:26:39+00:00"
}, },
{
"name": "paragonie/constant_time_encoding",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512",
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512",
"shasum": ""
},
"require": {
"php": "^8"
},
"require-dev": {
"phpunit/phpunit": "^9",
"vimeo/psalm": "^4|^5"
},
"type": "library",
"autoload": {
"psr-4": {
"ParagonIE\\ConstantTime\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com",
"role": "Maintainer"
},
{
"name": "Steve 'Sc00bz' Thomas",
"email": "steve@tobtu.com",
"homepage": "https://www.tobtu.com",
"role": "Original Developer"
}
],
"description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
"keywords": [
"base16",
"base32",
"base32_decode",
"base32_encode",
"base64",
"base64_decode",
"base64_encode",
"bin2hex",
"encoding",
"hex",
"hex2bin",
"rfc4648"
],
"support": {
"email": "info@paragonie.com",
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
"source": "https://github.com/paragonie/constant_time_encoding"
},
"time": "2024-05-08T12:36:18+00:00"
},
{ {
"name": "peppeocchi/php-cron-scheduler", "name": "peppeocchi/php-cron-scheduler",
"version": "v4.0", "version": "v4.0",
@@ -2102,6 +2169,88 @@
}, },
"time": "2019-03-08T08:55:37+00:00" "time": "2019-03-08T08:55:37+00:00"
}, },
{
"name": "spomky-labs/otphp",
"version": "11.3.0",
"source": {
"type": "git",
"url": "https://github.com/Spomky-Labs/otphp.git",
"reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33",
"reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"paragonie/constant_time_encoding": "^2.0 || ^3.0",
"php": ">=8.1",
"psr/clock": "^1.0",
"symfony/deprecation-contracts": "^3.2"
},
"require-dev": {
"ekino/phpstan-banned-code": "^1.0",
"infection/infection": "^0.26|^0.27|^0.28|^0.29",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5.26|^10.0|^11.0",
"qossmic/deptrac-shim": "^1.0",
"rector/rector": "^1.0",
"symfony/phpunit-bridge": "^6.1|^7.0",
"symplify/easy-coding-standard": "^12.0"
},
"type": "library",
"autoload": {
"psr-4": {
"OTPHP\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Florent Morselli",
"homepage": "https://github.com/Spomky"
},
{
"name": "All contributors",
"homepage": "https://github.com/Spomky-Labs/otphp/contributors"
}
],
"description": "A PHP library for generating one time passwords according to RFC 4226 (HOTP Algorithm) and the RFC 6238 (TOTP Algorithm) and compatible with Google Authenticator",
"homepage": "https://github.com/Spomky-Labs/otphp",
"keywords": [
"FreeOTP",
"RFC 4226",
"RFC 6238",
"google authenticator",
"hotp",
"otp",
"totp"
],
"support": {
"issues": "https://github.com/Spomky-Labs/otphp/issues",
"source": "https://github.com/Spomky-Labs/otphp/tree/11.3.0"
},
"funding": [
{
"url": "https://github.com/Spomky",
"type": "github"
},
{
"url": "https://www.patreon.com/FlorentMorselli",
"type": "patreon"
}
],
"time": "2024-06-12T11:22:32+00:00"
},
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.4.17", "version": "v6.4.17",

View File

@@ -1,69 +0,0 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Models\Changelog;
use MyAAC\Models\Config;
use MyAAC\Models\ForumBoard;
use MyAAC\Models\Gallery;
use MyAAC\Models\NewsCategory;
if (Changelog::count() === 0) {
Changelog::create([
'type' => 3,
'where' => 2,
'date' => time(),
'body' => 'MyAAC installed. (:',
'hide' => 0,
]);
}
if (Config::where('name', 'database_version')->count() === 0) {
Config::create([
'name' => 'database_version',
'value' => DATABASE_VERSION,
]);
}
if (ForumBoard::count() === 0) {
$forumBoards = [
['name' => 'News', 'description' => 'News commenting', 'closed' => 1],
['name' => 'Trade', 'description' => 'Trade offers.', 'closed' => 0],
['name' => 'Quests', 'description' => 'Quest making.', 'closed' => 0],
['name' => 'Pictures', 'description' => 'Your pictures.', 'closed' => 0],
['name' => 'Bug Report', 'description' => 'Report bugs there.', 'closed' => 0],
];
$i = 0;
foreach ($forumBoards as $forumBoard) {
ForumBoard::create([
'name' => $forumBoard['name'],
'description' => $forumBoard['description'],
'ordering' => $i++,
'closed' => $forumBoard['closed'],
]);
}
}
if (NewsCategory::count() === 0) {
$newsCategoriesIcons = [
0, 1, 2, 3, 4
];
foreach ($newsCategoriesIcons as $iconId) {
NewsCategory::create([
'icon_id' => $iconId,
]);
}
}
if (Gallery::count() === 0) {
Gallery::create([
'comment' => 'Demon',
'image' => 'images/gallery/demon.jpg',
'thumb' => 'images/gallery/demon_thumb.gif',
'author' => 'MyAAC',
'ordering' => 0,
]);
}
success($locale['step_database_success_import_data']);

View File

@@ -1,4 +1,6 @@
CREATE TABLE IF NOT EXISTS `myaac_account_actions` SET @myaac_database_version = 45;
CREATE TABLE `myaac_account_actions`
( (
`account_id` int NOT NULL, `account_id` int NOT NULL,
`ip` int unsigned NOT NULL DEFAULT 0, `ip` int unsigned NOT NULL DEFAULT 0,
@@ -8,16 +10,16 @@ CREATE TABLE IF NOT EXISTS `myaac_account_actions`
KEY (`account_id`) KEY (`account_id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_account_emails_verify` CREATE TABLE `myaac_account_email_codes`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL, `account_id` int NOT NULL,
`hash` varchar(32) NOT NULL, `code` varchar(6) NOT NULL,
`sent_at` int NOT NULL DEFAULT 0, `created_at` int NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_admin_menu` CREATE TABLE `myaac_admin_menu`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '', `name` varchar(255) NOT NULL DEFAULT '',
@@ -28,7 +30,7 @@ CREATE TABLE IF NOT EXISTS `myaac_admin_menu`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_changelog` CREATE TABLE `myaac_changelog`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`body` varchar(500) NOT NULL DEFAULT '', `body` varchar(500) NOT NULL DEFAULT '',
@@ -40,7 +42,9 @@ CREATE TABLE IF NOT EXISTS `myaac_changelog`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_config` INSERT INTO `myaac_changelog` (`id`, `type`, `where`, `date`, `body`, `hide`) VALUES (1, 3, 2, UNIX_TIMESTAMP(), 'MyAAC installed. (:', 0);
CREATE TABLE `myaac_config`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL, `name` varchar(30) NOT NULL,
@@ -49,7 +53,9 @@ CREATE TABLE IF NOT EXISTS `myaac_config`
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_faq` INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version);
CREATE TABLE `myaac_faq`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`question` varchar(255) NOT NULL DEFAULT '', `question` varchar(255) NOT NULL DEFAULT '',
@@ -59,7 +65,7 @@ CREATE TABLE IF NOT EXISTS `myaac_faq`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_forum_boards` CREATE TABLE `myaac_forum_boards`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL, `name` varchar(32) NOT NULL,
@@ -71,8 +77,13 @@ CREATE TABLE IF NOT EXISTS `myaac_forum_boards`
`hide` tinyint NOT NULL DEFAULT 0, `hide` tinyint NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`, `closed`) VALUES (NULL, 'News', 'News commenting', 0, 1);
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Trade', 'Trade offers.', 1);
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Quests', 'Quest making.', 2);
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Pictures', 'Your pictures.', 3);
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Bug Report', 'Report bugs there.', 4);
CREATE TABLE IF NOT EXISTS `myaac_forum` CREATE TABLE `myaac_forum`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`first_post` int NOT NULL DEFAULT 0, `first_post` int NOT NULL DEFAULT 0,
@@ -96,7 +107,7 @@ CREATE TABLE IF NOT EXISTS `myaac_forum`
KEY `section` (`section`) KEY `section` (`section`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_menu` CREATE TABLE `myaac_menu`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`template` varchar(255) NOT NULL, `template` varchar(255) NOT NULL,
@@ -110,7 +121,7 @@ CREATE TABLE IF NOT EXISTS `myaac_menu`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_monsters` ( CREATE TABLE `myaac_monsters` (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`hide` tinyint NOT NULL DEFAULT 0, `hide` tinyint NOT NULL DEFAULT 0,
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
@@ -143,7 +154,7 @@ CREATE TABLE IF NOT EXISTS `myaac_monsters` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_news` CREATE TABLE `myaac_news`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL, `title` varchar(100) NOT NULL,
@@ -161,7 +172,7 @@ CREATE TABLE IF NOT EXISTS `myaac_news`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_news_categories` CREATE TABLE `myaac_news_categories`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT "", `name` varchar(50) NOT NULL DEFAULT "",
@@ -171,7 +182,13 @@ CREATE TABLE IF NOT EXISTS `myaac_news_categories`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_notepad` INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 0);
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 1);
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 2);
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 3);
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 4);
CREATE TABLE `myaac_notepad`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL, `account_id` int NOT NULL,
@@ -181,7 +198,7 @@ CREATE TABLE IF NOT EXISTS `myaac_notepad`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_pages` CREATE TABLE `myaac_pages`
( (
`id` INT NOT NULL AUTO_INCREMENT, `id` INT NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL, `name` varchar(30) NOT NULL,
@@ -197,7 +214,7 @@ CREATE TABLE IF NOT EXISTS `myaac_pages`
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_gallery` CREATE TABLE `myaac_gallery`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`comment` varchar(255) NOT NULL DEFAULT '', `comment` varchar(255) NOT NULL DEFAULT '',
@@ -209,7 +226,9 @@ CREATE TABLE IF NOT EXISTS `myaac_gallery`
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_settings` INSERT INTO `myaac_gallery` (`id`, `ordering`, `comment`, `image`, `thumb`, `author`) VALUES (NULL, 1, 'Demon', 'images/gallery/demon.jpg', 'images/gallery/demon_thumb.gif', 'MyAAC');
CREATE TABLE `myaac_settings`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '', `name` varchar(255) NOT NULL DEFAULT '',
@@ -219,7 +238,7 @@ CREATE TABLE IF NOT EXISTS `myaac_settings`
KEY `key` (`key`) KEY `key` (`key`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_spells` CREATE TABLE `myaac_spells`
( (
`id` int NOT NULL AUTO_INCREMENT, `id` int NOT NULL AUTO_INCREMENT,
`spell` varchar(255) NOT NULL DEFAULT '', `spell` varchar(255) NOT NULL DEFAULT '',
@@ -242,7 +261,7 @@ CREATE TABLE IF NOT EXISTS `myaac_spells`
UNIQUE (`name`) UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_visitors` CREATE TABLE `myaac_visitors`
( (
`ip` varchar(45) NOT NULL, `ip` varchar(45) NOT NULL,
`lastvisit` int NOT NULL DEFAULT 0, `lastvisit` int NOT NULL DEFAULT 0,
@@ -251,7 +270,7 @@ CREATE TABLE IF NOT EXISTS `myaac_visitors`
UNIQUE (`ip`) UNIQUE (`ip`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_weapons` CREATE TABLE `myaac_weapons`
( (
`id` int NOT NULL, `id` int NOT NULL,
`level` int NOT NULL DEFAULT 0, `level` int NOT NULL DEFAULT 0,

View File

@@ -30,23 +30,27 @@ if(!$error) {
} }
} }
// import schema if($db->hasTable(TABLE_PREFIX . 'account_actions')) {
try { $locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']);
warning($locale['step_database_error_table_exist']);
}
else {
// import schema
try {
$locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']); $locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']);
success($locale['step_database_importing']); success($locale['step_database_importing']);
$db->exec(file_get_contents(BASE . 'install/includes/schema.sql')); $db->query(file_get_contents(BASE . 'install/includes/schema.sql'));
$locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']);
success($locale['step_database_success_schema']); success($locale['step_database_success_schema']);
} }
catch(PDOException $error_) { catch(PDOException $error_) {
error($locale['step_database_error_schema'] . ' ' . $error_); error($locale['step_database_error_schema'] . ' ' . $error_);
return; return;
}
} }
require BASE . 'install/includes/import_base_data.php';
if(!$db->hasColumn('accounts', 'email')) { if(!$db->hasColumn('accounts', 'email')) {
if(query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';")) if(query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';"))
success($locale['step_database_adding_field'] . ' accounts.email...'); success($locale['step_database_adding_field'] . ' accounts.email...');
@@ -98,13 +102,18 @@ if(!$db->hasColumn('accounts', 'web_flags')) {
success($locale['step_database_adding_field'] . ' accounts.web_flags...'); success($locale['step_database_adding_field'] . ' accounts.web_flags...');
} }
if(!$db->hasColumn('accounts', 'email_hash')) {
if(query("ALTER TABLE `accounts` ADD `email_hash` VARCHAR(32) NOT NULL DEFAULT '' AFTER `web_flags`;"))
success($locale['step_database_adding_field'] . ' accounts.email_hash...');
}
if(!$db->hasColumn('accounts', 'email_verified')) { if(!$db->hasColumn('accounts', 'email_verified')) {
if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `web_flags`;")) if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `email_hash`;"))
success($locale['step_database_adding_field'] . ' accounts.email_verified...'); success($locale['step_database_adding_field'] . ' accounts.email_verified...');
} }
if(!$db->hasColumn('accounts', 'email_new')) { if(!$db->hasColumn('accounts', 'email_new')) {
if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_verified`;")) if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_hash`;"))
success($locale['step_database_adding_field'] . ' accounts.email_new...'); success($locale['step_database_adding_field'] . ' accounts.email_new...');
} }

View File

@@ -220,8 +220,6 @@ switch ($action) {
} }
} }
/*
* not needed anymore?
if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) { if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) {
$save = false; $save = false;
$timeNow = time(); $timeNow = time();
@@ -258,7 +256,6 @@ switch ($action) {
$account->save(); $account->save();
} }
} }
*/
$worlds = [$world]; $worlds = [$world];
$playdata = compact('worlds', 'characters'); $playdata = compact('worlds', 'characters');

View File

@@ -81,7 +81,6 @@ $deprecatedConfig = [
'account_change_character_name_points' => 'account_change_character_name_price', 'account_change_character_name_points' => 'account_change_character_name_price',
'account_change_character_sex', 'account_change_character_sex',
'account_change_character_sex_points' => 'account_change_character_name_price', 'account_change_character_sex_points' => 'account_change_character_name_price',
'email_lai_sec_interval' => 'mail_lost_account_interval',
]; ];
foreach ($deprecatedConfig as $key => $value) { foreach ($deprecatedConfig as $key => $value) {

View File

@@ -1142,18 +1142,10 @@ function getTopPlayers($limit = 5, $skill = 'level') {
'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet' 'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet'
]; ];
if ($db->hasColumn('players', 'promotion')) {
$columns[] = 'promotion';
}
if ($db->hasColumn('players', 'lookaddons')) { if ($db->hasColumn('players', 'lookaddons')) {
$columns[] = 'lookaddons'; $columns[] = 'lookaddons';
} }
if ($db->hasColumn('players', 'lookmount')) {
$columns[] = 'lookmount';
}
return Player::query() return Player::query()
->select($columns) ->select($columns)
->withOnlineStatus() ->withOnlineStatus()
@@ -1640,14 +1632,13 @@ function camelCaseToUnderscore($input)
return ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $input)), '_'); return ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $input)), '_');
} }
function removeIfFirstSlash(&$text): void function removeIfFirstSlash(&$text) {
{
if(strpos($text, '/') === 0) { if(strpos($text, '/') === 0) {
$text = str_replace_first('/', '', $text); $text = str_replace_first('/', '', $text);
} }
}; };
function escapeHtml($html): string { function escapeHtml($html) {
return htmlspecialchars($html); return htmlspecialchars($html);
} }
@@ -1661,7 +1652,7 @@ function getGuildNameById($id)
return false; return false;
} }
function getGuildLogoById($id): string function getGuildLogoById($id)
{ {
$logo = 'default.gif'; $logo = 'default.gif';
@@ -1677,8 +1668,7 @@ function getGuildLogoById($id): string
return BASE_URL . GUILD_IMAGES_DIR . $logo; return BASE_URL . GUILD_IMAGES_DIR . $logo;
} }
function displayErrorBoxWithBackButton($errors, $action = null): void function displayErrorBoxWithBackButton($errors, $action = null) {
{
global $twig; global $twig;
$twig->display('error_box.html.twig', ['errors' => $errors]); $twig->display('error_box.html.twig', ['errors' => $errors]);
$twig->display('account.back_button.html.twig', [ $twig->display('account.back_button.html.twig', [
@@ -1706,12 +1696,6 @@ function getAccountIdentityColumn(): string
return 'id'; return 'id';
} }
function isCanary(): bool
{
$vipSystemEnabled = configLua('vipSystemEnabled');
return isset($vipSystemEnabled);
}
// validator functions // validator functions
require_once SYSTEM . 'compat/base.php'; require_once SYSTEM . 'compat/base.php';

View File

@@ -443,18 +443,12 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
throw new E_OTS_NotLoaded(); throw new E_OTS_NotLoaded();
} }
if(isset($this->data['premium_ends_at']) || isset($this->data['premend']) || if(isset($this->data['premium_ends_at']) || isset($this->data['premend'])) {
(isCanary() && isset($this->data['lastday']))) { $col = isset($this->data['premium_ends_at']) ? 'premium_ends_at' : 'premend';
$col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend'));
$ret = ceil(($this->data[$col] - time()) / (24 * 60 * 60)); $ret = ceil(($this->data[$col] - time()) / (24 * 60 * 60));
return max($ret, 0); return max($ret, 0);
} }
if (isCanary() && isset($this->data['lastday'])) {
$ret = ceil(($this->data['lastday'] - time()) / 86400);
return max($ret, 0);
}
if($this->data['premdays'] == 0) { if($this->data['premdays'] == 0) {
return 0; return 0;
} }

View File

@@ -26,11 +26,10 @@ use MyAAC\Cache\Cache;
*/ */
class OTS_DB_MySQL extends OTS_Base_DB class OTS_DB_MySQL extends OTS_Base_DB
{ {
private array $has_table_cache = []; private $has_table_cache = array();
private array $has_column_cache = []; private $has_column_cache = array();
private array $get_column_info_cache = [];
private bool $clearCacheAfter = false; private $clearCacheAfter = false;
/** /**
* Creates database connection. * Creates database connection.
* *
@@ -120,11 +119,6 @@ class OTS_DB_MySQL extends OTS_Base_DB
if($cache->fetch('database_columns', $tmp) && $tmp) { if($cache->fetch('database_columns', $tmp) && $tmp) {
$this->has_column_cache = unserialize($tmp); $this->has_column_cache = unserialize($tmp);
} }
$tmp = null;
if($cache->fetch('database_columns_info', $tmp) && $tmp) {
$this->get_column_info_cache = unserialize($tmp);
}
} }
} }
@@ -161,13 +155,11 @@ class OTS_DB_MySQL extends OTS_Base_DB
if ($this->clearCacheAfter) { if ($this->clearCacheAfter) {
$cache->delete('database_tables'); $cache->delete('database_tables');
$cache->delete('database_columns'); $cache->delete('database_columns');
$cache->delete('database_columns_info');
$cache->delete('database_checksum'); $cache->delete('database_checksum');
} }
else { else {
$cache->set('database_tables', serialize($this->has_table_cache), 3600); $cache->set('database_tables', serialize($this->has_table_cache), 3600);
$cache->set('database_columns', serialize($this->has_column_cache), 3600); $cache->set('database_columns', serialize($this->has_column_cache), 3600);
$cache->set('database_columns_info', serialize($this->get_column_info_cache), 3600);
$cache->set('database_checksum', serialize(sha1($config['database_host'] . '.' . $config['database_name'])), 3600); $cache->set('database_checksum', serialize(sha1($config['database_host'] . '.' . $config['database_name'])), 3600);
} }
} }
@@ -217,8 +209,7 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $sql; return $sql;
} }
public function hasTable($name): bool public function hasTable($name) {
{
if(isset($this->has_table_cache[$name])) { if(isset($this->has_table_cache[$name])) {
return $this->has_table_cache[$name]; return $this->has_table_cache[$name];
} }
@@ -226,13 +217,12 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $this->hasTableInternal($name); return $this->hasTableInternal($name);
} }
private function hasTableInternal($name): bool private function hasTableInternal($name) {
{ global $config;
return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote(config('database_name')) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0); return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote($config['database_name']) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0);
} }
public function hasColumn($table, $column): bool public function hasColumn($table, $column) {
{
if(isset($this->has_column_cache[$table . '.' . $column])) { if(isset($this->has_column_cache[$table . '.' . $column])) {
return $this->has_column_cache[$table . '.' . $column]; return $this->has_column_cache[$table . '.' . $column];
} }
@@ -240,8 +230,8 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $this->hasColumnInternal($table, $column); return $this->hasColumnInternal($table, $column);
} }
private function hasColumnInternal($table, $column): bool { private function hasColumnInternal($table, $column) {
return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column))->fetchAll()) > 0); return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE '" . $column . "'")->fetchAll()) > 0);
} }
public function hasTableAndColumns(string $table, array $columns = []): bool public function hasTableAndColumns(string $table, array $columns = []): bool
@@ -257,53 +247,7 @@ class OTS_DB_MySQL extends OTS_Base_DB
return true; return true;
} }
public function getColumnInfo(string $table, string $column): bool|array public function revalidateCache() {
{
if(isset($this->get_column_info_cache[$table . '.' . $column])) {
return $this->get_column_info_cache[$table . '.' . $column];
}
return $this->getColumnInfoInternal($table, $column);
}
private function getColumnInfoInternal(string $table, string $column): bool|array
{
if (!$this->hasTable($table) || !$this->hasColumn($table, $column)) {
return false;
}
$formatResult = function ($result) {
return [
'field' => $result['Field'],
'type' => $result['Type'],
'null' => strtolower($result['Null']),
'default' => $result['Default'],
'extra' => $result['Extra'],
];
};
$query = $this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column));
$rowCount = $query->rowCount();
if ($rowCount > 1) {
$tmp = [];
$results = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($results as $result) {
$tmp[] = $formatResult($result);
}
return ($this->get_column_info_cache[$table . '.' . $column] = $tmp);
}
else if ($rowCount == 1) {
$result = $query->fetch(PDO::FETCH_ASSOC);
return ($this->get_column_info_cache[$table . '.' . $column] = $formatResult($result));
}
return [];
}
public function revalidateCache(): void
{
foreach($this->has_table_cache as $key => $value) { foreach($this->has_table_cache as $key => $value) {
$this->hasTableInternal($key); $this->hasTableInternal($key);
} }
@@ -318,21 +262,6 @@ class OTS_DB_MySQL extends OTS_Base_DB
$this->hasColumnInternal($explode[0], $explode[1]); $this->hasColumnInternal($explode[0], $explode[1]);
} }
} }
foreach($this->get_column_info_cache as $key => $value) {
$explode = explode('.', $key);
if(!isset($this->has_table_cache[$explode[0]])) { // first check if table exist
$this->hasTableInternal($explode[0]);
}
if($this->has_table_cache[$explode[0]]) {
$this->hasColumnInternal($explode[0], $explode[1]);
}
if($this->has_table_cache[$explode[0]]) {
$this->getColumnInfoInternal($explode[0], $explode[1]);
}
}
} }
public function setClearCacheAfter($clearCache) public function setClearCacheAfter($clearCache)

View File

@@ -78,7 +78,6 @@ $locale['step_database_error_mysql_connect_3'] = 'MySQL ist nicht richtig konfig
$locale['step_database_error_mysql_connect_4'] = 'MySQL-Server läuft nicht.'; $locale['step_database_error_mysql_connect_4'] = 'MySQL-Server läuft nicht.';
$locale['step_database_error_schema'] = 'Fehler beim Importieren des Schemas:'; $locale['step_database_error_schema'] = 'Fehler beim Importieren des Schemas:';
$locale['step_database_success_schema'] = '$PREFIX$ Tabellen wurden erfolgreich installiert.'; $locale['step_database_success_schema'] = '$PREFIX$ Tabellen wurden erfolgreich installiert.';
$locale['step_database_success_import_data'] = 'Import von Daten für Tabellen was erfolgreich.';
$locale['step_database_error_file'] = '$FILE$ konnte nicht geöffnet werden. Bitte kopieren Sie diesen Inhalt und fügen Sie ihn dort ein:'; $locale['step_database_error_file'] = '$FILE$ konnte nicht geöffnet werden. Bitte kopieren Sie diesen Inhalt und fügen Sie ihn dort ein:';
$locale['step_database_adding_field'] = 'Folgendes Feld wurde hinzugefügt: '; $locale['step_database_adding_field'] = 'Folgendes Feld wurde hinzugefügt: ';
$locale['step_database_modifying_field'] = 'Folgendes Feld wurde geändert: '; $locale['step_database_modifying_field'] = 'Folgendes Feld wurde geändert: ';

View File

@@ -83,7 +83,6 @@ $locale['step_database_error_mysql_connect_3'] = 'MySQL is not configured proper
$locale['step_database_error_mysql_connect_4'] = 'MySQL server is not running.'; $locale['step_database_error_mysql_connect_4'] = 'MySQL server is not running.';
$locale['step_database_error_schema'] = 'Error while importing schema:'; $locale['step_database_error_schema'] = 'Error while importing schema:';
$locale['step_database_success_schema'] = 'Successfully installed $PREFIX$ tables.'; $locale['step_database_success_schema'] = 'Successfully installed $PREFIX$ tables.';
$locale['step_database_success_import_data'] = 'Successfully imported base data for tables.';
$locale['step_database_error_file'] = '$FILE$ couldn\'t be opened. Please copy this content and paste there:'; $locale['step_database_error_file'] = '$FILE$ couldn\'t be opened. Please copy this content and paste there:';
$locale['step_database_adding_field'] = 'Adding field'; $locale['step_database_adding_field'] = 'Adding field';
$locale['step_database_modifying_field'] = 'Modifying field'; $locale['step_database_modifying_field'] = 'Modifying field';

View File

@@ -81,8 +81,7 @@ $locale['step_database_error_mysql_connect_2'] = 'Możliwe przyczyny:';
$locale['step_database_error_mysql_connect_3'] = 'MySQL nie jest poprawnie skonfigurowane w <i>config.lua</i>.'; $locale['step_database_error_mysql_connect_3'] = 'MySQL nie jest poprawnie skonfigurowane w <i>config.lua</i>.';
$locale['step_database_error_mysql_connect_4'] = 'Serwer MySQL nie jest uruchomiony.'; $locale['step_database_error_mysql_connect_4'] = 'Serwer MySQL nie jest uruchomiony.';
$locale['step_database_error_schema'] = 'Błąd podczas importowania struktury bazy danych:'; $locale['step_database_error_schema'] = 'Błąd podczas importowania struktury bazy danych:';
$locale['step_database_success_schema'] = 'Pomyślnie zaimportowano tabele $PREFIX$.'; $locale['step_database_success_schema'] = 'Pomyślnie zainstalowano tabele $PREFIX$.';
$locale['step_database_success_import_data'] = 'Pomyślnie załadowano bazowe dane dla tabel.';
$locale['step_database_error_file'] = '$FILE$ nie mógł zostać otwarty. Proszę skopiować zawartość pola tekstowego i wkleić do tego pliku:'; $locale['step_database_error_file'] = '$FILE$ nie mógł zostać otwarty. Proszę skopiować zawartość pola tekstowego i wkleić do tego pliku:';
$locale['step_database_adding_field'] = 'Dodawanie pola'; $locale['step_database_adding_field'] = 'Dodawanie pola';
$locale['step_database_modifying_field'] = 'Modyfikacja pola'; $locale['step_database_modifying_field'] = 'Modyfikacja pola';

View File

@@ -34,10 +34,8 @@ if($logged) {
$twig->addGlobal('account_logged', $account_logged); $twig->addGlobal('account_logged', $account_logged);
} }
if (!defined('IGNORE_SET_LAST_VISIT') || !IGNORE_SET_LAST_VISIT) { setSession('last_visit', time());
setSession('last_visit', time()); if(defined('PAGE')) {
if(defined('PAGE')) {
setSession('last_page', PAGE); setSession('last_page', PAGE);
}
setSession('last_uri', $_SERVER['REQUEST_URI']);
} }
setSession('last_uri', $_SERVER['REQUEST_URI']);

View File

@@ -9,8 +9,6 @@
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
global $db;
// database migrations // database migrations
$tmp = ''; $tmp = '';
if(fetchDatabaseConfig('database_version', $tmp)) { // we got version if(fetchDatabaseConfig('database_version', $tmp)) { // we got version

View File

@@ -0,0 +1,8 @@
CREATE TABLE `myaac_account_email_codes`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL,
`code` varchar(6) NOT NULL,
`created_at` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;

View File

@@ -1,8 +0,0 @@
CREATE TABLE `myaac_account_emails_verify`
(
`id` int NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL,
`hash` varchar(32) NOT NULL,
`sent_at` int NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;

View File

@@ -1,24 +1,27 @@
<?php <?php
// add the myaac_account_email_codes
/** /**
* @var OTS_DB_MySQL $db * @var OTS_DB_MySQL $db
*/ */
$up = function () use ($db) { $up = function () use ($db) {
if ($db->hasColumn('accounts', 'email_hash')) { if (!$db->hasColumn('accounts', '2fa_type')) {
$db->dropColumn('accounts', 'email_hash'); $db->addColumn('accounts', '2fa_type', "tinyint NOT NULL DEFAULT 0 AFTER `web_flags`");
} }
if (!$db->hasTable(TABLE_PREFIX . 'account_emails_verify')) { // add myaac_account_email_codes table
$db->query(file_get_contents(__DIR__ . '/46-account_emails_verify.sql')); if (!$db->hasTable(TABLE_PREFIX . 'account_email_codes')) {
$db->exec(file_get_contents(__DIR__ . '/46-account_email_codes.sql'));
} }
}; };
$down = function () use ($db) { $down = function () use ($db) {
if (!$db->hasColumn('accounts', 'email_hash')) { if ($db->hasColumn('accounts', '2fa_type')) {
$db->addColumn('accounts', 'email_hash', "varchar(32) NOT NULL DEFAULT ''"); $db->dropColumn('accounts', '2fa_type');
} }
if ($db->hasTable(TABLE_PREFIX . 'account_emails_verify')) { //if ($db->hasTable(TABLE_PREFIX . 'account_email_codes')) {
$db->dropTable(TABLE_PREFIX . 'account_emails_verify'); // $db->dropTable(TABLE_PREFIX . 'account_email_codes');
} //}
}; };

View File

@@ -0,0 +1,124 @@
<?php
/**
* 2-factor authentication
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
use MyAAC\TwoFactorAuth\TwoFactorAuth;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Two Factor Authentication';
require __DIR__ . '/base.php';
csrfProtect();
/**
* @var OTS_Account $account_logged
*/
$step = $_REQUEST['step'] ?? '';
$code = $_REQUEST['auth-code'] ?? '';
if ((!setting('core.mail_enabled')) && ACTION == 'email-code') {
$twig->display('error_box.html.twig', ['errors' => ['Account two-factor e-mail authentication disabled.']]);
return;
}
if (!isset($account_logged) || !$account_logged->isLoaded()) {
$current_session = getSession('account');
if($current_session) {
$account_logged = new OTS_Account();
$account_logged->load($current_session);
}
}
$twoFactorAuth = TwoFactorAuth::getInstance($account_logged);
$twig->addGlobal('account_logged', $account_logged);
if (ACTION == 'email-code') {
if ($step == 'resend') {
if ($twoFactorAuth->hasRecentEmailCode(15 * 60)) {
$errors = ['Sorry, one email per 15 minutes'];
}
else {
$twoFactorAuth->resendEmailCode();
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
}
$twig->display('account.2fa.email.login.html.twig');
}
else if ($step == 'activate') {
if (!$twoFactorAuth->hasRecentEmailCode(15 * 60)) {
$twoFactorAuth->resendEmailCode();
}
if (isset($_POST['save'])) {
if (!empty($code)) {
$twoFactorAuth->setAuthGateway(TwoFactorAuth::TYPE_EMAIL);
if ($twoFactorAuth->getAuthGateway()->verifyCode($code)) {
$serverName = configLua('serverName');
$twoFactorAuth->enable(TwoFactorAuth::TYPE_EMAIL);
$twoFactorAuth->deleteOldCodes();
$twig->display('success.html.twig', [
'title' => 'Email Code Authentication Activated',
'description' => sprintf('You have successfully activated <b>email code authentication</b> for your account. This means an <b>email code</b> will be sent to the email address assigned to your account whenever you try to log in to the %s client or the %s website. In order to log in, you will need to enter the <b>most recent email code</b> you have received.', $serverName, $serverName)
]);
return;
}
else {
$errors[] = 'Invalid email code!';
}
}
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
}
$twig->display('account.2fa.email_code.html.twig', ['wrongCode' => count($errors) > 0]);
}
else if ($step == 'deactivate') {
//if (!$twoFactorAuth->hasRecentEmailCode(15 * 60)) {
// $twoFactorAuth->resendEmailCode();
//}
/*if (isset($_POST['save'])) {
if (!empty($code)) {
if ($twoFactorAuth->getAuthGateway()->verifyCode($code)) {
*/
$twoFactorAuth->disable();
$twoFactorAuth->deleteOldCodes();
$twig->display('success.html.twig',
[
'title' => 'Email Code Authentication Deactivated',
'description' => 'You have successfully <b>deactivated</b> the <b>Email Code Authentication</b> for your account.'
]
);
/*
}
else {
$errors[] = 'Invalid email code!';
}
}
}*/
/*
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
}
$twig->display('account.2fa.email.deactivate.html.twig', ['wrongCode' => count($errors) > 0]);
*/
}
}

View File

@@ -17,6 +17,10 @@ if(!$logged)
if(!empty($errors)) if(!empty($errors))
$twig->display('error_box.html.twig', array('errors' => $errors)); $twig->display('error_box.html.twig', array('errors' => $errors));
if (defined('HIDE_LOGIN_BOX') && HIDE_LOGIN_BOX) {
return;
}
$twig->display('account.login.html.twig', array( $twig->display('account.login.html.twig', array(
'redirect' => $_REQUEST['redirect'] ?? null, 'redirect' => $_REQUEST['redirect'] ?? null,
'account' => USE_ACCOUNT_NAME ? 'Name' : 'Number', 'account' => USE_ACCOUNT_NAME ? 'Name' : 'Number',

View File

@@ -19,17 +19,18 @@ if(!$logged) {
csrfProtect(); csrfProtect();
$new_password = $_POST['new_password'] ?? null; $new_password = $_POST['newpassword'] ?? NULL;
$new_password_confirm = $_POST['new_password_confirm'] ?? null; $new_password_confirm = $_POST['newpassword_confirm'] ?? NULL;
$old_password = $_POST['old_password'] ?? null; $old_password = $_POST['oldpassword'] ?? NULL;
if(empty($new_password) && empty($new_password_confirm) && empty($old_password)) { if(empty($new_password) && empty($new_password_confirm) && empty($old_password)) {
$twig->display('account.change-password.html.twig'); $twig->display('account.change-password.html.twig');
} }
else { else
{
if(empty($new_password) || empty($new_password_confirm) || empty($old_password)){ if(empty($new_password) || empty($new_password_confirm) || empty($old_password)){
$errors[] = 'Please fill in form.'; $errors[] = 'Please fill in form.';
} }
$password_strlen = strlen($new_password);
if($new_password != $new_password_confirm) { if($new_password != $new_password_confirm) {
$errors[] = 'The new passwords do not match!'; $errors[] = 'The new passwords do not match!';
} }
@@ -40,13 +41,10 @@ else {
} }
/** @var OTS_Account $account_logged */ /** @var OTS_Account $account_logged */
$old_password_hashed = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password); $old_password = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password);
if($old_password_hashed != $account_logged->getPassword()) { if($old_password != $account_logged->getPassword()) {
$errors[] = 'Current password is incorrect!'; $errors[] = 'Current password is incorrect!';
} }
else if ($old_password == $new_password) {
$errors[] = 'The old password is same as the new password!';
}
$hooks->trigger(HOOK_ACCOUNT_CHANGE_PASSWORD_POST); $hooks->trigger(HOOK_ACCOUNT_CHANGE_PASSWORD_POST);
} }

View File

@@ -9,7 +9,6 @@
*/ */
use MyAAC\Models\Account; use MyAAC\Models\Account;
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -21,20 +20,16 @@ if(empty($hash)) {
return; return;
} }
// by default link is valid for 30 days if(!Account::where('email_hash', $hash)->exists()) {
$accountEmailVerify = AccountEmailVerify::where('hash', $hash)->where('sent_at', '>', time() - 30 * 24 * 60 * 60)->first(); note("Your email couldn't be verified. Please contact staff to do it manually.");
if(!$accountEmailVerify) {
note("Wrong link or link has expired.");
} }
else else
{ {
$accountModel = Account::where('id', $accountEmailVerify->account_id)->where('email_verified', 0)->first(); $accountModel = Account::where('email_hash', $hash)->where('email_verified', 0)->first();
if ($accountModel) { if ($accountModel) {
$accountModel->email_verified = 1; $accountModel->email_verified = 1;
$accountModel->save(); $accountModel->save();
AccountEmailVerify::where('account_id', $accountModel->id)->delete();
success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this. You can now <a href=' . getLink('account/manage') . '>log in</a>.'); success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this. You can now <a href=' . getLink('account/manage') . '>log in</a>.');
$account = new OTS_Account(); $account = new OTS_Account();
@@ -44,6 +39,6 @@ else
} }
} }
else { else {
error('Your account is already verified.'); error('Link has expired.');
} }
} }

View File

@@ -10,7 +10,6 @@
*/ */
use MyAAC\CreateCharacter; use MyAAC\CreateCharacter;
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Create Account'; $title = 'Create Account';
@@ -245,12 +244,7 @@ if($save)
if(setting('core.mail_enabled') && setting('core.account_mail_verify')) if(setting('core.mail_enabled') && setting('core.account_mail_verify'))
{ {
$hash = md5(generateRandomString(16, true, true) . $email); $hash = md5(generateRandomString(16, true, true) . $email);
$new_account->setCustomField('email_hash', $hash);
AccountEmailVerify::create([
'account_id' => $new_account->getId(),
'hash' => $hash,
'sent_at' => time(),
]);
$verify_url = getLink('account/confirm-email/' . $hash); $verify_url = getLink('account/confirm-email/' . $hash);
$body_html = $twig->render('mail.account.verify.html.twig', array( $body_html = $twig->render('mail.account.verify.html.twig', array(
@@ -274,10 +268,8 @@ if($save)
} }
else else
{ {
error('An error occurred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log'); error('An error occorred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log');
$new_account->delete(); $new_account->delete();
return;
} }
} }
else else

View File

@@ -10,6 +10,7 @@
*/ */
use MyAAC\RateLimit; use MyAAC\RateLimit;
use MyAAC\TwoFactorAuth\TwoFactorAuth;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
@@ -48,12 +49,16 @@ if(!empty($login_account) && !empty($login_password))
) )
{ {
if (setting('core.account_mail_verify') && (int)$account_logged->getCustomField('email_verified') !== 1) { if (setting('core.account_mail_verify') && (int)$account_logged->getCustomField('email_verified') !== 1) {
$link = getLink('account/resend-email-verify'); $errors[] = 'Your account is not verified. Please verify your email address. If the message is not coming check the SPAM folder in your E-Mail client.';
$errors[] = 'Your account is not verified. Please verify your email address. If the message is not coming check the SPAM folder in your E-Mail client.<br/>' .
'You can resend the Email here: <a href="' . $link . '">' . $link . '</a>';
} else { } else {
session_regenerate_id();
setSession('account', $account_logged->getId()); setSession('account', $account_logged->getId());
$twoFactorAuth = TwoFactorAuth::getInstance($account_logged);
if (!$twoFactorAuth->process($login_account, $login_password, $remember_me, $_POST['auth-code'] ?? '')) {
return;
}
session_regenerate_id();
setSession('password', encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password)); setSession('password', encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password));
if($remember_me) { if($remember_me) {
setSession('remember_me', true); setSession('remember_me', true);

View File

@@ -8,6 +8,9 @@
* @copyright 2019 MyAAC * @copyright 2019 MyAAC
* @link https://my-aac.org * @link https://my-aac.org
*/ */
use MyAAC\TwoFactorAuth\TwoFactorAuth;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Account Management'; $title = 'Account Management';
@@ -38,24 +41,15 @@ csrfProtect();
$groups = new OTS_Groups_List(); $groups = new OTS_Groups_List();
$freePremium = isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium']) || $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS;
$dayOrDays = $account_logged->getPremDays() == 1 ? 'day' : 'days';
/** /**
* @var OTS_Account $account_logged * @var OTS_Account $account_logged
*/ */
$premDays = $account_logged->getPremDays(); if(!$account_logged->isPremium())
$freePremium = isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium']) || $premDays == OTS_Account::GRATIS_PREMIUM_DAYS;
$dayOrDays = ($premDays == 1 ? 'day' : 'days');
$vipSystemEnabled = isset($config['lua']['vipSystemEnabled']) && getBoolean($config['lua']['vipSystemEnabled']);
$premiumLabel = $vipSystemEnabled ? 'VIP' : 'Premium Account';
if ($freePremium && !$vipSystemEnabled) {
$account_status = '<b><span style="color: green">Gratis Premium Account</span></b>';
} else if(!$account_logged->isPremium()) {
$account_status = '<b><span style="color: red">Free Account</span></b>'; $account_status = '<b><span style="color: red">Free Account</span></b>';
} else { else
$account_status = '<b><span style="color: green">' . $premiumLabel . ', ' . $premDays . ' '.$dayOrDays.' left</span></b>'; $account_status = '<b><span style="color: green">' . ($freePremium ? 'Gratis Premium Account' : 'Premium Account, ' . $account_logged->getPremDays() . ' '.$dayOrDays.' left') . '</span></b>';
}
$recovery_key = $account_logged->getCustomField('key'); $recovery_key = $account_logged->getCustomField('key');
if(empty($recovery_key)) if(empty($recovery_key))
@@ -120,6 +114,8 @@ $twig->display('account.management.html.twig', array(
'account_registered' => $account_registered, 'account_registered' => $account_registered,
'account_rlname' => $account_rlname, 'account_rlname' => $account_rlname,
'account_location' => $account_location, 'account_location' => $account_location,
'twoFactorViews' => TwoFactorAuth::getInstance($account_logged)->getAccountManageViews(),
'actions' => $actions, 'actions' => $actions,
'players' => $account_players 'players' => $account_players,
)); ));

View File

@@ -1,94 +0,0 @@
<?php
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Resend Email';
$errorWithBackButton = function ($msg) use ($twig) {
$errors = [$msg];
$twig->display('error_box.html.twig', ['errors' => $errors]);
$twig->display('account.back_button.html.twig', [
'action' => getLink('account/resend-email-verify'),
]);
};
if (!setting('core.mail_enabled') || !setting('core.account_mail_verify')) {
$errorWithBackButton('Resending email is not possible on this server.');
return;
}
$showForm = true;
if (isset($_POST['submit']) && $_POST['submit'] == '1') {
$email = $_REQUEST['email'];
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errorWithBackButton('Please enter valid Email.');
return;
}
$account = new OTS_Account();
$account->findByEMail($email);
if ($account->isLoaded()) {
if ($account->getCustomField('email_verified') == '1') {
$errorWithBackButton('This account is already verified! You can <a href=' . getLink('account/manage') . '>log in</a> on the website.');
return;
}
$accountEmailVerify = AccountEmailVerify::where('account_id', $account->getId())->orderBy('sent_at', 'DESC')->first();
if ($accountEmailVerify && time() - $accountEmailVerify->sent_at < 60) {
$errorWithBackButton('Only one Email per minute is allowed. Please try again later.');
return;
}
$tmp_account = $email;
if (!config('account_login_by_email')) {
$tmp_account = (USE_ACCOUNT_NAME ? $account->getName() : $account->getId());
}
$hash = md5(generateRandomString(16, true, true) . $email);
AccountEmailVerify::create([
'account_id' => $account->getId(),
'hash' => $hash,
'sent_at' => time(),
]);
$verify_url = getLink('account/confirm-email/' . $hash);
$body_html = $twig->render('mail.account.resend-email-verify.html.twig', array(
'account' => $tmp_account,
'verify_url' => generateLink($verify_url, $verify_url, true)
));
if (_mail($account->getEMail(), configLua('serverName') . ' - Verify Account', $body_html)) {
$message = "If account with this email exists - you will become an email with verification link.";
$showForm = false;
} else {
$message = "<p class='error'>An error occurred while sending email (<b>{$email}</b> )! Try again later. For Admin: More info can be found in system/logs/mailer-error.log</p>";
}
}
else {
$message = "<br />If account with this email exists - you will become an email with verification link.";
$showForm = false;
}
$twig->display('success.html.twig', array(
'title' => 'Verify Email Sent',
'description' => $message,
));
}
//show errors if not empty
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
$twig->display('account.back_button.html.twig', [
'action' => getLink('account/resend-email-verify'),
]);
}
if ($showForm) {
$twig->display('account.resend-email-verify.html.twig');
}

View File

@@ -21,9 +21,6 @@ if(!$logged) {
$errors[] = 'You are not logged in. You can\'t create guild.'; $errors[] = 'You are not logged in. You can\'t create guild.';
} }
$configLuaFreePremium = configLua('freePremium');
$freePremium = (isset($configLuaFreePremium) && getBoolean($configLuaFreePremium)) || ($logged && $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS);
$array_of_player_nig = array(); $array_of_player_nig = array();
if(empty($errors)) if(empty($errors))
{ {
@@ -34,7 +31,7 @@ if(empty($errors))
if(!$player_rank->isLoaded()) if(!$player_rank->isLoaded())
{ {
if($player->getLevel() >= setting('core.guild_need_level')) { if($player->getLevel() >= setting('core.guild_need_level')) {
if(!setting('core.guild_need_premium') || $account_logged->isPremium() || $freePremium) { if(!setting('core.guild_need_premium') || $account_logged->isPremium()) {
$array_of_player_nig[] = $player->getName(); $array_of_player_nig[] = $player->getName();
} }
} }
@@ -98,7 +95,7 @@ if($todo == 'save')
if($player->getLevel() < setting('core.guild_need_level')) { if($player->getLevel() < setting('core.guild_need_level')) {
$errors[] = 'Character <b>'.$name.'</b> has too low level. To create guild you need character with level <b>' . setting('core.guild_need_level') . '</b>.'; $errors[] = 'Character <b>'.$name.'</b> has too low level. To create guild you need character with level <b>' . setting('core.guild_need_level') . '</b>.';
} }
if(setting('core.guild_need_premium') && !$account_logged->isPremium() && !$freePremium) { if(setting('core.guild_need_premium') && !$account_logged->isPremium()) {
$errors[] = 'Character <b>'.$name.'</b> is on FREE account. To create guild you need PREMIUM account.'; $errors[] = 'Character <b>'.$name.'</b> is on FREE account. To create guild you need PREMIUM account.';
} }
} }

View File

@@ -88,10 +88,8 @@ if($logged && $account_logged && $account_logged->isLoaded()) {
/** /**
* Routes loading * Routes loading
*/ */
$routesFinal = [];
$dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) { $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) {
global $cache, $routesFinal; $routesFinal = [];
foreach(getDatabasePages() as $page) { foreach(getDatabasePages() as $page) {
$routesFinal[] = ['*', $page, '__database__/' . $page, 100]; $routesFinal[] = ['*', $page, '__database__/' . $page, 100];
} }
@@ -167,7 +165,7 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r)
echo '</pre>'; echo '</pre>';
die; die;
*/ */
foreach ($routesFinal as &$route) { foreach ($routesFinal as $route) {
if ($route[0] === '*') { if ($route[0] === '*') {
$route[0] = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD']; $route[0] = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'];
} }
@@ -200,10 +198,6 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r)
log_append('router.log', $warning); log_append('router.log', $warning);
} }
} }
if ($cache->enabled()) {
$cache->set('routes_final', serialize($routesFinal), 10 * 365 * 24 * 60 * 60); // 10 years / infinite
}
}, },
[ [
'cacheFile' => CACHE . 'route.cache', 'cacheFile' => CACHE . 'route.cache',
@@ -218,7 +212,7 @@ $found = true;
// old support for pages like /?subtopic=accountmanagement // old support for pages like /?subtopic=accountmanagement
$page = $_REQUEST['p'] ?? ($_REQUEST['subtopic'] ?? ''); $page = $_REQUEST['p'] ?? ($_REQUEST['subtopic'] ?? '');
if(!empty($page) && preg_match('/^[A-z0-9\/\-]+$/', $page)) { if(!empty($page) && preg_match('/^[A-z0-9\-]+$/', $page)) {
if (isset($_REQUEST['p'])) { // some plugins may require this if (isset($_REQUEST['p'])) { // some plugins may require this
$_REQUEST['subtopic'] = $_REQUEST['p']; $_REQUEST['subtopic'] = $_REQUEST['p'];
} }
@@ -227,27 +221,10 @@ if(!empty($page) && preg_match('/^[A-z0-9\/\-]+$/', $page)) {
require SYSTEM . 'compat/pages.php'; require SYSTEM . 'compat/pages.php';
} }
$foundRoute = false;
$tmp = null;
if ($cache->enabled() && $cache->fetch('routes_final', $tmp)) {
$routesFinal = unserialize($tmp);
}
foreach ($routesFinal as $route) {
if ($page === $route[1]) {
$file = $route[2];
$foundRoute = true;
break;
}
}
if (!$foundRoute) {
$file = loadPageFromFileSystem($page, $found); $file = loadPageFromFileSystem($page, $found);
if(!$found) { if(!$found) {
$file = false; $file = false;
} }
}
} }
else { else {
$routeInfo = $dispatcher->dispatch($httpMethod, $uri); $routeInfo = $dispatcher->dispatch($httpMethod, $uri);

View File

@@ -115,11 +115,6 @@ class Cache
return unserialize($value); return unserialize($value);
} }
// -1 for infinite cache
if ($ttl == -1) {
$ttl = 10 * 365 * 24 * 60 * 60; // 10 years should be enough
}
$value = $callback(); $value = $callback();
$cache->set($key, serialize($value), $ttl); $cache->set($key, serialize($value), $ttl);
return $value; return $value;

View File

@@ -1,33 +0,0 @@
<?php
namespace MyAAC\Commands;
use POT;
trait Env
{
protected function init(): void
{
global $config;
if (!isset($config['installed']) || !$config['installed']) {
throw new \RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.');
}
if(empty($config['server_path'])) {
throw new \RuntimeException('Server Path has been not set. Go to config.php and set it.');
}
// take care of trailing slash at the end
if($config['server_path'][strlen($config['server_path']) - 1] !== '/')
$config['server_path'] .= '/';
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua');
// POT
require_once SYSTEM . 'libs/pot/OTS.php';
$ots = POT::getInstance();
$eloquentConnection = null;
require_once SYSTEM . 'database.php';
}
}

View File

@@ -9,8 +9,6 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class MigrateCommand extends Command class MigrateCommand extends Command
{ {
use Env;
protected function configure(): void protected function configure(): void
{ {
$this->setName('migrate') $this->setName('migrate')
@@ -19,19 +17,9 @@ class MigrateCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$this->init(); require SYSTEM . 'init.php';
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
$tmp = '';
if(fetchDatabaseConfig('database_version', $tmp)) { // we got version
$tmp = (int)$tmp;
if ($tmp >= DATABASE_VERSION) {
$io->success('Already on latest version.');
return Command::SUCCESS;
}
}
require SYSTEM . 'migrate.php'; require SYSTEM . 'migrate.php';
$io->success('Migrated to latest version (' . DATABASE_VERSION . ')'); $io->success('Migrated to latest version (' . DATABASE_VERSION . ')');

View File

@@ -10,8 +10,6 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class MigrateRunCommand extends Command class MigrateRunCommand extends Command
{ {
use Env;
protected function configure(): void protected function configure(): void
{ {
$this->setName('migrate:run') $this->setName('migrate:run')
@@ -25,12 +23,12 @@ class MigrateRunCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
require SYSTEM . 'init.php';
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
$ids = $input->getArgument('id'); $ids = $input->getArgument('id');
$this->init();
// pre-check // pre-check
// in case one of the migrations doesn't exist - we won't execute any of them // in case one of the migrations doesn't exist - we won't execute any of them
foreach ($ids as $id) { foreach ($ids as $id) {

View File

@@ -11,8 +11,6 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class MigrateToCommand extends Command class MigrateToCommand extends Command
{ {
use Env;
protected function configure(): void protected function configure(): void
{ {
$this->setName('migrate:to') $this->setName('migrate:to')
@@ -34,7 +32,7 @@ class MigrateToCommand extends Command
return Command::FAILURE; return Command::FAILURE;
} }
$this->init(); $this->initEnv();
$currentVersion = Config::where('name', 'database_version')->first()->value; $currentVersion = Config::where('name', 'database_version')->first()->value;
if ($currentVersion > $versionDest) { if ($currentVersion > $versionDest) {
@@ -82,4 +80,29 @@ class MigrateToCommand extends Command
updateDatabaseConfig('database_version', ($_up ? $id : $id - 1)); updateDatabaseConfig('database_version', ($_up ? $id : $id - 1));
} }
private function initEnv()
{
global $config;
if (!isset($config['installed']) || !$config['installed']) {
throw new \RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.');
}
if(empty($config['server_path'])) {
throw new \RuntimeException('Server Path has been not set. Go to config.php and set it.');
}
// take care of trailing slash at the end
if($config['server_path'][strlen($config['server_path']) - 1] !== '/')
$config['server_path'] .= '/';
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua');
// POT
require_once SYSTEM . 'libs/pot/OTS.php';
$ots = POT::getInstance();
$eloquentConnection = null;
require_once SYSTEM . 'database.php';
}
} }

View File

@@ -33,11 +33,10 @@ class Account extends Model {
public function getPremiumDaysAttribute() public function getPremiumDaysAttribute()
{ {
if(isset($this->premium_ends_at) || isset($this->premend) || if(isset($this->premium_ends_at) || isset($this->premend)) {
(isCanary() && isset($this->data['lastday']))) { $col = isset($this->premium_ends_at) ? 'premium_ends_at' : 'premend';
$col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->data['lastday']) ? 'lastday' : 'premend'));
$ret = ceil(($this->{$col}- time()) / (24 * 60 * 60)); $ret = ceil(($this->{$col}- time()) / (24 * 60 * 60));
return max($ret, 0); return $ret > 0 ? $ret : 0;
} }
if($this->premdays == 0) { if($this->premdays == 0) {

View File

@@ -0,0 +1,14 @@
<?php
namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
class AccountEMailCode extends Model {
protected $table = TABLE_PREFIX . 'account_email_codes';
public $timestamps = false;
protected $fillable = ['account_id', 'code', 'created_at'];
}

View File

@@ -1,15 +0,0 @@
<?php
namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
class AccountEmailVerify extends Model
{
protected $table = TABLE_PREFIX . 'account_emails_verify';
public $timestamps = false;
protected $fillable = ['account_id', 'hash', 'sent_at'];
}

View File

@@ -18,16 +18,7 @@ class Changelog extends Model {
public $timestamps = false; public $timestamps = false;
protected $fillable = [
'body', 'type', 'where',
'date', 'player_id', 'hide',
];
public function scopeIsPublic($query) { public function scopeIsPublic($query) {
$query->where('hide', '!=', 1); $query->where('hide', '!=', 1);
} }
public function player() {
return $this->belongsTo(Player::class);
}
} }

View File

@@ -1,16 +0,0 @@
<?php
namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
class ForumBoard extends Model {
protected $table = TABLE_PREFIX . 'forum_boards';
public $timestamps = false;
protected $fillable = [
'name', 'description', 'ordering',
'guild', 'access', 'closed', 'hide',
];
}

View File

@@ -10,9 +10,4 @@ class Gallery extends Model {
public $timestamps = false; public $timestamps = false;
protected $fillable = [
'comment', 'image', 'thumb',
'author', 'ordering', 'hide',
];
} }

View File

@@ -1,15 +0,0 @@
<?php
namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
class NewsCategory extends Model {
protected $table = TABLE_PREFIX . 'news_categories';
public $timestamps = false;
protected $fillable = [
'name', 'description', 'icon_id', 'hide'
];
}

View File

@@ -0,0 +1,13 @@
<?php
namespace MyAAC\TwoFactorAuth\Gateway;
use MyAAC\TwoFactorAuth\Interface\AuthGatewayInterface;
class AppAuthGateway extends BaseAuthGateway implements AuthGatewayInterface
{
public function verifyCode(string $code): bool
{
return true;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace MyAAC\TwoFactorAuth\Gateway;
class BaseAuthGateway
{
protected \OTS_Account $account;
public function __construct(\OTS_Account $account) {
$this->account = $account;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace MyAAC\TwoFactorAuth\Gateway;
use MyAAC\Models\AccountEMailCode;
use MyAAC\TwoFactorAuth\Interface\AuthGatewayInterface;
use MyAAC\TwoFactorAuth\TwoFactorAuth;
class EmailAuthGateway extends BaseAuthGateway implements AuthGatewayInterface
{
public function verifyCode(string $code): bool
{
return AccountEMailCode::where('account_id', '=', $this->account->getId())->where('code', $code)->where('created_at', '>', time() - TwoFactorAuth::EMAIL_CODE_VALID_UNTIL)->first() !== null;
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace MyAAC\TwoFactorAuth\Interface;
interface AuthGatewayInterface
{
public function __construct(\OTS_Account $account);
public function verifyCode(string $code): bool;
}

View File

@@ -0,0 +1,183 @@
<?php
namespace MyAAC\TwoFactorAuth;
use MyAAC\Models\AccountEMailCode;
use MyAAC\TwoFactorAuth\Gateway\AppAuthGateway;
use MyAAC\TwoFactorAuth\Gateway\EmailAuthGateway;
class TwoFactorAuth
{
const TYPE_NONE = 0;
const TYPE_EMAIL = 1;
const TYPE_APP = 2;
// maybe later
//const TYPE_SMS = 3;
const EMAIL_CODE_VALID_UNTIL = 24 * 60 * 60;
private static self $instance;
private \OTS_Account $account;
private int $authType;
private EmailAuthGateway|AppAuthGateway $authGateway;
public function __construct(\OTS_Account|int $account) {
if (is_int($account)) {
$this->account = new \OTS_Account();
$this->account->load($account);
}
else {
$this->account = $account;
}
$this->authType = (int)$this->account->getCustomField('2fa_type');
$this->setAuthGateway($this->authType);
}
public static function getInstance($account = null): self
{
if (!isset(self::$instance)) {
self::$instance = new self($account);
}
return self::$instance;
}
public function process($login_account, $login_password, $remember_me, $code): bool
{
global $twig;
if (!$this->isActive()) {
return true;
}
if (empty($code)) {
if ($this->authType == self::TYPE_EMAIL) {
if (!$this->hasRecentEmailCode(15 * 60)) {
$this->resendEmailCode();
//success('Resent email.');
}
define('HIDE_LOGIN_BOX', true);
$twig->display('account.2fa.email.login.html.twig', [
'account_login' => $login_account,
'password_login' => $login_password,
'remember_me' => $remember_me,
]);
}
else {
echo 'Two Factor App Auth';
}
return false;
}
if ($this->getAuthGateway()->verifyCode($code)) {
if ($this->authType === self::TYPE_EMAIL) {
$this->deleteOldCodes();
}
return true;
}
if (setting('core.mail_enabled')) {
$mailBody = $twig->render('mail.account.2fa.email-code.wrong-attempt.html.twig');
if (!_mail($this->account->getEMail(), configLua('serverName') . ' - Failed Two-Factor Authentication Attempt', $mailBody)) {
error('An error occurred while sending email. For Admin: More info can be found in system/logs/mailer-error.log');
}
}
define('HIDE_LOGIN_BOX', true);
$errors[] = 'Invalid email code!';
$twig->display('error_box.html.twig', ['errors' => $errors]);
$twig->display('account.2fa.email.login.html.twig',
[
'account_login' => $login_account,
'password_login' => $login_password,
'remember_me' => $remember_me,
'wrongCode' => true,
]);
return false;
}
public function setAuthGateway(int $authType): void
{
if ($authType === self::TYPE_EMAIL) {
$this->authGateway = new EmailAuthGateway($this->account);
}
else if ($authType === self::TYPE_APP) {
$this->authGateway = new AppAuthGateway($this->account);
}
}
public function getAccountManageViews(): array
{
$twoFactorView = 'account.2fa.protected.html.twig';
if ($this->authType == self::TYPE_EMAIL) {
$twoFactorView2 = 'account.2fa.email.activated.html.twig';
}
elseif ($this->authType == self::TYPE_APP) {
$twoFactorView2 = 'account.2fa.app.activated.html.twig';
}
else {
$twoFactorView = 'account.2fa.connect.html.twig';
$twoFactorView2 = 'account.2fa.email.activate.html.twig';
}
return [$twoFactorView, $twoFactorView2];
}
public function enable(int $type): void {
$this->account->setCustomField('2fa_type', $type);
}
public function disable(): void {
$this->account->setCustomField('2fa_type', self::TYPE_NONE);
}
public function isActive(): bool {
return $this->authType != self::TYPE_NONE;
}
public function getAuthType(): int {
return $this->authType;
}
public function getAuthGateway(): AppAuthGateway|EmailAuthGateway {
return $this->authGateway;
}
public function hasRecentEmailCode($since = self::EMAIL_CODE_VALID_UNTIL): bool {
return AccountEMailCode::where('account_id', '=', $this->account->getId())->where('created_at', '>', time() - $since)->first() !== null;
}
public function deleteOldCodes(): void {
AccountEMailCode::where('account_id', '=', $this->account->getId())->delete();
}
public function resendEmailCode(): void
{
global $twig;
$newCode = generateRandomString(6, true, false, true);
AccountEMailCode::create([
'account_id' => $this->account->getId(),
'code' => $newCode,
'created_at' => time(),
]);
$mailBody = $twig->render('mail.account.2fa.email-code.html.twig', [
'code' => $newCode,
]);
if (!_mail($this->account->getEMail(), configLua('serverName') . ' - Requested Authentication Email Code', $mailBody)) {
error('An error occurred while sending email. For Admin: More info can be found in system/logs/mailer-error.log');
}
}
}

View File

@@ -28,8 +28,6 @@ define('HOOK_CHARACTERS_AFTER_CHARACTERS', ++$i);
define('HOOK_LOGIN', ++$i); define('HOOK_LOGIN', ++$i);
define('HOOK_LOGIN_ATTEMPT', ++$i); define('HOOK_LOGIN_ATTEMPT', ++$i);
define('HOOK_LOGOUT', ++$i); define('HOOK_LOGOUT', ++$i);
define('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_OLD_PASSWORD', ++$i);
define('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_NEW_PASSWORD', ++$i);
define('HOOK_ACCOUNT_CHANGE_PASSWORD_POST', ++$i); define('HOOK_ACCOUNT_CHANGE_PASSWORD_POST', ++$i);
define('HOOK_ACCOUNT_CREATE_BEFORE_FORM', ++$i); define('HOOK_ACCOUNT_CREATE_BEFORE_FORM', ++$i);
define('HOOK_ACCOUNT_CREATE_BEFORE_BOXES', ++$i); define('HOOK_ACCOUNT_CREATE_BEFORE_BOXES', ++$i);

View File

@@ -0,0 +1,36 @@
<tr>
<td>
<div class="TableShadowContainerRightTop">
<div class="TableShadowRightTop" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rt.gif);"></div>
</div>
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);">
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody><tr>
<td class="LabelV"><b>Connect your {{ config.lua.serverName }} account to an authenticator app!</b>
<div style="float: right; font-size: 1px;">
<form action="{{ getLink('account/2fa') }}?action=email-code" method="post" style="margin: 0px; padding: 0px;">
{{ csrf() }}
{% set button_name = 'Request' %}
{% include('buttons.base.html.twig') %}
</form>
</div>
</td>
</tr>
<tr>
<td>
<p>As a first step to connect an <b>authenticator app</b> to your account, click on "Request"! An email with a confirmation key will be sent to the email address assigned to your account.</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="TableShadowContainer">
<div class="TableBottomShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bm.gif);">
<div class="TableBottomLeftShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bl.gif);"></div>
<div class="TableBottomRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-br.gif);"></div>
</div>
</div>
</td>
</tr>

View File

@@ -0,0 +1,37 @@
<tr>
<td>
<div class="TableShadowContainerRightTop">
<div class="TableShadowRightTop" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rt.gif);"></div>
</div>
<div class="TableContentAndRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-rm.gif);">
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td class="LabelV"><b>Activate email code authentication for your account!</b>
<div style="float: right; font-size: 1px;">
<form action="{{ getLink('account/2fa') }}?action=email-code&step=activate" method="post" style="margin: 0; padding: 0;">
{{ csrf() }}
{% set button_name = 'Request' %}
{% include('buttons.base.html.twig') %}
</form>
</div>
</td>
</tr>
<tr>
<td>
<p>As a first step to activate <b>email code authentication</b> for your account, click on "Request"! An <b>email code</b> will be sent to the email address assigned to your account. You will be asked to enter this <b>email code</b> on the next page within 24 hours.</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="TableShadowContainer">
<div class="TableBottomShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bm.gif);">
<div class="TableBottomLeftShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-bl.gif);"></div>
<div class="TableBottomRightShadow" style="background-image:url({{ template_path }}/images/global/content/table-shadow-br.gif);"></div>
</div>
</div>
</td>
</tr>

View File

@@ -0,0 +1,26 @@
<tr>
<td>
<div class="TableContentContainer ">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>
<div style="float: right; width: 135px;">
<form action="{{ getLink('account/2fa') }}?action=email-code" method="post" style="padding:0;margin:0;">
{{ csrf() }}
<input type="hidden" name="step" value="deactivate">
{% set button_name = 'Deactivate' %}
{{ include('buttons.base.html.twig') }}
</form>
</div>
<b>Two-Factor Email Code Authentication <span style="color: green">Activated</span>!</b>
<p>To deactivate <b>email code authentication</b>, click on the "Deactivate" button.</p>
<!--p>You will have to confirm the deactivation by entering an <b>email code</b> which will be sent
to the email address assigned to your account.</p-->
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>

View File

@@ -0,0 +1,109 @@
{% set title = 'Deactivate Email Code Authentication' %}
{% set content %}
<table style="width:100%;">
<tbody>
<tr>
<td>
<div class="TableContentContainer ">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>To deactivate <b>two-factor email code authentication</b> for your account, enter the
received <b>email code</b> below. Note, however, that <b>email code authentication</b>
is an important security feature which helps to prevent any unauthorised access to your
Tibia account.
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
<tr>
<td>
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>
<div style="float: right;">
<form
action="{{ getLink('account/2fa') }}?action=email-code&step=resend"
method="post"
style="padding:0;margin:0;"
>
{{ csrf() }}
{% set button_name = 'Resend Email Code' %}
{{ include('buttons.base.html.twig') }}
</form>
</div>
An <b>email code</b> has already been sent to the email address assigned to your
account.
Please check your email account's spam/junk filter and make sure that your mailbox is
not
full.<br>In case you need a new email code, you can request one by clicking on "Resend
Email
Code".
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
<tr>
<td>
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>To complete the deactivation of <b>email code authentication</b>, please enter the <b>email
code</b> you received at the email address assigned to your account.
<div style="margin-top: 15px; margin-bottom: 15px;">
<div class="LabelV150 {{ wrongCode ? 'red' : '' }}" style="float:left;"><label
for="email-code">Email Code:</label></div>
<input form="form-code" id="auth-code" name="email-code" maxlength="15"
autocomplete="off">
{% if wrongCode %}
<br/>
<div class="LabelV150" style="float:left;">&nbsp; </div>
<div class="FormFieldError">Invalid email code!</div>
{% endif %}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
{% endset %}
{% include 'tables.headline.html.twig' %}
<table style="width: 100%;">
<tbody>
<tr align="center" valign="top">
<td>
<form id="form-code" method="post" action="{{ getLink('account/2fa') }}?action=email-code">
{{ csrf() }}
<input type="hidden" name="step" value="deactivate">
<input type="hidden" name="save" value="1">
{% set button_name = 'Continue' %}
{% set button_color = 'green' %}
{{ include('buttons.submit.html.twig') }}
</form>
</td>
<td>
<form action="{{ getLink('account/manage') }}" method="post" style="padding:0;margin:0;">
{{ csrf() }}
{% set button_color = 'blue' %}
{{ include('buttons.back.html.twig') }}
</form>
</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,92 @@
{% set title = 'Enter Email Code' %}
{% set content %}
<table style="width:100%;">
<tbody>
<tr>
<td>
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>
<div style="float: right;">
<form
action="{{ getLink('account/2fa') }}?action=email-code&step=resend"
method="post"
style="padding:0;margin:0;"
>
{{ csrf() }}
{% set button_name = 'Resend Email Code' %}
{{ include('buttons.base.html.twig') }}
</form>
</div>
An <b>email code</b> has already been sent to the email address assigned to your account.
Please check your email account's spam/junk filter and make sure that your mailbox is not
full.<br>In case you need a new email code, you can request one by clicking on "Resend Email
Code".
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
<tr>
<td>
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td><b>Email code authentication is activated for your account.</b><br><br>Please enter the <b>most
recent email code</b> you have received in order to log in.<br>
<div style="margin-top: 15px; margin-bottom: 15px;">
<div class="LabelV150 {{ wrongCode ? 'red' : '' }}" style="float:left;"><label for="email-code">Email Code:</label></div>
<input form="form-code" id="auth-code" name="auth-code" maxlength="15" autocomplete="off">
{% if wrongCode %}
<br/>
<div class="LabelV150" style="float:left;">&nbsp; </div>
<div class="FormFieldError">Invalid email code!</div>
{% endif %}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
{% endset %}
{% include 'tables.headline.html.twig' %}
<table style="width: 100%;">
<tbody>
<tr align="center" valign="top">
<td>
<form id="form-code" method="post" action="{{ getLink('account/manage') }}">
{{ csrf() }}
<input type="hidden" name="account_login" value="{{ account_login ?? '' }}" />
<input type="hidden" name="password_login" value="{{ password_login ?? '' }}" />
{% if remember_me %}
<input type="hidden" name="remember_me" value="true" />
{% endif %}
<input type="hidden" name="step" value="verify">
{% set button_name = 'Continue' %}
{% set button_color = 'green' %}
{{ include('buttons.submit.html.twig') }}
</form>
</td>
<td>
<form action="{{ getLink('account/manage') }}" method="post" style="padding:0;margin:0;">
{{ csrf() }}
{% set button_color = 'blue' %}
{{ include('buttons.back.html.twig') }}
</form>
</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,110 @@
{% set title = 'Activate Email Code Authentication' %}
{% set content %}
<table style="width:100%;">
<tbody>
<tr>
<td>
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>Enter the email code below to activate <b>two-factor email code authentication</b>. Note
that this code is only valid for 24 hours.<br><br>
<div class="AttentionSign"><img src="{{ template_path }}/images/global/content/attentionsign.gif"></div>
<b>Note:</b> Once you have email code authentication activated, an <b>email code</b> will be
sent to the email address assigned to your account whenever you try to log in to the Tibia
client or the {{ config.lua.serverName }} website. In order to log in, you will need to enter the <b>most recent
email code</b> you have received.
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
<tr>
<td>
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>
<div style="float: right;">
<form action="{{ getLink('account/2fa') }}?action=email-code"
method="post" style="padding:0;margin:0;">
{{ csrf() }}
{% if account_logged is defined %}
<input type="hidden" name="account_logged" value="{{ account_logged.getId() }}">
{% endif %}
<input type="hidden" name="step" value="resend">
{% set button_name = 'Resend Email Code' %}
{% include('buttons.base.html.twig') %}
</form>
</div>
An <b>email code</b> has already been sent to the email address assigned to your account.
Please check your email account's spam/junk filter and make sure that your mailbox is not
full.<br>In case you need a new email code, you can request one by clicking on "Resend Email
Code".
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
<tr>
<td>
<div class="TableContentContainer">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>To complete the activation of email code authentication for your Tibia account, please enter
the email code you received at the email address assigned to your account.
<div style="margin-top: 15px; margin-bottom: 15px;">
<div class="LabelV150 {{ wrongCode ? 'red' : '' }}" style="float:left;">Email Code:</div>
<input form="confirmActivateForm" name="auth-code" maxlength="6">
{% if wrongCode %}
<br/>
<div class="LabelV150" style="float:left;">&nbsp; </div>
<div class="FormFieldError">Invalid email code!</div>
{% endif %}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
{% endset %}
{% include 'tables.headline.html.twig' %}
<br/>
<table style="width: 100%;">
<tbody>
<tr align="center" valign="top">
<td>
<form id="confirmActivateForm" action="{{ getLink('account/2fa') }}?action=email-code" method="post" style="padding:0;margin:0;">
{{ csrf() }}
<input type="hidden" name="step" value="activate">
<input type="hidden" name="save" value="1">
{% set button_color = 'green' %}
{{ include('buttons.submit.html.twig') }}
</form>
</td>
<td>
<form action="{{ getLink('account/manage') }}" method="post" style="padding:0;margin:0;">
{{ csrf() }}
{% set button_color = 'blue' %}
{{ include('buttons.back.html.twig') }}
</form>
</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,12 @@
{% set title = 'Two-Factor Authentication' %}
{% set content %}
<table style="width:100%;">
<tbody>
{{ include(twoFactorViews[0]) }}
{{ include(twoFactorViews[1]) }}
</tbody>
</table>
{% endset %}
{% include('tables.headline.html.twig') %}
<br/>

View File

@@ -0,0 +1,18 @@
<tr>
<td>
<div class="TableContentContainer ">
<table class="TableContent" width="100%" style="border:1px solid #faf0d7;">
<tbody>
<tr>
<td>
<div class="InTableRightButtonContainer"></div>
<b>Two-Factor Authenticator App</b>
<p>Your account is currently protected by email code authentication. If you prefer to use a <b>two-factor
authentication app</b>, you have to "Deactivate" email code authentication first.</p>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>

View File

@@ -9,29 +9,23 @@ Please enter your current password and a new password. For your security, please
<span>Current Password:</span> <span>Current Password:</span>
</td> </td>
<td> <td>
<input form="form" type="password" id="old_password" name="old_password" size="30" maxlength="29"> <input form="form" type="password" name="oldpassword" size="30" maxlength="29">
</td> </td>
</tr> </tr>
{{ hook('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_OLD_PASSWORD') }}
<tr> <tr>
<td class="LabelV"> <td class="LabelV">
<span>New Password:</span> <span>New Password:</span>
</td> </td>
<td style="width:90%;"> <td style="width:90%;">
<input form="form" type="password" id="new_password" name="new_password" size="30" maxlength="29"> <input form="form" type="password" name="newpassword" size="30" maxlength="29">
</td> </td>
</tr> </tr>
{{ hook('HOOK_ACCOUNT_CHANGE_PASSWORD_AFTER_NEW_PASSWORD') }}
<tr> <tr>
<td class="LabelV"> <td class="LabelV">
<span>New Password Again:</span> <span>New Password Again:</span>
</td> </td>
<td> <td>
<input form="form" type="password" id="new_password_confirm" name="new_password_confirm" size="30" maxlength="29"> <input form="form" type="password" name="newpassword_confirm" size="30" maxlength="29">
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -147,6 +147,9 @@
{% include('buttons.base.html.twig') %} {% include('buttons.base.html.twig') %}
</form> </form>
<br/> <br/>
{{ include('account.2fa.main.html.twig') }}
{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS') }} {{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS') }}
<a name="Account+Logs" ></a> <a name="Account+Logs" ></a>
<h2>Account Logs</h2> <h2>Account Logs</h2>

View File

@@ -1,45 +0,0 @@
Please enter your account Email address.<br/><br/>
{% set title = 'Resend Email' %}
{% set background = config('darkborder') %}
{% set content %}
<table style="width:100%;">
<tr>
<td class="LabelV" >
<span><label for="email">Email Address:</label></span>
</td>
<td style="width:90%;">
<input type="email" form="form" id="email" name="email" size="30" maxlength="50" autofocus/>
</td>
</tr>
</table>
{% endset %}
{% include 'tables.headline.html.twig' %}
<br/>
<table style="width:100%;">
<tr align="center">
<td>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td style="border:0;">
<form id="form" action="{{ getLink('account/resend-email-verify') }}" method="post">
{{ csrf() }}
<input type="hidden" name="submit" value="1"/>
{{ include('buttons.submit.html.twig') }}
</form>
</td>
<tr>
</table>
</td>
<td>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td style="border:0;">
<form action="{{ getLink('news') }}" method="post">
{{ include('buttons.back.html.twig') }}
</form>
</td>
</tr>
</table>
</td>
</tr>
</table>

View File

@@ -9,7 +9,7 @@
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr> <table border="0" cellpadding="0" cellspacing="0" width="100%"><tr>
<td><img src="{{ template_path }}/images/general/blank.gif" width="10" height="1" border="0"></td> <td><img src="{{ template_path }}/images/general/blank.gif" width="10" height="1" border="0"></td>
<td> <td>
{{ hook('HOOK_CHARACTERS_BEFORE_INFORMATIONS') }} {{ hook(constant('HOOK_CHARACTERS_BEFORE_INFORMATIONS')) }}
{% if canEdit %} {% if canEdit %}
<a href="{{ constant('ADMIN_URL') }}?p=players&id={{ player.getId() }}" title="Edit in Admin Panel" target="_blank"> <a href="{{ constant('ADMIN_URL') }}?p=players&id={{ player.getId() }}" title="Edit in Admin Panel" target="_blank">
<img src="images/edit.png"/>Edit <img src="images/edit.png"/>Edit
@@ -153,11 +153,11 @@
<td>{% if account.isPremium() %}Premium Account{% else %}Free Account{% endif %}</td> <td>{% if account.isPremium() %}Premium Account{% else %}Free Account{% endif %}</td>
</tr> </tr>
</table> </table>
{{ hook('HOOK_CHARACTERS_AFTER_INFORMATIONS') }} {{ hook(constant('HOOK_CHARACTERS_AFTER_INFORMATIONS')) }}
<br/> <br/>
<table border="0" width="100%"> <table border="0" width="100%">
<tr> <tr>
{{ hook('HOOK_CHARACTERS_BEFORE_SKILLS') }} {{ hook(constant('HOOK_CHARACTERS_BEFORE_SKILLS')) }}
{% if config.characters.skills %} {% if config.characters.skills %}
<!-- SKILLS --> <!-- SKILLS -->
@@ -179,7 +179,7 @@
<!-- SKILLS_END --> <!-- SKILLS_END -->
{% endif %} {% endif %}
{{ hook('HOOK_CHARACTERS_AFTER_SKILLS') }} {{ hook(constant('HOOK_CHARACTERS_AFTER_SKILLS')) }}
{% if quests_enabled %} {% if quests_enabled %}
<!-- QUESTS --> <!-- QUESTS -->
@@ -201,7 +201,7 @@
<!-- QUESTS_END --> <!-- QUESTS_END -->
{% endif %} {% endif %}
{{ hook('HOOK_CHARACTERS_AFTER_QUESTS') }} {{ hook(constant('HOOK_CHARACTERS_AFTER_QUESTS')) }}
{% if config.characters.equipment %} {% if config.characters.equipment %}
<!-- EQUIPMENT --> <!-- EQUIPMENT -->
@@ -239,11 +239,11 @@
<!-- EQUIPMENT_END --> <!-- EQUIPMENT_END -->
{% endif %} {% endif %}
{{ hook('HOOK_CHARACTERS_AFTER_EQUIPMENT') }} {{ hook(constant('HOOK_CHARACTERS_AFTER_EQUIPMENT')) }}
</tr> </tr>
</table> </table>
{{ hook('HOOK_CHARACTERS_BEFORE_DEATHS') }} {{ hook(constant('HOOK_CHARACTERS_BEFORE_DEATHS')) }}
{% if deaths|length > 0 %} {% if deaths|length > 0 %}
<!-- DEATHS --> <!-- DEATHS -->
@@ -283,7 +283,7 @@
<!-- FRAGS_END --> <!-- FRAGS_END -->
{% endif %} {% endif %}
{{ hook('HOOK_CHARACTERS_BEFORE_SIGNATURE') }} {{ hook(constant('HOOK_CHARACTERS_BEFORE_SIGNATURE')) }}
{% if setting('core.signature_enabled') %} {% if setting('core.signature_enabled') %}
<!-- SIGNATURE --> <!-- SIGNATURE -->
@@ -327,7 +327,7 @@
</table> </table>
<!-- SIGNATURE_END --> <!-- SIGNATURE_END -->
{% endif %} {% endif %}
{{ hook('HOOK_CHARACTERS_AFTER_SIGNATURE') }} {{ hook(constant('HOOK_CHARACTERS_AFTER_SIGNATURE')) }}
{% if not player.isHidden() %} {% if not player.isHidden() %}
{% set rows = 0 %} {% set rows = 0 %}
<!-- ACCOUNT_INFORMATION --> <!-- ACCOUNT_INFORMATION -->
@@ -377,7 +377,7 @@
</tr> </tr>
</table> </table>
<!-- ACCOUNT_INFORMATION_END --> <!-- ACCOUNT_INFORMATION_END -->
{{ hook('HOOK_CHARACTERS_AFTER_ACCOUNT') }} {{ hook(constant('HOOK_CHARACTERS_AFTER_ACCOUNT')) }}
<!-- CHARACTERS_LIST --> <!-- CHARACTERS_LIST -->
<br/><br/> <br/><br/>
<table border="0" cellspacing="1" cellpadding="4" width="100%"> <table border="0" cellspacing="1" cellpadding="4" width="100%">
@@ -421,7 +421,7 @@
</table> </table>
<!-- CHARACTERS_LIST_END --> <!-- CHARACTERS_LIST_END -->
{% endif %} {% endif %}
{{ hook('HOOK_CHARACTERS_AFTER_CHARACTERS') }} {{ hook(constant('HOOK_CHARACTERS_AFTER_CHARACTERS')) }}
{% if canEdit %} {% if canEdit %}
<a href="{{ constant('ADMIN_URL') }}?p=players&id={{ player.getId() }}" title="Edit in Admin Panel" target="_blank"> <a href="{{ constant('ADMIN_URL') }}?p=players&id={{ player.getId() }}" title="Edit in Admin Panel" target="_blank">
<img src="images/edit.png"/>Edit <img src="images/edit.png"/>Edit

View File

@@ -9,7 +9,7 @@
<div class="AttentionSign" style="background-image:url({{ template_path }}/images/content/attentionsign.gif);"></div> <div class="AttentionSign" style="background-image:url({{ template_path }}/images/content/attentionsign.gif);"></div>
<b>The Following Errors Have Occurred:</b><br/> <b>The Following Errors Have Occurred:</b><br/>
{% for error in errors %} {% for error in errors %}
<li>{{ error|striptags('<b><a>')|raw }}</li> <li>{{ error|striptags('<b>')|raw }}</li>
{% endfor %} {% endfor %}
</div> </div>
<div class="BoxFrameHorizontal" style="background-image:url({{ template_path }}/images/content/box-frame-horizontal.gif);"></div> <div class="BoxFrameHorizontal" style="background-image:url({{ template_path }}/images/content/box-frame-horizontal.gif);"></div>

View File

@@ -0,0 +1,9 @@
Dear {{ config.lua.serverName}} player,
<br/><br/>
Your account is protected by email code authentication, and you requested a new email code:
<br/><br/>
<p>{{ code }}</p>
<br/>
Note that the code is only valid for 24 hours.
<br/><br/>
Kind Regards,

View File

@@ -0,0 +1,5 @@
Dear {{ config.lua.serverName}} player,<br/>
<br/>
A <strong>wrong two-factor authentication code</strong> was entered for your {{ config.lua.serverName}} account. If you simply mistyped the code, please try again.<br/>
<br/>
However, if this was <strong>not you</strong>, someone else may be trying to access your account. Since they already know your password, we strongly recommend that you <strong>change your password immediately</strong>.

View File

@@ -1,7 +0,0 @@
Hello {{ account }}!<br/>
<br/>
You requested to resend the verify Email on {{ config.lua.serverName }}!<br/>
<br/>
To verify your email address please click the link below:<br/>
{{ verify_url|raw }}

View File

@@ -101,7 +101,7 @@
<tr> <tr>
<td class="LabelV150"><b>Location Datacenter:</b></td> <td class="LabelV150"><b>Location Datacenter:</b></td>
<td>{{ setting('core.online_datacenter')|raw }} <small>(Server date & time: - {{ "now"|date("d/m/Y H:i:s") }})</small></td> <td>{{ setting('core.online_datacenter') }} <small>(Server date & time: - {{ "now"|date("d/m/Y H:i:s") }})</small></td>
</tr> </tr>
<tr> <tr>
<td class="LabelV150"><b>PvP Type:</b></td> <td class="LabelV150"><b>PvP Type:</b></td>

View File

@@ -1,9 +1,6 @@
<style> <style>
.myaac-table {border-spacing: 1px;} .myaac-table tbody tr:nth-child(even) {background: {{ config.lightborder }}}
.myaac-table > tbody > tr:nth-child(even) {background: {{ config.lightborder }}} .myaac-table tbody tr:nth-child(odd) {background: {{ config.darkborder }}}
.myaac-table > tbody > tr:nth-child(odd) {background: {{ config.darkborder }}} .myaac-table thead td {background: {{ config.vdarkborder }}; color: #ffffff !important;}
.myaac-table > tbody > tr > td {padding: 4px; } .myaac-table tfoot td {background: {{ config.vdarkborder }}; color: #ffffff !important;}
.myaac-table > thead > tr > td {padding: 4px; background: {{ config.vdarkborder }}; color: #ffffff !important;}
.myaac-table > thead > tr > th {padding: 4px; background: {{ config.vdarkborder }}; color: #ffffff !important;}
.myaac-table > tfoot > tr > td {padding: 4px; background: {{ config.vdarkborder }}; color: #ffffff !important;}
</style> </style>

View File

@@ -101,10 +101,6 @@ $twig->addFunction($function);
$function = new TwigFunction('hook', function ($context, $hook, array $params = []) { $function = new TwigFunction('hook', function ($context, $hook, array $params = []) {
global $hooks; global $hooks;
if (config('hooks_debug')) {
note($hook);
}
if(is_string($hook)) { if(is_string($hook)) {
if (defined($hook)) { if (defined($hook)) {
$hook = constant($hook); $hook = constant($hook);

View File

@@ -130,7 +130,6 @@
<div style="float: right; margin-top: 20px;" > <div style="float: right; margin-top: 20px;" >
{% apply spaceless %} {% apply spaceless %}
<form class="MediumButtonForm" action="{{ getLink('account/create') }}" method="post" > <form class="MediumButtonForm" action="{{ getLink('account/create') }}" method="post" >
{{ csrf() }}
<div class="MediumButtonBackground" style="background-image:url({{ template_path }}/images/global/buttons/mediumbutton.gif)" onMouseOver="MouseOverBigButton(this);" onMouseOut="MouseOutBigButton(this);"> <div class="MediumButtonBackground" style="background-image:url({{ template_path }}/images/global/buttons/mediumbutton.gif)" onMouseOver="MouseOverBigButton(this);" onMouseOut="MouseOutBigButton(this);">
<div class="MediumButtonOver" style="background-image:url({{ template_path }}/images/global/buttons/mediumbutton-over.gif)" onMouseOver="MouseOverBigButton(this);" onMouseOut="MouseOutBigButton(this);"></div> <div class="MediumButtonOver" style="background-image:url({{ template_path }}/images/global/buttons/mediumbutton-over.gif)" onMouseOver="MouseOverBigButton(this);" onMouseOut="MouseOutBigButton(this);"></div>
<input class="MediumButtonText" type="image" name="Create Account" alt="Create Account" src="{{ template_path }}/images/global/buttons/mediumbutton_createaccount.png" /> <input class="MediumButtonText" type="image" name="Create Account" alt="Create Account" src="{{ template_path }}/images/global/buttons/mediumbutton_createaccount.png" />

View File

@@ -290,6 +290,9 @@
{% endset %} {% endset %}
{% include 'tables.headline.html.twig' %} {% include 'tables.headline.html.twig' %}
<br/> <br/>
{{ include('account.2fa.main.html.twig') }}
{{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS') }} {{ hook('HOOK_ACCOUNT_MANAGE_BEFORE_ACCOUNT_LOGS') }}
<a name="Account+Logs" ></a> <a name="Account+Logs" ></a>
<div class="TopButtonContainer"> <div class="TopButtonContainer">

View File

@@ -943,6 +943,14 @@ img {
font-size: 8pt; font-size: 8pt;
color: red; color: red;
} }
.AttentionSign img {
float: left;
top: 3px;
left: 8px;
width: 15px;
height: 13px;
margin-right: 5px;
}
.SmallBox { .SmallBox {
position: relative; position: relative;
font-size: 1px; font-size: 1px;

View File

@@ -27,12 +27,17 @@ if(isset($config['boxes']))
var loginStatus="<?php echo ($logged ? 'true' : 'false'); ?>"; var loginStatus="<?php echo ($logged ? 'true' : 'false'); ?>";
<?php <?php
if(PAGE !== 'news') { if(PAGE !== 'news') {
$tmp = str_replace('/', '_', isset($_REQUEST['subtopic']) ? escapeHtml($_REQUEST['subtopic']) : PAGE); if(isset($_REQUEST['subtopic'])) {
$tmp = escapeHtml($_REQUEST['subtopic']);
if($tmp === 'accountmanagement') {
$tmp = 'accountmanage';
}
}
else {
$tmp = str_replace('/', '_', PAGE);
$exp = explode('/', PAGE); $exp = explode('/', PAGE);
if(PAGE !== 'account/create' && PAGE !== 'account/lost' && isset($exp[1])) { if(PAGE !== 'account/create' && PAGE !== 'account/lost' && isset($exp[1])) {
if ($exp[0] === 'account' && $exp[1] === 'lost') { if ($exp[0] === 'account') {
$tmp = 'account_lost';
} elseif ($exp[0] === 'account') {
$tmp = 'account_manage'; $tmp = 'account_manage';
} else if ($exp[0] === 'news' && $exp[1] === 'archive') { } else if ($exp[0] === 'news' && $exp[1] === 'archive') {
$tmp = 'news_archive'; $tmp = 'news_archive';
@@ -42,6 +47,7 @@ if(isset($config['boxes']))
} }
} }
} }
}
else { else {
$tmp = 'news'; $tmp = 'news';
} }
@@ -84,24 +90,24 @@ if(isset($config['boxes']))
// mouse-over and click events of the loginbox // mouse-over and click events of the loginbox
function MouseOverLoginBoxText(source) function MouseOverLoginBoxText(source)
{ {
source.lastElementChild.style.visibility = "visible"; source.lastChild.style.visibility = "visible";
source.firstElementChild.style.visibility = "hidden"; source.firstChild.style.visibility = "hidden";
} }
function MouseOutLoginBoxText(source) function MouseOutLoginBoxText(source)
{ {
source.firstElementChild.style.visibility = "visible"; source.firstChild.style.visibility = "visible";
source.lastElementChild.style.visibility = "hidden"; source.lastChild.style.visibility = "hidden";
} }
function LoginButtonAction() function LoginButtonAction()
{ {
if(loginStatus === "false") { if(loginStatus == "false") {
window.location = "<?php echo getLink('account/manage'); ?>"; window.location = "<?php echo getLink('account/manage'); ?>";
} else { } else {
window.location = "<?php echo getLink('account/manage'); ?>"; window.location = "<?php echo getLink('account/manage'); ?>";
} }
} }
function LoginstatusTextAction(source) { function LoginstatusTextAction(source) {
if(loginStatus === "false") { if(loginStatus == "false") {
window.location = "<?php echo getLink('account/create'); ?>"; window.location = "<?php echo getLink('account/create'); ?>";
} else { } else {
window.location = "<?php echo getLink('account/logout'); ?>"; window.location = "<?php echo getLink('account/logout'); ?>";
@@ -220,11 +226,11 @@ if(isset($config['boxes']))
// mouse-over effects of menubuttons and submenuitems // mouse-over effects of menubuttons and submenuitems
function MouseOverMenuItem(source) function MouseOverMenuItem(source)
{ {
source.firstElementChild.style.visibility = "visible"; source.firstChild.style.visibility = "visible";
} }
function MouseOutMenuItem(source) function MouseOutMenuItem(source)
{ {
source.firstElementChild.style.visibility = "hidden"; source.firstChild.style.visibility = "hidden";
} }
function MouseOverSubmenuItem(source) function MouseOverSubmenuItem(source)
{ {
@@ -330,7 +336,7 @@ if(isset($config['boxes']))
<div id="LoginBottom" class="Loginstatus" style="background-image:url(<?php echo $template_path; ?>/images/general/box-bottom.gif)" ></div> <div id="LoginBottom" class="Loginstatus" style="background-image:url(<?php echo $template_path; ?>/images/general/box-bottom.gif)" ></div>
</div> </div>
<div id='Menu'> <div-- id='Menu'>
<div id='MenuTop' style='background-image:url(<?php echo $template_path; ?>/images/general/box-top.gif);'></div> <div id='MenuTop' style='background-image:url(<?php echo $template_path; ?>/images/general/box-top.gif);'></div>
<?php <?php
@@ -395,7 +401,6 @@ foreach($config['menu_categories'] as $id => $cat) {
<?php <?php
} }
?> ?>
</div>
<script type="text/javascript"> <script type="text/javascript">
InitializePage(); InitializePage();
</script> </script>

View File

@@ -1,11 +1,11 @@
function MouseOverBigButton(source) { function MouseOverBigButton(source) {
if (source?.firstElementChild?.style) { if (source?.firstChild?.style) {
source.firstElementChild.style.visibility = "visible"; source.firstChild.style.visibility = "visible";
} }
} }
function MouseOutBigButton(source) { function MouseOutBigButton(source) {
if (source?.firstElementChild?.style) { if (source?.firstChild?.style) {
source.firstElementChild.style.visibility = "hidden"; source.firstChild.style.visibility = "hidden";
} }
} }
function BigButtonAction(path) { function BigButtonAction(path) {

View File

@@ -9,8 +9,6 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
const IGNORE_SET_LAST_VISIT = true;
// we need some functions // we need some functions
require '../common.php'; require '../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -1,7 +1,4 @@
<?php <?php
const IGNORE_SET_LAST_VISIT = true;
require '../common.php'; require '../common.php';
require SYSTEM . 'init.php'; require SYSTEM . 'init.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';

View File

@@ -12,8 +12,6 @@
use MyAAC\CreateCharacter; use MyAAC\CreateCharacter;
use MyAAC\Models\Account; use MyAAC\Models\Account;
const IGNORE_SET_LAST_VISIT = true;
// we need some functions // we need some functions
require '../common.php'; require '../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';