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

+149 -15
View File
@@ -11,7 +11,7 @@
namespace IPS\Session;
/* 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;
@@ -41,7 +41,20 @@ class _Front extends \IPS\Session
*/
public static function loggedIn()
{
return isset( \IPS\Request::i()->cookie['member_id'] ) and \IPS\Request::i()->cookie['member_id'];
/* If we have a "member_id" cookie, we're probably logged in... */
if ( isset( \IPS\Request::i()->cookie['member_id'] ) and \IPS\Request::i()->cookie['member_id'] )
{
return TRUE;
}
/* If the request sent an access token which has GraphQL acceess we'll need to check that */
if ( isset( $_SERVER['HTTP_X_IPS_ACCESSTOKENMEMBER'] ) or isset( \IPS\Request::i()->access_token_member ) )
{
return TRUE;
}
/* Still here: assume not logged in */
return FALSE;
}
/**
@@ -54,6 +67,11 @@ class _Front extends \IPS\Session
*/
protected $save = TRUE;
/**
* @brief No write guest session?
*/
protected $noWriteGuestSession = FALSE;
/**
* Open Session
*
@@ -78,11 +96,17 @@ class _Front extends \IPS\Session
/* Get user agent info */
$this->userAgent = \IPS\Http\Useragent::parse();
if ( ! static::loggedIn() and isset( \IPS\Request::i()->cookie['guestTime'] ) and ( !isset( \IPS\Request::i()->cookie['noCache'] ) or !\IPS\Request::i()->cookie['noCache'] ) and time() < ( \IPS\Request::i()->cookie['guestTime'] + \IPS\CACHE_PAGE_TIMEOUT ) and \IPS\Request::i()->requestMethod() == 'GET' )
{
$this->sessionData = $this->setNoWriteGuestSession();
return (string) $this->sessionData['data'];
}
$session = \IPS\Session\Store::i()->loadSession( $this->sessionId );
/* Only use sessions with matching IP address */
if( \IPS\Settings::i()->match_ipaddress and $session['ip_address'] != \IPS\Request::i()->ipAddress() )
if( $session and \IPS\Settings::i()->match_ipaddress and $session['ip_address'] != \IPS\Request::i()->ipAddress() )
{
$session = NULL;
}
@@ -99,11 +123,15 @@ class _Front extends \IPS\Session
/* Got one? */
if ( $session )
{
/* If this is a guest and the "running time" on this is less than 30 seconds ago, or if a member and less than 15 seconds ago, we don't need a database write */
if ( ( !$session['member_id'] and $session['running_time'] > ( time() - 30 ) ) or ( $session['member_id'] and $session['running_time'] > ( time() - 15 ) ) )
/* If this is a guest and the "running time" on this is less than the guest page cache, or if a member and less than 15 seconds ago, we don't need a database write */
if ( ( !$session['member_id'] and $session['running_time'] < ( time() - \IPS\CACHE_PAGE_TIMEOUT ) ) or ( $session['member_id'] and $session['running_time'] < ( time() - 15 ) ) )
{
$this->save = TRUE;
}
else
{
$this->save = FALSE;
}
/* Set member */
try
@@ -120,8 +148,59 @@ class _Front extends \IPS\Session
{
$this->member = new \IPS\Member;
}
/* If we don't have a member, but the request *did* send an access token which has GraphQL acceess (i.e. unfettered access to act as the user), then use that */
if ( !$this->member->member_id and ( isset( $_SERVER['HTTP_X_IPS_ACCESSTOKENMEMBER'] ) or isset( \IPS\Request::i()->access_token_member ) ) and $authorizationHeader = \IPS\Request::i()->authorizationHeader() and mb_substr( $authorizationHeader, 0, 7 ) === 'Bearer ' and ( !\IPS\OAUTH_REQUIRES_HTTPS or \IPS\Request::i()->isSecure() ) )
{
$expectedMember = \IPS\Member::load( isset( $_SERVER['HTTP_X_IPS_ACCESSTOKENMEMBER'] ) ? $_SERVER['HTTP_X_IPS_ACCESSTOKENMEMBER'] : \IPS\Request::i()->access_token_member );
if ( $expectedMember->member_id )
{
/* Start by checking the access token is valid and for this member */
try
{
$accessToken = \IPS\Api\OAuthClient::accessTokenDetails( mb_substr( $authorizationHeader, 7 ) );
$client = \IPS\Api\OAuthClient::load( $accessToken['client_id'] );
if ( $client->graphql and $accessToken['member_id'] === $expectedMember->member_id )
{
$success = TRUE;
}
else
{
$success = FALSE;
}
}
catch ( \Exception $e )
{
$success = FALSE;
}
/* Because this is effectively a log in attempt, we need to make sure the account is not locked */
try
{
\IPS\Login::checkIfAccountIsLocked( $expectedMember, $success );
/* If it isn't, we can either set that we are that member... */
if ( $success )
{
$this->member = $expectedMember;
}
/* Or if the access token wasn't valid, log it as a fail so that it can't be bruteforced */
else
{
$failedLogins = \is_array( $expectedMember->failed_logins ) ? $expectedMember->failed_logins : array();
$failedLogins[ \IPS\Request::i()->ipAddress() ][] = time();
$expectedMember->failed_logins = $failedLogins;
$expectedMember->save();
}
}
catch ( \Exception $e )
{
// Account is locked. Do nothing.
}
}
}
/* If we don't have a member, check the cookies */
/* If we still don't have a member, check the cookies */
$device = NULL;
if ( !$this->member->member_id and isset( \IPS\Request::i()->cookie['device_key'] ) and isset( \IPS\Request::i()->cookie['member_id'] ) and isset( \IPS\Request::i()->cookie['login_key'] ) )
{
@@ -148,7 +227,7 @@ class _Front extends \IPS\Session
catch ( \OutOfRangeException $e )
{
/* ... so log it as a failed login */
$failedLogins = is_array( $member->failed_logins ) ? $member->failed_logins : array();
$failedLogins = \is_array( $member->failed_logins ) ? $member->failed_logins : array();
$failedLogins[ \IPS\Request::i()->ipAddress() ][] = time();
$member->failed_logins = $failedLogins;
$member->save();
@@ -169,7 +248,7 @@ class _Front extends \IPS\Session
/* Work out the type */
if ( $this->member->member_id )
{
if ( ( $session and $session['login_type'] === static::LOGIN_TYPE_ANONYMOUS ) or ( $device and $device->anonymous ) OR $this->member->group['g_hide_online_list'] )
if ( $this->member->group['g_hide_online_list'] != 2 AND ( ( $session and $session['login_type'] === static::LOGIN_TYPE_ANONYMOUS ) or ( $device and $device->anonymous ) OR $this->member->group['g_hide_online_list'] == 1 ) )
{
$type = static::LOGIN_TYPE_ANONYMOUS;
}
@@ -184,6 +263,8 @@ class _Front extends \IPS\Session
}
else
{
\IPS\Request::i()->setCookie( 'guestTime', time() );
$type = $this->userAgent->spider ? static::LOGIN_TYPE_SPIDER : static::LOGIN_TYPE_GUEST;
}
@@ -203,11 +284,11 @@ class _Front extends \IPS\Session
'current_appcomponent' => ( \IPS\Request::i()->isAjax() ) ? ( $session ? $session['current_appcomponent'] : '' ) : '',
'current_module' => ( \IPS\Request::i()->isAjax() ) ? ( $session ? $session['current_module'] : '' ) : '',
'current_controller' => ( \IPS\Request::i()->isAjax() ) ? ( $session ? $session['current_controller'] : NULL ) : NULL,
'current_id' => ( \IPS\Request::i()->isAjax() ) ? ( $session ? $session['current_id'] : NULL ) : intval( \IPS\Request::i()->id ),
'current_id' => ( \IPS\Request::i()->isAjax() ) ? ( $session ? $session['current_id'] : NULL ) : \intval( \IPS\Request::i()->id ),
'uagent_key' => $this->userAgent->browser ?: '',
'uagent_version' => $this->userAgent->browserVersion ?: '',
'uagent_type' => $this->userAgent->spider ? 'search' : 'browser',
'search_thread_id' => $session ? intval( $session['search_thread_id'] ) : 0,
'search_thread_id' => $session ? \intval( $session['search_thread_id'] ) : 0,
'search_thread_time' => $session ? $session['search_thread_time'] : 0,
'data' => $session ? $session['data'] : '',
'location_url' => $session ? $session['location_url'] : NULL,
@@ -262,6 +343,11 @@ class _Front extends \IPS\Session
*/
public function write( $sessionId, $data )
{
if ( $this->noWriteGuestSession and empty( $_SESSION['forcedWrite'] ) )
{
return TRUE;
}
if ( !isset( $this->data['data'] ) or $data !== $this->data['data'] or $this->data['member_id'] != $this->member->member_id )
{
$this->save = TRUE;
@@ -383,7 +469,7 @@ class _Front extends \IPS\Session
$this->data['current_appcomponent'] = \IPS\Dispatcher::i()->application ? \IPS\Dispatcher::i()->application->directory : '';
$this->data['current_module'] = \IPS\Dispatcher::i()->module ? \IPS\Dispatcher::i()->module->key : '';
$this->data['current_controller'] = \IPS\Dispatcher::i()->controller;
$this->data['current_id'] = intval( \IPS\Request::i()->id );
$this->data['current_id'] = \intval( \IPS\Request::i()->id );
}
/**
@@ -415,7 +501,7 @@ class _Front extends \IPS\Session
$this->data['location_url'] = (string) $url;
$this->data['location_lang'] = $lang;
$this->data['location_data'] = json_encode( $data );
$this->data['current_id'] = intval( \IPS\Request::i()->id );
$this->data['current_id'] = \intval( \IPS\Request::i()->id );
if ( !$this->data['current_appcomponent'] )
{
@@ -428,7 +514,7 @@ class _Front extends \IPS\Session
$groupIds = (string) $groupIds;
}
$groupIds = is_string( $groupIds ) ? explode( ',', $groupIds ) : ( $groupIds ?: NULL );
$groupIds = \is_string( $groupIds ) ? explode( ',', $groupIds ) : ( $groupIds ?: NULL );
$app = \IPS\Application::load( $this->data['current_appcomponent'] );
if ( !$app->enabled )
@@ -442,7 +528,7 @@ class _Front extends \IPS\Session
$groupIds = $groupIds ? array_intersect( $groupIds, explode( ',', $modulePermissions['perm_view'] ) ) : explode( ',', $modulePermissions['perm_view'] );
}
$this->data['location_permissions'] = ( $groupIds !== NULL ) ? ( is_string( $groupIds ) ? $groupIds : implode( ',', $groupIds ) ) : NULL;
$this->data['location_permissions'] = ( $groupIds !== NULL ) ? ( \is_string( $groupIds ) ? $groupIds : implode( ',', $groupIds ) ) : NULL;
$this->save = TRUE;
}
@@ -496,6 +582,11 @@ class _Front extends \IPS\Session
*/
public function setType( $type )
{
if ( $this->data['login_type'] !== $type )
{
$this->save = TRUE;
}
switch ( $type )
{
case static::LOGIN_TYPE_MEMBER:
@@ -570,4 +661,47 @@ class _Front extends \IPS\Session
static::clearSessions( $lifetime );
return TRUE;
}
/**
* Sets up a session that doesn't require a DB read or write
*
* @return array
*/
protected function setNoWriteGuestSession()
{
$this->noWriteGuestSession = TRUE;
$this->member = new \IPS\Member;
/* Set data */
$this->data = array(
'id' => $this->sessionId,
'member_name' => '',
'seo_name' => '',
'member_id' => 0,
'ip_address' => \IPS\Request::i()->ipAddress(),
'browser' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '',
'running_time' => time(),
'login_type' => $this->userAgent->spider ? static::LOGIN_TYPE_SPIDER : static::LOGIN_TYPE_GUEST,
'member_group' => \IPS\Settings::i()->guest_group,
'current_appcomponent' => '',
'current_module' => '',
'current_controller' => NULL,
'current_id' => \intval( \IPS\Request::i()->id ),
'uagent_key' => $this->userAgent->browser ?: '',
'uagent_version' => $this->userAgent->browserVersion ?: '',
'uagent_type' => $this->userAgent->spider ? 'search' : 'browser',
'search_thread_id' => 0,
'search_thread_time' => 0,
'data' => '',
'location_url' => NULL,
'location_lang' => NULL,
'location_data' => NULL,
'location_permissions' => NULL,
'theme_id' => isset( \IPS\Request::i()->cookie['theme'] ) ? \IPS\Request::i()->cookie['theme'] : 0,
'in_editor' => 0,
);
return $this->data;
}
}