DIR : /home/kozerus/public_html/go/dgs/include/register_functions.php
/home/kozerus/public_html/go/dgs/include
<?php
/*
Dragon Go Server
Copyright (C) 2001- Erik Ouchterlony, Rod Ival, Jens-Uwe Gaspar
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
$TranslateGroups[] = "Start";
require_once 'include/std_functions.php';
require_once 'include/classlib_user.php';
require_once 'include/classlib_userconfig.php';
require_once 'include/classlib_userquota.php';
require_once 'include/db/verification.php';
require_once 'forum/forum_functions.php';
require_once 'include/error_codes.php';
define('USE_REGEXP_REGISTRATION', 1); // loose account name reject
/*!
* \class UserRegistration
*
* \brief Class to manage error-code and some attributes of additional logging with error-texts
*/
class UserRegistration
{
private $die_on_error;
private $errors = array();
private $key_suffix; // for register-bot prevention
public $uhandle;
public $policy;
public $name;
public $password;
public $password2;
public $email;
public $comment;
public function __construct( $die_on_error=true )
{
$this->die_on_error = $die_on_error;
$this->key_suffix = $this->build_key_suffix();
}//__construct
/*! \brief Parses arguments from URL with dynamic form-keys. */
public function parse_args()
{
// check for correct key-suffix (day-switch for example)
// NOTE: allow 2 hours for registering, see also build_key_suffix()-func
$cnt = 2;
while ( $cnt-- && !isset($_REQUEST[$this->build_key('userid')]) )
$this->key_suffix = $this->build_key_suffix( -1 );
if ( $cnt <= 0 )
{
$this->errors[] = ErrorCode::get_error_text('miss_args');
return;
}
// for both normal and blocked registration
$this->uhandle = get_request_arg($this->build_key('userid'));
$this->policy = get_request_arg($this->build_key('policy'));
$this->email = trim(get_request_arg($this->build_key('email')));
// only for normal-registration
$this->name = trim(get_request_arg($this->build_key('name')));
$this->password = get_request_arg($this->build_key('passwd'));
$this->password2 = get_request_arg($this->build_key('passwd2'));
// only for blocked-registration
$this->comment = trim(get_request_arg($this->build_key('comment')));
}
private function build_key_suffix( $add=0 )
{
// NOTE: use different form-keys to make it more difficult for register-bots to register
// - use dynamic suffix dependent on current hour
return substr( md5( floor($GLOBALS['NOW'] / SECS_PER_HOUR) + $add ), 4, 5 );
}
public function build_key( $key )
{
return $key . '_' . $this->key_suffix;
}
// returns 0=no-error, array with error-texts otherwise or error thrown (depends on die-mode)
public function check_registration_normal()
{
$this->errors = array();
$this->parse_args();
$this->check_userid();
if ( !$this->die_on_error )
$this->check_existing_user();
$this->check_name();
$this->check_password();
$this->check_policy();
if ( $this->die_on_error )
$this->check_existing_user();
$this->check_email();
return (count($this->errors)) ? $this->errors : 0;
}//check_registration_normal
// returns 0=no-error, array with error-texts otherwise or error thrown (depends on die-mode)
public function check_registration_blocked()
{
$this->errors = array();
$this->parse_args();
$this->check_userid();
if ( !$this->die_on_error )
$this->check_existing_user();
$this->check_email();
$this->check_policy();
if ( $this->die_on_error )
$this->check_existing_user();
return (count($this->errors)) ? $this->errors : 0;
}//check_registration_blocked
private function check_userid()
{
if ( strlen( $this->uhandle ) < 3 )
$this->_error('userid_too_short', "UserReg.check_userid({$this->uhandle})");
if ( strlen( $this->uhandle ) > 16 )
$this->_error('userid_too_long', "UserReg.check_userid({$this->uhandle})");
if ( illegal_chars( $this->uhandle ) )
$this->_error('userid_illegal_chars', "UserReg.check_userid({$this->uhandle})");
$this->check_userid_spam();
}
/*! \brief Checks and prevent new user-id matching patterns for spam-accounts. */
private function check_userid_spam()
{
// SPAM-accounts: http://www.dragongoserver.net/forum/read.php?forum=2&thread=36701
// - prevent user-id like 'defgh384...' with consecutive letters
if ( preg_match("/^([a-z]{4,})(\\d{3,})$/i", $this->uhandle, $matches) )
{
$wordpart = strtolower($matches[1]);
$base = ord($wordpart[0]);
$len = strlen($wordpart) - 1;
$sum = 0;
for ( $n=0; $n <= $len; $n++ )
$sum += ord($wordpart[$n]) - $base;
if ( $sum <= $len * ($len+1) / 2 )
$this->_error('userid_spam_account', "UserReg.check_userid_spam({$this->uhandle})");
}
}//check_userid_spam
private function check_name()
{
if ( strlen($this->name) < 1 )
$this->_error('name_not_given', "UserReg.check_name({$this->name})");
}
private function check_password()
{
if ( strlen($this->password) < 6 )
$this->_error('password_too_short', 'UserReg.check_password');
if ( illegal_chars( $this->password, true ) )
$this->_error('password_illegal_chars', 'UserReg.check_password');
if ( $this->password != $this->password2 )
$this->_error('password_mismatch', 'UserReg.check_password');
}//check_password
private function check_policy()
{
if ( !$this->policy )
$this->_error('registration_policy_not_checked', 'UserReg.check_policy');
}
// returns 0=no-error, array with error-texts otherwise or error thrown (depends on die-mode)
private function check_email()
{
if ( (string)$this->email == '' )
$this->_error('register_miss_email', "UserReg.check.miss_email");
else
{
$errorcode = verify_invalid_email( "UserReg.check_email({$this->uhandle})", $this->email, $this->die_on_error );
if ( $errorcode )
$this->_error($errorcode, "UserReg.check_email2({$this->uhandle})");
}
}//check_email
// internal (throw error or add to error-list)
private function _error( $error_code, $dbg_msg=null )
{
if ( $this->die_on_error )
error($error_code, $dbg_msg);
else
$this->errors[] = ErrorCode::get_error_text($error_code);
}
private function check_existing_user()
{
if ( (string)$this->uhandle == '' )
return;
if ( !USE_REGEXP_REGISTRATION )
{
//if foO exist, reject foo but accept fo0 (with a zero instead of uppercase o)
$result = db_query( "UserReg.check_existing_user.find_player({$this->uhandle})",
"SELECT Handle FROM Players WHERE Handle='".mysql_addslashes($this->uhandle)."'" );
}
else
{
//reject the O0, l1I and S5 confusing matchings (used by account usurpers)
//for instance, with the Arial font, a I and a l can't be distinguished
$regx = preg_replace(
array( '/[0o]/i', '/[1li]/i', '/[5s]/i' ), // match
array( '[0o]', '[1li]', '[5s]' ), // replacements (regex for REGEXP-SQL-match)
preg_quote($this->uhandle) ); //quotemeta()
$regx = '^' . mysql_addslashes($regx) . '$';
$result = db_query( "UserReg.check_existing_user.find_player_regexp({$this->uhandle},[$regx]})",
"SELECT Handle FROM Players WHERE Handle REGEXP '$regx'" );
}
if ( @mysql_num_rows($result) > 0 )
$this->_error('userid_in_use', "UserReg.check_existing_user({$this->uhandle})");
}//check_existing_user
// do the registration to the database
public function register_user( $set_cookie=true )
{
global $NOW, $base_path;
$code = make_session_code();
$ip = (string)@$_SERVER['REMOTE_ADDR'];
$browser = substr(@$_SERVER['HTTP_USER_AGENT'], 0, 150);
$user_flags = USERFLAG_JAVASCRIPT_ENABLED;
if ( SEND_ACTIVATION_MAIL )
$user_flags |= USERFLAG_ACTIVATE_REGISTRATION|USERFLAG_VERIFY_EMAIL;
ta_begin();
{//HOT-section for registering new player
$upd = new UpdateQuery('Players');
$upd->upd_txt('Handle', $this->uhandle );
$upd->upd_txt('Name', $this->name );
$upd->upd_raw('Password', sprintf( "%s('%s')", PASSWORD_ENCRYPT, mysql_addslashes($this->password) ));
if ( $this->email )
$upd->upd_txt('Email', $this->email );
$upd->upd_time('Registerdate', $NOW);
$upd->upd_time('Lastaccess', $NOW); // with time of registration
$upd->upd_txt('Sessioncode', $code);
$upd->upd_time('Sessionexpire', $NOW + SESSION_DURATION );
if ( $ip )
$upd->upd_txt('IP', $ip );
if ( $browser )
$upd->upd_txt('Browser', $browser );
$upd->upd_num('VaultCnt', VAULT_CNT ); // initial quota
$upd->upd_time('VaultTime', $NOW + VAULT_DELAY );
$upd->upd_num('UserFlags', $user_flags );
$result = db_query( "UserReg.register_user.insert_player({$this->uhandle})",
"INSERT INTO Players SET " . $upd->get_query() );
$new_id = mysql_insert_id();
if ( mysql_affected_rows() != 1 )
error('mysql_insert_player', "UserReg.register_user.insert_player2({$this->uhandle})");
ConfigPages::insert_default( $new_id );
ConfigBoard::insert_default( $new_id );
UserQuota::insert_default( $new_id );
if ( SEND_ACTIVATION_MAIL )
{
// send activation-mail with verification-code for email
$vfy_code = Verification::build_code( $new_id, $this->email );
$vfy = new Verification( 0, $new_id, 0, $NOW, VFY_TYPE_USER_REGISTRATION, $this->email, $vfy_code );
if ( $vfy->insert() )
{
list( $subject, $text, $mail_from ) = self::build_email_verification(
$new_id, $this->uhandle, $vfy->ID, $vfy->VType, $vfy_code, $this->email );
send_email( "UserReg.register_user.send_activation($new_id,{$vfy->ID})",
$this->email, EMAILFMT_SKIP_WORDWRAP, $text, $subject, $mail_from );
}
}
}
ta_end();
if ( $set_cookie )
set_login_cookie( $this->uhandle, $code );
}//register_user
// send request to Support-forum (moderated)
public function register_blocked_user()
{
$ip = (string)@$_SERVER['REMOTE_ADDR'];
$Subject = "Admin-Request to register account to bypass IP-block";
$Text = T_("This is an automated support-request to register a new account on behalf of an IP-blocked user with the following credentials:")
. "\n\n"
. "Userid: {$this->uhandle}\n"
. "Email: {$this->email}\n"
. "Blocked-IP: $ip\n\n"
. "User-Comment:\n" . $this->comment;
send_email( "UserReg.register_blocked_user({$this->uhandle},$ip)", EMAIL_SUPPORT, 0, $Text, $Subject, 'From: '.EMAIL_SUPPORT );
}//register_blocked_user
/*!
* \brief Processes email-verification (optionally coupled with account activation after registration).
* \param $user User-object of user to verify code for
* \param $vid Verification.ID to verify code against
* \param $code input-code to verify against
* \return error-string on failure to process verification successfully; or integer-bitmask-value on success
* with set flags (USERFLAG_VERIFY_EMAIL, USERFLAG_ACTIVATE_REGISTRATION) depending on executed action
*
* \note User need to be logged-in!
*/
public static function process_verification( User $user, $vid, $code )
{
global $player_row, $NOW;
// paranoid checking to avoid abuse ....
if ( @$player_row['ID'] == 0 )
error('login_if_not_logged_in', "UserReg.process_verification.check_login");
$uid = $user->ID;
if ( !is_numeric($uid) )
error('invalid_args:nolog', "UserReg.process_verification.check.uid($uid,$vid)");
if ( !is_numeric($vid) || $vid <= 0 )
return sprintf( T_('Missing valid id to process verification for user [%s].'), $user->Handle );
if ( $uid != $player_row['ID'] )
return sprintf( T_('Logged-in as wrong user [%s] to process verification with id [%s] for user [%s].'),
@$player_row['Handle'], $vid, $user->Handle );
$user_flags = (int)$user->urow['UserFlags'];
if ( $user_flags == 0 )
return sprintf( T_('There is nothing to verify for user [%s].'), $user->Handle );
if ( strlen($code) == 0 )
return sprintf( T_('Missing code to process verification with id [%s].'), $vid );
$verification = Verification::load_verification( $vid );
if ( is_null($verification) )
return sprintf( T_('No verification entry found for verification-id [%s].'), $vid );
if ( $verification->uid != $uid )
return sprintf( T_('Found wrong user [%s] to process verification with id [%s].'), $user->Handle, $vid );
if ( $verification->Verified != 0 )
return sprintf( T_('Verification with id [%s] has been processed already and is no longer valid.'), $vid );
$vfy_type = $verification->VType;
// expire verification by invalidating for too old codes
if ( $verification->Created < $NOW - VFY_MAX_DAYS_CODE_VALID*SECS_PER_HOUR )
{
if ( $vfy_type == VFY_TYPE_USER_REGISTRATION )
$helptext = T_('Please contact support to help with your registration.');
elseif ( $vfy_type == VFY_TYPE_EMAIL_CHANGE )
$helptext = T_('Please repeat changing your email getting a new verification-code, or else contact support.');
$verification->Verified = $NOW;
$verification->update();
return sprintf( T_('Verification-code expired after %s days.'), VFY_MAX_DAYS_CODE_VALID ) . "<br>\n$helptext";
}
// safety-checks on verification-db-data (shouldn't happen)
$errorcode = verify_invalid_email( "UserReg:process_verification.verify_email($uid,$vid)",
$verification->Email, /*die-on-err*/false );
if ( $errorcode )
error($errorcode, "UserReg:process_verification.check_email($uid,$vid)");
if ( strlen(trim($verification->Code)) < VFY_MIN_CODELEN )
error('internal_error', "UserReg.process_verification.bad_code.verify_code($uid,$vid)");
// invalidate verification if tried too often (to prevent brute-force attack)
if ( $verification->increase_verification_counter(25) )
error('verification_invalidated', "UserReg.process_verification.check.count($uid,$vid)");
if ( strcmp($code, $verification->Code) != 0 )
return T_('Verification code is invalid!');
// determine updates for verification-action
$set_userflags = $clear_userflags = 0;
switch ( $vfy_type )
{
case VFY_TYPE_USER_REGISTRATION:
// activate account by clearing user-flags, if email verified
if ( $user_flags & USERFLAG_ACTIVATE_REGISTRATION )
$clear_userflags |= (USERFLAG_ACTIVATE_REGISTRATION|USERFLAG_VERIFY_EMAIL);
$set_userflags |= USERFLAG_EMAIL_VERIFIED;
break;
case VFY_TYPE_EMAIL_CHANGE:
// replace email and clear flag, if email verified
if ( $user_flags & USERFLAG_VERIFY_EMAIL )
$clear_userflags |= USERFLAG_VERIFY_EMAIL;
$set_userflags |= USERFLAG_EMAIL_VERIFIED;
break;
default:
error('invalid_args', "UserReg.process_verification.check.bad_vfy_type($uid,$vid,$vfy_type)");
}
// verify-email and/or activate registration
ta_begin();
{//HOT-section for handling verification
$verification->Verified = $NOW;
$verification->update();
if ( $set_userflags || $clear_userflags )
{
// NOTE: this update could go wrong leaving verification invalidated -> must be handled by admin
$upd = new UpdateQuery('Players');
if ( $set_userflags & USERFLAG_EMAIL_VERIFIED )
$upd->upd_txt('Email', $verification->Email );
$upd->upd_raw('UserFlags', "(UserFlags | $set_userflags) & ~$clear_userflags" );
db_query("UserReg:process_verification.upd_email_uflags($uid,$vid,$vfy_type,$user_flags->$clear_userflags)",
"UPDATE Players SET " . $upd->get_query() . " WHERE ID=$uid LIMIT 1" );
}
}
ta_end();
return $clear_userflags;
}//process_verification
/*! \brief Returns array( subject, text, mail_from|'' ) for email sent for new email-verification according to $vfy_type. */
public static function build_email_verification( $uid, $uhandle, $vfy_id, $vfy_type, $vfy_code, $vfy_email )
{
$text_account = T_('Your account\'s user-id is:') . ' ' . $uhandle . "\n\n";
$vfy_url = "\n ".HOSTBASE."verify_email.php?uid=$uid".URI_AMP_IN."vid={$vfy_id}".URI_AMP_IN."code=".urlencode($vfy_code) . "\n\n";
$text_code_use = sprintf( T_('This verification code can only be used once and expires after %s days.'), VFY_MAX_DAYS_CODE_VALID ) . "\n\n";
$text_support_email =
ErrorCode::fill_email_support(
T_('In case of problems, please contact the support by sending an email to {{mailto::EMAIL_SUPPORT}}'),
false, true ) . "\n"
. ErrorCode::get_error_text('contact:context') . "\n\n";
$mail_from = 'From: '.EMAIL_SUPPORT; // mail-header for send_mail(..)-func
switch ( $vfy_type )
{
case VFY_TYPE_USER_REGISTRATION:
$subj = T_('Welcome to the Dragon Go Server');
$text = sprintf( T_('You are now registered with an account at Dragon Go Server, %s!'), $uhandle ) . "\n\n"
. $text_account
. T_('Before you can use your account, you first need to activate it.') . "\n"
. T_('You may be redirected to login first with your chosen password.') . "\n\n"
. T_('To activate your account, please follow this link:#reg') . "\n"
. $vfy_url
. $text_code_use
. $text_support_email;
break;
case VFY_TYPE_EMAIL_CHANGE:
$subj = sprintf( '%s: %s', FRIENDLY_LONG_NAME, sprintf( T_('Verify email for [%s]'), $uhandle ));
$text = T_('To be able to use your new email, it needs to be verified!') . "\n\n"
. $text_account
. sprintf( T_('To verify your new email [%s], please follow this link:#reg'), $vfy_email) . "\n"
. $vfy_url
. $text_code_use
. $text_support_email;
break;
default:
error('invalid_args', "UserReg.build_email_changed_email.check.bad_vfy_type($vfy_type,$uid,$vfy_id)");
}
return array( $subj, $text, $mail_from );
}//build_email_verification
/*!
* \brief Removes own verification with given id and if needed update Players.UserFlags accordingly.
* \return 0 = nothing deleted; -1 = failed because verification of other user; 1 = delete successful
*/
public static function remove_verification( $dbgmsg, $vfy_id )
{
global $player_row;
if ( !is_numeric($vfy_id) || $vfy_id <= 0 )
return 0;
$verification = Verification::load_verification( (int)$vfy_id );
if ( is_null($verification) )
return 0;
$my_id = $player_row['ID'];
if ( $verification->uid != $my_id ) // can only delete own verifications
return -1;
ta_begin();
{//HOT-section for deleting verification and updating Players-table
if ( $verification->delete() )
{
// fix Players.UserFlags according to existing Verification-entries
// - load all verification for existing types
$arr = array(
VFY_TYPE_USER_REGISTRATION => 0,
VFY_TYPE_EMAIL_CHANGE => 0,
);
$result = db_query( $dbgmsg."UserReg.remove_verification.count_types($vfy_id)",
"SELECT SQL_SMALL_RESULT VType, COUNT(*) AS X_Count " .
"FROM Verification WHERE uid=$my_id AND Verified=0 GROUP BY VType" );
while ( $row = mysql_fetch_assoc($result) )
$arr[$row['VType']] = (int)$row['X_Count'];
mysql_free_result($result);
// - determine what to fix in Players.UserFlags
$my_uflags = (int)$player_row['UserFlags'];
$set_uflags = $clear_uflags = 0;
foreach ( $arr as $vtype => $count )
{
if ( $vtype == VFY_TYPE_USER_REGISTRATION )
$chk_uflag = USERFLAG_ACTIVATE_REGISTRATION;
elseif ( $vtype == VFY_TYPE_EMAIL_CHANGE )
$chk_uflag = USERFLAG_VERIFY_EMAIL;
if ( $count == 0 && ($my_uflags & $chk_uflag) )
$clear_uflags |= $chk_uflag;
elseif ( $count > 0 && !($my_uflags & $chk_uflag) )
$set_uflags |= $chk_uflag;
}
if ( $set_uflags || $clear_uflags )
db_query( $dbgmsg."UserReg.remove_verification.fix_user_flags($vfy_id,$my_uflags>+$set_uflags-$clear_uflags)",
"UPDATE Players SET UserFlags=(UserFlags | $set_uflags) & ~$clear_uflags WHERE ID=$my_id LIMIT 1" );
}
}
ta_end();
return 1;
}//remove_verification
public static function build_common_verify_texts( $with_email_link=false )
{
$text_email_use = T_('The email is used to send you new passwords or to inform about server related issues.');
$text_email_priv = sprintf( T_('The email is kept confidential, see "Privacy Policy" in the DGS <a href="%s" target="dgsTOS">Rules of Conduct</a>.'),
HOSTBASE."policy.php" );
$subnotes_problems_support = array(
T_('In case of problems with your account activation or email-change:'),
ErrorCode::fill_email_support( ErrorCode::get_error_text('contact:mail_support'), $with_email_link ),
ErrorCode::get_error_text('contact:context') );
return array( $text_email_use, $text_email_priv, $subnotes_problems_support );
}//build_common_verify_texts
} // end of 'UserRegistration'
?>
//
koh5_pano
Drag mouse to navigate.
Navigation
- Left/Right Mouse drag: Changes camera heading.
- Up/Sown Mouse drag: Changes camera pitch.
- Scroll wheel: Changes camera field of view.
- I-Key: Displays Info panel with canvas size, image size and FPS.
17.Aug.2010, Martin Wengenmayer