diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index 600b0b7b..1ff0f712 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -22,8 +22,9 @@ jobs: strategy: fail-fast: false matrix: - php-versions: [ '7.4', '8.0', '8.1' ] - name: MyAAC on PHP ${{ matrix.php-versions }} + php-versions: [ '8.1', '8.2', '8.3' ] + ots: ['tfs-1.4', 'canary-3.1.2'] # TODO: add 'tfs-master' (actually doesn't work cause AAC doesn't support reading .env configuration) + name: Cypress (PHP ${{ matrix.php-versions }}, ${{ matrix.ots }}) steps: - name: 📌 MySQL Start & init & show db run: | @@ -32,47 +33,81 @@ jobs: mysql -e "SHOW DATABASES" -uroot -proot - name: Checkout MyAAC - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - ref: 0.9 + ref: develop + + - uses: actions/setup-node@v4 + with: + node-version: 18 + - run: npm ci - name: Checkout TFS - uses: actions/checkout@v3 + uses: actions/checkout@v4 + if: matrix.ots == 'tfs-1.4' with: repository: otland/forgottenserver ref: 1.4 - path: tfs + path: ots - - name: Import TFS Schema + - name: Checkout TFS + uses: actions/checkout@v4 + if: matrix.ots == 'tfs-master' + with: + repository: otland/forgottenserver + ref: master + path: ots + + - name: Checkout Canary + uses: actions/checkout@v4 + if: matrix.ots == 'canary-3.1.2' + with: + repository: opentibiabr/canary + ref: v3.1.2 + path: ots + + - name: Import OTS Schema run: | - mysql -uroot -proot myaac < tfs/schema.sql + mysql -uroot -proot myaac < ots/schema.sql - name: Rename config.lua - run: mv tfs/config.lua.dist tfs/config.lua + run: mv ots/config.lua.dist ots/config.lua - - name: Replace mysqlUser - uses: jacobtomlinson/gha-find-replace@v2 + - name: Replace mysqlUser (TFS 1.4) + uses: jacobtomlinson/gha-find-replace@v3 + if: matrix.ots == 'tfs-1.4' with: find: 'mysqlUser = "forgottenserver"' replace: 'mysqlUser = "root"' regex: false - include: 'tfs/config.lua' + include: 'ots/config.lua' - - name: Replace mysqlPass - uses: jacobtomlinson/gha-find-replace@v2 + - name: Replace mysqlPass (TFS 1.4) + uses: jacobtomlinson/gha-find-replace@v3 + if: matrix.ots == 'tfs-1.4' with: find: 'mysqlPass = ""' replace: 'mysqlPass = "root"' regex: false - include: 'tfs/config.lua' + include: 'ots/config.lua' - - name: Replace mysqlDatabase - uses: jacobtomlinson/gha-find-replace@v2 + - name: Replace mysqlDatabase (TFS 1.4) + uses: jacobtomlinson/gha-find-replace@v3 + if: matrix.ots == 'tfs-1.4' with: find: 'mysqlDatabase = "forgottenserver"' replace: 'mysqlDatabase = "myaac"' regex: false - include: 'tfs/config.lua' + include: 'ots/config.lua' + + - name: Replace mysqlDatabase (Canary) + uses: jacobtomlinson/gha-find-replace@v3 + if: matrix.ots == 'canary-3.1.2' + with: + find: 'mysqlDatabase = "otservbr-global"' + replace: 'mysqlDatabase = "myaac"' + regex: false + include: 'ots/config.lua' - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -85,13 +120,13 @@ jobs: run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache composer dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} # Use composer.json for key, if composer.lock is not committed. - # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + #key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - name: Install Composer dependencies run: composer install --no-progress --prefer-dist --optimize-autoloader @@ -100,21 +135,28 @@ jobs: run: nohup php -S localhost:8080 > php.log 2>&1 & - name: Cypress Run - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: CYPRESS_URL: http://localhost:8080 - CYPRESS_SERVER_PATH: /home/runner/work/myaac/myaac/tfs + CYPRESS_SERVER_PATH: /home/runner/work/myaac/myaac/ots - name: Save screenshots - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: - name: cypress-screenshots + name: cypress-screenshots-${{ matrix.php-versions }}-${{ matrix.ots }} path: cypress/screenshots - name: Upload Cypress Videos - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: - name: cypress-videos + name: cypress-videos-${{ matrix.php-versions }}-${{ matrix.ots }} path: cypress/videos + + - name: Upload PHP Logs + uses: actions/upload-artifact@v4 + if: always() + with: + name: php-log-${{ matrix.php-versions }}-${{ matrix.ots }} + path: php.log diff --git a/.gitignore b/.gitignore index 7a0569b3..cc9460c2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,15 +6,18 @@ Thumbs.db /.htaccess # composer +composer.phar composer.lock vendor # npm node_modules +tools/ext # cypress cypress.env.json cypress/e2e/2-advanced-examples +cypress/screenshots # created by release.sh releases @@ -48,6 +51,7 @@ system/cache/* !system/cache/twig/index.html !system/cache/signatures/index.html !system/cache/plugins/index.html +!system/cache/persistent/index.html # logs system/logs/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 399eba44..7327c8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [0.9.0-alpha - 02.06.2023] +## [1.0-beta - 02.02.2024] -Minimum PHP version for this release is 7.2.5. +Minimum PHP version for this release is 8.1. ### Added * reworked Admin Panel (@Leesneaks, @gpedro, @slawkens) @@ -11,17 +11,26 @@ Minimum PHP version for this release is 7.2.5. * new Dashboard: statistics, server status * new Admin Bar showed on top when admin logged in * new page: Server Data, to reload server data + * Towns, NPCs & Items are stored in permanent cache * new pages: mass account & teleport tools * changelogs editor * revised Accounts & Players editors - * option to add/modify menus with plugins + * option to add/modify admin menus with plugins * option to enable/disable plugins * better, updated TinyMCE editor (v6.x) * with option to upload images - * list of open source libraries used in project + * list of open source libraries used in project page +* auto-loading of themes, commands & pages from plugins/ folder. You need just to place them in correct folder and they will be loaded automatically - this allows better customization, without interfering with core AAC folders. This will allow in the future automatic updates for plugins as well the AAC as whole. +* config.php moved to Admin Panel -> Settings page +* new console script: aac (comes from MyAAC) - using symfony/console + * usage: `php aac` (will list all commands by default) + * example: `php aac cache:clear` + * example: `php aac plugin:install theme-example.zip` +* replace POT Query Builder to Eloquent ORM. Not 100% yet - in some places there is still old $db approach used (@gpedro) (https://github.com/slawkens/myaac/pull/230) * brand new charming installation page (by @fernandomatos) * using Bootstrap * new pages router: nikic/fast-route, allowing for better customisation +* Plugin cronjobs: central control of the cronjobs * Guild Wars support (available as plugin) * support for login and create account only by email (configurable) * with no need for account name @@ -31,7 +40,10 @@ Minimum PHP version for this release is 7.2.5. * suggest account number option * many new functions, hooks and configurables * better Exception Handler (Whoops - https://github.com/filp/whoops) -* add Cypress testing +* automated website tests (using Cypress) +* csrf protection (https://github.com/slawkens/myaac/pull/235) +* option to restrict Page view to specified group of users (Not-Logged in, logged-in players, tutors, gamemasters etc.) +* phpdebug bar (http://phpdebugbar.com/). Activated if env == 'dev', can be also activated in production by enabling "enable_debugbar" in local config ### Changed * Composer is now used for external libraries like: Twig, PHPMailer, fast-route etc. @@ -45,7 +57,7 @@ Minimum PHP version for this release is 7.2.5. * Highscores * frags works for TFS 1.x * cached - * creatures + * Monsters * moved pages to Twig: * experience stages * update player_deaths entries on name change diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index dd7aafdd..50c6f2ff 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -8,7 +8,11 @@ Fernando Matos Lee <42119604+Leesneaks@users.noreply.github.com> caio slawkens -tobi132 <52947952+tobi132@users.noreply.github.com> +tobi132 vankk whiteblXK xitobuh +Danilo Pucci +gpedro +Matheus Collier +SRNT-GG <95472530+SRNT-GG@users.noreply.github.com> diff --git a/README.md b/README.md index 3597df17..dc0bbff6 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,20 @@ Official website: https://my-aac.org [![OpenTibia Discord](https://img.shields.io/discord/288399552581468162)](https://discord.gg/2J39Wus) [![Closed Issues](https://img.shields.io/github/issues-closed-raw/slawkens/myaac)](https://github.com/slawkens/myaac/issues?q=is%3Aissue+is%3Aclosed) -| Version | Status | Branch | Requirements | -|:-----------|:------------------------------------------|:--------|:---------------| -| **0.10.x** | **Active development** | develop | **PHP >= 8.0** | -| 0.9.x | Active support | 0.9 | PHP >= 7.2.5 | -| 0.8.x | Active support | master | PHP >= 7.2.5 | -| 0.7.x | End Of Life | 0.7 | PHP >= 5.3.3 | +| Version | Status | Branch | Requirements | +|:--------|:-----------------------|:--------|:---------------| +| **1.x** | **Active development** | develop | **PHP >= 8.1** | +| 0.9.x | Not developed anymore | 0.9 | PHP >= 7.2.5 | +| 0.8.x | Active support | master | PHP >= 7.2.5 | +| 0.7.x | End Of Life | 0.7 | PHP >= 5.3.3 | ### Requirements - - PHP 8.0 or later - MySQL database - - PDO PHP Extension - - XML PHP Extension - - (optional) ZIP PHP Extension - - (optional) mod_rewrite to use friendly_urls + - PHP Extensions: pdo, xml, json + - (optional) apache2 mod_rewrite (to use friendly_urls) + - (optional) zip PHP Extension (to install plugins) + - (optional) gd PHP Extension (for generating signature images) ### Installation @@ -48,7 +47,8 @@ Official website: https://my-aac.org ### Configuration -Check *config.php* to get more informations. +Check *config.php* to get more informations. (Notice: MyAAC 1.0+ doesn't use config.php anymore, it has been moved to Admin Panel - Settings page). + Use *config.local.php* for your local configuration changes. ### Branches diff --git a/aac b/aac new file mode 100644 index 00000000..d87042f8 --- /dev/null +++ b/aac @@ -0,0 +1,40 @@ +#!/usr/bin/env php +add(new ($commandPre . $name)); +} + +$pluginCommands = Plugins::getCommands(); +foreach ($pluginCommands as $item) { + $application->add(require $item); +} + +$application->setName('MyAAC'); +$application->setVersion(MYAAC_VERSION); + +$application->run(); diff --git a/admin/includes/debugbar.php b/admin/includes/debugbar.php new file mode 100644 index 00000000..3a9ae893 --- /dev/null +++ b/admin/includes/debugbar.php @@ -0,0 +1,22 @@ +register('debugbar_admin_head_end', HOOK_ADMIN_HEAD_END, function ($params) { + global $debugBar; + + if (!isset($debugBar)) { + return; + } + + $debugBarRenderer = $debugBar->getJavascriptRenderer(); + echo $debugBarRenderer->renderHead(); +}); +$hooks->register('debugbar_admin_body_end', HOOK_ADMIN_BODY_END, function ($params) { + global $debugBar; + + if (!isset($debugBar)) { + return; + } + + $debugBarRenderer = $debugBar->getJavascriptRenderer(); + echo $debugBarRenderer->render(); +}); diff --git a/admin/includes/settings_menus.php b/admin/includes/settings_menus.php index 2ce784fc..e612a888 100644 --- a/admin/includes/settings_menus.php +++ b/admin/includes/settings_menus.php @@ -1,5 +1,7 @@ hasTable('myaac_account_actions')) { - throw new RuntimeException('Seems that the table myaac_account_actions of MyAAC doesn\'t exist in the database. This is a fatal error. You can try to reinstall MyAAC by visiting this url.'); -} - +require __DIR__ . '/includes/debugbar.php'; require SYSTEM . 'status.php'; require SYSTEM . 'login.php'; require __DIR__ . '/includes/functions.php'; @@ -49,7 +45,7 @@ if(!$logged || !admin()) { // include our page $file = __DIR__ . '/pages/' . $page . '.php'; if(!@file_exists($file)) { - if (strpos($page, 'plugins/') !== false) { + if (str_contains($page, 'plugins/')) { $file = BASE . $page; } else { diff --git a/admin/pages/accounts.php b/admin/pages/accounts.php index 214b82f0..34b3941b 100644 --- a/admin/pages/accounts.php +++ b/admin/pages/accounts.php @@ -13,6 +13,9 @@ use MyAAC\Models\Player; defined('MYAAC') or die('Direct access not allowed!'); $title = 'Account editor'; + +csrfProtect(); + $admin_base = ADMIN_URL . '?p=accounts'; $use_datatable = true; @@ -82,7 +85,7 @@ else if (isset($_REQUEST['search'])) { $account = new OTS_Account(); $account->load($id); - if (isset($account, $_POST['save']) && $account->isLoaded()) { + if (isset($_POST['save']) && $account->isLoaded()) { $error = false; $_error = ''; @@ -288,7 +291,8 @@ else if (isset($_REQUEST['search'])) {
-
+ +
@@ -581,6 +585,7 @@ else if (isset($_REQUEST['search'])) {
+
@@ -590,6 +595,7 @@ else if (isset($_REQUEST['search'])) {
+
diff --git a/admin/pages/changelog.php b/admin/pages/changelog.php index 3d5cad64..3be99498 100644 --- a/admin/pages/changelog.php +++ b/admin/pages/changelog.php @@ -9,34 +9,33 @@ * @link https://my-aac.org */ +use MyAAC\Changelog; use MyAAC\Models\Changelog as ModelsChangelog; defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Changelog'; + +csrfProtect(); + if (!hasFlag(FLAG_CONTENT_PAGES) && !superAdmin()) { echo 'Access denied.'; return; } -$title = 'Changelog'; $use_datatable = true; const CL_LIMIT = 600; // maximum changelog body length -?> - - -orderBy('group_id', POT::ORDER_DESC); $twig->display('admin.changelog.form.html.twig', array( 'action' => $action, - 'cl_link_form' => constant('ADMIN_URL').'?p=changelog&action=' . ($action == 'edit' ? 'edit' : 'new'), + 'cl_link_form' => constant('ADMIN_URL').'?p=changelog', 'cl_id' => $id ?? null, 'body' => isset($body) ? escapeHtml($body) : '', 'create_date' => $create_date ?? '', @@ -128,15 +129,3 @@ if($action == 'edit' || $action == 'new') { $twig->display('admin.changelog.html.twig', array( 'changelogs' => $changelogs, )); - -?> - diff --git a/admin/pages/dashboard.php b/admin/pages/dashboard.php index e24b98ad..73430456 100644 --- a/admin/pages/dashboard.php +++ b/admin/pages/dashboard.php @@ -10,7 +10,9 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Dashboard'; -if (isset($_GET['clear_cache'])) { +csrfProtect(); + +if (isset($_POST['clear_cache'])) { if (clearCache()) { success('Cache cleared.'); } else { @@ -18,7 +20,7 @@ if (isset($_GET['clear_cache'])) { } } -if (isset($_GET['maintenance'])) { +if (isset($_POST['maintenance'])) { $message = (!empty($_POST['message']) ? $_POST['message'] : null); $_status = (isset($_POST['status']) && $_POST['status'] == 'true'); $_status = ($_status ? '0' : '1'); diff --git a/admin/pages/login.php b/admin/pages/login.php index 8bb25f36..eb6466d3 100644 --- a/admin/pages/login.php +++ b/admin/pages/login.php @@ -10,6 +10,8 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Login'; +csrfProtect(); + require PAGES . 'account/login.php'; if ($logged) { header('Location: ' . (admin() ? ADMIN_URL : BASE_URL)); diff --git a/admin/pages/mailer.php b/admin/pages/mailer.php index 732b7461..d9cf8888 100644 --- a/admin/pages/mailer.php +++ b/admin/pages/mailer.php @@ -10,6 +10,8 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Mailer'; +csrfProtect(); + if (!hasFlag(FLAG_CONTENT_MAILER) && !superAdmin()) { echo 'Access denied.'; return; @@ -20,7 +22,7 @@ if (!setting('core.mail_enabled')) { return; } -$mail_to = isset($_REQUEST['mail_to']) ? stripslashes(trim($_REQUEST['mail_to'])) : null; +$mail_to = isset($_POST['mail_to']) ? stripslashes(trim($_POST['mail_to'])) : null; $mail_subject = isset($_POST['mail_subject']) ? stripslashes($_POST['mail_subject']) : null; $mail_content = isset($_POST['mail_content']) ? stripslashes($_POST['mail_content']) : null; diff --git a/admin/pages/mass_account.php b/admin/pages/mass_account.php index 63bec54c..dc921ac5 100644 --- a/admin/pages/mass_account.php +++ b/admin/pages/mass_account.php @@ -16,6 +16,8 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Mass Account Actions'; +csrfProtect(); + $hasCoinsColumn = $db->hasColumn('accounts', 'coins'); $hasPointsColumn = $db->hasColumn('accounts', 'premium_points'); $freePremium = $config['lua']['freePremium']; @@ -160,9 +162,9 @@ function admin_give_premdays($days) displayMessage('Premium Days not supported.'); } -if (isset($_POST['action']) && $_POST['action']) { +if (!empty(ACTION) && isRequestMethod('post')) { - $action = $_POST['action']; + $action = ACTION; if (preg_match("/[^A-z0-9_\-]/", $action)) { displayMessage('Invalid action.'); diff --git a/admin/pages/mass_teleport.php b/admin/pages/mass_teleport.php index 5027fa1c..5264914d 100644 --- a/admin/pages/mass_teleport.php +++ b/admin/pages/mass_teleport.php @@ -16,6 +16,8 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Mass Teleport Actions'; +csrfProtect(); + function admin_teleport_position($x, $y, $z) { if (!Player::query()->update([ 'posx' => $x, 'posy' => $y, 'posz' => $z @@ -38,9 +40,9 @@ function admin_teleport_town($town_id) { displayMessage('Player\'s town updated.', true); } -if (isset($_POST['action']) && $_POST['action']) { +if (!empty(ACTION) && isRequestMethod('post')) { - $action = $_POST['action']; + $action = ACTION; if (preg_match("/[^A-z0-9_\-]/", $action)) { displayMessage('Invalid action.'); diff --git a/admin/pages/menus.php b/admin/pages/menus.php index a0b492df..0e153cd8 100644 --- a/admin/pages/menus.php +++ b/admin/pages/menus.php @@ -8,24 +8,27 @@ * @link https://my-aac.org */ +use MyAAC\Cache\Cache; use MyAAC\Models\Menu; defined('MYAAC') or die('Direct access not allowed!'); $title = 'Menus'; +csrfProtect(); + if (!hasFlag(FLAG_CONTENT_MENUS) && !superAdmin()) { echo 'Access denied.'; return; } -if (isset($_REQUEST['template'])) { - $template = $_REQUEST['template']; +if (isset($_POST['template'])) { + $template = $_POST['template']; - if (isset($_REQUEST['menu'])) { - $post_menu = $_REQUEST['menu']; - $post_menu_link = $_REQUEST['menu_link']; - $post_menu_blank = $_REQUEST['menu_blank']; - $post_menu_color = $_REQUEST['menu_color']; + if (isset($_POST['menu'])) { + $post_menu = $_POST['menu']; + $post_menu_link = $_POST['menu_link']; + $post_menu_blank = $_POST['menu_blank']; + $post_menu_color = $_POST['menu_color']; if (count($post_menu) != count($post_menu_link)) { echo 'Menu count is not equal menu links. Something went wrong when sending form.'; return; @@ -69,9 +72,10 @@ if (isset($_REQUEST['template'])) { return; } - if (isset($_REQUEST['reset_colors'])) { + if (isset($_GET['reset_colors'])) { if (isset($config['menu_default_color'])) { Menu::where('template', $template)->update(['color' => str_replace('#', '', $config['menu_default_color'])]); + success('Colors has been reset.'); } else { warning('There is no default color defined, cannot reset colors.'); @@ -93,6 +97,7 @@ if (isset($_REQUEST['template'])) {

+ @@ -112,6 +117,7 @@ if (isset($_REQUEST['template'])) { $last_id = array(); ?>