Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F800334
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Feb 22, 12:05 AM
Size
19 KB
Mime Type
text/x-diff
Expires
Mon, Feb 24, 12:05 AM (7 h, 35 m)
Engine
blob
Format
Raw Data
Handle
573591
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/5.2.x/core/units/helpers/user_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/user_helper.php (revision 15409)
+++ branches/5.2.x/core/units/helpers/user_helper.php (revision 15410)
@@ -1,632 +1,634 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class UserHelper extends kHelper {
/**
* Event to be used during login processings
*
* @var kEvent
*/
var $event = null;
/**
* Performs user login and returns the result
*
* @param string $username
* @param string $password
* @param bool $dry_run
* @param bool $remember_login
* @param string $remember_login_cookie
* @return int
*/
function loginUser($username, $password, $dry_run = false, $remember_login = false, $remember_login_cookie = '')
{
if (!isset($this->event)) {
$this->event = new kEvent('u:OnLogin');
}
if (!$password && !$remember_login_cookie) {
return LoginResult::INVALID_PASSWORD;
}
$object =& $this->getUserObject();
// process "Save Username" checkbox
if ($this->Application->isAdmin) {
$save_username = $this->Application->GetVar('cb_save_username') ? $username : '';
$this->Application->Session->SetCookie('save_username', $save_username, strtotime('+1 year'));
// cookie will be set on next refresh, but refresh won't occur if
// login error present, so duplicate cookie in kHTTPQuery
$this->Application->SetVar('save_username', $save_username);
}
// logging in "root" (admin only)
$super_admin = ($username == 'super-root') && $this->verifySuperAdmin();
if ($this->Application->isAdmin && ($username == 'root') || ($super_admin && $username == 'super-root')) {
$root_password = $this->Application->ConfigValue('RootPass');
$password_formatter = $this->Application->recallObject('kPasswordFormatter');
/* @var $password_formatter kPasswordFormatter */
if ($root_password != $password_formatter->EncryptPassword($password, 'b38')) {
return LoginResult::INVALID_PASSWORD;
}
$user_id = USER_ROOT;
$object->Clear($user_id);
$object->SetDBField('Username', 'root');
if (!$dry_run) {
$this->loginUserById($user_id, $remember_login_cookie);
if ($super_admin) {
$this->Application->StoreVar('super_admin', 1);
}
// reset counters
$this->Application->resetCounters('UserSessions');
$this->_processLoginRedirect('root', $password);
$this->_processInterfaceLanguage();
}
return LoginResult::OK;
}
$user_id = $this->getUserId($username, $password, $remember_login_cookie);
if ($user_id) {
$object->Load($user_id);
if (!$this->checkBanRules($object)) {
return LoginResult::BANNED;
}
if ($object->GetDBField('Status') == STATUS_ACTIVE) {
if ( !$this->checkLoginPermission() ) {
return LoginResult::NO_PERMISSION;
}
if (!$dry_run) {
$this->loginUserById($user_id, $remember_login_cookie);
if ($remember_login) {
// remember username & password when "Remember Login" checkbox us checked (when user is using login form on Front-End)
$this->Application->Session->SetCookie('remember_login', $username . '|' . md5($password), strtotime('+1 month'));
}
if (!$remember_login_cookie) {
// reset counters
$this->Application->resetCounters('UserSessions');
$this->_processLoginRedirect($username, $password);
$this->_processInterfaceLanguage();
}
}
return LoginResult::OK;
}
else {
$pending_template = $this->Application->GetVar('pending_disabled_template');
if ($pending_template !== false && !$dry_run) {
// when user found, but it's not yet approved redirect hit to notification template
$this->event->redirect = $pending_template;
return LoginResult::OK;
}
else {
// when no notification template given return an error
return LoginResult::INVALID_PASSWORD;
}
}
}
if (!$dry_run) {
$this->event->SetRedirectParam('pass', 'all');
// $this->event->SetRedirectParam('pass_category', 1); // to test
}
return LoginResult::INVALID_PASSWORD;
}
/**
* Login user by it's id
*
* @param int $user_id
* @param bool $remember_login_cookie
*/
function loginUserById($user_id, $remember_login_cookie = false)
{
$object =& $this->getUserObject();
$this->Application->StoreVar('user_id', $user_id);
$this->Application->SetVar('u.current_id', $user_id);
$this->Application->Session->SetField('PortalUserId', $user_id);
if ($user_id != USER_ROOT) {
$groups = $this->Application->RecallVar('UserGroups');
$this->Application->Session->SetField('GroupId', reset( explode(',', $groups) ));
$this->Application->Session->SetField('GroupList', $groups);
$this->Application->Session->SetField('TimeZone', $object->GetDBField('TimeZone'));
}
$this->Application->LoadPersistentVars();
if (!$remember_login_cookie) {
// don't change last login time when auto-login is used
$this_login = (int)$this->Application->RecallPersistentVar('ThisLogin');
$this->Application->StorePersistentVar('LastLogin', $this_login);
$this->Application->StorePersistentVar('ThisLogin', adodb_mktime());
}
$this->Application->HandleEvent(new kEvent('u:OnAfterLogin'));
}
/**
* Checks login permission
*
* @return bool
*/
function checkLoginPermission()
{
$object =& $this->getUserObject();
$ip_restrictions = $object->GetDBField('IPRestrictions');
if ( $ip_restrictions && !$this->Application->isDebugMode() && !kUtil::ipMatch($ip_restrictions, "\n") ) {
return false;
}
$groups = $object->getMembershipGroups(true);
if ( !$groups ) {
$groups = Array ();
}
$default_group = $this->getUserTypeGroup();
if ( $default_group !== false ) {
array_push($groups, $default_group);
}
// store groups, because kApplication::CheckPermission will use them!
array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup'));
$groups = array_unique($groups);
$this->Application->StoreVar('UserGroups', implode(',', $groups), true); // true for optional
return $this->Application->CheckPermission($this->Application->isAdmin ? 'ADMIN' : 'LOGIN', 1);
}
/**
* Returns default user group for it's type
*
* @return bool|string
* @access protected
*/
protected function getUserTypeGroup()
{
$group_id = false;
$object =& $this->getUserObject();
if ( $object->GetDBField('UserType') == UserType::USER ) {
$group_id = $this->Application->ConfigValue('User_NewGroup');
}
elseif ( $object->GetDBField('UserType') == UserType::ADMIN ) {
$group_id = $this->Application->ConfigValue('User_AdminGroup');
}
$ip_restrictions = $this->getGroupsWithIPRestrictions();
if ( !isset($ip_restrictions[$group_id]) || kUtil::ipMatch($ip_restrictions[$group_id], "\n") ) {
return $group_id;
}
return false;
}
/**
* Returns groups with IP restrictions
*
* @return Array
* @access public
*/
public function getGroupsWithIPRestrictions()
{
static $cache = null;
if ( $this->Application->isDebugMode() ) {
return Array ();
}
if ( !isset($cache) ) {
$sql = 'SELECT IPRestrictions, GroupId
FROM ' . TABLE_PREFIX . 'UserGroups
WHERE IPRestrictions IS NOT NULL';
$cache = $this->Conn->GetCol($sql, 'GroupId');
}
return $cache;
}
/**
* Performs user logout
*
*/
function logoutUser()
{
if (!isset($this->event)) {
$this->event = new kEvent('u:OnLogout');
}
$sync_manager = $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize'));
/* @var $sync_manager UsersSyncronizeManager */
$sync_manager->performAction('LogoutUser');
$this->Application->HandleEvent(new kEvent('u:OnBeforeLogout'));
$user_id = USER_GUEST;
$this->Application->SetVar('u.current_id', $user_id);
$object = $this->Application->recallObject('u.current', null, Array('skip_autoload' => true));
/* @var $object UsersItem */
$object->Load($user_id);
$this->Application->DestroySession();
$this->Application->StoreVar('user_id', $user_id, true);
$this->Application->Session->SetField('PortalUserId', $user_id);
$group_list = $this->Application->ConfigValue('User_GuestGroup') . ',' . $this->Application->ConfigValue('User_LoggedInGroup');
$this->Application->StoreVar('UserGroups', $group_list, true);
$this->Application->Session->SetField('GroupList', $group_list);
if ($this->Application->ConfigValue('UseJSRedirect')) {
$this->event->SetRedirectParam('js_redirect', 1);
}
$this->Application->resetCounters('UserSessions');
$this->Application->Session->SetCookie('remember_login', '', strtotime('-1 hour'));
// don't pass user prefix on logout, since resulting url will have broken "env"
$this->event->SetRedirectParam('pass', MOD_REWRITE ? 'm' : 'all');
}
/**
* Returns user id based on given criteria
*
* @param string $username
* @param string $password
* @param string $remember_login_cookie
* @return int
*/
function getUserId($username, $password, $remember_login_cookie)
{
$password = md5($password);
if ($remember_login_cookie) {
list ($username, $password) = explode('|', $remember_login_cookie); // 0 - username, 1 - md5(password)
}
$sql = 'SELECT PortalUserId
FROM ' . TABLE_PREFIX . 'Users
WHERE (Email = %1$s OR Username = %1$s) AND (Password = %2$s)';
return $this->Conn->GetOne( sprintf($sql, $this->Conn->qstr($username), $this->Conn->qstr($password) ) );
}
/**
* Process all required data and redirect logged-in user
*
* @param string $username
* @param string $password
*/
function _processLoginRedirect($username, $password)
{
// set next template
$next_template = $this->Application->GetVar('next_template');
if ($next_template) {
$this->event->redirect = $next_template;
}
// process IIS redirect
if ($this->Application->ConfigValue('UseJSRedirect')) {
$this->event->SetRedirectParam('js_redirect', 1);
}
// synchronize login
$sync_manager = $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize'));
/* @var $sync_manager UsersSyncronizeManager */
$sync_manager->performAction('LoginUser', $username, $password);
}
/**
* Sets correct interface language after successful login, based on user settings
*
* @return void
* @access protected
*/
protected function _processInterfaceLanguage()
{
if ( defined('IS_INSTALL') && IS_INSTALL ) {
$this->event->SetRedirectParam('m_lang', 1); // data
$this->Application->Session->SetField('Language', 1); // interface
return;
}
$language_field = $this->Application->isAdmin ? 'AdminLanguage' : 'FrontLanguage';
$primary_language_field = $this->Application->isAdmin ? 'AdminInterfaceLang' : 'PrimaryLang';
$is_root = $this->Application->RecallVar('user_id') == USER_ROOT;
$object =& $this->getUserObject();
$user_language_id = $is_root ? $this->Application->RecallPersistentVar($language_field) : $object->GetDBField($language_field);
$sql = 'SELECT LanguageId, IF(LanguageId = ' . (int)$user_language_id . ', 2, ' . $primary_language_field . ') AS SortKey
FROM ' . TABLE_PREFIX . 'Languages
WHERE Enabled = 1
HAVING SortKey <> 0
ORDER BY SortKey DESC';
$language_info = $this->Conn->GetRow($sql);
$language_id = $language_info && $language_info['LanguageId'] ? $language_info['LanguageId'] : $user_language_id;
if ( $user_language_id != $language_id ) {
// first login OR language was deleted or disabled
if ( $is_root ) {
$this->Application->StorePersistentVar($language_field, $language_id);
}
else {
$object->SetDBField($language_field, $language_id);
$object->Update();
}
}
// set language for Admin Console & Front-End with disabled Mod-Rewrite
$this->event->SetRedirectParam('m_lang', $language_id); // data
$this->Application->Session->SetField('Language', $language_id); // interface
// set language for Front-End with enabled Mod-Rewrite
if ( MOD_REWRITE ) {
$this->_injectLanguageIntoUrl($language_id);
}
}
/**
* Inject language into whatever page user wants to go after login
*
* @param int $language_id
* @return void
* @access protected
*/
protected function _injectLanguageIntoUrl($language_id)
{
- $url = $this->Application->HREF($this->event->redirect, '', $this->event->getRedirectParams(), $this->event->redirectScript);
+ // solve problem, when template is "true" instead of actual template name
+ $template = is_string($this->event->redirect) ? $this->event->redirect : '';
+ $url = $this->Application->HREF($template, '', $this->event->getRedirectParams(), $this->event->redirectScript);
$vars = $this->Application->parseRewriteUrl($url, 'pass');
$vars['pass'] = implode(',', $vars['pass']);
$vars['m_lang'] = $language_id;
$template = $vars['t'];
unset($vars['is_virtual'], $vars['t']);
$this->event->redirect = $template;
$this->event->setRedirectParams($vars, false);
}
/**
* Checks that user is allowed to use super admin mode
*
* @return bool
*/
function verifySuperAdmin()
{
$sa_mode = kUtil::ipMatch(defined('SA_IP') ? SA_IP : '');
return $sa_mode || $this->Application->isDebugMode();
}
/**
* Returns user object, used during login processing
*
* @return UsersItem
* @access public
*/
public function &getUserObject()
{
$prefix_special = $this->Application->isAdmin ? 'u.current' : 'u'; // "u" used on front not to change theme
$object = $this->Application->recallObject($prefix_special, null, Array('skip_autoload' => true));
/* @var $object UsersItem */
return $object;
}
/**
* Checks, if given user fields matches at least one of defined ban rules
*
* @param kDBItem $object
* @return bool
*/
function checkBanRules(&$object)
{
$table = $this->Application->getUnitOption('ban-rule', 'TableName');
if (!$this->Conn->TableFound($table)) {
// when ban table not found -> assume user is ok by default
return true;
}
$sql = 'SELECT *
FROM ' . $table . '
WHERE ItemType = 6 AND Status = ' . STATUS_ACTIVE . '
ORDER BY Priority DESC';
$rules = $this->Conn->Query($sql);
$found = false;
foreach ($rules as $rule) {
$field = $rule['ItemField'];
$this_value = mb_strtolower( $object->GetDBField($field) );
$test_value = mb_strtolower( $rule['ItemValue'] );
switch ( $rule['ItemVerb'] ) {
case 1: // is
if ($this_value == $test_value) {
$found = true;
}
break;
case 2: // is not
if ($this_value != $test_value) {
$found = true;
}
break;
case 3: // contains
if ( strstr($this_value, $test_value) ) {
$found = true;
}
break;
case 4: // not contains
if ( !strstr($this_value, $test_value) ) {
$found = true;
}
break;
case 7: // exists
if ( strlen($this_value) > 0 ) {
$found = true;
}
break;
case 8: // unique
if ( $this->_checkValueExist($field, $this_value) ) {
$found = true;
}
break;
}
if ( $found ) {
// check ban rules, until one of them matches
if ( $rule['RuleType'] ) {
// invert rule type
$found = false;
}
break;
}
}
return !$found;
}
/**
* Checks if value is unique in Users table against the specified field
*
* @param string $field
* @param string $value
* @return string
*/
function _checkValueExist($field, $value)
{
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('u', 'TableName') . '
WHERE '. $field .' = ' . $this->Conn->qstr($value);
return $this->Conn->GetOne($sql);
}
public function validateUserCode($user_code, $code_type, $expiration_timeout = null)
{
$expiration_timeouts = Array (
'forgot_password' => 'config:Users_AllowReset',
'activation' => 'config:UserEmailActivationTimeout',
'verify_email' => 'config:Users_AllowReset',
'custom' => '',
);
if ( !$user_code ) {
return 'code_is_not_valid';
}
$sql = 'SELECT PwRequestTime, PortalUserId
FROM ' . TABLE_PREFIX . 'Users
WHERE PwResetConfirm = ' . $this->Conn->qstr( trim($user_code) );
$user_info = $this->Conn->GetRow($sql);
if ( $user_info === false ) {
return 'code_is_not_valid';
}
$expiration_timeout = isset($expiration_timeout) ? $expiration_timeout : $expiration_timeouts[$code_type];
if ( preg_match('/^config:(.*)$/', $expiration_timeout, $regs) ) {
$expiration_timeout = $this->Application->ConfigValue( $regs[1] );
}
if ( $expiration_timeout && $user_info['PwRequestTime'] < strtotime('-' . $expiration_timeout . ' minutes') ) {
return 'code_expired';
}
return $user_info['PortalUserId'];
}
/**
* Restores user's email, returns error label, if error occurred
*
* @param string $hash
* @return string
* @access public
*/
public function restoreEmail($hash)
{
if ( !preg_match('/^[a-f0-9]{32}$/', $hash) ) {
return 'invalid_hash';
}
$sql = 'SELECT PortalUserId, PrevEmails
FROM ' . TABLE_PREFIX . 'Users
WHERE PrevEmails LIKE ' . $this->Conn->qstr('%' . $hash . '%');
$user_info = $this->Conn->GetRow($sql);
if ( $user_info === false ) {
return 'invalid_hash';
}
$prev_emails = $user_info['PrevEmails'];
$prev_emails = $prev_emails ? unserialize($prev_emails) : Array ();
if ( !isset($prev_emails[$hash]) ) {
return 'invalid_hash';
}
$email_to_restore = $prev_emails[$hash];
unset($prev_emails[$hash]);
$object = $this->Application->recallObject('u.email-restore', null, Array ('skip_autoload' => true));
/* @var $object UsersItem */
$object->Load($user_info['PortalUserId']);
$object->SetDBField('PrevEmails', serialize($prev_emails));
$object->SetDBField('Email', $email_to_restore);
$object->SetDBField('EmailVerified', 1);
return $object->Update() ? '' : 'restore_impossible';
}
}
Event Timeline
Log In to Comment