Version 4.5.0

This commit is contained in:
Neo committed 2025-12-19 05:51:58 -08:00
1 parent 1a0c7fd3c2
commit f79dcf067a
3791 files changed
+248032 -76372

No files matched your search

@@ -11,7 +11,7 @@
namespace IPS\Login\Handler;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -174,24 +174,37 @@ class _ExternalDatabase extends \IPS\Login\Handler
)
) );
$nameChangesDisabled = array();
if ( $forceNameHandler = static::handlerHasForceSync( 'name', $this ) )
{
$nameChangesDisabled[] = 'force';
\IPS\Member::loggedIn()->language()->words['login_update_changes_yes_name_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'login_update_changes_yes_disabled', FALSE, array( 'sprintf' => $forceNameHandler->_title ) );
}
$emailChangesDisabled = array();
if ( $forceEmailHandler = static::handlerHasForceSync( 'email', $this ) )
{
$emailChangesDisabled[] = 'force';
\IPS\Member::loggedIn()->language()->words['login_update_changes_yes_email_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'login_update_changes_yes_disabled', FALSE, array( 'sprintf' => $forceEmailHandler->_title ) );
}
$return['update_name_changes_inc_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_name_changes_inc_optional', isset( $this->settings['update_name_changes'] ) ? $this->settings['update_name_changes'] : 'disabled', FALSE, array( 'options' => array(
'force' => 'login_update_changes_yes',
'force' => 'login_update_changes_yes_name',
'optional' => 'login_update_changes_optional',
'disabled' => 'login_update_changes_no',
) ), NULL, NULL, NULL, 'login_update_name_changes_inc_optional' );
), 'disabled' => $nameChangesDisabled ), NULL, NULL, NULL, 'login_update_name_changes_inc_optional' );
$return['update_name_changes_no_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_name_changes_no_optional', ( isset( $this->settings['update_name_changes'] ) and $this->settings['update_name_changes'] != 'optional' ) ? $this->settings['update_name_changes'] : 'disabled', FALSE, array( 'options' => array(
'force' => 'login_update_changes_yes',
'force' => 'login_update_changes_yes_name',
'disabled' => 'login_update_changes_no',
) ), NULL, NULL, NULL, 'login_update_name_changes_no_optional' );
), 'disabled' => $nameChangesDisabled ), NULL, NULL, NULL, 'login_update_name_changes_no_optional' );
$return['update_email_changes_inc_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_email_changes_inc_optional', isset( $this->settings['update_email_changes'] ) ? $this->settings['update_email_changes'] : 'force', FALSE, array( 'options' => array(
'force' => 'login_update_changes_yes',
'force' => 'login_update_changes_yes_email',
'optional' => 'login_update_changes_optional',
'disabled' => 'login_update_changes_no',
) ), NULL, NULL, NULL, 'login_update_email_changes_inc_optional' );
), 'disabled' => $emailChangesDisabled ), NULL, NULL, NULL, 'login_update_email_changes_inc_optional' );
$return['update_email_changes_no_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_email_changes_no_optional', ( isset( $this->settings['update_email_changes'] ) and $this->settings['update_email_changes'] != 'optional' ) ? $this->settings['update_email_changes'] : 'force', FALSE, array( 'options' => array(
'force' => 'login_update_changes_yes',
'force' => 'login_update_changes_yes_email',
'disabled' => 'login_update_changes_no',
) ), NULL, NULL, NULL, 'login_update_email_changes_no_optional' );
), 'disabled' => $emailChangesDisabled ), NULL, NULL, NULL, 'login_update_email_changes_no_optional' );
\IPS\Member::loggedIn()->language()->words['login_update_name_changes_inc_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_name_changes');
\IPS\Member::loggedIn()->language()->words['login_update_name_changes_no_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_name_changes');
\IPS\Member::loggedIn()->language()->words['login_update_email_changes_inc_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_email_changes');
@@ -255,7 +268,7 @@ class _ExternalDatabase extends \IPS\Login\Handler
try
{
$result = $this->_externalDb()->select( implode( ',', $select ), $this->settings['db_table'], ( isset( $this->settings['db_extra'] ) AND $this->settings['db_extra'] != '' ) ? array( $this->settings['db_extra'] ) : NULL )->first();
$result = $this->_externalDb()->select( implode( ',', $select ), $this->settings['db_table'], ( isset( $this->settings['db_extra'] ) AND $this->settings['db_extra'] != '' ) ? array( $this->settings['db_extra'] ) : NULL )->first();
}
catch ( \UnderflowException $e )
{
@@ -271,8 +284,8 @@ class _ExternalDatabase extends \IPS\Login\Handler
* Authenticate
*
* @param \IPS\Login $login The login object
* @param string $usernameOrEmail The username or email address provided by the user
* @param string $password The plaintext password provided by the user
* @param string $usernameOrEmail The username or email address provided by the user
* @param object $password The plaintext password provided by the user, wrapped in an object that can be cast to a string so it doesn't show in any logs
* @return \IPS\Member
* @throws \IPS\Login\Exception
*/
@@ -281,6 +294,11 @@ class _ExternalDatabase extends \IPS\Login\Handler
/* Fetch result */
try
{
if( !$usernameOrEmail )
{
throw new \UnderflowException;
}
$result = $this->_getRowFromExternalDb( $usernameOrEmail );
}
catch ( \IPS\Db\Exception $e )
@@ -405,12 +423,25 @@ class _ExternalDatabase extends \IPS\Login\Handler
{
if ( $exception->getCode() === \IPS\Login\Exception::MERGE_SOCIAL_ACCOUNT )
{
\IPS\Db::i()->insert( 'core_login_links', array(
'token_login_method' => $this->id,
'token_member' => $exception->member->member_id,
'token_identifier' => $result[ $this->settings['db_col_id'] ],
'token_linked' => 0,
) );
try
{
$identifier = \IPS\Db::i()->select( 'token_identifier', 'core_login_links', array( 'token_login_method=? AND token_member=?', $this->id, $exception->member->member_id ) )->first();
if( $identifier != $result[ $this->settings['db_col_id'] ] )
{
$exception->setCode( \IPS\Login\Exception::LOCAL_ACCOUNT_ALREADY_MERGED );
throw $exception;
}
}
catch( \UnderflowException $e )
{
\IPS\Db::i()->insert( 'core_login_links', array(
'token_login_method' => $this->id,
'token_member' => $exception->member->member_id,
'token_identifier' => $result[ $this->settings['db_col_id'] ],
'token_linked' => 0,
) );
}
}
throw $exception;
@@ -426,7 +457,7 @@ class _ExternalDatabase extends \IPS\Login\Handler
* Authenticate
*
* @param \IPS\Member $member The member
* @param string $password The plaintext password provided by the user
* @param object $password The plaintext password provided by the user, wrapped in an object that can be cast to a string so it doesn't show in any logs
* @return bool
*/
public function authenticatePasswordForMember( \IPS\Member $member, $password )
@@ -472,19 +503,21 @@ class _ExternalDatabase extends \IPS\Login\Handler
*/
public function _getRowFromExternalDb( $usernameOrEmail )
{
$where = array();
/* Build where clause */
switch ( $this->authType() )
{
case \IPS\Login::AUTH_TYPE_USERNAME:
$where = array( "{$this->settings['db_col_user']}=?", $usernameOrEmail );
$where[] = array( "{$this->settings['db_col_user']}=?", $usernameOrEmail );
break;
case \IPS\Login::AUTH_TYPE_EMAIL:
$where = array( "{$this->settings['db_col_email']}=?", $usernameOrEmail );
$where[] = array( "{$this->settings['db_col_email']}=?", $usernameOrEmail );
break;
case \IPS\Login::AUTH_TYPE_USERNAME + \IPS\Login::AUTH_TYPE_EMAIL:
$where = array( "{$this->settings['db_col_user']}=? OR {$this->settings['db_col_email']}=?", $usernameOrEmail, $usernameOrEmail );
$where[] = array( "({$this->settings['db_col_user']}=? OR {$this->settings['db_col_email']}=?)", $usernameOrEmail, $usernameOrEmail );
break;
}
@@ -492,7 +525,7 @@ class _ExternalDatabase extends \IPS\Login\Handler
{
$where[] = array( $this->settings['db_extra'] );
}
/* Fetch */
return $this->_externalDb()->select( '*', $this->settings['db_table'], $where )->first();
}
@@ -538,6 +571,16 @@ class _ExternalDatabase extends \IPS\Login\Handler
return FALSE;
}
/**
* Can this handler sync passwords?
*
* @return bool
*/
public function canSyncPassword()
{
return (bool) ( isset( $this->settings['sync_password_changes'] ) AND $this->settings['sync_password_changes'] );
}
/**
* Email is in use?
* Used when registering or changing an email address to check the new one is available
@@ -659,7 +702,7 @@ class _ExternalDatabase extends \IPS\Login\Handler
* Change Password
*
* @param \IPS\Member $member The member
* @param string $newPassword New Password
* @param string $newPassword New Password, wrapped in an object that can be cast to a string so it doesn't show in any logs
* @return void
* @throws \IPS\Db\Exception
*/
@@ -738,6 +781,18 @@ class _ExternalDatabase extends \IPS\Login\Handler
{
return ( isset( $this->settings['forgot_password_url'] ) and $this->settings['forgot_password_url'] ) ? \IPS\Http\Url::external( $this->settings['forgot_password_url'] ) : NULL;
}
/**
* Force Password Reset URL
*
* @param \IPS\Member $member The member
* @param \IPS\Http\Url|NULL $ref Referrer
* @return \IPS\Http\Url|NULL
*/
public function forcePasswordResetUrl( \IPS\Member $member, ?\IPS\Http\Url $ref = NULL ): ?\IPS\Http\Url
{
return $member->passwordResetForced( $ref );
}
/**
* Get user's profile name
@@ -871,6 +926,15 @@ class _ExternalDatabase extends \IPS\Login\Handler
return $return;
}
/**
* Has any sync options
*
* @return bool
*/
public function hasSyncOptions()
{
return TRUE;
}
/* !Utility Methods */
@@ -882,14 +946,14 @@ class _ExternalDatabase extends \IPS\Login\Handler
*/
protected function _externalDb()
{
return \IPS\Db::i( 'external_login', $this->settings );
return \IPS\Db::i( 'external_login_' . $this->id, $this->settings );
}
/**
* Password is valid
*
* @param array $row The member row
* @param string $providedPassword The provided password
* @param array $row The member row
* @param object $providedPassword The plaintext password provided by the user, wrapped in an object that can be cast to a string so it doesn't show in any logs
* @return bool
*/
protected function _passwordIsValid( $row, $providedPassword )
@@ -923,11 +987,13 @@ class _ExternalDatabase extends \IPS\Login\Handler
/**
* Encrypted password
*
* @param string $providedPassword The plaintext password
* @return bool
* @param object $providedPassword The plaintext password provided by the user, wrapped in an object that can be cast to a string so it doesn't show in any logs
* @return string
*/
protected function _encryptedPassword( $providedPassword )
{
$providedPassword = (string) $providedPassword;
switch ( $this->settings['db_encryption'] )
{
case 'md5':