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

+143 -20
View File
@@ -12,7 +12,7 @@
namespace IPS\Login;
/* 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;
@@ -25,11 +25,14 @@ abstract class _Handler extends \IPS\Node\Model
{
/**
* Get all handler classes
*
* @return array
*/
public static function handlerClasses()
{
return array(
'IPS\Login\Handler\Standard',
'IPS\Login\Handler\OAuth2\Apple',
'IPS\Login\Handler\OAuth2\Facebook',
'IPS\Login\Handler\OAuth2\Google',
'IPS\Login\Handler\OAuth2\LinkedIn',
@@ -107,12 +110,18 @@ abstract class _Handler extends \IPS\Node\Model
$settings = array();
foreach ( $this->acpForm() as $key => $field )
{
if ( is_object( $field ) )
if ( \is_object( $field ) )
{
$settings[ $key ] = $values[ $field->name ];
unset( $values[ $field->name ] );
}
}
/* If the legacy_redirect flag is set, make sure it stays set otherwise logins will break once the login method has been edited */
if ( isset( $this->settings['legacy_redirect'] ) AND $this->settings['legacy_redirect'] )
{
$settings['legacy_redirect'] = TRUE;
}
return $settings;
}
@@ -126,6 +135,7 @@ abstract class _Handler extends \IPS\Node\Model
/**
* Can this handler process a login for a member?
*
* @param \IPS\Member $member Member
* @return bool
*/
public function canProcess( \IPS\Member $member )
@@ -133,6 +143,16 @@ abstract class _Handler extends \IPS\Node\Model
return (bool) $this->_link( $member );
}
/**
* Can this handler sync passwords?
*
* @return bool
*/
public function canSyncPassword()
{
return FALSE;
}
/**
* @brief Cached links
*/
@@ -163,6 +183,7 @@ abstract class _Handler extends \IPS\Node\Model
/**
* Can this handler process a password change for a member?
*
* @param \IPS\Member $member Member
* @return bool
*/
public function canChangePassword( \IPS\Member $member )
@@ -174,8 +195,8 @@ abstract class _Handler extends \IPS\Node\Model
* Email is in use?
* Used when registering or changing an email address to check the new one is available
*
* @param string $email Email Address
* @param \IPS\Member|NULL $eclude Member to exclude
* @param string $email Email Address
* @param \IPS\Member|NULL $exclude Member to exclude
* @return bool|NULL Boolean indicates if email is in use (TRUE means is in use and thus not registerable) or NULL if this handler does not support such an API
*/
public function emailIsInUse( $email, \IPS\Member $exclude=NULL )
@@ -187,8 +208,8 @@ abstract class _Handler extends \IPS\Node\Model
* Username is in use?
* Used when registering or changing an username to check the new one is available
*
* @param string $username Username
* @param \IPS\Member|NULL $eclude Member to exclude
* @param string $username Username
* @param \IPS\Member|NULL $exclude Member to exclude
* @return bool|NULL Boolean indicates if username is in use (TRUE means is in use and thus not registerable) or NULL if this handler does not support such an API
*/
public function usernameIsInUse( $username, \IPS\Member $exclude=NULL )
@@ -233,6 +254,18 @@ abstract class _Handler extends \IPS\Node\Model
{
return 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 ): ?\IPS\Http\Url
{
return NULL;
}
/**
* Create an account from login - checks registration is enabled, the name/email doesn't already exists and calls the spam service
@@ -271,7 +304,7 @@ abstract class _Handler extends \IPS\Node\Model
$member->member_group_id = \IPS\Settings::i()->member_group;
$member->members_bitoptions['view_sigs'] = TRUE;
$member->members_bitoptions['must_reaccept_terms'] = (bool) \IPS\Settings::i()->force_reg_terms;
if ( $name and ( !\IPS\Settings::i()->username_characters or preg_match( '/^[' . str_replace( '\-', '-', preg_quote( \IPS\Settings::i()->username_characters, '/' ) ) . ']*$/i', $name ) ) )
if ( $name and \IPS\Login::usernameIsAllowed( $name ) )
{
$existingUsername = \IPS\Member::load( $name, 'name' );
if ( !$existingUsername->member_id )
@@ -290,7 +323,7 @@ abstract class _Handler extends \IPS\Node\Model
$allowed = FALSE;
foreach ( $allowedEmailDomains AS $domain )
{
if( \mb_stripos( $this->value, "@" . $domain ) !== FALSE )
if( \mb_stripos( $email, "@" . $domain ) !== FALSE )
{
$allowed = TRUE;
}
@@ -323,7 +356,21 @@ abstract class _Handler extends \IPS\Node\Model
/* If registration is complete, do post-registration stuff */
if ( $member->real_name and $member->email and !$member->members_bitoptions['bw_is_spammer'] )
{
$member->postRegistration( TRUE );
$postBeforeRegister = NULL;
if ( isset( \IPS\Request::i()->cookie['post_before_register'] ) )
{
try
{
$postBeforeRegister = \IPS\Db::i()->select( '*', 'core_post_before_registering', array( 'secret=?', \IPS\Request::i()->cookie['post_before_register'] ) )->first();
}
catch ( \UnderflowException $e ) { }
}
/* If account wasn't flagged as spammer and banned, handle validation stuff */
if( $spamAction != 3 )
{
$member->postRegistration( TRUE, FALSE, $postBeforeRegister );
}
}
/* Return our new member */
@@ -360,12 +407,23 @@ abstract class _Handler extends \IPS\Node\Model
public function disassociate( \IPS\Member $member = NULL )
{
$member = $member ?: \IPS\Member::loggedIn();
try
{
$userId = $this->userId( $member );
$userName = $this->userProfileName( $member );
}
catch( \IPS\Login\Exception $e )
{
$userId = NULL;
$userName = NULL;
}
$member->logHistory( 'core', 'social_account', array(
'service' => static::getTitle(),
'handler' => $this->id,
'account_id' => $this->userId( $member ),
'account_name' => $this->userProfileName( $member ),
'account_id' => $userId,
'account_name' => $userName,
'linked' => FALSE,
) );
@@ -376,7 +434,7 @@ abstract class _Handler extends \IPS\Node\Model
* Get logo to display in information about logins with this method
* Returns NULL for methods where it is not necessary to indicate the method, e..g Standard
*
* @return \IPS\Http\Url
* @return \IPS\Http\Url|NULL
*/
public function logoForDeviceInformation()
{
@@ -386,7 +444,7 @@ abstract class _Handler extends \IPS\Node\Model
/**
* Get logo to display in user cp sidebar
*
* @return \IPS\Http\Url
* @return \IPS\Http\Url|string
*/
public function logoForUcp()
{
@@ -419,10 +477,62 @@ abstract class _Handler extends \IPS\Node\Model
return FALSE;
}
/**
* Things which must be synced if a member is using this handler
*
* @return array
*/
public function forceSync()
{
$return = array();
if ( isset( $this->settings['update_name_changes'] ) and $this->settings['update_name_changes'] === 'force' )
{
$return[] = 'name';
}
if ( isset( $this->settings['update_email_changes'] ) and $this->settings['update_email_changes'] === 'force' )
{
$return[] = 'email';
}
return $return;
}
/**
* Check if any handler has a particular value set in forceSync()
*
* @note Deliberately checks disabled methods, otherwise you'd be able to re-enable two which have it enabled bypassing the check
* @param string $type The type to check for
* @param \IPS\Login\Handler|NULL $not Exclude a particular handler from the check
* @param \IPS\Member $member If specified, only login handlers that member has set up will be checked
* @return \IPS\Login\Handler|FALSE
*/
public static function handlerHasForceSync( $type, $not = NULL, \IPS\Member $member = NULL )
{
foreach ( \IPS\Db::i()->select( '*', 'core_login_methods' ) as $row )
{
try
{
$method = static::constructFromData( $row );
if ( ( !$not or $not->_id != $method->_id ) and ( !$member or $method->canProcess( $member ) ) )
{
if ( \in_array( $type, $method->forceSync() ) )
{
return $method;
}
}
}
catch ( \Exception $e ) { }
}
return FALSE;
}
/**
* Syncing Options
*
* @param \IPS\Member $member The member we're asking for (can be used to not show certain options iof the user didn't grant those scopes)
* @param \IPS\Member $member The member we're asking for (can be used to not show certain options if the user didn't grant those scopes)
* @param bool $defaultOnly If TRUE, only returns which options should be enabled by default for a new account
* @return array
*/
@@ -430,6 +540,16 @@ abstract class _Handler extends \IPS\Node\Model
{
return array();
}
/**
* Has any sync options
*
* @return bool
*/
public function hasSyncOptions()
{
return FALSE;
}
/**
* Get user's identifier (may not be a number)
@@ -541,7 +661,7 @@ abstract class _Handler extends \IPS\Node\Model
* Parse status text - ensures valid and safe HTML, filters profanity, etc.
*
* @param \IPS\Member $member Member
* @param string $value
* @param string $value Status text to parse
* @return void
*/
protected function _parseStatusText( \IPS\Member $member, $value )
@@ -686,13 +806,16 @@ abstract class _Handler extends \IPS\Node\Model
{
if ( parent::canDelete() )
{
return count( static::roots() ) > 1;
return \count( static::roots() ) > 1;
}
return FALSE;
}
/* !AdminCP Management */
/**
* @brief Should ACP logins be enabled by default
*/
protected static $enableAcpLoginByDefault = TRUE;
/**
@@ -735,11 +858,11 @@ abstract class _Handler extends \IPS\Node\Model
foreach ( $this->acpForm() as $key => $field )
{
if ( is_string( $field ) )
if ( \is_string( $field ) )
{
$form->addHeader( $field );
}
elseif ( is_array( $field ) )
elseif ( \is_array( $field ) )
{
$form->addHeader( $field[0] );
$form->addMessage( $field[1] );
@@ -838,7 +961,7 @@ abstract class _Handler extends \IPS\Node\Model
*
* @return void
*/
function save()
public function save()
{
parent::save();
unset( \IPS\Data\Store::i()->loginMethods );