Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

+94 -18
View File
@@ -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;
}
}