mirror of
https://github.com/slawkens/myaac.git
synced 2025-10-16 10:44:55 +02:00
Merge branch 'develop' into feature/new-router
This commit is contained in:
15
system/compat/classes.php
Normal file
15
system/compat/classes.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* Compat classes (backward support for Gesior AAC)
|
||||
*
|
||||
* @package MyAAC
|
||||
* @author Slawkens <slawkens@gmail.com>
|
||||
* @copyright 2022 MyAAC
|
||||
* @link https://my-aac.org
|
||||
*/
|
||||
defined('MYAAC') or die('Direct access not allowed!');
|
||||
|
||||
class Player extends OTS_Player {}
|
||||
class Guild extends OTS_Guild {}
|
||||
class GuildRank extends OTS_GuildRank {}
|
||||
class House extends OTS_House {}
|
@@ -39,7 +39,7 @@ function exception_handler($exception) {
|
||||
// we just replace some values manually
|
||||
// cause in case Twig throws exception, we can show it too
|
||||
$content = file_get_contents($template_file);
|
||||
$content = str_replace(array('{{ BASE_URL }}', '{{ message }}', '{{ backtrace }}', '{{ powered_by }}'), array(BASE_URL, $message, $backtrace_formatted, base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=')), $content);
|
||||
$content = str_replace(array('{{ BASE_URL }}', '{{ exceptionClass }}', '{{ message }}', '{{ backtrace }}', '{{ powered_by }}'), array(BASE_URL, get_class($exception), $message, $backtrace_formatted, base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4=')), $content);
|
||||
|
||||
echo $content;
|
||||
}
|
||||
|
@@ -1476,9 +1476,26 @@ function truncate($string, $length)
|
||||
return $string;
|
||||
}
|
||||
|
||||
function getAccountLoginByLabel()
|
||||
{
|
||||
$ret = '';
|
||||
if (config('account_login_by_email')) {
|
||||
$ret = 'Email Address';
|
||||
if (config('account_login_by_email_fallback')) {
|
||||
$ret .= ' or ';
|
||||
}
|
||||
}
|
||||
|
||||
if (!config('account_login_by_email') || config('account_login_by_email_fallback')) {
|
||||
$ret .= 'Account ' . (USE_ACCOUNT_NAME ? 'Name' : 'Number');
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// validator functions
|
||||
require_once LIBS . 'validator.php';
|
||||
require_once SYSTEM . 'compat.php';
|
||||
require_once SYSTEM . 'compat/base.php';
|
||||
|
||||
// custom functions
|
||||
require SYSTEM . 'functions_custom.php';
|
||||
|
@@ -127,6 +127,8 @@ $ots = POT::getInstance();
|
||||
require_once SYSTEM . 'database.php';
|
||||
|
||||
define('USE_ACCOUNT_NAME', $db->hasColumn('accounts', 'name'));
|
||||
define('USE_ACCOUNT_NUMBER', $db->hasColumn('accounts', 'number'));
|
||||
|
||||
// load vocation names
|
||||
$tmp = '';
|
||||
if($cache->enabled() && $cache->fetch('vocations', $tmp)) {
|
||||
@@ -158,4 +160,4 @@ else {
|
||||
unset($tmp, $id, $vocation);
|
||||
|
||||
require LIBS . 'Towns.php';
|
||||
Towns::load();
|
||||
Towns::load();
|
||||
|
@@ -12,27 +12,44 @@
|
||||
class CreateCharacter
|
||||
{
|
||||
/**
|
||||
* @param string $name
|
||||
* @param int $sex
|
||||
* @param int $vocation
|
||||
* @param int $town
|
||||
* @param array $errors
|
||||
* @param $name
|
||||
* @param $errors
|
||||
* @return bool
|
||||
*/
|
||||
public function check($name, $sex, &$vocation, &$town, &$errors) {
|
||||
public function checkName($name, &$errors)
|
||||
{
|
||||
$minLength = config('character_name_min_length');
|
||||
$maxLength = config('character_name_max_length');
|
||||
|
||||
if(empty($name))
|
||||
if(empty($name)) {
|
||||
$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();
|
||||
}
|
||||
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();
|
||||
@@ -42,20 +59,38 @@ class CreateCharacter
|
||||
return false;
|
||||
}
|
||||
|
||||
if(empty($sex) && $sex != "0")
|
||||
return empty($errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param int $sex
|
||||
* @param int $vocation
|
||||
* @param int $town
|
||||
* @param array $errors
|
||||
* @return bool
|
||||
*/
|
||||
public function check($name, $sex, &$vocation, &$town, &$errors)
|
||||
{
|
||||
$this->checkName($name, $errors);
|
||||
|
||||
if(empty($sex) && $sex != "0") {
|
||||
$errors['sex'] = 'Please select the sex for your character!';
|
||||
}
|
||||
|
||||
if(count(config('character_samples')) > 1)
|
||||
{
|
||||
if(!isset($vocation))
|
||||
$errors['vocation'] = 'Please select a vocation for your character.';
|
||||
}
|
||||
else
|
||||
else {
|
||||
$vocation = config('character_samples')[0];
|
||||
}
|
||||
|
||||
if(count(config('character_towns')) > 1) {
|
||||
if(!isset($town))
|
||||
if(!isset($town)) {
|
||||
$errors['town'] = 'Please select a town for your character.';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$town = config('character_towns')[0];
|
||||
|
79
system/libs/GoogleReCAPTCHA.php
Normal file
79
system/libs/GoogleReCAPTCHA.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
class GoogleReCAPTCHA
|
||||
{
|
||||
private static $errorMessage = '';
|
||||
private static $errorType;
|
||||
|
||||
const ERROR_MISSING_RESPONSE = 1;
|
||||
const ERROR_INVALID_ACTION = 2;
|
||||
const ERROR_LOW_SCORE = 3;
|
||||
const ERROR_NO_SUCCESS = 4;
|
||||
|
||||
public static function verify($action = '')
|
||||
{
|
||||
if (!isset($_POST['g-recaptcha-response']) || empty($_POST['g-recaptcha-response'])) {
|
||||
self::$errorType = self::ERROR_MISSING_RESPONSE;
|
||||
self::$errorMessage = "Please confirm that you're not a robot.";
|
||||
return false;
|
||||
}
|
||||
|
||||
$recaptchaApiUrl = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
$secretKey = config('recaptcha_secret_key');
|
||||
|
||||
$recaptchaResponse = $_POST['g-recaptcha-response'];
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
$params = 'secret='.$secretKey.'&response='.$recaptchaResponse.'&remoteip='.$ip;
|
||||
|
||||
if (function_exists('curl_version')) {
|
||||
$curl_connection = curl_init($recaptchaApiUrl);
|
||||
|
||||
curl_setopt($curl_connection, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl_connection, CURLOPT_FOLLOWLOCATION, 0);
|
||||
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $params);
|
||||
|
||||
$response = curl_exec($curl_connection);
|
||||
curl_close($curl_connection);
|
||||
} else {
|
||||
$response = file_get_contents($recaptchaApiUrl . '?' . $params);
|
||||
}
|
||||
|
||||
$json = json_decode($response);
|
||||
//log_append('recaptcha.log', 'recaptcha_score: ' . $json->score . ', action:' . $json->action);
|
||||
if (!isset($json->action) || $json->action !== $action) {
|
||||
self::$errorType = self::ERROR_INVALID_ACTION;
|
||||
self::$errorMessage = 'Google ReCaptcha returned invalid action.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($json->score) || $json->score < config('recaptcha_min_score')) {
|
||||
self::$errorType = self::ERROR_LOW_SCORE;
|
||||
self::$errorMessage = 'Your Google ReCaptcha score was too low.';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($json->success) || !$json->success) {
|
||||
self::$errorType = self::ERROR_NO_SUCCESS;
|
||||
self::$errorMessage = "Please confirm that you're not a robot.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getErrorMessage() {
|
||||
return self::$errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public static function getErrorType() {
|
||||
return self::$errorType;
|
||||
}
|
||||
}
|
@@ -101,6 +101,37 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $email
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createWithEmail($email = null)
|
||||
{
|
||||
// if name is not passed then it will be generated randomly
|
||||
if( !isset($email) )
|
||||
{
|
||||
throw new Exception(__CLASS__ . ':' . __METHOD__ . ' createWithEmail called without e-mail.');
|
||||
}
|
||||
|
||||
// repeats until name is unique
|
||||
do
|
||||
{
|
||||
$name = uniqid();
|
||||
|
||||
$query = $this->db->query('SELECT `id` FROM `accounts` WHERE `name` = ' . $this->db->quote($name));
|
||||
} while($query->rowCount() >= 1);
|
||||
|
||||
// saves blank account info
|
||||
$this->db->exec('INSERT INTO `accounts` (`name`, `password`, `email`, `created`) VALUES (' . $this->db->quote($name) . ', ' . '\'\', ' . $this->db->quote($email) . ', ' . time() . ')');
|
||||
|
||||
// reads created account's ID
|
||||
$this->data['id'] = $this->db->lastInsertId();
|
||||
$this->data['name'] = $name;
|
||||
|
||||
// return name of newly created account
|
||||
return $name;
|
||||
}
|
||||
/**
|
||||
* Creates new account.
|
||||
*
|
||||
@@ -138,11 +169,32 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
|
||||
*/
|
||||
public function create($name = NULL, $id = NULL)
|
||||
{
|
||||
// saves blank account info
|
||||
$this->db->exec('INSERT INTO `accounts` (' . (isset($id) ? '`id`,' : '') . (isset($name) ? '`name`,' : '') . '`password`, `email`, `created`) VALUES (' . (isset($id) ? $id . ',' : '') . (isset($name) ? $this->db->quote($name) . ',' : '') . ' \'\', \'\',' . time() . ')');
|
||||
if(isset($name)) {
|
||||
$nameOrNumber = 'name';
|
||||
$nameOrNumberValue = $name;
|
||||
}
|
||||
else {
|
||||
if (USE_ACCOUNT_NUMBER) {
|
||||
$nameOrNumber = 'number';
|
||||
$nameOrNumberValue = $id;
|
||||
$id = null;
|
||||
}
|
||||
else {
|
||||
$nameOrNumber = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($name))
|
||||
// saves blank account info
|
||||
$this->db->exec('INSERT INTO `accounts` (' . (isset($id) ? '`id`,' : '') . (isset($nameOrNumber) ? '`' . $nameOrNumber . '`,' : '') . '`password`, `email`, `created`) VALUES (' . (isset($id) ? $id . ',' : '') . (isset($nameOrNumber) ? $this->db->quote($nameOrNumberValue) . ',' : '') . ' \'\', \'\',' . time() . ')');
|
||||
|
||||
if(isset($name)) {
|
||||
$this->data['name'] = $name;
|
||||
}
|
||||
else {
|
||||
if (USE_ACCOUNT_NUMBER) {
|
||||
$this->data['number'] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$lastInsertId = $this->db->lastInsertId();
|
||||
if($lastInsertId != 0) {
|
||||
@@ -179,15 +231,26 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
|
||||
* @param int $id Account number.
|
||||
* @throws PDOException On PDO operation error.
|
||||
*/
|
||||
public function load($id, $fresh = false)
|
||||
public function load($id, $fresh = false, $searchOnlyById = false)
|
||||
{
|
||||
if(!$fresh && isset(self::$cache[$id])) {
|
||||
$this->data = self::$cache[$id];
|
||||
return;
|
||||
}
|
||||
|
||||
$numberColumn = 'id';
|
||||
$nameOrNumber = '';
|
||||
if (!$searchOnlyById) {
|
||||
if (USE_ACCOUNT_NAME) {
|
||||
$nameOrNumber = '`name`,';
|
||||
} else if (USE_ACCOUNT_NUMBER) {
|
||||
$nameOrNumber = '`number`,';
|
||||
$numberColumn = 'number';
|
||||
}
|
||||
}
|
||||
|
||||
// SELECT query on database
|
||||
$this->data = $this->db->query('SELECT `id`, ' . ($this->db->hasColumn('accounts', 'name') ? '`name`,' : '') . '`password`, `email`, `blocked`, `rlname`, `location`, `country`, `web_flags`, ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays`, ' : '') . ($this->db->hasColumn('accounts', 'lastday') ? '`lastday`, ' : ($this->db->hasColumn('accounts', 'premend') ? '`premend`,' : ($this->db->hasColumn('accounts', 'premium_ends_at') ? '`premium_ends_at`,' : ''))) . '`created` FROM `accounts` WHERE `id` = ' . (int) $id)->fetch();
|
||||
$this->data = $this->db->query('SELECT `id`, ' . $nameOrNumber . '`password`, `email`, `blocked`, `rlname`, `location`, `country`, `web_flags`, ' . ($this->db->hasColumn('accounts', 'premdays') ? '`premdays`, ' : '') . ($this->db->hasColumn('accounts', 'lastday') ? '`lastday`, ' : ($this->db->hasColumn('accounts', 'premend') ? '`premend`,' : ($this->db->hasColumn('accounts', 'premium_ends_at') ? '`premium_ends_at`,' : ''))) . '`created` FROM `accounts` WHERE `' . $numberColumn . '` = ' . (int) $id)->fetch();
|
||||
self::$cache[$id] = $this->data;
|
||||
}
|
||||
|
||||
@@ -306,6 +369,15 @@ class OTS_Account extends OTS_Row_DAO implements IteratorAggregate, Countable
|
||||
return $this->data['id'];
|
||||
}
|
||||
|
||||
public function getNumber()
|
||||
{
|
||||
if (isset($this->data['number'])) {
|
||||
return $this->data['number'];
|
||||
}
|
||||
|
||||
return $this->data['id'];
|
||||
}
|
||||
|
||||
public function getRLName()
|
||||
{
|
||||
if( !isset($this->data['rlname']) )
|
||||
|
@@ -602,7 +602,7 @@ class OTS_Player extends OTS_Row_DAO
|
||||
}
|
||||
|
||||
$account = new OTS_Account();
|
||||
$account->load($this->data['account_id']);
|
||||
$account->load($this->data['account_id'], false, true);
|
||||
return $account;
|
||||
}
|
||||
|
||||
|
285
system/libs/rfc6238.php
Normal file
285
system/libs/rfc6238.php
Normal 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;
|
||||
}
|
||||
}
|
||||
?>
|
@@ -354,16 +354,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;
|
||||
}
|
||||
|
||||
|
@@ -34,11 +34,13 @@ $errors = array();
|
||||
$save = isset($_POST['save']) && $_POST['save'] == 1;
|
||||
if($save)
|
||||
{
|
||||
if(USE_ACCOUNT_NAME) {
|
||||
$account_name = $_POST['account'];
|
||||
}
|
||||
else {
|
||||
$account_id = $_POST['account'];
|
||||
if(!config('account_login_by_email')) {
|
||||
if(USE_ACCOUNT_NAME) {
|
||||
$account_name = $_POST['account'];
|
||||
}
|
||||
else {
|
||||
$account_id = $_POST['account'];
|
||||
}
|
||||
}
|
||||
|
||||
$email = $_POST['email'];
|
||||
@@ -46,12 +48,14 @@ if($save)
|
||||
$password2 = $_POST['password2'];
|
||||
|
||||
// account
|
||||
if(isset($account_id)) {
|
||||
if(!Validator::accountId($account_id))
|
||||
if(!config('account_login_by_email')) {
|
||||
if (isset($account_id)) {
|
||||
if (!Validator::accountId($account_id)) {
|
||||
$errors['account'] = Validator::getLastError();
|
||||
}
|
||||
} else if (!Validator::accountName($account_name))
|
||||
$errors['account'] = Validator::getLastError();
|
||||
}
|
||||
else if(!Validator::accountName($account_name))
|
||||
$errors['account'] = Validator::getLastError();
|
||||
|
||||
// email
|
||||
if(!Validator::email($email))
|
||||
@@ -68,17 +72,12 @@ if($save)
|
||||
$errors['country'] = 'Country is invalid.';
|
||||
}
|
||||
|
||||
if($config['recaptcha_enabled'])
|
||||
if(config('recaptcha_enabled'))
|
||||
{
|
||||
if(isset($_POST['g-recaptcha-response']) && !empty($_POST['g-recaptcha-response']))
|
||||
{
|
||||
$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$config['recaptcha_secret_key'].'&response='.$_POST['g-recaptcha-response']);
|
||||
$responseData = json_decode($verifyResponse);
|
||||
if(!$responseData->success)
|
||||
$errors['verification'] = "Please confirm that you're not a robot.";
|
||||
require LIBS . 'GoogleReCAPTCHA.php';
|
||||
if (!GoogleReCAPTCHA::verify('register')) {
|
||||
$errors['verification'] = GoogleReCAPTCHA::getErrorMessage();
|
||||
}
|
||||
else
|
||||
$errors['verification'] = "Please confirm that you're not a robot.";
|
||||
}
|
||||
|
||||
// password
|
||||
@@ -93,7 +92,7 @@ if($save)
|
||||
}
|
||||
|
||||
// check if account name is not equal to password
|
||||
if(USE_ACCOUNT_NAME && strtoupper($account_name) == strtoupper($password)) {
|
||||
if(!config('account_login_by_email') && USE_ACCOUNT_NAME && strtoupper($account_name) == strtoupper($password)) {
|
||||
$errors['password'] = 'Password may not be the same as account name.';
|
||||
}
|
||||
|
||||
@@ -106,16 +105,28 @@ if($save)
|
||||
}
|
||||
|
||||
$account_db = new OTS_Account();
|
||||
if(USE_ACCOUNT_NAME)
|
||||
$account_db->find($account_name);
|
||||
else
|
||||
$account_db->load($account_id);
|
||||
if (config('account_login_by_email')) {
|
||||
$account_db->findByEMail($email);
|
||||
}
|
||||
else {
|
||||
if(USE_ACCOUNT_NAME) {
|
||||
$account_db->find($account_name);
|
||||
}
|
||||
else {
|
||||
$account_db->load($account_id);
|
||||
}
|
||||
}
|
||||
|
||||
if($account_db->isLoaded()) {
|
||||
if(USE_ACCOUNT_NAME)
|
||||
$errors['account'] = 'Account with this name already exist.';
|
||||
else
|
||||
$errors['account'] = 'Account with this id already exist.';
|
||||
if (config('account_login_by_email') && !config('account_mail_unique')) {
|
||||
$errors['account'] = 'Account with this email already exist.';
|
||||
}
|
||||
else if (!config('account_login_by_email')) {
|
||||
if (USE_ACCOUNT_NAME)
|
||||
$errors['account'] = 'Account with this name already exist.';
|
||||
else
|
||||
$errors['account'] = 'Account with this id already exist.';
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($_POST['accept_rules']) || $_POST['accept_rules'] !== 'true')
|
||||
@@ -130,11 +141,12 @@ if($save)
|
||||
'accept_rules' => isset($_POST['accept_rules']) ? $_POST['accept_rules'] === 'true' : false,
|
||||
);
|
||||
|
||||
if(USE_ACCOUNT_NAME) {
|
||||
$params['account_name'] = $_POST['account'];
|
||||
}
|
||||
else {
|
||||
$params['account_id'] = $_POST['account'];
|
||||
if (!config('account_login_by_email')) {
|
||||
if (USE_ACCOUNT_NAME) {
|
||||
$params['account_name'] = $_POST['account'];
|
||||
} else {
|
||||
$params['account_id'] = $_POST['account'];
|
||||
}
|
||||
}
|
||||
|
||||
$hooks->trigger(HOOK_ACCOUNT_CREATE_AFTER_SUBMIT, $params);
|
||||
@@ -151,10 +163,15 @@ if($save)
|
||||
if(empty($errors))
|
||||
{
|
||||
$new_account = new OTS_Account();
|
||||
if(USE_ACCOUNT_NAME)
|
||||
$new_account->create($account_name);
|
||||
else
|
||||
$new_account->create(NULL, $account_id);
|
||||
if (config('account_login_by_email')) {
|
||||
$new_account->createWithEmail($email);
|
||||
}
|
||||
else {
|
||||
if(USE_ACCOUNT_NAME)
|
||||
$new_account->create($account_name);
|
||||
else
|
||||
$new_account->create(NULL, $account_id);
|
||||
}
|
||||
|
||||
$config_salt_enabled = $db->hasColumn('accounts', 'salt');
|
||||
if($config_salt_enabled)
|
||||
@@ -192,7 +209,11 @@ if($save)
|
||||
$new_account->setCustomField('premium_points', $config['account_premium_points']);
|
||||
}
|
||||
|
||||
$tmp_account = (USE_ACCOUNT_NAME ? $account_name : $account_id);
|
||||
$tmp_account = $email;
|
||||
if (!config('account_login_by_email')) {
|
||||
$tmp_account = (USE_ACCOUNT_NAME ? $account_name : $account_id);
|
||||
}
|
||||
|
||||
if($config['mail_enabled'] && $config['account_mail_verify'])
|
||||
{
|
||||
$hash = md5(generateRandomString(16, true, true) . $email);
|
||||
|
@@ -13,5 +13,6 @@ $title = 'Login';
|
||||
$twig->display('admin.login.html.twig', [
|
||||
'logout' => (ACTION == 'logout' ? 'You have been logged out!' : ''),
|
||||
'account' => USE_ACCOUNT_NAME ? 'Name' : 'Number',
|
||||
'errors' => $errors ?? ''
|
||||
]);
|
||||
'account_login_by' => getAccountLoginByLabel(),
|
||||
'errors' => isset($errors)? $errors : ''
|
||||
));
|
||||
|
@@ -41,13 +41,10 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') {
|
||||
$player->find($name);
|
||||
if(!$player->isLoaded()) {
|
||||
$errors[] = 'Player with name <b>'.$name.'</b> doesn\'t exist.';
|
||||
}
|
||||
else
|
||||
{
|
||||
$rank_of_player = $player->getRank();
|
||||
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.';
|
||||
}
|
||||
}else if ($player->getAccountID() != $account_logged->getId()) {
|
||||
$errors[] = 'Character with name <b> ' . $name. ' </b> is not in your account.';
|
||||
}else if ($player->getRank()->isLoaded()){
|
||||
$errors[] = 'Character with name <b>'.$name.'</b> is already in guild. You must leave guild before you join other guild.';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,9 +62,8 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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>.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -88,7 +88,7 @@ if($guild_vice)
|
||||
else
|
||||
{
|
||||
$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_has_lower_rank = false;
|
||||
|
@@ -30,15 +30,20 @@
|
||||
|
||||
{{ hook('HOOK_ACCOUNT_CREATE_BEFORE_ACCOUNT') }}
|
||||
|
||||
{% if not config.account_login_by_email %}
|
||||
<tr>
|
||||
<td class="LabelV" style="width: 150px">
|
||||
<span{% if errors.account is defined %} class="red"{% endif %}>Account {% if constant('USE_ACCOUNT_NAME') %}Name{% else %}Number{% endif %}:</span>
|
||||
{% if not constant('USE_ACCOUNT_NAME') %}
|
||||
<div id="SuggestAccountNumber">[<a href="#">suggest number</a>]</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="account" id="account_input" size="30" maxlength="{% if constant('USE_ACCOUNT_NAME') %}30{% else %}10{% endif %}" value="{{ account }}" autofocus/>
|
||||
<img id="account_indicator" src="images/global/general/{% if not save or errors.account is defined %}n{% endif %}ok.gif" style="display: none;" />
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr><td></td><td><span id="account_error" class="FormFieldError">{% if errors.account is defined %}{{ errors.account }}{% endif %}</span></td></tr>
|
||||
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_ACCOUNT') }}
|
||||
<tr>
|
||||
@@ -104,19 +109,9 @@
|
||||
|
||||
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_PASSWORDS') }}
|
||||
|
||||
{% if config.recaptcha_enabled %}
|
||||
<tr>
|
||||
<td class="LabelV" style="width: 150px">
|
||||
<span{% if errors.verification[0] is defined %} class="red"{% endif %}>Verification:</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="g-recaptcha" data-sitekey="{{ config.recaptcha_site_key }}" data-theme="{{ config.recaptcha_theme }}"></div>
|
||||
</td>
|
||||
</tr>
|
||||
{% if errors.verification is defined %}
|
||||
<tr><td></td><td><span class="FormFieldError">{{ errors.verification }}</span></td></tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if config.recaptcha_enabled %}
|
||||
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" />
|
||||
{% endif %}
|
||||
|
||||
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_RECAPTCHA') }}
|
||||
</tbody>
|
||||
@@ -334,3 +329,12 @@
|
||||
</form>
|
||||
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_FORM') }}
|
||||
<script type="text/javascript" src="tools/check_name.js"></script>
|
||||
{% if config.recaptcha_enabled %}
|
||||
{% set action = 'register' %}
|
||||
{{ include('google_recaptcha.html.twig') }}
|
||||
{% endif %}
|
||||
<style>
|
||||
#SuggestAccountNumber {
|
||||
font-size: 7pt;
|
||||
}
|
||||
</style>
|
||||
|
@@ -20,6 +20,9 @@
|
||||
$('#password2').blur(function() {
|
||||
checkPassword();
|
||||
});
|
||||
$('#SuggestAccountNumber a').click(function (event) {
|
||||
generateAccountNumber(event);
|
||||
});
|
||||
});
|
||||
|
||||
function updateFlag()
|
||||
@@ -192,4 +195,18 @@
|
||||
|
||||
lastSend = timeNow;
|
||||
}
|
||||
|
||||
function generateAccountNumber(event)
|
||||
{
|
||||
event.preventDefault();
|
||||
$.getJSON("tools/generate_account_number.php", { uid: Math.random() },
|
||||
function(data){
|
||||
if(data.hasOwnProperty('success')) {
|
||||
$('#account_input').val(data.success);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
setTimeout(checkAccount, 1000);
|
||||
}
|
||||
</script>
|
||||
|
@@ -24,7 +24,7 @@ Please enter your account {{ account|lower }} and your password.<br/><a href="{{
|
||||
<table style="width:100%;" >
|
||||
<tr>
|
||||
<td class="LabelV" >
|
||||
<span{% if error is not null %} class="red"{% endif %}>Account {{ account }}:</span>
|
||||
<span{% if error is not null %} class="red"{% endif %}>{{ account_login_by }}:</span>
|
||||
</td>
|
||||
<td style="width:100%;" ><input type="text" name="account_login" size="30" maxlength="30" autofocus/></td>
|
||||
</tr>
|
||||
@@ -39,6 +39,9 @@ Please enter your account {{ account|lower }} and your password.<br/><a href="{{
|
||||
<td><input type="checkbox" id="remember_me" name="remember_me" value="true" />
|
||||
<label for="remember_me"> Remember me</label></td>
|
||||
</tr>
|
||||
{% if config.recaptcha_enabled %}
|
||||
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" />
|
||||
{% endif %}
|
||||
{% if error is not null %}
|
||||
<tr><td></td><td><span class="FormFieldError">{{ error }}</span></td></tr>
|
||||
{% endif %}
|
||||
@@ -74,3 +77,7 @@ Please enter your account {{ account|lower }} and your password.<br/><a href="{{
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{% if config.recaptcha_enabled %}
|
||||
{% set action = 'login' %}
|
||||
{{ include('google_recaptcha.html.twig') }}
|
||||
{% endif %}
|
||||
|
@@ -23,8 +23,7 @@
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-lock"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="account-name-input" name="account_login"
|
||||
placeholder="Account {{ account }}" required autofocus>
|
||||
<input type="text" class="form-control" id="account-name-input" name="account_login" placeholder="{{ account_login_by }}" required autofocus>
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
|
@@ -1,7 +1,8 @@
|
||||
<script type="text/javascript" src="{{ constant('BASE_URL') }}node_modules/tinymce/tinymce.min.js"></script>
|
||||
<script type="text/javascript" src="{{ constant('BASE_URL') }}tools/tinymce/tinymce.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
tinymce.init({
|
||||
selector: "textarea",
|
||||
theme: "modern",
|
||||
plugins: 'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists textcolor wordcount spellchecker imagetools contextmenu colorpicker textpattern help code emoticons',
|
||||
toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | emoticons link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat code',
|
||||
image_advtab: true,
|
||||
|
@@ -116,13 +116,14 @@
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<script type="text/javascript" src="{{ constant('BASE_URL') }}node_modules/tinymce/tinymce.min.js"></script>
|
||||
<script type="text/javascript" src="{{ constant('BASE_URL') }}tools/tinymce/tinymce.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
let unsaved = false;
|
||||
let lastContent = '';
|
||||
|
||||
tinymce.init({
|
||||
selector: "#body",
|
||||
theme: "modern",
|
||||
plugins: 'preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists textcolor wordcount spellchecker imagetools contextmenu colorpicker textpattern help code emoticons',
|
||||
toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | emoticons link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat code',
|
||||
image_advtab: true,
|
||||
|
@@ -64,7 +64,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="{{ constant('BASE_URL') }}node_modules/tinymce/tinymce.min.js"></script>
|
||||
<script type="text/javascript" src="{{ constant('BASE_URL') }}tools/tinymce/tinymce.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#enable_tinymce').on('change', function (e) {
|
||||
@@ -86,6 +86,7 @@
|
||||
function init_tinymce() {
|
||||
tinymce.init({
|
||||
selector: "#body",
|
||||
theme: "modern",
|
||||
plugins: 'code print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists textcolor wordcount spellchecker imagetools contextmenu colorpicker textpattern help emoticons',
|
||||
toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | emoticons link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat code',
|
||||
image_advtab: true,
|
||||
|
@@ -64,6 +64,8 @@
|
||||
<div class="center wide">
|
||||
<h2 class="wide">Whoops something went wrong...</h2>
|
||||
<div class="error wide">
|
||||
Exception class: {{ exceptionClass }}()
|
||||
<br/><br/>
|
||||
{{ message }}
|
||||
<br/><br/><br/>
|
||||
<b>Backtrace:</b><br/><br/>
|
||||
|
11
system/templates/google_recaptcha.html.twig
Normal file
11
system/templates/google_recaptcha.html.twig
Normal file
@@ -0,0 +1,11 @@
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
grecaptcha.ready(function() {
|
||||
grecaptcha.execute('{{ config.recaptcha_site_key }}', {action: '{{ action }}'}).then(function(token) {
|
||||
if (token) {
|
||||
document.getElementById('g-recaptcha-response').value = token;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
@@ -1,19 +1,18 @@
|
||||
<div class="TableContainer">
|
||||
<table class="Table1" cellpadding="0" cellspacing="0" style="background-color: {{ config.lightborder }}">
|
||||
<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" >Support in game</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 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" >Support in game</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">
|
||||
|
@@ -17,5 +17,5 @@
|
||||
</div>
|
||||
</noscript>
|
||||
{% if config.recaptcha_enabled %}
|
||||
<script src="https://www.google.com/recaptcha/api.js"></script>
|
||||
{% endif %}
|
||||
<script src="https://www.google.com/recaptcha/api.js?render={{ config.recaptcha_site_key }}"></script>
|
||||
{% endif %}
|
||||
|
Reference in New Issue
Block a user