Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: api client account creator #33

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ node_modules

# Files
login.php
clientcreateaccount.php

# Styles
admin/bootstrap/pace/templates/pace-theme-loading-bar.tmpl.css
Expand Down
279 changes: 279 additions & 0 deletions clientcreateaccount.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
<?php
/**
* Create account by client
*
* @package MyAAC
* @author Elson <[email protected]>
* @author OpenTibiaBR
* @copyright 2023 MyAAC
* @link https://github.com/opentibiabr/myaac
*/

global $config, $db;
require_once 'common.php';
require_once 'config.php';
require_once 'config.local.php';
require_once SYSTEM . 'functions.php';
require_once SYSTEM . 'init.php';

$request = file_get_contents('php://input');
$result = json_decode($request);
//log_append('create_account_service.log', "req: $request");

if ($result === null || (isset($result->Type) && isset($result->type))) {
log_append('create_account_service.log', 'Request error!');
}

$action = mb_strtolower($result->type ?? ($result->Type ?? ''));

$response = null;

switch ($action) {
case 'getaccountcreationstatus':
$response = json_encode([
"Worlds" => [getServerStatus()],
"RecommendedWorld" => configLua('serverName'),
"IsCaptchaDeactivated" => true
]);
break;

case 'generatecharactername':
// todo generate suggested names.
$response = json_encode([
"GeneratedName" => ""
]);
break;

case 'checkcharactername':
$name = $result->CharacterName;
$check = $db->query("SELECT `name` FROM `players` WHERE `name` = {$db->quote($name)}")->rowCount() == 0;
$response = json_encode([
"CharacterName" => $name,
"IsAvailable" => $check
]);
break;

case 'checkemail':
$email = mb_strtolower($result->Email);
$check = filter_var($email, FILTER_VALIDATE_EMAIL) && $db->query("SELECT `email` FROM `accounts` WHERE `email` = {$db->quote($email)}")->rowCount() == 0;
$response = json_encode($check ? [
"IsValid" => true,
"EMail" => $email
] : [
"IsValid" => false,
"errorCode" => 59,
"errorMessage" => "This email address has an invalid format. Please enter a correct email address!",
"EMail" => $email
]);
break;

case 'checkpassword':
$errors = validatePassword($pass = $result->Password1);
$response = json_encode([
"PasswordRequirements" => [
"PasswordLength" => !in_array(0, $errors),
"InvalidCharacters" => !in_array(1, $errors),
"HasLowerCase" => !in_array(2, $errors),
"HasUpperCase" => !in_array(3, $errors),
"HasNumber" => !in_array(4, $errors)
],
"Password1" => $pass,
"PasswordStrength" => count($errors) == 0 ? 4 : abs(count($errors) - 4),
"PasswordStrengthColor" => count($errors) == 0 ? "#20a000" : '#ec644b',
"PasswordValid" => count($errors) == 0,
]);
break;

case 'createaccountandcharacter':
$email = mb_strtolower($result->EMail);
try {
if (filter_var($email, FILTER_VALIDATE_EMAIL) && $db->query("SELECT `email` FROM `accounts` WHERE `email` = {$db->quote($email)}")->rowCount() == 0) {
$response = json_encode([
"Success" => true,
"AccountID" => createAccount([
"email" => $email,
"password" => $result->Password,
"characterName" => stripslashes(ucwords(strtolower($result->CharacterName))),
"characterSex" => $result->CharacterSex == 'male' ? 1 : 0,
//"clientType" => "Client",
//"recaptcha2token" => "",
//"recaptcha3token" => "",
//"selectedWorld" => configLua('serverName'),
]),
// "Password" => $result->Password
]);
} else {
throw new Exception('Email invalid!');
}
} catch (Exception $e) {
log_append('create_account_service.log', "Error caught: {$e->getMessage()}");
$response = json_encode([
"errorCode" => 101,
"errorMessage" => $e->getMessage(), //"An internal error has occurred. Please try again later!",
"Success" => false,
"IsRecaptcha2Requested" => false,
]);
}
break;
}
log_append('create_account_service.log', "response: $response");
die($response);

/**
* Function to return server status as array to worlds list
*
* @return array
*/
function getServerStatus(): array
{
global $db;
$playersOnline = $db->query("SELECT COUNT(*) FROM `players_online`")->fetchAll()[0][0] ?? 0;
$date = $db->query("SELECT `date` FROM `myaac_changelog`")->fetch()['date'] ?? 0;
switch (configLua('worldType')) {
default:
case 'pvp':
$pvpType = "Open PVP";
break;
case 'no-pvp':
$pvpType = 'Optional PVP';
break;
case 'pvp-enforced':
$pvpType = 'PVP';
break;
case 'retro-pvp':
$pvpType = 'Retro PvP';
break;
}
return [
"Name" => configLua('serverName'),
"PlayersOnline" => intval($playersOnline),
"CreationDate" => intval($date),
"Region" => "America",
"PvPType" => $pvpType,
"PremiumOnly" => configLua('onlyPremiumAccount'),
"TransferType" => "Blocked",
"BattlEyeActivationTimestamp" => intval($date),
"BattlEyeInitiallyActive" => 0
];

}

/**
* Function to check strength of password
*
* @param $password
* @return array|int[]
*/
function validatePassword($password): array
{
$checks = [];
$minLength = 10;
$invalids = [' ', '\'', '"', '\\', '/'];

if (strlen($password) < $minLength) $checks = [0];
foreach ($invalids as $char) {
if (strpos($password, $char) !== false) $checks = array_merge($checks, [1]);
}
if (!preg_match('/[a-z]/', $password)) $checks = array_merge($checks, [2]);
if (!preg_match('/[A-Z]/', $password)) $checks = array_merge($checks, [3]);
if (!preg_match('/[0-9]/', $password)) $checks = array_merge($checks, [4]);
return $checks;
}

/**
* Function to create account
*
* @param array $data
* @return false|string
* @throws Exception
*/
function createAccount(array $data)
{
global $db, $config, $twig;
try {
$account_name = USE_ACCOUNT_NAME ?
@(explode('@', $data['email']))[0] . date('isH')
: date('HisdmyHi');

if (USE_ACCOUNT_NAME && mb_strtolower($account_name) == mb_strtolower($data['password'])) {
throw new Exception('Password may not be the same as account name.');
}

$account_db = new OTS_Account();
$account_db->find($account_name);
if ($account_db->isLoaded()) {
throw new Exception('Account with this name already exist.');
}

$info = json_decode(@file_get_contents('https://ipinfo.io/' . $_SERVER['REMOTE_ADDR'] . '/geo'), true);
$country = strtolower($info['country'] ?? 'br');

$new_account = new OTS_Account();
$new_account->create($account_name);

$config_salt_enabled = $db->hasColumn('accounts', 'salt');
if ($config_salt_enabled) {
$salt = generateRandomString(10, false, true, true);
$data['password'] = $salt . $data['password'];
$new_account->setCustomField('salt', $salt);
}

$new_account->setPassword(encrypt($data['password']));
$new_account->setEMail($data['email']);
$new_account->setCustomField('created', time());
$new_account->setCustomField('country', $country);
$new_account->save();

$new_account->logAction('Account created.');

if (($premdays = ($config['account_premium_days'] ?? 0)) > 0) {
if ($db->hasColumn('accounts', 'premend')) { // othire
$new_account->setCustomField('premend', time() + $premdays * 86400);
} else {
$new_account->setCustomField('premdays', $premdays);
$lastDay = ($premdays < OTS_Account::GRATIS_PREMIUM_DAYS) ? time() + ($premdays * 86400) : 0;
$new_account->setCustomField('lastday', $lastDay);
}
}

if (($welcomeCoins = ($config['account_welcome_coins'] ?? 0)) > 0) {
$coinType = $config['account_coin_type_usage'] ?? 'coins_transferable';
$new_account->setCustomField($coinType, $welcomeCoins);
}

if ($config['mail_enabled'] && $config['account_mail_verify']) {
$hash = md5(generateRandomString(16, true, true) . $data['email']);
$new_account->setCustomField('email_hash', $hash);

$verify_url = getLink('account/confirm_email/' . $hash);
$body_html = $twig->render('mail.account.verify.html.twig', array(
'account' => $account_name,
'verify_url' => generateLink($verify_url, $verify_url, true)
));

if (!_mail($data['email'], 'New account on ' . configLua('serverName'), $body_html)) {
$new_account->delete();
throw new Exception('An error occurred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log');
}
} else if ($config['mail_enabled'] && $config['account_welcome_mail']) {
$mailBody = $twig->render('account.welcome_mail.html.twig', ['account' => $account_name]);
if (!_mail($data['email'], 'Your account on ' . configLua('serverName'), $mailBody)) {
throw new Exception('An error occurred while sending email. For Admin: More info can be found in system/logs/mailer-error.log');
}
}

// character creation only if start in dawnport
if (count(config('character_samples')) == 1 && !empty($data['characterName'])) {
require_once LIBS . 'CreateCharacter.php';
$createCharacter = new CreateCharacter();
$errors = [];
if (!$createCharacter->doCreate($data['characterName'], $data['characterSex'], 0, 0, $new_account, $errors)) {
throw new Exception('There was an error creating your character. Please create your character later in account management page.');
}
}

return $account_name;
} catch (Exception $e) {
throw new Exception($e->getMessage());
}
}
4 changes: 2 additions & 2 deletions config.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,14 @@
],
'account_mail_unique' => true, // email addresses cannot be duplicated? (one account = one email)
'account_premium_days' => 0, // default premium days on new account
'account_premium_coins' => 0, // default coins on new account
'account_welcome_coins' => 0, // default coins on new account
'account_welcome_mail' => false, // send welcome email when user registers
'account_welcome_mail_show_pass' => false, // send password in welcome email
'account_mail_change' => 2, // how many days user need to change email to account - block hackers
'account_country' => true, // user will be able to set country of origin when registering account, this information will be viewable in others places aswell
'account_country_recognize' => true, // should country of user be automatically recognized by his IP? This makes an external API call to http://ipinfo.io

'account_change_coin_type' => 'coins', // which coin you want to use, coins or coins_transferable to buy changes at site
'account_coin_type_usage' => 'coins_transferable', // which coin you want to use, coins or coins_transferable to buy changes at site
'account_change_character_name' => false, // can user change their character name for coins?
'account_change_character_name_coins' => 250, // cost of name change
'account_change_character_sex' => false, // can user change their character sex for coins?
Expand Down
2 changes: 1 addition & 1 deletion system/pages/account/change_main.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
echo 'Changing main character for coins is disabled on this server.';
return;
}
$coinType = $config['account_change_coin_type'] ?? 'coins';
$coinType = $config['account_coin_type_usage'] ?? 'coins_transferable';
$coinName = $coinType == 'coins' ? $coinType : 'transferable coins';
$needCoins = $config['account_change_character_main_coins'];

Expand Down
2 changes: 1 addition & 1 deletion system/pages/account/change_name.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

$player_id = isset($_POST['player_id']) ? (int)$_POST['player_id'] : NULL;
$name = isset($_POST['name']) ? stripslashes(ucwords(strtolower($_POST['name']))) : NULL;
$coinType = $config['account_change_coin_type'] ?? 'coins';
$coinType = $config['account_coin_type_usage'] ?? 'coins_transferable';
$coinName = $coinType == 'coins' ? $coinType : 'transferable coins';
$needCoins = $config['account_change_character_name_coins'];

Expand Down
2 changes: 1 addition & 1 deletion system/pages/account/change_sex.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
$sex_changed = false;
$player_id = isset($_POST['player_id']) ? (int)$_POST['player_id'] : NULL;
$new_sex = isset($_POST['new_sex']) ? (int)$_POST['new_sex'] : NULL;
$coinType = $config['account_change_coin_type'] ?? 'coins';
$coinType = $config['account_coin_type_usage'] ?? 'coins_transferable';
$coinName = $coinType == 'coins' ? $coinType : 'transferable coins';
$needCoins = $config['account_change_character_sex_coins'];

Expand Down
2 changes: 1 addition & 1 deletion system/pages/account/register_new.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
if ((!$config['generate_new_reckey'] || !$config['mail_enabled']) || empty($reckey))
echo "You can't get new recovery key";
else {
$coinType = $config['account_change_coin_type'] ?? 'coins';
$coinType = $config['account_coin_type_usage'] ?? 'coins_transferable';
$coinName = $coinType == 'coins' ? $coinType : 'transferable coins';
$needCoins = $config['generate_new_reckey_price'];

Expand Down
5 changes: 3 additions & 2 deletions system/pages/createaccount.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,9 @@
}
}

if ($config['account_premium_coins']) {
$new_account->setCustomField('coins', $config['account_premium_coins']);
if (($welcomeCoins = ($config['account_welcome_coins'] ?? 0)) > 0) {
$coinType = $config['account_coin_type_usage'] ?? 'coins_transferable';
$new_account->setCustomField($coinType, $welcomeCoins);
}

$tmp_account = (USE_ACCOUNT_NAME ? $account_name : $account_id);
Expand Down
Loading