Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
+94
-18
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Login Handler
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 13 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -158,8 +158,12 @@ class _Login
|
||||
/* If there's an explicit ref value, go there */
|
||||
if( !empty( \IPS\Request::i()->ref ) )
|
||||
{
|
||||
$ref = new \IPS\Http\Url( @base64_decode( \IPS\Request::i()->ref ) ?: \IPS\Request::i()->ref );
|
||||
return $ref;
|
||||
try
|
||||
{
|
||||
$ref = \IPS\Http\Url::createFromString( @base64_decode( \IPS\Request::i()->ref ) ?: \IPS\Request::i()->ref );
|
||||
return $ref;
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
|
||||
/* Don't redirect to an external domain unless explicitly requested, and don't redirect back to ACP */
|
||||
@@ -179,7 +183,7 @@ class _Login
|
||||
}
|
||||
}
|
||||
|
||||
$ref = new \IPS\Http\Url( ( isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '' ) );
|
||||
$ref = isset( $_SERVER['HTTP_REFERER'] ) ? \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal('');
|
||||
}
|
||||
|
||||
return isset( $ref ) ? $ref->stripQueryString( 'csrfKey' ) : \IPS\Http\Url::internal( '' );
|
||||
@@ -201,12 +205,26 @@ class _Login
|
||||
}
|
||||
}
|
||||
|
||||
$ref = NULL;
|
||||
if ( isset( \IPS\Request::i()->ref ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$ref = \IPS\Http\Url::createFromString( base64_decode( \IPS\Request::i()->ref ) );
|
||||
if ( !( $ref instanceof \IPS\Http\Url\Internal ) )
|
||||
{
|
||||
$ref = NULL;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
|
||||
if ( in_array( \IPS\Settings::i()->reg_auth_type, array( 'admin', 'admin_user' ) ) )
|
||||
{
|
||||
return \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=validating', 'front', 'register' );
|
||||
}
|
||||
|
||||
return \IPS\Http\Url::internal( '' );
|
||||
return $ref ?: \IPS\Http\Url::internal( '' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,7 +247,7 @@ class _Login
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->forms[ $key ] = $handler->loginForm( $this->url );
|
||||
$this->forms[ $key ] = $handler->loginForm( $this->url, FALSE, $skipReferer ? $this->url : static::getDestination() );
|
||||
}
|
||||
catch( \BadMethodCallException $e )
|
||||
{
|
||||
@@ -272,8 +290,8 @@ class _Login
|
||||
$classname = 'IPS\Helpers\Form\Email';
|
||||
}
|
||||
$standardForm->class = 'ipsForm_vertical';
|
||||
$standardForm->add( new $classname( 'auth', NULL, TRUE, array( '_loginType' => $standardTypes ), NULL, NULL, NULL, 'auth' ) );
|
||||
$standardForm->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array(), NULL, NULL, NULL, 'password' ) );
|
||||
$standardForm->add( new $classname( 'auth', NULL, TRUE, array( '_loginType' => $standardTypes, 'bypassProfanity' => TRUE ), NULL, NULL, NULL, 'auth' ) );
|
||||
$standardForm->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'bypassProfanity' => TRUE ), NULL, NULL, NULL, 'password' ) );
|
||||
|
||||
/* Are we adding the referer value to the form? */
|
||||
if( !$skipReferer )
|
||||
@@ -380,17 +398,33 @@ class _Login
|
||||
{
|
||||
$removeLoginsOlderThan = \IPS\DateTime::create()->sub( new \DateInterval( 'PT' . \IPS\Settings::i()->ipb_bruteforce_period . 'M' ) );
|
||||
$failedLogins = $member->failed_logins;
|
||||
foreach ( $failedLogins as $ipAddress => $times )
|
||||
|
||||
/* The failed login data could potentially not be an array (i.e. a float) but as this code executes during the first
|
||||
step of upgrading to 4.0 if we don't force it to be an array here we could end up with an error exception we can't
|
||||
get past when attempting to upgrade. */
|
||||
if( !is_array( $failedLogins ) )
|
||||
{
|
||||
foreach ( $times as $k => $v )
|
||||
$failedLogins = array();
|
||||
}
|
||||
|
||||
if ( is_array( $failedLogins ) )
|
||||
{
|
||||
foreach ( $failedLogins as $ipAddress => $times )
|
||||
{
|
||||
if ( $v < $removeLoginsOlderThan->getTimestamp() )
|
||||
foreach ( $times as $k => $v )
|
||||
{
|
||||
unset( $failedLogins[ $ipAddress ][ $k ] );
|
||||
if ( $v < $removeLoginsOlderThan->getTimestamp() )
|
||||
{
|
||||
unset( $failedLogins[ $ipAddress ][ $k ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
$member->failed_logins = $failedLogins;
|
||||
}
|
||||
else
|
||||
{
|
||||
$member->failed_logins = array();
|
||||
}
|
||||
$member->failed_logins = $failedLogins;
|
||||
$member->save();
|
||||
}
|
||||
|
||||
@@ -468,7 +502,7 @@ class _Login
|
||||
{
|
||||
$failedLogins = $member->failed_logins[ \IPS\Request::i()->ipAddress() ];
|
||||
sort( $failedLogins );
|
||||
|
||||
|
||||
while ( count( $failedLogins ) > \IPS\Settings::i()->ipb_bruteforce_attempts )
|
||||
{
|
||||
array_pop( $failedLogins );
|
||||
@@ -476,13 +510,31 @@ class _Login
|
||||
$unlockTime = \IPS\DateTime::ts( array_pop( $failedLogins ) );
|
||||
$unlockTime->add( new \DateInterval( 'PT' . \IPS\Settings::i()->ipb_bruteforce_period . 'M' ) );
|
||||
$timeToUnlock = $unlockTime->diff( new DateTime() );
|
||||
|
||||
|
||||
/* If Unlock Time is in the past, return FALSE to avoid the exception and allow login */
|
||||
if ( $unlockTime->getTimestamp() < time() )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Notify the member if they've been locked */
|
||||
if( count( $member->failed_logins[ \IPS\Request::i()->ipAddress() ] ) == \IPS\Settings::i()->ipb_bruteforce_attempts )
|
||||
{
|
||||
/* Can we get a physical location */
|
||||
try
|
||||
{
|
||||
$location = \IPS\GeoLocation::getByIp( \IPS\Request::i()->ipAddress() );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$location = \IPS\Request::i()->ipAddress();
|
||||
}
|
||||
\IPS\Email::buildFromTemplate( 'core', 'account_locked', array( $member, $location, isset( $unlockTime ) ? $unlockTime : NULL ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
}
|
||||
|
||||
if ( \IPS\Settings::i()->ipb_bruteforce_period and \IPS\Settings::i()->ipb_bruteforce_unlock )
|
||||
{
|
||||
throw new \IPS\Login\Exception( \IPS\Member::loggedIn()->language()->addToStack( 'login_err_locked_unlock', FALSE, array( 'pluralize' => array( $timeToUnlock->format('%i') ) ) ) );
|
||||
}
|
||||
else
|
||||
@@ -501,7 +553,7 @@ class _Login
|
||||
*/
|
||||
public static function compareHashes( $expected, $provided )
|
||||
{
|
||||
if ( !is_string( $expected ) || !is_string( $provided ) )
|
||||
if ( !is_string( $expected ) || !is_string( $provided ) || $expected === '*0' || $expected === '*1' || $provided === '*0' || $provided === '*1' ) // *0 and *1 are failures from crypt() - if we have ended up with an invalid hash anywhere, we will reject it to prevent a possible vulnerability from deliberately generating invalid hashes
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -520,4 +572,28 @@ class _Login
|
||||
|
||||
return $status === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random string
|
||||
*
|
||||
* @param int $length The length of the final string
|
||||
* @return string
|
||||
*/
|
||||
public static function generateRandomString( $length=32 )
|
||||
{
|
||||
$return = '';
|
||||
|
||||
if( function_exists( 'openssl_random_pseudo_bytes' ) )
|
||||
{
|
||||
$return = \substr( bin2hex( openssl_random_pseudo_bytes( ceil( $length / 2 ) ) ), 0, $length );
|
||||
}
|
||||
|
||||
/* Fallback JUST IN CASE */
|
||||
if( !$return OR \strlen( $return ) != $length )
|
||||
{
|
||||
$return = \substr( md5( uniqid( microtime(), true ) ) . md5( uniqid( microtime(), true ) ), 0, $length );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user