Move session library inside repository

For too long, ntbb-session and ntbb-database have been maintained
outside of this repo, but no longer! All these files are now part of the
repository, making it significantly more self-contained.

If I had to say why it took this long, I think it was mostly inertia. It
was easier leaving them where they were than having to audit them for
private keys in the wrong places, etc.

I'm starting to think of PS more as sim first, website secondary than
the other way around, now. Especially now that we don't have a forum,
the website itself isn't really important... Maybe one day I'll get rid
of the landing page and make the sim itself the first thing you see when
you hit pokemonshowdown.com... but today is not that day!

The repo is still not "batteries-included" since I am not going to teach
anyone how to set up PHP and MySQL or even get the config files working.
But for anyone who wanted their own client, well, it gets a lot easier
to do now.
This commit is contained in:
Guangcong Luo 2016-10-20 12:53:53 -04:00
parent 1c18bf0f4d
commit 82e7a917ab
9 changed files with 860 additions and 9 deletions

View File

@ -42,19 +42,16 @@ Everything else can be tested, though.
Warning
------------------------------------------------------------------------
This repository is not "batteries included". It does NOT include everything
necessary to run a full Pokémon Showdown client.
In particular, it doesn't include a login/authentication server, nor does it
include the database abstraction library used by the ladder library (although
it's similar enough to `mysqli` that you can use that with minimal changes).
This repository is not "batteries included". It does NOT include instructions
to run a full Pokémon Showdown client, and we will not provide them. Please
do not ask for help on this; you will be turned away.
It also doesn't include several resource files (namely, the `/audio/` and
`/sprites/` directories) for size reasons.
In other words, this repository is incomplete and NOT intended for people
who wish to serve their own Pokémon Showdown client (you can, but it'll
require you to rewrite some things). Rather, it's intended for people who
require you figure it out yourself). Rather, it's intended for people who
wish to contribute and submit pull requests to Pokémon Showdown's client.
License

View File

@ -24,7 +24,7 @@ if (preg_match('/^http\\:\\/\\/[a-z0-9]+\\.psim\\.us\\//', @$_SERVER['HTTP_REFER
}
// header("X-Debug: " . @$_SERVER['HTTP_REFERER']);
include_once '../pokemonshowdown.com/lib/ntbb-session.lib.php';
include_once 'lib/ntbb-session.lib.php';
include_once '../pokemonshowdown.com/config/servers.inc.php';
include_once 'lib/dispatcher.lib.php';

View File

@ -0,0 +1,46 @@
<?php
mb_internal_encoding('UTF-8');
$psconfig = [
'sysops' => ['zarel'],
// password and SID hashing settings
'password_cost' => 12,
'sid_length' => 15,
'sid_cost' => 4,
// database
'server' => 'localhost',
'username' => '',
'password' => '',
'database' => '',
'prefix' => 'ps_',
'charset' => 'utf8',
// CORS requests
'cors' => [
'/^http:\/\/smogon\.com$/' => 'smogon.com_',
'/^http:\/\/www\.smogon\.com$/' => 'www.smogon.com_',
'/^http:\/\/logs\.psim\.us$/' => 'logs.psim.us_',
'/^http:\/\/logs\.psim\.us:8080$/' => 'logs.psim.us_',
'/^http:\/\/[a-z0-9]+\.psim\.us$/' => '',
'/^http:\/\/play\.pokemonshowdown\.com$/' => '',
],
// key signing for SSO
'privatekeys' => [
1 => '-----BEGIN PRIVATE KEY-----
[insert RSA private key]
-----END PRIVATE KEY-----
',
]
];

View File

@ -0,0 +1,11 @@
<?php
$PokemonServers = array (
'showdown' =>
array (
'name' => 'Smogon University',
'id' => 'showdown',
'server' => 'sim.psim.us',
'port' => 8000,
),
);

65
lib/ntbb-database.lib.php Normal file
View File

@ -0,0 +1,65 @@
<?php
include_once dirname(__FILE__).'/../config/config.inc.php';
class NTBBDatabase {
var $db = null;
var $server = null;
var $username = null;
var $password = null;
var $database = null;
var $prefix = null;
var $charset = null;
//var $queries = array();
function NTBBDatabase($server, $username, $password, $database, $prefix, $charset) {
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->database = $database;
$this->prefix = $prefix;
$this->charset = $charset;
}
function connect() {
if (!$this->db) {
$this->db = mysqli_connect($this->server, $this->username, $this->password, $this->database);
if ($this->charset) {
mysqli_set_charset($this->db, $this->charset);
}
}
}
function query($query) {
$this->connect();
//$this->queries[] = $query;
return mysqli_query($this->db, $query);
}
function fetch_assoc($resource) {
return mysqli_fetch_assoc($resource);
}
function fetch($resource) {
return mysqli_fetch_assoc($resource);
}
function escape($data) {
$this->connect();
return mysqli_real_escape_string($this->db, $data);
}
function error() {
if ($this->db) {
return mysqli_error($this->db);
}
}
function insert_id() {
if ($this->db) {
return mysqli_insert_id($this->db);
}
}
}
$psdb = new NTBBDatabase($psconfig['server'],
$psconfig['username'],
$psconfig['password'],
$psconfig['database'],
$psconfig['prefix'],
$psconfig['charset']);

2
lib/ntbb-ladder.lib.php Executable file → Normal file
View File

@ -4,7 +4,7 @@ error_reporting(E_ALL);
// An implementation of the Glicko2 rating system.
@include_once dirname(__FILE__).'/../../pokemonshowdown.com/lib/ntbb-database.lib.php';
@include_once dirname(__FILE__).'/ntbb-database.lib.php';
// connect to the ladder database (if we aren't already connected)
if (empty($ladderdb)) {

640
lib/ntbb-session.lib.php Normal file
View File

@ -0,0 +1,640 @@
<?php
require_once dirname(__FILE__) . '/ntbb-database.lib.php';
// require_once dirname(__FILE__) . '/password_compat/lib/password.php';
$curuser = false;
class NTBBSession {
var $cookiedomain = 'pokemonshowdown.com';
var $trustedproxies = array(
'103.21.244.0/22',
'103.22.200.0/22',
'103.31.4.0/22',
'104.16.0.0/12',
'108.162.192.0/18',
'131.0.72.0/22',
'141.101.64.0/18',
'162.158.0.0/15',
'172.64.0.0/13',
'173.245.48.0/20',
'188.114.96.0/20',
'190.93.240.0/20',
'197.234.240.0/22',
'198.41.128.0/17',
'199.27.128.0/21',
);
var $sid = '';
var $session = 0;
function NTBBSession() {
global $psdb, $curuser;
$ctime = time();
$curuser = $this->getGuest();
// see if we're logged in
$osid = @$_COOKIE['sid'];
if (!$osid) {
// nope, not logged in
return;
}
$osidsplit = explode('x', $osid, 2);
if (count($osidsplit) !== 2) {
// malformed `sid` cookie
$this->killCookie();
return;
}
$session = intval($osidsplit[0]);
$res = $psdb->query(
"SELECT sid, timeout, `{$psdb->prefix}users`.* " .
"FROM `{$psdb->prefix}sessions`, `{$psdb->prefix}users` " .
"WHERE `session` = $session " .
"AND `{$psdb->prefix}sessions`.`userid` = `{$psdb->prefix}users`.`userid` " .
"LIMIT 1");
if (!$res) {
// query problem?
$this->killCookie();
return;
}
$sess = $psdb->fetch_assoc($res);
if (!$sess || !password_verify(base64_decode($osidsplit[1]), $sess['sid'])) {
// invalid session ID
$this->killCookie();
return;
}
if (intval($sess['timeout'])<$ctime) {
// session expired
// delete all sessions that will expire within 30 minutes
$ctime += 60 * 30;
$psdb->query("DELETE FROM `{$psdb->prefix}sessions` WHERE `timeout` < $ctime");
$this->killCookie();
return;
}
// okay, legit session ID - you're logged in now.
$curuser = $sess;
$curuser['loggedin'] = true;
// unset these values to avoid them being leaked accidentally
$curuser['outdatedpassword'] = !!$curuser['password'];
unset($curuser['password']);
unset($curuser['nonce']);
unset($curuser['passwordhash']);
$this->sid = $osid;
$this->session = $session;
}
// taken from http://stackoverflow.com/questions/594112/matching-an-ip-to-a-cidr-mask-in-php5
function cidr_match($ip, $range) {
list($subnet, $bits) = explode('/', $range);
$ip = ip2long($ip);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
$subnet &= $mask; # nb: in case the supplied subnet wasn't correctly aligned
return ($ip & $mask) == $subnet;
}
function getIp() {
$ip = $_SERVER['REMOTE_ADDR'];
foreach ($this->trustedproxies as &$proxyip) {
if ($this->cidr_match($ip, $proxyip)) {
$parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$ip = array_pop($parts);
break;
}
}
return $ip;
}
function userid($username) {
if (!$username) $username = '';
$username = strtr($username, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz");
return preg_replace('/[^A-Za-z0-9]+/','',$username);
}
function getGuest($username='') {
$userid = $this->userid($username);
if (!$userid)
{
$username = 'Guest';
$userid = 'guest';
}
return array(
'username' => $username,
'userid' => $userid,
'group' => 0,
'loggedin' => false
);
}
function qsid() { return $this->sid ? '?sid='.$this->sid : ''; }
function asid() { return $this->sid ? '&sid='.$this->sid : ''; }
function hasid() { return $this->sid ? '&amp;sid='.$this->sid : ''; }
function fsid() { return $this->sid ? '<input type="hidden" name="sid" id="sid" value="'.$this->sid.'" />' : ''; }
/**
* New SID and password hashing functions.
*/
function mksid() {
global $psconfig;
if (!function_exists('mcrypt_create_iv')) {
error_log('mcrypt_create_iv is not defined!');
die;
}
return mcrypt_create_iv($psconfig['sid_length'], MCRYPT_DEV_URANDOM);
}
function sidHash($sid) {
global $psconfig;
return password_hash($sid, PASSWORD_DEFAULT, array('cost' => $psconfig['sid_cost']));
}
function passwordNeedsRehash($hash) {
global $psconfig;
return password_needs_rehash($hash, PASSWORD_DEFAULT,
array('cost' => $psconfig['password_cost'])
);
}
function passwordHash($pass) {
global $psconfig;
return password_hash($pass, PASSWORD_DEFAULT,
array('cost' => $psconfig['password_cost'])
);
}
public function passwordVerify($name, $pass) {
global $psdb;
$userid = $this->userid($name);
$res = $psdb->query(
"SELECT `password`, `nonce`, `passwordhash` " .
"FROM `{$psdb->prefix}users` " .
"WHERE `userid` = '".$psdb->escape($userid)."' " .
"LIMIT 1"
);
if (!$res) return false;
$user = $psdb->fetch_assoc($res);
return $this->passwordVerifyInner($userid, $pass, $user);
}
private function passwordVerifyInner($userid, $pass, $user) {
global $psdb;
// throttle
$ip = $this->getIp();
$res = $psdb->query(
"SELECT `count`, `time` " .
"FROM `{$psdb->prefix}loginthrottle` " .
"WHERE `ip` = '".$ip."' " .
"LIMIT 1"
);
$loginthrottle = null;
if ($res) $loginthrottle = $psdb->fetch_assoc($res);
if ($loginthrottle) {
if ($loginthrottle['count'] > 500) {
$loginthrottle['count']++;
$psdb->query("UPDATE `{$psdb->prefix}loginthrottle` SET count = {$loginthrottle['count']}, lastuserid = '".$userid."', `time` = '".time()."' WHERE ip = '".$ip."'");
return false;
} else if ($loginthrottle['time'] + 24 * 60 * 60 < time()) {
$loginthrottle = [
'count' => 0,
'time' => time(),
];
}
}
$rehash = false;
if ($user['passwordhash']) {
// new password hashes
if (!password_verify($pass, $user['passwordhash'])) {
// wrong password
if ($loginthrottle) {
$loginthrottle['count']++;
$psdb->query("UPDATE `{$psdb->prefix}loginthrottle` SET count = {$loginthrottle['count']}, lastuserid = '".$userid."', `time` = '".time()."' WHERE ip = '".$ip."'");
} else {
$psdb->query("INSERT INTO `{$psdb->prefix}loginthrottle` (ip, count, lastuserid, `time`) VALUES ('".$ip."', 1, '".$userid."', '".time()."')");
}
return false;
}
$rehash = $this->passwordNeedsRehash($user['passwordhash']);
} else if ($user['password'] && $user['nonce']) {
// original ntbb-session password hashes
return false;
} else {
// error
return false;
}
if ($rehash) {
// create a new password hash for the user
$hash = $this->passwordHash($pass);
if ($hash) {
$psdb->query("UPDATE `{$psdb->prefix}users` SET `passwordhash`='" . $psdb->escape($hash) . "', `password`=NULL, `nonce`=NULL WHERE `userid`='" . $psdb->escape($userid) . "'");
}
}
return true;
}
function login($name, $pass, $timeout = false, $debug = false) {
global $psdb, $curuser;
$ctime = time();
$this->logout();
$userid = $this->userid($name);
$res = $psdb->query("SELECT * FROM `{$psdb->prefix}users` WHERE `userid` = '".$psdb->escape($userid)."' LIMIT 1");
if (!$res) {
if ($debug) error_log('no such user');
return $curuser;
}
$user = $psdb->fetch_assoc($res);
if ($user['banstate'] >= 100) {
return $curuser;
}
if (!$this->passwordVerifyInner($userid, $pass, $user)) {
if ($debug) error_log('wrong password');
return $curuser;
}
if (!$timeout) {
// expire in a week and 30 minutes
$timeout = (14*24*60+30)*60;
}
$timeout += $ctime;
$nsid = $this->mksid();
$nsidhash = $this->sidHash($nsid);
$res = $psdb->query("INSERT INTO `{$psdb->prefix}sessions` (`userid`,`sid`,`time`,`timeout`,`ip`) VALUES ('".$psdb->escape($user['userid'])."', '" . $psdb->escape($nsidhash) . "',$ctime,$timeout,'".$psdb->escape($this->getIp())."')");
if (!$res) die;
$this->session = $psdb->insert_id();
$this->sid = $this->session . 'x' . base64_encode($nsid);
$curuser = $user;
$curuser['loggedin'] = true;
// unset these values to avoid them being leaked accidentally
$curuser['outdatedpassword'] = !!$curuser['password'];
unset($curuser['password']);
unset($curuser['nonce']);
unset($curuser['passwordhash']);
setcookie('sid', $this->sid, $timeout, '/', $this->cookiedomain, false, true);
return $curuser;
}
function killCookie() {
setcookie('sid', '', time()-60*60*24*2,
'/', $this->cookiedomain, false, true);
}
function csrfData() {
echo '<input type="hidden" name="csrf" value="'.$this->sid.'" />';
return '';
}
function csrfCheck() {
if (empty($_POST['csrf'])) return false;
$csrf = $_POST['csrf'];
if ($csrf === @$_COOKIE['sid']) return true;
return false;
}
function logout() {
global $psdb,$curuser;
if (!$this->session) return $curuser;
$curuser = $this->getGuest();
$psdb->query("DELETE FROM `{$psdb->prefix}sessions` WHERE `session` = '{$this->session}' LIMIT 1");
$this->sid = '';
$this->session = 0;
$this->killCookie();
return $curuser;
}
function createPasswordResetToken($name, $timeout=false) {
global $psdb, $curuser;
$ctime = time();
$userid = $this->userid($name);
$res = $psdb->query("SELECT * FROM `{$psdb->prefix}users` WHERE `userid` = '".$psdb->escape($userid)."' LIMIT 1");
if (!$res) // user doesn't exist
return false;
$user = $psdb->fetch_assoc($res);
if (!$timeout) {
$timeout = 7*24*60*60;
}
$timeout += $ctime;
{
$modlogentry = "Password reset token generated";
$psdb->query("INSERT INTO `{$psdb->prefix}usermodlog` (`userid`,`actorid`,`date`,`ip`,`entry`) VALUES ('".$psdb->escape($user['userid'])."','".$psdb->escape($curuser['userid'])."','" . $psdb->escape(time()) . "','".$psdb->escape($this->getIp())."','".$psdb->escape($modlogentry)."')");
// magical character string...
$nsid = bin2hex($this->mksid());
$res = $psdb->query("INSERT INTO `{$psdb->prefix}sessions` (`userid`,`sid`,`time`,`timeout`,`ip`) VALUES ('".$psdb->escape($user['userid'])."', '$nsid',$ctime,$timeout,'".$psdb->escape($this->getIp())."')");
if (!$res) die($psdb->error());
}
return $nsid;
}
function validatePasswordResetToken($token) {
global $psdb, $psconfig;
if (strlen($token) !== ($psconfig['sid_length'] * 2)) return false;
$res = $psdb->query("SELECT * FROM `{$psdb->prefix}sessions` WHERE `sid` = '".$psdb->escape($token)."' LIMIT 1");
$session = $psdb->fetch_assoc($res);
if (!$session) return false;
if (intval($session['timeout'])<time()) {
// session expired
return false;
}
return $session['userid'];
}
function getUser($userid=false) {
global $psdb, $curuser;
if (is_array($userid)) $userid = $userid['userid'];
$userid = $this->userid($userid);
if (!$userid ||
(($userid === $curuser['userid']) && !empty($user['loggedin']))) {
return $curuser;
}
$res = $psdb->query("SELECT * FROM `{$psdb->prefix}users` WHERE `userid` = '".$psdb->escape($userid)."' LIMIT 1");
if (!$res) // query failed for weird reason
return false;
$user = $psdb->fetch_assoc($res);
if (!$user)
{
return false;
}
// unset these values to avoid them being leaked accidentally
$user['outdatedpassword'] = !!$user['password'];
unset($user['password']);
unset($user['nonce']);
unset($user['passwordhash']);
return $user;
}
function getGroupName($user=false) {
global $ntbb_cache;
$user = $this->getUser($user);
return @$ntbb_cache['groups'][$user['group']]['name'];
}
function getGroupSymbol($user=false) {
global $ntbb_cache;
$user = $this->getUser($user);
return @$ntbb_cache['groups'][$user['group']]['symbol'];
}
function getUserData($username) {
$userdata = $this->getUser($username);
if ($userdata) return $userdata;
$userdata = $this->getGuest($username);
return $userdata;
}
function getAssertion($userid, $serverhostname, $user = null, $challengekeyid = -1, $challenge = '', $challengeprefix = '') {
global $psdb, $curuser, $psconfig;
if (substr($userid, 0, 5) === 'guest') {
return ';;Your username cannot start with \'guest\'.';
} else if (strlen($userid) > 18) {
return ';;Your username must be less than 19 characters long.';
} else if (!$this->isUseridAllowed($userid)) {
return ';;Your username contains disallowed text.';
}
$data = '';
if (!$user) {
$user = $curuser;
}
$ip = $this->getIp();
$forceUsertype = false;
if (($user['userid'] === $userid) && !empty($user['loggedin'])) {
// already logged in
$usertype = '2';
if (in_array($userid, $psconfig->sysops, true)) {
$usertype = '3';
} else {
// check autoconfirmed
if ($forceUsertype) {
$usertype = $forceUsertype;
} else if (intval(@$user['banstate']) <= -10) {
$usertype = '4';
} else if (@$user['banstate'] >= 100) {
return ';;Your account is disabled.';
} else if (@$user['banstate'] >= 40) {
if ($serverhostname === 'sim.psim.us') {
$usertype = '40';
} else {
$usertype = '2';
}
} else if (@$user['banstate'] >= 30) {
$usertype = '6';
} else if (@$user['banstate'] >= 20) {
$usertype = '5';
} else if (@$user['banstate'] == 0) {
if (@$user['registertime'] && time() - $user['registertime'] > 7*24*60*60) {
$res = $psdb->query("SELECT formatid FROM ntbb_ladder WHERE userid = '".$psdb->escape($userid)."' LIMIT 1");
if ($psdb->fetch_assoc($res)) {
$usertype = '4';
$psdb->query("UPDATE ntbb_users SET banstate = -10 WHERE userid = '".$psdb->escape($userid)."' LIMIT 1");
}
}
}
}
if (!@$user['logintime'] || time() - $user['logintime'] > 24*60*60) {
$psdb->query("UPDATE ntbb_users SET logintime = " . time() . ", loginip = '".$psdb->escape($ip)."' WHERE userid = '".$psdb->escape($userid)."' LIMIT 1");
}
$data = $user['userid'].',' . $usertype . ','.time().','.$serverhostname;
} else {
if ((strlen($userid) < 1) || ctype_digit($userid)) {
return ';;Your username must contain at least one letter.';
}
$res = $psdb->query("SELECT * FROM `{$psdb->prefix}users` WHERE `userid` = '".$psdb->escape($userid)."' LIMIT 1");
if (!$res) {
// query failed for weird reason
return ';;The login server is under heavy load, please try logging in again later';
} else if ($row = $psdb->fetch_assoc($res)) {
// Username exists, but the user isn't logged in: require authentication.
if ($row['banstate'] >= 100) {
return ';;Your account is disabled.';
}
if ($row['password'] && $row['nonce']) {
return ';;Your account is disabled.';
}
return ';';
} else {
// Unregistered username.
$usertype = '1';
if ($forceUsertype) $usertype = $forceUsertype;
$data = $userid.','.$usertype.','.time().','.$serverhostname;
}
}
$splitChallenge = explode(';', $challenge);
if (count($splitChallenge) == 1) {
$splitChallenge = explode('|', $challenge);
}
if (count($splitChallenge) == 1) {
$splitChallenge = explode('%7C', $challenge);
}
$challengetoken = @$_REQUEST['challengetoken'];
if (count($splitChallenge) > 1) {
$challengekeyid = intval($splitChallenge[0]);
$challenge = $splitChallenge[1];
if (@$splitChallenge[2] && !$challengetoken) $challengetoken = $splitChallenge[2];
}
if ($challengekeyid < 1) {
return ';;This server is requesting an invalid login key. This probably means that either you are not connected to a server, or the server is set up incorrectly.';
} else if ($challengekeyid < 2) {
// Compromised keys - no longer supported.
return ';;This server is using login key ' . $challengekeyid . ', which is no longer supported. Please tell the server operator to update their config.js file.';
} else if (empty($psconfig['privatekeys'][$challengekeyid])) {
// Bogus key id.
return ';;Unknown key ID';
} else if (!preg_match('/^[0-9a-f]*$/', $challenge)) {
// Bogus challenge.
return ';;Corrupt challenge';
} else {
// Include the challenge in the assertion.
$data = $challengeprefix . $challenge . ',' . $data;
}
if (strpos($challengeprefix . $challenge, ',') !== false) {
trigger_error("challenge contains comma? ".$challengeprefix." // ".$challenge, E_USER_ERROR);
}
if (function_exists('psconfig_validate_assertion')) {
psconfig_validate_assertion($data, $serverhostname);
}
$sig = '';
openssl_sign($data, $sig, openssl_get_privatekey($psconfig['privatekeys'][$challengekeyid]));
return $data.';'.bin2hex($sig);
}
function modifyUser($user, $changes) {
global $psdb, $curuser;
$userid = $user;
if (is_array($user)) $userid = $user['userid'];
$res = $psdb->query("SELECT * FROM `{$psdb->prefix}users` WHERE `userid` = '".$psdb->escape($userid)."' LIMIT 1");
if (!$res) // query failed for weird reason
return false;
$user = $psdb->fetch_assoc($res);
if (!$user['userid']) return false;
if (@$changes['password']) {
$modlogentry = "Password changed from: {$user['passwordhash']}";
$psdb->query("INSERT INTO `{$psdb->prefix}usermodlog` (`userid`,`actorid`,`date`,`ip`,`entry`) VALUES ('".$psdb->escape($user['userid'])."','".$psdb->escape($curuser['userid'])."','" . $psdb->escape(time()) . "','".$psdb->escape($this->getIp())."','".$psdb->escape($modlogentry)."')");
$passwordhash = $this->passwordHash($changes['password']);
$psdb->query("UPDATE `{$psdb->prefix}users` SET `passwordhash`='" . $psdb->escape($passwordhash) . "', `password`=NULL, `nonce`=NULL WHERE `userid` = '".$psdb->escape($user['userid'])."'");
if ($psdb->error()) {
return false;
}
$psdb->query("DELETE FROM `{$psdb->prefix}sessions` WHERE `userid` = '".$psdb->escape($user['userid'])."'");
if ($curuser['userid'] === $userid) {
$this->login($userid, $changes['password']);
}
}
if (!empty($changes['group'])) {
$group = intval($changes['group']);
$psdb->query("UPDATE `{$psdb->prefix}users` SET `group` = $group WHERE `userid` = '".$psdb->escape($user['userid'])."'");
if ($psdb->error()) {
return false;
}
}
if (!empty($changes['username'])) {
$newUsername = $changes['username'];
if (strlen($newUsername) > 18) return false;
$newUserid = $this->userid($newUsername);
if ($userid !== $newUserid) return false;
$psdb->query("UPDATE `{$psdb->prefix}users` SET `username` = '".$psdb->escape($newUsername)."' WHERE `userid` = '".$psdb->escape($userid)."'");
if ($psdb->error()) {
return false;
}
}
if (!empty($changes['userdata'])) {
$psdb->query("UPDATE `{$psdb->prefix}users` SET `userdata` = '".$psdb->escape($changes['userdata'])."' WHERE `userid` = '".$psdb->escape($user['userid'])."'");
if ($psdb->error()) {
return false;
}
$user['userdata'] = $changes['userdata'];
}
return true;
}
function getRecentRegistrationCount($ip = '', $timeperiod = 7200 /* 2 hours */) {
global $psdb;
if ($ip === '') {
$ip = $this->getIp();
}
$timestamp = time() - $timeperiod;
$res = $psdb->query("SELECT COUNT(*) AS `registrationcount` FROM `{$psdb->prefix}users` WHERE `ip` = '" . $psdb->escape($ip) . "' AND `registertime` > '" . $timestamp . "'");
if (!$res) {
return false;
}
$user = $psdb->fetch_assoc($res);
if ($user === NULL) { // Should be impossible.
return 0;
}
return $user['registrationcount'];
}
function addUser($user, $password)
{
global $psdb, $curuser;
$ctime = time();
$user['userid'] = $this->userid($user['username']);
$user['passwordhash'] = $this->passwordHash($password);
if (!$this->isUseridAllowed($user['userid'])) {
return false;
}
$psdb->query("INSERT INTO `{$psdb->prefix}users` (`userid`,`username`,`passwordhash`,`email`,`registertime`,`ip`) VALUES ('".$psdb->escape($user['userid'])."','".$psdb->escape($user['username'])."','" . $psdb->escape($user['passwordhash']) . "','".$psdb->escape(@$user['email'])."',$ctime,'".$psdb->escape($this->getIp())."')");
if ($psdb->error())
{
return false;
}
$user['usernum'] = $psdb->insert_id();
$user['loggedin'] = true;
$this->login($user['username'], $password);
return $user;
}
function wordfilter($text) {
$text = str_ireplace('lolicon', '*', $text);
$text = str_ireplace('roricon', '*', $text);
return $text;
}
function isUseridAllowed($userid) {
if (strpos($userid, 'nigger') !== false) return false;
if (strpos($userid, 'nigga') !== false) return false;
if (strpos($userid, 'faggot') !== false) return false;
if (strpos($userid, 'lolicon') !== false) return false;
if (strpos($userid, 'roricon') !== false) return false;
if (strpos($userid, 'lazyafrican') !== false) return false;
return true;
}
}
$users = new NTBBSession();

51
lib/ntbb-users.sql Normal file
View File

@ -0,0 +1,51 @@
-- Database: showdown
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `ntbb_users`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `ntbb_users` (
`userid` varbinary(255) NOT NULL,
`usernum` int(11) NOT NULL AUTO_INCREMENT,
`username` varbinary(255) NOT NULL,
`password` varbinary(255) DEFAULT NULL,
`nonce` varbinary(255) DEFAULT NULL,
`passwordhash` varbinary(255) DEFAULT NULL,
`email` varbinary(255) DEFAULT NULL,
`registertime` bigint(20) NOT NULL,
`group` int(11) NOT NULL DEFAULT '1',
`banstate` int(11) NOT NULL DEFAULT '0',
`ip` varchar(255) NOT NULL DEFAULT '',
`avatar` int(11) NOT NULL DEFAULT '0',
`account` varbinary(255) DEFAULT NULL,
`logintime` bigint(20) NOT NULL DEFAULT '0',
`loginip` varbinary(255) DEFAULT NULL,
PRIMARY KEY (`userid`),
UNIQUE KEY `usernum` (`usernum`),
KEY `ip` (`ip`),
KEY `loginip` (`loginip`),
KEY `account` (`account`)
) ENGINE=InnoDB AUTO_INCREMENT=7379773 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

41
lib/ntbb_sessions.sql Normal file
View File

@ -0,0 +1,41 @@
-- Database: showdown
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `ntbb_sessions`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `ntbb_sessions` (
`session` bigint(20) NOT NULL AUTO_INCREMENT,
`sid` varchar(255) NOT NULL,
`userid` varchar(255) NOT NULL,
`time` int(11) NOT NULL,
`timeout` int(11) NOT NULL,
`ip` varchar(255) NOT NULL,
PRIMARY KEY (`session`),
KEY `userid` (`userid`),
KEY `sid` (`sid`),
KEY `timeout` (`timeout`)
) ENGINE=InnoDB AUTO_INCREMENT=1700523 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;