First commit

This commit is contained in:
2025-02-26 13:42:34 +01:00
commit f465c9072c
2467 changed files with 426214 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
<?php
class Cache
{
protected $_file = false;
protected $_lifespan = 0;
protected $_content;
protected $_memory = false;
protected $_canMemory = false;
const EXT = '.cache.php';
/**
* @param string $file
* @access public
* @return void
**/
public function __construct($file) {
$cfg = config('cache');
$this->setExpiration($cfg['lifespan']);
if (function_exists('apcu_fetch')) {
$this->_canMemory = true;
$this->_memory = $cfg['memory'];
}
$this->_file = $file . self::EXT;
if (!$this->_memory && $cfg['memory']) die("
<p><strong>Configuration error!</strong>
<br>Cannot save cache to memory, but it is configured to do so.
<br>You need to enable PHP extension APCu to enable memory cache.
<br>Install it or set \$config['cache']['memory'] to false!
<br><strong>Ubuntu install:</strong> sudo apt install php-apcu</p>
");
}
/**
* Sets the cache expiration limit (IMPORTANT NOTE: seconds, NOT ms!).
*
* @param integer $span
* @access public
* @return void
**/
public function setExpiration($span) {
$this->_lifespan = $span;
}
/**
* Enable or disable memory RAM storage.
*
* @param bool $bool
* @access public
* @return bool $status
**/
public function useMemory($bool) {
if ($bool and $this->_canMemory) {
$this->_memory = true;
return true;
}
$this->_memory = false;
return false;
}
/**
* Set the content you'd like to cache.
*
* @param mixed $content
* @access public
* @return void
**/
public function setContent($content) {
$this->_content = (!$this->_memory && strtolower(gettype($content)) == 'array') ? json_encode($content) : $content;
}
/**
* Validates whether it is time to refresh the cache data or not.
*
* @access public
* @return boolean
**/
public function hasExpired() {
if ($this->_memory) {
return !apcu_exists($this->_file);
}
if (is_file($this->_file) && time() < filemtime($this->_file) + $this->_lifespan) {
return false;
}
return true;
}
/**
* Returns remaining time before scoreboard will update itself.
*
* @access public
* @return integer
**/
public function remainingTime() {
$remaining = 0;
if ($this->_memory) {
if (apcu_exists($this->_file)) {
$meta = apcu_cache_info();
foreach ($meta['cache_list'] AS $item) {
if ($item['info'] == $this->_file) {
$remaining = ($item['creation_time'] + $item['ttl']) - time();
return ($remaining > 0) ? $remaining : 0;
}
}
}
return $remaining;
}
if (!$this->hasExpired()) {
$remaining = (filemtime($this->_file) + $this->_lifespan) - time();
}
return $remaining;
}
/**
* Saves the content into its appropriate cache file.
*
* @access public
* @return void
**/
public function save() {
if ($this->_memory) {
return apcu_store($this->_file, $this->_content, $this->_lifespan);
}
$handle = fopen($this->_file, 'w');
fwrite($handle, $this->_content);
fclose($handle);
}
/**
* Loads the content from a specified cache file.
*
* @access public
* @return mixed
**/
public function load() {
if ($this->_memory) {
return apcu_fetch($this->_file);
}
if (!is_file($this->_file)) {
return false;
}
ob_start();
include_once($this->_file);
$content = ob_get_clean();
if (!isset($content) && strlen($content) == 0) {
return false;
}
if ($content = json_decode($content, true)) {
return (array) $content;
} else {
return $content;
}
}
}

View File

@@ -0,0 +1,613 @@
<?php
function setSession($key, $data) {
global $sessionPrefix;
$_SESSION[$sessionPrefix.$key] = $data;
}
function getSession($key) {
global $sessionPrefix;
return (isset($_SESSION[$sessionPrefix.$key])) ? $_SESSION[$sessionPrefix.$key] : false;
}
// Fetch and sanitize POST and GET values
function getValue($value) {
return (!empty($value)) ? sanitize($value) : false;
}
function SendGet($getArray, $location = 'error.php') {
$string = "";
$count = 0;
foreach ($getArray as $getKey => $getValue) {
if ($count > 0) $string .= '&';
$string .= "{$getKey}={$getValue}";
}
header("Location: {$location}?{$string}");
exit();
}
// Sweet error reporting
function data_dump($print = false, $var = false, $title = false) {
if ($title !== false) echo "<pre><font color='red' size='5'>$title</font><br>";
else echo '<pre>';
if ($print !== false) {
echo 'Print: - ';
print_r($print);
echo "<br>";
}
if ($var !== false) {
echo 'Var_dump: - ';
var_dump($var);
}
echo '</pre><br>';
}
function accountAccess($accountId, $TFS) {
$accountId = (int)$accountId;
$access = 0;
// TFS 0.3/4
$yourChars = mysql_select_multi("SELECT `name`, `group_id`, `account_id` FROM `players` WHERE `account_id`='$accountId';");
if ($yourChars !== false) {
foreach ($yourChars as $char) {
if ($TFS === 'TFS_03' || $TFS === 'OTHIRE') {
if ($char['group_id'] > $access) $access = $char['group_id'];
} else {
if ($char['group_id'] > 1) {
if ($access == 0) {
$acc = mysql_select_single("SELECT `type` FROM `accounts` WHERE `id`='". $char['account_id'] ."' LIMIT 1;");
$access = $acc['type'];
}
}
}
}
if ($access == 0) $access++;
return $access;
} else return false;
//
}
// Generate recovery key
function generate_recovery_key($lenght) {
$lenght = (int)$lenght;
$tmp = rand(1000, 9000);
$tmp += time();
$tmp = sha1($tmp);
$results = '';
for ($i = 0; $i < $lenght; $i++) $results = $results.''.$tmp[$i];
return $results;
}
// Calculate discount
function calculate_discount($orig, $new) {
$orig = (int)$orig;
$new = (int)$new;
$tmp = '';
if ($new >= $orig) {
if ($new != $orig) {
$calc = ($new/$orig) - 1;
$calc *= 100;
$tmp = '+'. floor($calc) .'%';
} else $tmp = '0%';
} else {
$calc = 1 - ($new/$orig);
$calc *= 100;
$tmp = '-'. floor($calc) .'%';
}
return $tmp;
}
// Proper URLs
function url($path = false) {
$folder = dirname($_SERVER['SCRIPT_NAME']);
return config('site_url') . '/' . $path;
}
function getCache() {
$results = mysql_select_single("SELECT `cached` FROM `znote`;");
return ($results !== false) ? $results['cached'] : false;
}
function setCache($time) {
$time = (int)$time;
mysql_update("UPDATE `znote` set `cached`='$time'");
}
// Get visitor basic data
function znote_visitors_get_data() {
return mysql_select_multi("SELECT `ip`, `value` FROM `znote_visitors` ORDER BY `id` DESC LIMIT 1000;");
}
// Set visitor basic data
function znote_visitor_set_data($visitor_data) {
$exist = false;
$ip = getIPLong();
foreach ((array)$visitor_data as $row) {
if ($ip == $row['ip']) {
$exist = true;
$value = $row['value'];
}
}
if ($exist && isset($value)) {
// Update the value
$value++;
mysql_update("UPDATE `znote_visitors` SET `value` = '$value' WHERE `ip` = '$ip'");
} else {
// Insert new row
mysql_insert("INSERT INTO `znote_visitors` (`ip`, `value`) VALUES ('$ip', '1')");
}
}
// Get visitor basic data
function znote_visitors_get_detailed_data($cache_time) {
$period = (int)time() - (int)$cache_time;
return mysql_select_multi("SELECT `ip`, `time`, `type`, `account_id` FROM `znote_visitors_details` WHERE `time` >= '$period' LIMIT 0, 50");
}
function znote_visitor_insert_detailed_data($type) {
$type = (int)$type;
/*
type 0 = normal visits
type 1 = register form
type 2 = character creation
type 3 = fetch highscores
type 4 = search character
*/
$time = time();
$ip = getIPLong();
if (user_logged_in()) {
$acc = (int)getSession('user_id');
mysql_insert("INSERT INTO `znote_visitors_details` (`ip`, `time`, `type`, `account_id`) VALUES ('$ip', '$time', '$type', '$acc')");
} else mysql_insert("INSERT INTO `znote_visitors_details` (`ip`, `time`, `type`, `account_id`) VALUES ('$ip', '$time', '$type', '0')");
}
function something () {
// Make acc data compatible:
$ip = getIPLong();
}
// Secret token
function create_token() {
echo 'Checking whether to create token or not<br />';
#if (empty($_SESSION['token'])) {
echo 'Creating token<br />';
$token = sha1(uniqid(time(), true));
$token2 = $token;
var_dump($token, $token2);
$_SESSION['token'] = $token2;
#}
echo "<input type=\"hidden\" name=\"token\" value=\"". $_SESSION['token'] ."\" />";
}
function reset_token() {
echo 'Reseting token<br />';
unset($_SESSION['token']);
}
// Time based functions
// 60 seconds to 1 minute
function second_to_minute($seconds) {
return ($seconds / 60);
}
// 1 minute to 60 seconds
function minute_to_seconds($minutes) {
return ($minutes * 60);
}
// 60 minutes to 1 hour
function minute_to_hour($minutes) {
return ($minutes / 60);
}
// 1 hour to 60 minutes
function hour_to_minute($hours) {
return ($hour * 60);
}
// seconds / 60 / 60 = hours.
function seconds_to_hours($seconds) {
$minutes = second_to_minute($seconds);
$hours = minute_to_hour($minutes);
return $hours;
}
function remaining_seconds_to_clock($seconds) {
return date("(H:i)",time() + $seconds);
}
/**
* Check if name contains more than configured max words
*
* @param string $string
* @return string|boolean
*/
function validate_name($string) {
return (str_word_count(trim($string)) > config('maxW')) ? false : trim($string);
}
// Checks if an IPv4(or localhost IPv6) address is valid
function validate_ip($ip) {
$ipL = safeIp2Long($ip);
$ipR = long2ip((int)$ipL);
if ($ip === $ipR) {
return true;
} elseif ($ip=='::1') {
return true;
} else {
return false;
}
}
// Fetch a config value. Etc config('vocations') will return vocation array from config.php.
function config($value) {
global $config;
return $config[$value];
}
// Some functions uses several configurations from config.php, so it sounds
// smarter to give them the whole array instead of calling the function all the time.
function fullConfig() {
global $config;
return $config;
}
// Capitalize Every Word In String.
function format_character_name($name) {
return ucwords(strtolower($name));
}
// Gets you the actual IP address even from users behind ISP proxies and so on.
function getIP() {
/*
$IP = '';
if (getenv('HTTP_CLIENT_IP')) {
$IP =getenv('HTTP_CLIENT_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR')) {
$IP =getenv('HTTP_X_FORWARDED_FOR');
} elseif (getenv('HTTP_X_FORWARDED')) {
$IP =getenv('HTTP_X_FORWARDED');
} elseif (getenv('HTTP_FORWARDED_FOR')) {
$IP =getenv('HTTP_FORWARDED_FOR');
} elseif (getenv('HTTP_FORWARDED')) {
$IP = getenv('HTTP_FORWARDED');
} else {
$IP = $_SERVER['REMOTE_ADDR'];
} */
return $_SERVER['REMOTE_ADDR'];
}
function safeIp2Long($ip) {
return sprintf('%u', ip2long($ip));
}
// Gets you the actual IP address even from users in long type
function getIPLong() {
return safeIp2Long(getIP());
}
// Deprecated, just use count($array) instead.
function array_length($ar) {
$r = 1;
foreach($ar as $a) {
$r++;
}
return $r;
}
// Parameter: level, returns experience for that level from an experience table.
function level_to_experience($level) {
return 50/3*(pow($level, 3) - 6*pow($level, 2) + 17*$level - 12);
}
// Parameter: players.hide_char returns: Status word inside a font with class identifier so it can be designed later on by CSS.
function hide_char_to_name($id) {
$id = (int)$id;
if ($id == 1) {
return 'hidden';
} else {
return 'visible';
}
}
// Parameter: players.online returns: Status word inside a font with class identifier so it can be designed later on by CSS.
function online_id_to_name($id) {
$id = (int)$id;
if ($id == 1) {
return '<font class="status_online">ONLINE</font>';
} else {
return '<font class="status_offline">offline</font>';
}
}
// Parameter: players.vocation_id. Returns: Configured vocation name.
function vocation_id_to_name($id) {
$vocations = config('vocations');
return (isset($vocations[$id]['name'])) ? $vocations[$id]['name'] : "{$id} - Unknown";
}
// Parameter: players.name. Returns: Configured vocation id.
function vocation_name_to_id($name) {
$vocations = config('vocations');
foreach ($vocations as $id => $vocation)
if ($vocation['name'] == $name)
return $id;
return false;
}
// Parameter: players.group_id. Returns: Configured group name.
function group_id_to_name($id) {
$positions = config('ingame_positions');
return ($positions[$id] >= 0) ? $positions[$id] : false;
}
function gender_exist($gender) {
// Range of allowed gender ids, fromid toid
if ($gender >= 0 && $gender <= 1) {
return true;
} else {
return false;
}
}
function skillid_to_name($skillid) {
$skillname = array(
0 => 'fist fighting',
1 => 'club fighting',
2 => 'sword fighting',
3 => 'axe fighting',
4 => 'distance fighting',
5 => 'shielding',
6 => 'fishing',
7 => 'experience', // Hardcoded, does not actually exist in database as a skillid.
8 => 'magic level' // Hardcoded, does not actually exist in database as a skillid.
);
return ($skillname[$skillid] >= 0) ? $skillname[$skillid] : false;
}
// Parameter: players.town_id. Returns: Configured town name.
function town_id_to_name($id) {
$towns = config('towns');
return (array_key_exists($id, $towns)) ? $towns[$id] : 'Missing Town';
}
// Unless you have an internal mail server then mail sending will not be supported in this version.
function email($to, $subject, $body) {
mail($to, $subject, $body, 'From: TEST');
}
function logged_in_redirect() {
if (user_logged_in() === true) {
header('Location: myaccount.php');
}
}
function protect_page() {
if (user_logged_in() === false) {
header('Location: protected.php');
exit();
}
}
// When function is called, you will be redirected to protect_page and deny access to rest of page, as long as you are not admin.
function admin_only($user_data) {
// Chris way
$gotAccess = is_admin($user_data);
if ($gotAccess == false) {
logged_in_redirect();
exit();
}
}
function is_admin($user_data) {
if (config('ServerEngine') === 'OTHIRE')
return in_array($user_data['id'], config('page_admin_access')) ? true : false;
else
return in_array($user_data['name'], config('page_admin_access')) ? true : false;
}
function array_sanitize(&$item) {
$item = htmlentities(strip_tags(mysql_znote_escape_string($item)));
}
function sanitize($data) {
return htmlentities(strip_tags(mysql_znote_escape_string($data)));
}
function output_errors($errors) {
return '<ul><li>'. implode('</li><li>', $errors) .'</li></ul>';
}
// Resize images
function resize_imagex($file, $width, $height) {
list($w, $h) = getimagesize($file['tmp']);
$ratio = max($width/$w, $height/$h);
$h = ceil($height / $ratio);
$x = ($w - $width / $ratio) / 2;
$w = ceil($width / $ratio);
$path = 'engine/guildimg/'.$file['new_name'];
$imgString = file_get_contents($file['tmp']);
$image = imagecreatefromstring($imgString);
$tmp = imagecreatetruecolor($width, $height);
imagecopyresampled($tmp, $image,
0, 0,
$x, 0,
$width, $height,
$w, $h);
imagegif($tmp, $path);
imagedestroy($image);
imagedestroy($tmp);
return true;
}
// Guild logo upload security
function check_image($image) {
$image_data = array('new_name' => $_GET['name'].'.gif', 'name' => $image['name'], 'tmp' => $image['tmp_name'], 'error' => $image['error'], 'size' => $image['size'], 'type' => $image['type']);
// First security check, quite useless but still do its job
if ($image_data['type'] === 'image/gif') {
// Second security check, lets go
$check = getimagesize($image_data['tmp']);
if ($check) {
// Third
if ($check['mime'] === 'image/gif') {
$path_info = pathinfo($image_data['name']);
// Last one
if ($path_info['extension'] === 'gif') {
// Resize image
$img = resize_imagex($image_data, 100, 100);
if ($img) {
header('Location: guilds.php?name='. $_GET['name']);
exit();
}
} else {
header('Location: guilds.php?error=Only gif images accepted, you uploaded:['.$path_info['extension'].'].&name='. $_GET['name']);
exit();
}
} else {
header('Location: guilds.php?error=Only gif images accepted, you uploaded:['.$check['mime'].'].&name='. $_GET['name']);
exit();
}
} else {
header('Location: guilds.php?error=Uploaded image is invalid.&name='. $_GET['name']);
exit();
}
} else {
header('Location: guilds.php?error=Only gif images are accepted, you uploaded:['.$image_data['type'].'].&name='. $_GET['name']);
exit();
}
}
// Check guild logo
function logo_exists($guild) {
$guild = sanitize($guild);
if (file_exists('engine/guildimg/'.$guild.'.gif')) {
echo'engine/guildimg/'.$guild.'.gif';
} else {
echo'engine/guildimg/default@logo.gif';
}
}
function generateRandomString($length = 16) {
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
function verifyGoogleReCaptcha($postResponse = null) {
if(!isset($postResponse) || empty($postResponse)) {
return false;
}
$recaptcha_api_url = 'https://www.google.com/recaptcha/api/siteverify';
$secretKey = config('captcha_secret_key');
$ip = $_SERVER['REMOTE_ADDR'];
$params = 'secret='.$secretKey.'&response='.$postResponse.'&remoteip='.$ip;
$useCurl = config('captcha_use_curl');
if($useCurl) {
$curl_connection = curl_init($recaptcha_api_url);
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($recaptcha_api_url . '?' . $params);
}
$json = json_decode($response);
return isset($json->success) && $json->success;
}
// html encoding function (encode any string to valid UTF-8 HTML)
function hhb_tohtml(/*string*/ $str)/*:string*/ {
return htmlentities($str, ENT_QUOTES | ENT_HTML401 | ENT_SUBSTITUTE | ENT_DISALLOWED, 'UTF-8', true);
}
// php5-compatibile version of php7's random_bytes()
// $crypto_strong: a boolean value that determines if the algorithm used was "cryptographically strong"
function random_bytes_compat($length, &$crypto_strong = null) {
$crypto_strong = false;
if (!is_int($length)) {
throw new \InvalidArgumentException("argument 1 must be an int, is " . gettype($length));
}
if ($length < 0) {
throw new \InvalidArgumentException("length must be >= 0");
}
if (is_callable("random_bytes")) {
$crypto_strong = true;
return random_bytes($length);
}
if (is_callable("openssl_random_pseudo_bytes")) {
return openssl_random_pseudo_bytes($length, $crypto_strong);
}
$ret = @file_get_contents("/dev/urandom", false, null, 0, $length);
if (is_string($ret) && strlen($ret) === $length) {
$crypto_strong = true;
return $ret;
}
// fallback to non-cryptographically-secure mt_rand() implementation...
$crypto_strong = false;
$ret = "";
for ($i = 0; $i < $length; ++$i) {
$ret .= chr(mt_rand(0, 255));
}
return $ret;
}
// hash_equals legacy support < 5.6
if(!function_exists('hash_equals')) {
function hash_equals($str1, $str2) {
if(strlen($str1) != strlen($str2)) {
return false;
}
$res = $str1 ^ $str2;
$ret = 0;
for($i = strlen($res) - 1; $i >= 0; $i--) {
$ret |= ord($res[$i]);
}
return !$ret;
}
}
?>

View File

@@ -0,0 +1,34 @@
<?php
/* Returns a PHP array $id => 'name'
$items = getItemList();
echo $items[2160]; // Returns 'Crystal Coin'
*/
function getItemList() {
return parseItems();
}
function getItemById($id) {
$items = parseItems();
if(isset($items[$id])) {
return $items[$id];
}
return false;
}
function parseItems() {
$file = Config('server_path') . '/data/items/items.xml';
if (file_exists($file)) {
$itemList = array();
$items = simplexml_load_file($file);
// Create our parsed item list
foreach ($items->children() as $item) {
if ($item['id'] && $item['name'] != NULL) {
$itemList[(int)$item['id']] = (string)$item['name'];
}
}
return $itemList;
}
return $file;
}
?>

View File

@@ -0,0 +1,99 @@
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
class Mail {
protected $_config = false;
/**
* @param array $config
* @access public
* @return void
**/
public function __construct($config) {
$this->_config = $config;
}
/**
* Sets the cache expiration limit (IMPORTANT NOTE: seconds, NOT ms!).
*
* @param string $to, string $title, string $text, string $accname
* @access public
* @return boolean
**/
public function sendMail($to, $title, $text, $accname = '') {
//SMTP needs accurate times, and the PHP time zone MUST be set
//This should be done in your php.ini, but this is how to do it if you don't have access to that
//date_default_timezone_set('Etc/UTC');
require_once __DIR__.'/../../PHPMailer/src/Exception.php';
require_once __DIR__.'/../../PHPMailer/src/PHPMailer.php';
require_once __DIR__.'/../../PHPMailer/src/SMTP.php';
//Create a new PHPMailer instance
$mail = new PHPMailer();
//Tell PHPMailer to use SMTP
$mail->isSMTP();
//Enable SMTP debugging
// 0 = off (for production use)
// 1 = client messages
// 2 = client and server messages
$mail->SMTPDebug = ($this->_config['debug']) ? 2 : 0;
//Ask for HTML-friendly debug output
$mail->Debugoutput = 'html';
//Set the hostname of the mail server
$mail->Host = $this->_config['host'];
//Set the SMTP port number - likely to be 25, 465 or 587
$mail->Port = $this->_config['port'];
//Whether to use SMTP authentication
$mail->SMTPAuth = true;
$mail->SMTPSecure = $this->_config['securityType'];
//Username to use for SMTP authentication
$mail->Username = $this->_config['username'];
//Password to use for SMTP authentication
$mail->Password = $this->_config['password'];
//Set who the message is to be sent from
$mail->setFrom($this->_config['email'], $this->_config['fromName']);
//Set who the message is to be sent to
$mail->addAddress($to, $accname);
//Set the subject line
$mail->Subject = $title;
// Body
$mail->Body = $text;
// Convert HTML -> plain for legacy mail recievers
// Create new lines instead of <br> html tags.
$text = str_replace("<br>", "\n", $text);
$text = str_replace("<br\>", "\n", $text);
$text = str_replace("<br \>", "\n", $text);
// Then get rid of the rest of the html tags.
$text = strip_tags($text);
//Replace the plain text body with one created manually
$mail->AltBody = $text;
//send the message, check for errors
$status = false;
if (!$mail->send()) {
echo "Mailer Error: " . $mail->ErrorInfo;
exit();
} else {
$status = true;
}
return $status;
}
}

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

@@ -0,0 +1,89 @@
<?php
// List of characters: $, {}, []
class Token {
public static function generate() {
$token = sha1(uniqid(time(), true));
$_SESSION['token'] = $token;
}
/**
* Displays a random token to prevent CSRF attacks.
*
* @access public
* @static true
* @return void
**/
public static function create() {
echo '<input type="hidden" name="token" value="' . self::get() . '" />';
}
/**
* Returns the active token, if there is one.
*
* @access public
* @static true
* @return mixed
**/
public static function get() {
return isset($_SESSION['token']) ? $_SESSION['token'] : false;
}
/**
* Validates whether the active token is valid or not.
*
* @param string $post
* @access public
* @static true
* @return boolean
**/
public static function isValid($post) {
if (config('use_token')) {
// Token doesn't exist yet, return false.
if (!self::get()) {
return false;
}
// Token was invalid, return false.
if ($post == $_SESSION['old_token'] || $post == $_SESSION['token']) {
//self::_reset();
return true;
} else {
return false;
}
} else {
return true;
}
}
/**
* Destroys the active token.
*
* @access protected
* @static true
* @return void
**/
protected static function _reset() {
unset($_SESSION['token']);
}
/**
* Displays information on both the post token and the session token.
*
* @param string $post
* @access public
* @static true
* @return void
**/
public static function debug($post) {
echo '<pre>', var_dump(array(
'post' => $post,
'old_token' => $_SESSION['old_token'],
'token' => self::get()
)), '</pre>';
}
}
?>

File diff suppressed because it is too large Load Diff