Compare commits

..

47 Commits

Author SHA1 Message Date
slawkens
095ff7963d Update CHANGELOG.md 2022-08-31 19:01:30 +02:00
slawkens
dfb8be07f0 Fix: get_version for release 2022-08-31 18:56:48 +02:00
slawkens
74b4d98bba Update to 0.8.7 2022-08-31 18:45:57 +02:00
slawkens
8a7e4f0132 Update CHANGELOG.md 2022-08-31 18:45:40 +02:00
slawkens
6ebdb0ba89 Update CHANGELOG.md 2022-08-31 18:45:13 +02:00
slawkens
33817e5ab1 Fix undefined notice
Ahh @gpedro ;)
2022-08-31 18:43:42 +02:00
slawkens
cd1b481de5 Delete VERSION 2022-08-16 17:38:50 +02:00
slawkens
ab99db62bd Update version 2022-08-15 20:14:24 +02:00
Gabriel Pedro
dd3d6b3f47 feat: custom words blocked (#190)
* Update config.php

* Update validator.php

* Update config.php
2022-07-30 22:53:19 +02:00
Gabriel Pedro
d99f507244 fix: query blob param escape (#200) 2022-07-30 22:47:44 +02:00
Gabriel Pedro
b6c8a0923f feat: config use character sample skill (#201) 2022-07-27 10:12:30 +02:00
davi costa
0663b3bbf4 fix guild invite page (#196)
* fix guild invite

* removing var_dump

* sending error
2022-06-05 16:52:22 +02:00
slawkens
d683fce2b9 Fix #171 2022-06-04 21:43:37 +02:00
slawkens
3d56214c07 Fix #195 2022-06-04 20:45:12 +02:00
slawkens
e2575c3612 Don't count deleted players (patched from develop) 2022-05-31 11:54:56 +02:00
slawkens
084256ce01 Comment useless log line 2022-05-16 20:37:36 +02:00
slawkens
240be18367 Update login.php for latest TFS 1.x and otservbr
Works in both.
Thanks for Znote for rfc6238 lib.
2022-05-16 20:31:19 +02:00
slawkens
ac271839a6 Merge branch 'master' of https://github.com/otsoft/myaac 2022-05-16 14:33:53 +02:00
slawkens
734a63f6c3 Fix #191
Allow admin to create GM, God etc. names
2022-05-16 14:33:50 +02:00
thatmichaelguy
e73daedd42 Update change_rank.php (#194) 2022-04-26 21:17:40 +02:00
slawkens
802e6c228c login.php is now part of official repo
Big thanks to folks from OpenTibiaBR Team
Will be updated in next commits to support latest TFS too
2022-04-15 19:34:12 +02:00
slawkens
edf2004539 Fiz wrong path in .gitignore 2022-04-15 19:30:38 +02:00
slawkens
9e949eb32a Fix highscores page bug with high pages 2022-03-16 16:56:03 +01:00
slawkens
e255c35002 Add tables.headline
For future reference
2022-02-26 17:50:50 +01:00
slawkens
dfd3c2c4a5 <div> should not be inside of <table> element 2022-02-26 17:50:31 +01:00
slawkens
876543f064 Fix monsters reloading
Was wrong code applied from develop branch
2022-02-26 17:27:10 +01:00
slawkens
e10f82e0e9 Fix typo 2022-01-07 08:32:37 +01:00
slawkens
f496a48a4d Add notice about branch for contributions 2022-01-07 08:28:33 +01:00
slawkens
1fbb7c373e Fixes (config.news_author, group_name|capitalize) 2022-01-02 07:31:57 +01:00
slawkens
d58d7f79e7 Save php sessions in myaac dir
Instead of default PHP location
This fixes problem with permissions
2021-12-28 07:28:16 +01:00
slawkens
0643c56bc5 move contributing to wiki 2021-12-27 10:03:10 +01:00
slawkens
c51acf9dbd Add browsehappy code 2021-12-22 07:03:05 +01:00
slawkens
2f2a326eac Revert "Update CHANGELOG.md"
This reverts commit 10dad0fb4e.
2021-12-16 20:17:44 +01:00
slawkens
10dad0fb4e Update CHANGELOG.md 2021-12-16 20:17:24 +01:00
slawkens
fe01070bd1 Update README.md 2021-12-07 19:44:55 +01:00
slawkens
b558109844 Update README.md 2021-12-07 19:41:11 +01:00
slawkens
ac37802b7a Typo. 2021-12-04 14:38:17 +01:00
slawkens
f9c8027c3f Fix undefined variable notice 2021-11-04 19:54:27 +01:00
Silic0n Alph4
28dd1969b3 Fix rules page formatting (#177)
The rules page uses a textarea to show lines break.
This commit replaces the textarea and uses the Twig
nl2br function to format the text for web browsers.

Fixes #176
2021-10-30 19:29:36 +02:00
anyeor
50270f6d6f Update nginx-sample.conf (#175)
Now we prevent access to system directory and update php version.
2021-10-28 21:39:38 +02:00
slawkens
fad80307d8 Revert "Adjustments"
This reverts commit 323d1b0504.
2021-10-23 12:15:58 +02:00
slawkens
323d1b0504 Adjustments 2021-10-23 12:00:52 +02:00
slawkens
d6c1232d2d Update .gitignore 2021-10-23 11:52:20 +02:00
silic0nalph4
678d719036 Fix: admin page changed feet to match body colour (#174)
When saving changes to a character, the admin page
overwrote their foot colour with the body colour.
This fix renders the correct variable into the page
so the foot colour is preserved.
2021-10-20 20:58:28 +02:00
slawkens
723e81e90e Fix: undefined variable notice on database_log enabled 2021-08-30 16:10:54 +02:00
slawkens
60d2cfea99 Fix #169 2021-08-11 22:47:59 +02:00
slawkens
84c39676ee Fix account character create if auto_login is enabled 2021-07-27 18:42:52 +02:00
37 changed files with 887 additions and 156 deletions

13
.gitignore vendored
View File

@@ -1,15 +1,19 @@
Thumbs.db Thumbs.db
.DS_Store .DS_Store
.idea .idea
tmp
# composer # composer
composer.lock composer.lock
vendor vendor
# npm
node_modules
# created by release.sh
releases releases
tmp
config.local.php config.local.php
PERSONAL_NOTES
# all custom templates # all custom templates
templates/* templates/*
@@ -27,6 +31,10 @@ system/cache/*
!system/cache/signatures/index.html !system/cache/signatures/index.html
!system/cache/plugins/index.html !system/cache/plugins/index.html
# php sessions
system/php_sessions/*
!system/php_sessions//index.html
# logs # logs
system/logs/* system/logs/*
!system/logs/index.html !system/logs/index.html
@@ -42,7 +50,6 @@ plugins/*
!plugins/account-create-hint.json !plugins/account-create-hint.json
!plugins/account-create-hint !plugins/account-create-hint
landing landing
/login.php
# others/rest # others/rest
system/pages/downloads.php system/pages/downloads.php

View File

@@ -1,5 +1,32 @@
# Changelog # Changelog
## [0.8.7 - 31.08.2022]
### Added
* login.php for client 12.x is now part of official repo
* browsehappy code
* config use character sample skill (#201, @gpedro)
* custom words blocked (#190, @gpedro)
### Changed
* save php sessions in myaac dir
* don't count deleted players when creating new character
### Fixed
* patch vulnerability in change_rank.php (#194, @gesior, @thatmichaelguy)
* fix guild invite page (#196, @worthdavi)
* players not showing on highscores page (#195)
* highscores page bug with high pages
* $player->getStorage() does not work at all (#169, @gesior)
* copying sample character when it have items with quotes (#200, @gpedro)
* IPv6 issue when env is set to dev (#171)
* admin page changed feet to match body colour (#174, @silic0nalph4)
* exception being thrown when creating duplicated character name (#191)
* rules page formatting (#177, @silic0nalph4)
* account character create if auto_login is enabled
* undefined variable notice on database_log enabled
* removed VERSION file
## [0.8.6 - 10.07.2021] ## [0.8.6 - 10.07.2021]
This update contains very important security fix. This update contains very important security fix.

View File

@@ -1,4 +1,4 @@
# MyAAC # [MyAAC](https://my-aac.org)
[![Build Status Master](https://img.shields.io/travis/slawkens/myaac/master)](https://travis-ci.org/github/slawkens/myaac) [![Build Status Master](https://img.shields.io/travis/slawkens/myaac/master)](https://travis-ci.org/github/slawkens/myaac)
[![License: GPL-3.0](https://img.shields.io/github/license/slawkens/myaac)](https://opensource.org/licenses/gpl-license) [![License: GPL-3.0](https://img.shields.io/github/license/slawkens/myaac)](https://opensource.org/licenses/gpl-license)
@@ -9,9 +9,7 @@
MyAAC is a free and open-source Automatic Account Creator (AAC) written in PHP. It is a fork of the [Gesior](https://github.com/gesior/Gesior2012) project. It supports only MySQL databases. MyAAC is a free and open-source Automatic Account Creator (AAC) written in PHP. It is a fork of the [Gesior](https://github.com/gesior/Gesior2012) project. It supports only MySQL databases.
Official website: https://my-aac.org ### Requirements
### REQUIREMENTS
- PHP 5.6 or later - PHP 5.6 or later
- MySQL database - MySQL database
@@ -20,7 +18,7 @@ Official website: https://my-aac.org
- ZIP PHP Extension - ZIP PHP Extension
- (optional) mod_rewrite to use friendly_urls - (optional) mod_rewrite to use friendly_urls
### INSTALLATION AND CONFIGURATION ### Installation
Just decompress and untar the source (which you should have done by now, Just decompress and untar the source (which you should have done by now,
if you're reading this), into your webserver's document root. if you're reading this), into your webserver's document root.
@@ -40,15 +38,39 @@ Official website: https://my-aac.org
Visit http://your_domain/install (http://localhost/install) and follow instructions in the browser. Visit http://your_domain/install (http://localhost/install) and follow instructions in the browser.
### KNOWN PROBLEMS ### Configuration
- none - Check *config.php* to get more informations.
Use *config.local.php* for your local configuration changes.
### OTHER NOTES ### Branches
If you have a great idea or want contribute to the project - visit our website at https://www.my-aac.org This repository follows the Git Flow Workflow.
Cheatsheet: [Git-Flow-Cheetsheet](https://danielkummer.github.io/git-flow-cheatsheet)
### LICENSING That means, we use:
* master branch, for current stable release
* develop branch, for development version (next release)
* feature branches, for features etc.
This program and all associated files are released under the GNU Public ### Known Problems
License, see LICENSE for details.
- Some compatibility issues with some exotical distibutions.
### Contributing
Contributions are more than welcome.
Pull requests should be made to the Dev branch as that is the working branch, master is for release code.
Look: [Contributing](https://github.com/otsoft/myaac/wiki/Contributing) in our wiki.
### Other Notes
If you have a great idea or want contribute to the project - visit our website at https://www.my-aac.org
### License
This program and all associated files are released under the GNU Public License.
See [LICENSE](https://github.com/slawkens/myaac/blob/master/LICENSE) for details.

View File

@@ -1 +0,0 @@
0.8.6

View File

@@ -650,7 +650,7 @@ else if ($id > 0 && isset($player) && $player->isLoaded())
<label for="look_feet" class="control-label">Feet: <span <label for="look_feet" class="control-label">Feet: <span
id="look_feet_val"></span></label> id="look_feet_val"></span></label>
<input type="range" min="0" max="132" <input type="range" min="0" max="132"
value="<?php echo $player->getLookBody(); ?>" value="<?php echo $player->getLookFeet(); ?>"
class="slider form-control" id="look_feet" name="look_feet"> class="slider form-control" id="look_feet" name="look_feet">
</div> </div>
</div> </div>

View File

@@ -24,11 +24,10 @@
* @link https://my-aac.org * @link https://my-aac.org
*/ */
if (version_compare(phpversion(), '5.6', '<')) die('PHP version 5.6 or higher is required.'); if (version_compare(phpversion(), '5.6', '<')) die('PHP version 5.6 or higher is required.');
session_start();
define('MYAAC', true); define('MYAAC', true);
define('MYAAC_VERSION', '0.8.6'); define('MYAAC_VERSION', '0.8.7');
define('DATABASE_VERSION', 32); define('DATABASE_VERSION', 33);
define('TABLE_PREFIX', 'myaac_'); define('TABLE_PREFIX', 'myaac_');
define('START_TIME', microtime(true)); define('START_TIME', microtime(true));
define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX')); define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX'));
@@ -86,6 +85,9 @@ define('TFS_03', 4);
define('TFS_FIRST', TFS_02); define('TFS_FIRST', TFS_02);
define('TFS_LAST', TFS_03); define('TFS_LAST', TFS_03);
session_save_path(SYSTEM . 'php_sessions');
session_start();
// basedir // basedir
$basedir = ''; $basedir = '';
$tmp = explode('/', $_SERVER['SCRIPT_NAME']); $tmp = explode('/', $_SERVER['SCRIPT_NAME']);

View File

@@ -151,6 +151,8 @@ $config = array(
4 => 'Knight Sample' 4 => 'Knight Sample'
), ),
'use_character_sample_skills' => false,
// it must show limited number of players after using search in character page // it must show limited number of players after using search in character page
'characters_search_limit' => 15, 'characters_search_limit' => 15,
@@ -279,5 +281,13 @@ $config = array(
'date_timezone' => 'Europe/Berlin', // more info at http://php.net/manual/en/timezones.php 'date_timezone' => 'Europe/Berlin', // more info at http://php.net/manual/en/timezones.php
'footer_show_load_time' => true, // display load time of the page in the footer 'footer_show_load_time' => true, // display load time of the page in the footer
'npc' => array() 'npc' => array(),
// character name blocked
'character_name_blocked' => array(
'prefix' => array(),
'names' => array(),
'words' => array(),
),
); );

View File

@@ -1,4 +1,4 @@
SET @myaac_database_version = 32; SET @myaac_database_version = 33;
CREATE TABLE `myaac_account_actions` CREATE TABLE `myaac_account_actions`
( (
@@ -207,24 +207,10 @@ CREATE TABLE `myaac_monsters` (
`use_haste` tinyint(1) NOT NULL, `use_haste` tinyint(1) NOT NULL,
`voices` text NOT NULL, `voices` text NOT NULL,
`immunities` varchar(255) NOT NULL, `immunities` varchar(255) NOT NULL,
`elements` TEXT NOT NULL,
`summonable` tinyint(1) NOT NULL, `summonable` tinyint(1) NOT NULL,
`convinceable` tinyint(1) NOT NULL, `convinceable` tinyint(1) NOT NULL,
`pushable` TINYINT(1) NOT NULL DEFAULT '0',
`canpushitems` TINYINT(1) NOT NULL DEFAULT '0',
`canwalkonenergy` TINYINT(1) NOT NULL DEFAULT '0',
`canwalkonpoison` TINYINT(1) NOT NULL DEFAULT '0',
`canwalkonfire` TINYINT(1) NOT NULL DEFAULT '0',
`runonhealth` TINYINT(1) NOT NULL DEFAULT '0',
`hostile` TINYINT(1) NOT NULL DEFAULT '0',
`attackable` TINYINT(1) NOT NULL DEFAULT '0',
`rewardboss` TINYINT(1) NOT NULL DEFAULT '0',
`defense` INT(11) NOT NULL DEFAULT '0',
`armor` INT(11) NOT NULL DEFAULT '0',
`canpushcreatures` TINYINT(1) NOT NULL DEFAULT '0',
`race` varchar(255) NOT NULL, `race` varchar(255) NOT NULL,
`loot` text NOT NULL, `loot` text NOT NULL,
`summons` TEXT NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8; ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
@@ -338,7 +324,7 @@ CREATE TABLE `myaac_spells`
CREATE TABLE `myaac_visitors` CREATE TABLE `myaac_visitors`
( (
`ip` VARCHAR(16) NOT NULL, `ip` VARCHAR(45) NOT NULL,
`lastvisit` INT(11) NOT NULL DEFAULT 0, `lastvisit` INT(11) NOT NULL DEFAULT 0,
`page` VARCHAR(2048) NOT NULL, `page` VARCHAR(2048) NOT NULL,
UNIQUE (`ip`) UNIQUE (`ip`)

285
login.php Normal file
View File

@@ -0,0 +1,285 @@
<?php
require_once 'common.php';
require_once 'config.php';
require_once 'config.local.php';
require_once SYSTEM . 'functions.php';
require_once SYSTEM . 'init.php';
require_once SYSTEM . 'status.php';
# error function
function sendError($message, $code = 3){
$ret = [];
$ret['errorCode'] = $code;
$ret['errorMessage'] = $message;
die(json_encode($ret));
}
# event schedule function
function parseEvent($table1, $date, $table2)
{
if ($table1) {
if ($date) {
if ($table2) {
$date = $table1->getAttribute('startdate');
return date_create("{$date}")->format('U');
} else {
$date = $table1->getAttribute('enddate');
return date_create("{$date}")->format('U');
}
} else {
foreach($table1 as $attr) {
if ($attr) {
return $attr->getAttribute($table2);
}
}
}
}
return 'error';
}
$request = json_decode(file_get_contents('php://input'));
$action = $request->type ?? '';
/** @var OTS_Base_DB $db */
/** @var array $config */
switch ($action) {
case 'cacheinfo':
$playersonline = $db->query("select count(*) from `players_online`")->fetchAll();
die(json_encode([
'playersonline' => (intval($playersonline[0][0])),
'twitchstreams' => 0,
'twitchviewer' => 0,
'gamingyoutubestreams' => 0,
'gamingyoutubeviewer' => 0
]));
case 'eventschedule':
$eventlist = [];
$file_path = config('server_path') . 'data/XML/events.xml';
if (!file_exists($file_path)) {
die(json_encode([]));
}
$xml = new DOMDocument;
$xml->load($file_path);
$tmplist = [];
$tableevent = $xml->getElementsByTagName('event');
foreach ($tableevent as $event) {
if ($event) { $tmplist = [
'colorlight' => parseEvent($event->getElementsByTagName('colors'), false, 'colorlight'),
'colordark' => parseEvent($event->getElementsByTagName('colors'), false, 'colordark'),
'description' => parseEvent($event->getElementsByTagName('description'), false, 'description'),
'displaypriority' => intval(parseEvent($event->getElementsByTagName('details'), false, 'displaypriority')),
'enddate' => intval(parseEvent($event, true, false)),
'isseasonal' => getBoolean(intval(parseEvent($event->getElementsByTagName('details'), false, 'isseasonal'))),
'name' => $event->getAttribute('name'),
'startdate' => intval(parseEvent($event, true, true)),
'specialevent' => intval(parseEvent($event->getElementsByTagName('details'), false, 'specialevent'))
];
$eventlist[] = $tmplist; } }
die(json_encode(['eventlist' => $eventlist, 'lastupdatetimestamp' => time()]));
case 'boostedcreature':
$boostDB = $db->query("select * from " . $db->tableName('boosted_creature'))->fetchAll();
foreach ($boostDB as $Tableboost) {
die(json_encode([
'boostedcreature' => true,
'raceid' => intval($Tableboost['raceid'])
]));
}
break;
case 'login':
$port = $config['lua']['gameProtocolPort'];
// default world info
$world = [
'id' => 0,
'name' => $config['lua']['serverName'],
'externaladdress' => $config['lua']['ip'],
'externalport' => $port,
'externaladdressprotected' => $config['lua']['ip'],
'externalportprotected' => $port,
'externaladdressunprotected' => $config['lua']['ip'],
'externalportunprotected' => $port,
'previewstate' => 0,
'location' => 'BRA', // BRA, EUR, USA
'anticheatprotection' => false,
'pvptype' => array_search($config['lua']['worldType'], ['pvp', 'no-pvp', 'pvp-enforced']),
'istournamentworld' => false,
'restrictedstore' => false,
'currenttournamentphase' => 2
];
$characters = [];
$account = new OTS_Account();
$inputEmail = $request->email ?? false;
$inputAccountName = $request->accountname ?? false;
$inputToken = $request->token ?? false;
if ($inputEmail != false) { // login by email
$account->findByEmail($request->email);
}
else if($inputAccountName != false) { // login by account name
$account->find($inputAccountName);
}
$config_salt_enabled = fieldExist('salt', 'accounts');
$current_password = encrypt(($config_salt_enabled ? $account->getCustomField('salt') : '') . $request->password);
if (!$account->isLoaded() || $account->getPassword() != $current_password) {
sendError(($inputEmail != false ? 'Email' : 'Account name') . ' or password is not correct.');
}
//log_append('test.log', var_export($account->getCustomField('secret'), true));
$accountHasSecret = false;
if (fieldExist('secret', 'accounts')) {
$accountSecret = $account->getCustomField('secret');
if ($accountSecret != null && $accountSecret != '') {
$accountHasSecret = true;
if ($inputToken === false) {
sendError('Submit a valid two-factor authentication token.', 6);
} else {
require_once LIBS . 'rfc6238.php';
if (TokenAuth6238::verify($accountSecret, $inputToken) !== true) {
sendError('Two-factor authentication failed, token is wrong.', 6);
}
}
}
}
// common columns
$columns = 'id, name, level, sex, vocation, looktype, lookhead, lookbody, looklegs, lookfeet, lookaddons';
if (fieldExist('isreward', 'accounts')) {
$columns .= ', isreward';
}
if (fieldExist('istutorial', 'accounts')) {
$columns .= ', istutorial';
}
$players = $db->query("select {$columns} from players where account_id = " . $account->getId() . " AND deletion = 0");
if($players && $players->rowCount() > 0) {
$players = $players->fetchAll();
$highestLevelId = 0;
$highestLevel = 0;
foreach ($players as $player) {
if ($player['level'] >= $highestLevel) {
$highestLevel = $player['level'];
$highestLevelId = $player['id'];
}
}
foreach ($players as $player) {
$characters[] = create_char($player, $highestLevelId);
}
}
if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) {
$save = false;
$timeNow = time();
$query = $db->query("select `premdays`, `lastday` from `accounts` where `id` = " . $account->getId());
if ($query->rowCount() > 0) {
$query = $query->fetch();
$premDays = (int)$query['premdays'];
$lastDay = (int)$query['lastday'];
$lastLogin = $lastDay;
} else {
sendError("Error while fetching your account data. Please contact admin.");
}
if ($premDays != 0 && $premDays != PHP_INT_MAX) {
if ($lastDay == 0) {
$lastDay = $timeNow;
$save = true;
} else {
$days = (int)(($timeNow - $lastDay) / 86400);
if ($days > 0) {
if ($days >= $premDays) {
$premDays = 0;
$lastDay = 0;
} else {
$premDays -= $days;
$reminder = ($timeNow - $lastDay) % 86400;
$lastDay = $timeNow - $reminder;
}
$save = true;
}
}
} else if ($lastDay != 0) {
$lastDay = 0;
$save = true;
}
if ($save) {
$db->query("update `accounts` set `premdays` = " . $premDays . ", `lastday` = " . $lastDay . " where `id` = " . $account->getId());
}
}
$worlds = [$world];
$playdata = compact('worlds', 'characters');
$sessionKey = ($inputEmail !== false) ? $inputEmail : $inputAccountName; // email or account name
$sessionKey .= "\n" . $request->password; // password
if (!fieldExist('istutorial', 'players')) {
$sessionKey .= "\n";
}
$sessionKey .= ($accountHasSecret && strlen($accountSecret) > 5) ? $inputToken : '';
// this is workaround to distinguish between TFS 1.x and otservbr
// TFS 1.x requires the number in session key
// otservbr requires just login and password
// so we check for istutorial field which is present in otservbr, and not in TFS
if (!fieldExist('istutorial', 'players')) {
$sessionKey .= "\n".floor(time() / 30);
}
//log_append('slaw.log', $sessionKey);
$session = [
'sessionkey' => $sessionKey,
'lastlogintime' => 0,
'ispremium' => $config['lua']['freePremium'] || $account->isPremium(),
'premiumuntil' => ($account->getPremDays()) > 0 ? (time() + ($account->getPremDays() * 86400)) : 0,
'status' => 'active', // active, frozen or suspended
'returnernotification' => false,
'showrewardnews' => true,
'isreturner' => true,
'fpstracking' => false,
'optiontracking' => false,
'tournamentticketpurchasestate' => 0,
'emailcoderequest' => false
];
die(json_encode(compact('session', 'playdata')));
default:
sendError("Unrecognized event {$action}.");
break;
}
function create_char($player, $highestLevelId) {
global $config;
return [
'worldid' => 0,
'name' => $player['name'],
'ismale' => intval($player['sex']) === 1,
'tutorial' => isset($player['istutorial']) && $player['istutorial'],
'level' => intval($player['level']),
'vocation' => $config['vocations'][$player['vocation']],
'outfitid' => intval($player['looktype']),
'headcolor' => intval($player['lookhead']),
'torsocolor' => intval($player['lookbody']),
'legscolor' => intval($player['looklegs']),
'detailcolor' => intval($player['lookfeet']),
'addonsflags' => intval($player['lookaddons']),
'ishidden' => isset($player['deletion']) && (int)$player['deletion'] === 1,
'istournamentparticipant' => false,
'ismaincharacter' => $highestLevelId == $player['id'],
'dailyrewardstate' => isset($player['isreward']) ? intval($player['isreward']) : 0,
'remainingdailytournamentplaytime' => 0
];
}

View File

@@ -1,25 +1,25 @@
server { server {
listen 80; listen 80;
root /home/otserv/www/public; root /home/otserv/www/public;
index index.php; index index.php;
server_name your-domain.com; server_name your-domain.com;
location / { location ~ /system {
try_files $uri $uri/ /index.php; deny all;
} return 404;
}
location ~ \.php$ { location ~ /\.ht {
include snippets/fastcgi-php.conf; deny all;
fastcgi_read_timeout 240; }
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
}
location ~ /\.ht { location / {
deny all; try_files $uri $uri/ /index.php;
} }
location /system { location ~ \.php$ {
deny all; include snippets/fastcgi-php.conf;
return 404; fastcgi_read_timeout 240;
} fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
}
} }

View File

@@ -13,7 +13,7 @@ fi
if [ $1 = "prepare" ]; then if [ $1 = "prepare" ]; then
# define release version # define release version
version=`cat VERSION` version=`php system/get_version_for_release.php`
echo "Preparing to release version $version of the MyAAC Project!" echo "Preparing to release version $version of the MyAAC Project!"
@@ -41,7 +41,7 @@ fi
if [ $1 = "pack" ]; then if [ $1 = "pack" ]; then
# define release version # define release version
version=`cat VERSION` version=`php system/get_version_for_release.php`
cd tmp || exit cd tmp || exit

View File

@@ -451,7 +451,7 @@ function tickers()
*/ */
function template_place_holder($type) function template_place_holder($type)
{ {
global $template_place_holders; global $twig, $template_place_holders;
$ret = ''; $ret = '';
if(array_key_exists($type, $template_place_holders) && is_array($template_place_holders[$type])) if(array_key_exists($type, $template_place_holders) && is_array($template_place_holders[$type]))
@@ -460,6 +460,9 @@ function template_place_holder($type)
if($type === 'head_start') { if($type === 'head_start') {
$ret .= template_header(); $ret .= template_header();
} }
elseif ($type === 'body_start') {
$ret .= $twig->render('browsehappy.html.twig');
}
elseif($type === 'body_end') { elseif($type === 'body_end') {
$ret .= template_ga_code(); $ret .= template_ga_code();
} }

View File

@@ -0,0 +1,4 @@
<?php
require __DIR__ . '/../common.php';
echo MYAAC_VERSION;

View File

@@ -11,6 +11,57 @@
class CreateCharacter class CreateCharacter
{ {
/**
* @param $name
* @param $errors
* @return bool
*/
public function checkName($name, &$errors)
{
$minLength = config('character_name_min_length');
$maxLength = config('character_name_max_length');
if(empty($name)) {
$errors['name'] = 'Please enter a name for your character!';
return false;
}
if(strlen($name) > $maxLength) {
$errors['name'] = 'Name is too long. Max. length <b>' . $maxLength . '</b> letters.';
return false;
}
if(strlen($name) < $minLength) {
$errors['name'] = 'Name is too short. Min. length <b>' . $minLength . '</b> letters.';
return false;
}
$name_length = strlen($name);
if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- '") != $name_length) {
$errors['name'] = 'This name contains invalid letters, words or format. Please use only a-Z, - , \' and space.';
return false;
}
if(!preg_match("/[A-z ']/", $name)) {
$errors['name'] = 'Your name contains illegal characters.';
return false;
}
if(!admin() && !Validator::newCharacterName($name)) {
$errors['name'] = Validator::getLastError();
return false;
}
$player = new OTS_Player();
$player->find($name);
if($player->isLoaded()) {
$errors['name'] = 'Character with this name already exist.';
return false;
}
return empty($errors);
}
/** /**
* @param string $name * @param string $name
* @param int $sex * @param int $sex
@@ -19,36 +70,27 @@ class CreateCharacter
* @param array $errors * @param array $errors
* @return bool * @return bool
*/ */
public function check($name, $sex, &$vocation, &$town, &$errors) { public function check($name, $sex, &$vocation, &$town, &$errors)
$minLength = config('character_name_min_length'); {
$maxLength = config('character_name_max_length'); $this->checkName($name, $errors);
if(empty($name)) if(empty($sex) && $sex != "0") {
$errors['name'] = 'Please enter a name for your character!';
else if(strlen($name) > $maxLength)
$errors['name'] = 'Name is too long. Max. length <b>'.$maxLength.'</b> letters.';
else if(strlen($name) < $minLength)
$errors['name'] = 'Name is too short. Min. length <b>'.$minLength.'</b> letters.';
else {
if(!admin() && !Validator::newCharacterName($name)) {
$errors['name'] = Validator::getLastError();
}
}
if(empty($sex) && $sex != "0")
$errors['sex'] = 'Please select the sex for your character!'; $errors['sex'] = 'Please select the sex for your character!';
}
if(count(config('character_samples')) > 1) if(count(config('character_samples')) > 1)
{ {
if(!isset($vocation)) if(!isset($vocation))
$errors['vocation'] = 'Please select a vocation for your character.'; $errors['vocation'] = 'Please select a vocation for your character.';
} }
else else {
$vocation = config('character_samples')[0]; $vocation = config('character_samples')[0];
}
if(count(config('character_towns')) > 1) { if(count(config('character_towns')) > 1) {
if(!isset($town)) if(!isset($town)) {
$errors['town'] = 'Please select a town for your character.'; $errors['town'] = 'Please select a town for your character.';
}
} }
else { else {
$town = config('character_towns')[0]; $town = config('character_towns')[0];
@@ -96,7 +138,7 @@ class CreateCharacter
if(empty($errors)) if(empty($errors))
{ {
$number_of_players_on_account = $account->getPlayersList()->count(); $number_of_players_on_account = $account->getPlayersList(false)->count();
if($number_of_players_on_account >= config('characters_per_account')) if($number_of_players_on_account >= config('characters_per_account'))
$errors[] = 'You have too many characters on your account <b>('.$number_of_players_on_account.'/'.config('characters_per_account').')</b>!'; $errors[] = 'You have too many characters on your account <b>('.$number_of_players_on_account.'/'.config('characters_per_account').')</b>!';
} }
@@ -151,8 +193,14 @@ class CreateCharacter
$player->setManaSpent($char_to_copy->getManaSpent()); $player->setManaSpent($char_to_copy->getManaSpent());
$player->setSoul($char_to_copy->getSoul()); $player->setSoul($char_to_copy->getSoul());
for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) for($skill = POT::SKILL_FIRST; $skill <= POT::SKILL_LAST; $skill++) {
$player->setSkill($skill, 10); $value = 10;
if (config('use_character_sample_skills')) {
$value = $char_to_copy->getSkill($skill);
}
$player->setSkill($skill, $value);
}
$player->setLookBody($char_to_copy->getLookBody()); $player->setLookBody($char_to_copy->getLookBody());
$player->setLookFeet($char_to_copy->getLookFeet()); $player->setLookFeet($char_to_copy->getLookFeet());
@@ -191,17 +239,24 @@ class CreateCharacter
} }
if($db->hasTable('player_skills')) { if($db->hasTable('player_skills')) {
for($i=0; $i<7; $i++) { for($i=0; $i<7; $i++) {
$value = 10;
if (config('use_character_sample_skills')) {
$value = $char_to_copy->getSkill($i);
}
$skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $i); $skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $i);
if($skillExists->rowCount() <= 0) { if($skillExists->rowCount() <= 0) {
$db->query('INSERT INTO `player_skills` (`player_id`, `skillid`, `value`, `count`) VALUES ('.$player->getId().', '.$i.', 10, 0)'); $db->query('INSERT INTO `player_skills` (`player_id`, `skillid`, `value`, `count`) VALUES ('.$player->getId().', '.$i.', ' . $value . ', 0)');
} }
} }
} }
$loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$char_to_copy->getId().""); $loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$char_to_copy->getId()."");
foreach($loaded_items_to_copy as $save_item) foreach($loaded_items_to_copy as $save_item) {
$db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', '".$save_item['attributes']."');"); $blob = $db->quote($save_item['attributes']);
$db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', $blob);");
}
global $twig; global $twig;
$twig->display('success.html.twig', array( $twig->display('success.html.twig', array(

View File

@@ -733,7 +733,7 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
* @return OTS_Players_List List of players from current account. * @return OTS_Players_List List of players from current account.
* @throws E_OTS_NotLoaded If account is not loaded. * @throws E_OTS_NotLoaded If account is not loaded.
*/ */
public function getPlayersList() public function getPlayersList($withDeleted = true)
{ {
if( !isset($this->data['id']) ) if( !isset($this->data['id']) )
{ {
@@ -744,6 +744,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
$filter = new OTS_SQLFilter(); $filter = new OTS_SQLFilter();
$filter->compareField('account_id', (int) $this->data['id']); $filter->compareField('account_id', (int) $this->data['id']);
if(!$withDeleted) {
global $db;
if($db->hasColumn('players', 'deletion')) {
$filter->compareField('deletion', 0);
} else {
$filter->compareField('deleted', 0);
}
}
// creates list object // creates list object
$list = new OTS_Players_List(); $list = new OTS_Players_List();
$list->setFilter($filter); $list->setFilter($filter);

View File

@@ -83,10 +83,10 @@ abstract class OTS_Base_DB extends PDO implements IOTS_DB
$startTime = microtime(true); $startTime = microtime(true);
} }
$ret = parent::query(...$args);; $ret = parent::query(...$args);
if($this->logged) { if($this->logged) {
$totalTime = microtime(true) - $startTime; $totalTime = microtime(true) - $startTime;
$this->log .= round($totalTime, 4) . ' ms - ' . $query . PHP_EOL; $this->log .= round($totalTime, 4) . ' ms - ' . $args[0] . PHP_EOL;
} }
return $ret; return $ret;

View File

@@ -2489,7 +2489,7 @@ class OTS_Player extends OTS_Row_DAO
$value = $this->db->query('SELECT ' . $this->db->fieldName('value') . ' FROM ' . $this->db->tableName('player_storage') . ' WHERE ' . $this->db->fieldName('key') . ' = ' . (int) $key . ' AND ' . $this->db->fieldName('player_id') . ' = ' . $this->data['id'])->fetch(); $value = $this->db->query('SELECT ' . $this->db->fieldName('value') . ' FROM ' . $this->db->tableName('player_storage') . ' WHERE ' . $this->db->fieldName('key') . ' = ' . (int) $key . ' AND ' . $this->db->fieldName('player_id') . ' = ' . $this->data['id'])->fetch();
if($value !== false) if($value === false)
{ {
return null; return null;
} }

285
system/libs/rfc6238.php Normal file
View File

@@ -0,0 +1,285 @@
<?php
/** https://github.com/Voronenko/PHPOTP/blob/08cda9cb9c30b7242cf0b3a9100a6244a2874927/code/base32static.php
* Encode in Base32 based on RFC 4648.
* Requires 20% more space than base64
* Great for case-insensitive filesystems like Windows and URL's (except for = char which can be excluded using the pad option for urls)
*
* @package default
* @author Bryan Ruiz
**/
class Base32Static {
private static $map = array(
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
'=' // padding character
);
private static $flippedMap = array(
'A'=>'0', 'B'=>'1', 'C'=>'2', 'D'=>'3', 'E'=>'4', 'F'=>'5', 'G'=>'6', 'H'=>'7',
'I'=>'8', 'J'=>'9', 'K'=>'10', 'L'=>'11', 'M'=>'12', 'N'=>'13', 'O'=>'14', 'P'=>'15',
'Q'=>'16', 'R'=>'17', 'S'=>'18', 'T'=>'19', 'U'=>'20', 'V'=>'21', 'W'=>'22', 'X'=>'23',
'Y'=>'24', 'Z'=>'25', '2'=>'26', '3'=>'27', '4'=>'28', '5'=>'29', '6'=>'30', '7'=>'31'
);
/**
* Use padding false when encoding for urls
*
* @return base32 encoded string
* @author Bryan Ruiz
**/
public static function encode($input, $padding = true) {
if(empty($input)) return "";
$input = str_split($input);
$binaryString = "";
for($i = 0; $i < count($input); $i++) {
$binaryString .= str_pad(base_convert(ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT);
}
$fiveBitBinaryArray = str_split($binaryString, 5);
$base32 = "";
$i=0;
while($i < count($fiveBitBinaryArray)) {
$base32 .= self::$map[base_convert(str_pad($fiveBitBinaryArray[$i], 5,'0'), 2, 10)];
$i++;
}
if($padding && ($x = strlen($binaryString) % 40) != 0) {
if($x == 8) $base32 .= str_repeat(self::$map[32], 6);
else if($x == 16) $base32 .= str_repeat(self::$map[32], 4);
else if($x == 24) $base32 .= str_repeat(self::$map[32], 3);
else if($x == 32) $base32 .= self::$map[32];
}
return $base32;
}
public static function decode($input) {
if(empty($input)) return;
$paddingCharCount = substr_count($input, self::$map[32]);
$allowedValues = array(6,4,3,1,0);
if(!in_array($paddingCharCount, $allowedValues)) return false;
for($i=0; $i<4; $i++){
if($paddingCharCount == $allowedValues[$i] &&
substr($input, -($allowedValues[$i])) != str_repeat(self::$map[32], $allowedValues[$i])) return false;
}
$input = str_replace('=','', $input);
$input = str_split($input);
$binaryString = "";
for($i=0; $i < count($input); $i = $i+8) {
$x = "";
if(!in_array($input[$i], self::$map)) return false;
for($j=0; $j < 8; $j++) {
$x .= str_pad(base_convert(@self::$flippedMap[@$input[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
}
$eightBits = str_split($x, 8);
for($z = 0; $z < count($eightBits); $z++) {
$binaryString .= ( ($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48 ) ? $y:"";
}
}
return $binaryString;
}
}
// http://www.faqs.org/rfcs/rfc6238.html
// https://github.com/Voronenko/PHPOTP/blob/08cda9cb9c30b7242cf0b3a9100a6244a2874927/code/rfc6238.php
// Local changes: http -> https, consistent indentation, 200x200 -> 300x300 QR image size, PHP end tag
class TokenAuth6238 {
/**
* verify
*
* @param string $secretkey Secret clue (base 32).
* @return bool True if success, false if failure
*/
public static function verify($secretkey, $code, $rangein30s = 3) {
$key = base32static::decode($secretkey);
$unixtimestamp = time()/30;
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
$checktime = (int)($unixtimestamp+$i);
$thiskey = self::oath_hotp($key, $checktime);
if ((int)$code == self::oath_truncate($thiskey,6)) {
return true;
}
}
return false;
}
public static function getTokenCode($secretkey,$rangein30s = 3) {
$result = "";
$key = base32static::decode($secretkey);
$unixtimestamp = time()/30;
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
$checktime = (int)($unixtimestamp+$i);
$thiskey = self::oath_hotp($key, $checktime);
$result = $result." # ".self::oath_truncate($thiskey,6);
}
return $result;
}
public static function getTokenCodeDebug($secretkey,$rangein30s = 3) {
$result = "";
print "<br/>SecretKey: $secretkey <br/>";
$key = base32static::decode($secretkey);
print "Key(base 32 decode): $key <br/>";
$unixtimestamp = time()/30;
print "UnixTimeStamp (time()/30): $unixtimestamp <br/>";
for($i=-($rangein30s); $i<=$rangein30s; $i++) {
$checktime = (int)($unixtimestamp+$i);
print "Calculating oath_hotp from (int)(unixtimestamp +- 30sec offset): $checktime basing on secret key<br/>";
$thiskey = self::oath_hotp($key, $checktime, true);
print "======================================================<br/>";
print "CheckTime: $checktime oath_hotp:".$thiskey."<br/>";
$result = $result." # ".self::oath_truncate($thiskey,6,true);
}
return $result;
}
public static function getBarCodeUrl($username, $domain, $secretkey, $issuer) {
$url = "https://chart.apis.google.com/chart";
$url = $url."?chs=300x300&chld=M|0&cht=qr&chl=otpauth://totp/";
$url = $url.$username . "@" . $domain . "%3Fsecret%3D" . $secretkey . '%26issuer%3D' . rawurlencode($issuer);
return $url;
}
public static function generateRandomClue($length = 16) {
$b32 = "234567QWERTYUIOPASDFGHJKLZXCVBNM";
$s = "";
for ($i = 0; $i < $length; $i++)
$s .= $b32[rand(0,31)];
return $s;
}
private static function hotp_tobytestream($key) {
$result = array();
$last = strlen($key);
for ($i = 0; $i < $last; $i = $i + 2) {
$x = $key[$i] + $key[$i + 1];
$x = strtoupper($x);
$x = hexdec($x);
$result = $result.chr($x);
}
return $result;
}
private static function oath_hotp ($key, $counter, $debug=false) {
$result = "";
$orgcounter = $counter;
$cur_counter = array(0,0,0,0,0,0,0,0);
if ($debug) {
print "Packing counter $counter (".dechex($counter).")into binary string - pay attention to hex representation of key and binary representation<br/>";
}
for($i=7;$i>=0;$i--) { // C for unsigned char, * for repeating to the end of the input data
$cur_counter[$i] = pack ('C*', $counter);
if ($debug) {
print $cur_counter[$i]."(".dechex(ord($cur_counter[$i])).")"." from $counter <br/>";
}
$counter = $counter >> 8;
}
if ($debug) {
foreach ($cur_counter as $char) {
print ord($char) . " ";
}
print "<br/>";
}
$binary = implode($cur_counter);
// Pad to 8 characters
str_pad($binary, 8, chr(0), STR_PAD_LEFT);
if ($debug) {
print "Prior to HMAC calculation pad with zero on the left until 8 characters.<br/>";
print "Calculate sha1 HMAC(Hash-based Message Authentication Code http://en.wikipedia.org/wiki/HMAC).<br/>";
print "hash_hmac ('sha1', $binary, $key)<br/>";
}
$result = hash_hmac ('sha1', $binary, $key);
if ($debug) {
print "Result: $result <br/>";
}
return $result;
}
private static function oath_truncate($hash, $length = 6, $debug=false) {
$result="";
// Convert to dec
if($debug) {
print "converting hex hash into characters<br/>";
}
$hashcharacters = str_split($hash,2);
if($debug) {
print_r($hashcharacters);
print "<br/>and convert to decimals:<br/>";
}
for ($j=0; $j<count($hashcharacters); $j++) {
$hmac_result[]=hexdec($hashcharacters[$j]);
}
if($debug) {
print_r($hmac_result);
}
// http://php.net/manual/ru/function.hash-hmac.php
// adopted from brent at thebrent dot net 21-May-2009 08:17 comment
$offset = $hmac_result[19] & 0xf;
if($debug) {
print "Calculating offset as 19th element of hmac:".$hmac_result[19]."<br/>";
print "offset:".$offset;
}
$result = (
(($hmac_result[$offset+0] & 0x7f) << 24 ) |
(($hmac_result[$offset+1] & 0xff) << 16 ) |
(($hmac_result[$offset+2] & 0xff) << 8 ) |
($hmac_result[$offset+3] & 0xff)
) % pow(10,$length);
return $result;
}
}
?>

View File

@@ -218,8 +218,12 @@ class Validator
global $db, $config; global $db, $config;
$name_lower = strtolower($name); $name_lower = strtolower($name);
$custom_first_words_blocked = [];
if (isset($config['character_name_blocked']['prefix']) && $config['character_name_blocked']['prefix']) {
$custom_first_words_blocked = $config['character_name_blocked']['prefix'];
}
$first_words_blocked = array('admin ', 'administrator ', 'gm ', 'cm ', 'god ','tutor ', "'", '-'); $first_words_blocked = array_merge($custom_first_words_blocked, array('admin ', 'administrator ', 'gm ', 'cm ', 'god ','tutor ', "'", '-'));
foreach($first_words_blocked as $word) foreach($first_words_blocked as $word)
{ {
if($word == substr($name_lower, 0, strlen($word))) { if($word == substr($name_lower, 0, strlen($word))) {
@@ -254,7 +258,11 @@ class Validator
return false; return false;
} }
$names_blocked = array('admin', 'administrator', 'gm', 'cm', 'god', 'tutor'); $custom_names_blocked = [];
if (isset($config['character_name_blocked']['names']) && $config['character_name_blocked']['names']) {
$custom_names_blocked = $config['character_name_blocked']['names'];
}
$names_blocked = array_merge($custom_names_blocked, array('admin', 'administrator', 'gm', 'cm', 'god', 'tutor'));
foreach($names_blocked as $word) foreach($names_blocked as $word)
{ {
if($word == $name_lower) { if($word == $name_lower) {
@@ -263,7 +271,11 @@ class Validator
} }
} }
$words_blocked = array('admin', 'administrator', 'gamemaster', 'game master', 'game-master', "game'master", '--', "''","' ", " '", '- ', ' -', "-'", "'-", 'fuck', 'sux', 'suck', 'noob', 'tutor'); $custom_words_blocked = [];
if (isset($config['character_name_blocked']['words']) && $config['character_name_blocked']['words']) {
$custom_words_blocked = $config['character_name_blocked']['words'];
}
$words_blocked = array_merge($custom_words_blocked, array('admin', 'administrator', 'gamemaster', 'game master', 'game-master', "game'master", '--', "''","' ", " '", '- ', ' -', "-'", "'-", 'fuck', 'sux', 'suck', 'noob', 'tutor'));
foreach($words_blocked as $word) foreach($words_blocked as $word)
{ {
if(!(strpos($name_lower, $word) === false)) { if(!(strpos($name_lower, $word) === false)) {
@@ -323,16 +335,6 @@ class Validator
} }
} }
if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- '") != $name_length) {
self::$lastError = 'This name contains invalid letters, words or format. Please use only a-Z, - , \' and space.';
return false;
}
if(!preg_match("/[A-z ']/", $name)) {
self::$lastError = 'Your name containst illegal characters.';
return false;
}
return true; return true;
} }

6
system/migrations/33.php Normal file
View File

@@ -0,0 +1,6 @@
<?php
// Increase size of ip in myaac_visitors table
// according to this answer: https://stackoverflow.com/questions/166132/maximum-length-of-the-textual-representation-of-an-ipv6-address
// the size of ipv6 can be maximal 45 chars
$db->exec('ALTER TABLE `' . TABLE_PREFIX . "visitors` MODIFY `ip` VARCHAR(45) NOT NULL;");

View File

@@ -22,6 +22,7 @@ if(isset($_POST['registeraccountsave']) && $_POST['registeraccountsave'] == "1")
$account_logged->setCustomField("key", $new_rec_key); $account_logged->setCustomField("key", $new_rec_key);
$account_logged->logAction('Generated recovery key.'); $account_logged->logAction('Generated recovery key.');
$message = '';
if($config['mail_enabled'] && $config['send_mail_when_generate_reckey']) if($config['mail_enabled'] && $config['send_mail_when_generate_reckey'])
{ {

View File

@@ -40,7 +40,7 @@ else
$message = '<br />Your recovery key were send on email address <b>'.$account_logged->getEMail().'</b> for '.$config['generate_new_reckey_price'].' premium points.'; $message = '<br />Your recovery key were send on email address <b>'.$account_logged->getEMail().'</b> for '.$config['generate_new_reckey_price'].' premium points.';
} }
else else
$message = '<br /><p class="error">An error occorred while sending email ( <b>'.$account_logged->getEMail().'</b> ) with recovery key! Recovery key not changed. Try again later. For Admin: More info can be found in system/logs/mailer-error.log</p>'; $message = '<br /><p class="error">An error occurred while sending email ( <b>'.$account_logged->getEMail().'</b> ) with recovery key! Recovery key not changed. Try again later. For Admin: More info can be found in system/logs/mailer-error.log</p>';
$twig->display('success.html.twig', array( $twig->display('success.html.twig', array(
'title' => 'Account Registered', 'title' => 'Account Registered',

View File

@@ -223,6 +223,14 @@ if($save)
} }
else else
{ {
if(config('account_create_character_create')) {
// character creation
$character_created = $createCharacter->doCreate($character_name, $character_sex, $character_vocation, $character_town, $new_account, $errors);
if (!$character_created) {
error('There was an error creating your character. Please create your character later in account management page.');
}
}
if($config['account_create_auto_login']) { if($config['account_create_auto_login']) {
$_POST['account_login'] = USE_ACCOUNT_NAME ? $account_name : $account_id; $_POST['account_login'] = USE_ACCOUNT_NAME ? $account_name : $account_id;
$_POST['password_login'] = $password2; $_POST['password_login'] = $password2;
@@ -265,14 +273,6 @@ if($save)
error('An error occurred while sending email. For Admin: More info can be found in system/logs/mailer-error.log'); error('An error occurred while sending email. For Admin: More info can be found in system/logs/mailer-error.log');
} }
} }
if(config('account_create_character_create')) {
// character creation
$character_created = $createCharacter->doCreate($character_name, $character_sex, $character_vocation, $character_town, $new_account, $errors);
if (!$character_created) {
error('There was an error creating your character. Please create your character later in account management page.');
}
}
} }
return; return;

View File

@@ -39,13 +39,10 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') {
$player->find($name); $player->find($name);
if(!$player->isLoaded()) { if(!$player->isLoaded()) {
$errors[] = 'Player with name <b>'.$name.'</b> doesn\'t exist.'; $errors[] = 'Player with name <b>'.$name.'</b> doesn\'t exist.';
} }else if ($player->getAccountID() != $account_logged->getId()) {
else $errors[] = 'Character with name <b> ' . $name. ' </b> is not in your account.';
{ }else if ($player->getRank()->isLoaded()){
$rank_of_player = $player->getRank(); $errors[] = 'Character with name <b>'.$name.'</b> is already in guild. You must leave guild before you join other guild.';
if($rank_of_player->isLoaded()) {
$errors[] = 'Character with name <b>'.$name.'</b> is already in guild. You must leave guild before you join other guild.';
}
} }
} }
} }
@@ -63,9 +60,8 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') {
} }
} }
} }
if(!$is_invited) { if(!$is_invited) {
$errors[] = 'Character '.$player->getName.' isn\'t invited to guild <b>'.$guild->getName().'</b>.'; $errors[] = 'Character '.$player->getName() .' isn\'t invited to guild <b>'.$guild->getName().'</b>.';
} }
} }
} }

View File

@@ -86,7 +86,7 @@ if($guild_vice)
else else
{ {
$player_in_guild = false; $player_in_guild = false;
if($guild->getName() === $player_to_change->getRank()->getGuild()->getName() || $guild_leader) if($guild->getName() === $player_to_change->getRank()->getGuild()->getName())
{ {
$player_in_guild = true; $player_in_guild = true;
$player_has_lower_rank = false; $player_has_lower_rank = false;

View File

@@ -18,6 +18,10 @@ $list = isset($_GET['list']) ? $_GET['list'] : '';
$_page = isset($_GET['page']) ? $_GET['page'] : 0; $_page = isset($_GET['page']) ? $_GET['page'] : 0;
$vocation = isset($_GET['vocation']) ? $_GET['vocation'] : NULL; $vocation = isset($_GET['vocation']) ? $_GET['vocation'] : NULL;
if(!is_numeric($_page) || $_page < 0 || $_page > PHP_INT_MAX) {
$_page = 0;
}
$add_sql = ''; $add_sql = '';
$config_vocations = $config['vocations']; $config_vocations = $config['vocations'];
if($config['highscores_vocation_box'] && isset($vocation)) if($config['highscores_vocation_box'] && isset($vocation))

View File

@@ -111,7 +111,7 @@ elseif($action == 'sendcode')
else else
{ {
$account->setCustomField('email_next', (time() + 60)); $account->setCustomField('email_next', (time() + 60));
echo '<br /><p class="error">An error occorred while sending email! Try again later or contact with admin. For Admin: More info can be found in system/logs/mailer-error.log</p>'; echo '<br /><p class="error">An error occurred while sending email! Try again later or contact with admin. For Admin: More info can be found in system/logs/mailer-error.log</p>';
} }
} }
else else
@@ -330,7 +330,7 @@ elseif($action == 'step3')
} }
else else
{ {
echo '<br /><p class="error">An error occorred while sending email! You will not receive e-mail with this informations. For Admin: More info can be found in system/logs/mailer-error.log</p>'; echo '<br /><p class="error">An error occurred while sending email! You will not receive e-mail with this informations. For Admin: More info can be found in system/logs/mailer-error.log</p>';
} }
} }
else else
@@ -513,7 +513,7 @@ elseif($action == 'setnewpassword')
} }
else else
{ {
echo '<br /><p class="error">New password work! An error occorred while sending email! You will not receive e-mail with new password. For Admin: More info can be found in system/logs/mailer-error.log'; echo '<br /><p class="error">New password work! An error occurred while sending email! You will not receive e-mail with new password. For Admin: More info can be found in system/logs/mailer-error.log';
} }
echo '</TD></TR> echo '</TD></TR>
</TABLE> </TABLE>

View File

View File

@@ -2,7 +2,7 @@ Please choose a name{% if config.character_samples|length > 1 %}, vocation{% end
{% if config.character_towns|length > 1 %}, town{% endif %} {% if config.character_towns|length > 1 %}, town{% endif %}
and sex for your character. <br/> and sex for your character. <br/>
In any case the name must not violate the naming conventions stated in the <a href="?subtopic=rules" target="_blank" >{{ config.lua.serverName }} Rules</a>, or your character might get deleted or name locked. In any case the name must not violate the naming conventions stated in the <a href="?subtopic=rules" target="_blank" >{{ config.lua.serverName }} Rules</a>, or your character might get deleted or name locked.
{% if account_logged.getPlayersList()|length >= config.characters_per_account %} {% if account_logged.getPlayersList(false)|length >= config.characters_per_account %}
<b><span style="color: red"> You have maximum number of characters per account on your account. Delete one before you make new.</span></b> <b><span style="color: red"> You have maximum number of characters per account on your account. Delete one before you make new.</span></b>
{% endif %} {% endif %}
<br/><br/> <br/><br/>

View File

@@ -0,0 +1,3 @@
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->

View File

@@ -133,7 +133,7 @@
{% include('buttons.base.html.twig') %} {% include('buttons.base.html.twig') %}
</form> </form>
{% else %} {% else %}
<b>Before you can create guild you must login.</b> <b>Before you can create a guild you must login.</b>
<br/> <br/>
<form action="?subtopic=accountmanagement&redirect={{ getLink('guilds') }}" method="post"> <form action="?subtopic=accountmanagement&redirect={{ getLink('guilds') }}" method="post">
{% include('buttons.login.html.twig') %} {% include('buttons.login.html.twig') %}

View File

@@ -3,7 +3,7 @@
<img src="{{ template_path }}/images/news/icon_{{ icon }}.gif" class="NewsHeadlineIcon" /> <img src="{{ template_path }}/images/news/icon_{{ icon }}.gif" class="NewsHeadlineIcon" />
<div class="NewsHeadlineDate">{{ date|date(config.news_date_format) }} - </div> <div class="NewsHeadlineDate">{{ date|date(config.news_date_format) }} - </div>
<div class="NewsHeadlineText">{{ title }}</div> <div class="NewsHeadlineText">{{ title }}</div>
{% if author is not empty %} {% if config.news_author and author is not empty %}
<div class="NewsHeadlineAuthor"><b>Author: </b><i>{{ author }}</i></div> <div class="NewsHeadlineAuthor"><b>Author: </b><i>{{ author }}</i></div>
{% endif %} {% endif %}
</div> </div>

View File

@@ -1,8 +1,2 @@
{% if constant('PAGE') == 'rules' %}
<b>{{ config.lua.serverName }} Rules</b><br/> <b>{{ config.lua.serverName }} Rules</b><br/>
<textarea rows="25" wrap="physical" cols="70" readonly="true"> {{ getCustomPage('rules_on_the_page') | nl2br }}
{% endif %}
{{ getCustomPage('rules_on_the_page') }}
{% if constant('PAGE') == 'rules' %}
</textarea>
{% endif %}

View File

@@ -0,0 +1,24 @@
<div class="TableContainer">
<div class="CaptionContainer">
<div class="CaptionInnerContainer">
<span class="CaptionEdgeLeftTop" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeRightTop" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
<span class="CaptionBorderTop" style="background-image:url({{ template_path }}/images/content/table-headline-border.gif);"></span>
<span class="CaptionVerticalLeft" style="background-image:url({{ template_path }}/images/content/box-frame-vertical.gif);"></span>
<div class="Text" >{{ title|raw }}</div>
<span class="CaptionVerticalRight" style="background-image:url({{ template_path }}/images/content/box-frame-vertical.gif);"></span>
<span class="CaptionBorderBottom" style="background-image:url({{ template_path }}/images/content/table-headline-border.gif);"></span>
<span class="CaptionEdgeLeftBottom" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeRightBottom" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
</div>
</div>
<table class="Table1" cellpadding="0" cellspacing="0" style="background-color: {{ config.lightborder }}">
<tr>
<td>
<div class="InnerTableContainer">
{{ content|raw }}
</div>
</td>
</tr>
</table>
</div>

View File

@@ -1,19 +1,18 @@
<div class="TableContainer"> <div class="TableContainer">
<table class="Table1" cellpadding="0" cellspacing="0" style="background-color: {{ config.lightborder }}"> <div class="CaptionContainer">
<div class="CaptionContainer"> <div class="CaptionInnerContainer">
<div class="CaptionInnerContainer"> <span class="CaptionEdgeLeftTop" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeLeftTop" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span> <span class="CaptionEdgeRightTop" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeRightTop" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span> <span class="CaptionBorderTop" style="background-image:url({{ template_path }}/images/content/table-headline-border.gif);"></span>
<span class="CaptionBorderTop" style="background-image:url({{ template_path }}/images/content/table-headline-border.gif);"></span> <span class="CaptionVerticalLeft" style="background-image:url({{ template_path }}/images/content/box-frame-vertical.gif);"></span>
<span class="CaptionVerticalLeft" style="background-image:url({{ template_path }}/images/content/box-frame-vertical.gif);"></span> <div class="Text" >Support in game</div>
<div class="Text" >Support in game</div> <span class="CaptionVerticalRight" style="background-image:url({{ template_path }}/images/content/box-frame-vertical.gif);"></span>
<span class="CaptionVerticalRight" style="background-image:url({{ template_path }}/images/content/box-frame-vertical.gif);"></span> <span class="CaptionBorderBottom" style="background-image:url({{ template_path }}/images/content/table-headline-border.gif);"></span>
<span class="CaptionBorderBottom" style="background-image:url({{ template_path }}/images/content/table-headline-border.gif);"></span> <span class="CaptionEdgeLeftBottom" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeLeftBottom" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span> <span class="CaptionEdgeRightBottom" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
<span class="CaptionEdgeRightBottom" style="background-image:url({{ template_path }}/images/content/box-frame-edge.gif);"></span>
</div>
</div> </div>
</div>
<table class="Table1" cellpadding="0" cellspacing="0" style="background-color: {{ config.lightborder }}">
<tr> <tr>
<td> <td>
<div class="InnerTableContainer"> <div class="InnerTableContainer">
@@ -60,7 +59,7 @@
{% for member in group.members|reverse %} {% for member in group.members|reverse %}
{% set i = i + 1 %} {% set i = i + 1 %}
<tr bgcolor="{{ getStyle(i) }}" style="height: 32px;"> <tr bgcolor="{{ getStyle(i) }}" style="height: 32px;">
<td>{{ group.group_name }}</td> <td>{{ group.group_name|capitalize }}</td>
{% if config.team_display_outfit %} {% if config.team_display_outfit %}
<td> <td>
@@ -104,7 +103,7 @@
{% elseif config.team_style == 2 %} {% elseif config.team_style == 2 %}
{% for group in groupmember|reverse %} {% for group in groupmember|reverse %}
{% if group.members is not empty %} {% if group.members is not empty %}
<div style="text-align:center"><h2>{{ group.group_name }}</h2></div> <div style="text-align:center"><h2>{{ group.group_name|capitalize }}</h2></div>
<table cellspacing="1" cellpadding="4" border="0" width="100%"> <table cellspacing="1" cellpadding="4" border="0" width="100%">
<tr bgcolor="{{ config.vdarkborder }}"> <tr bgcolor="{{ config.vdarkborder }}">

View File

@@ -13,6 +13,7 @@
require '../common.php'; require '../common.php';
require SYSTEM . 'functions.php'; require SYSTEM . 'functions.php';
require SYSTEM . 'init.php'; require SYSTEM . 'init.php';
require SYSTEM . 'login.php';
$error = ''; $error = '';
if(isset($_GET['account'])) if(isset($_GET['account']))
@@ -58,8 +59,15 @@ else if(isset($_GET['name']))
if(!Validator::characterName($name)) if(!Validator::characterName($name))
error_(Validator::getLastError()); error_(Validator::getLastError());
if(!Validator::newCharacterName($name)) if(!admin() && !Validator::newCharacterName($name)){
error_(Validator::getLastError()); error_(Validator::getLastError());
}
require_once LIBS . 'CreateCharacter.php';
$createCharacter = new CreateCharacter();
if (!$createCharacter->checkName($name, $errors)) {
error_($errors['name']);
}
success_('Good. Your name will be:<br /><b>' . ucwords($name) . '</b>'); success_('Good. Your name will be:<br /><b>' . ucwords($name) . '</b>');
} }