Version 4.7.0
This commit is contained in:
1 parent
517a5e1f70
commit
8ba7d43898
1933 files changed
+65613
-11332
No files matched your search
+216
-85
@@ -191,83 +191,15 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
|
||||
/* Do we need more info from the member or do they need to validate? */
|
||||
|
||||
/* This controllers should always be accessible, no matter if the member is awaiting validation or needs to set up the email or name */
|
||||
$legalControllers = array( 'privacy', 'contact', 'terms', 'embed', 'metatags', 'store', 'checkout', 'subscriptions' );
|
||||
/* These controllers should always be accessible, no matter if the member is awaiting validation or needs to set up the email or name */
|
||||
$legalControllers = array( 'privacy', 'contact', 'terms', 'embed', 'metatags', 'subscriptions', 'serviceworker', 'settings' );
|
||||
|
||||
/* Do we need more info from the member or do they need to validate? */
|
||||
if( \IPS\Member::loggedIn()->member_id and $this->controller !== 'language' and $this->controller !== 'theme' and $this->controller !== 'ajax' and !\in_array( $this->controller, $legalControllers ) )
|
||||
{
|
||||
/* Need their name or email... */
|
||||
if( ( \IPS\Member::loggedIn()->real_name === '' or !\IPS\Member::loggedIn()->email ) and $this->controller !== 'register' and $this->controller !== 'login' )
|
||||
if ( $url = static::doMemberCheck() )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=complete' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
/* Need them to validate... */
|
||||
elseif( \IPS\Member::loggedIn()->members_bitoptions['validating'] and $this->controller !== 'register' and $this->controller !== 'login' and $this->controller != 'redirect' )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=validating', 'front', 'register' ) );
|
||||
}
|
||||
/* Need them to reconfirm terms/privacy policy... */
|
||||
elseif ( ( \IPS\Member::loggedIn()->members_bitoptions['must_reaccept_privacy'] or \IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] ) and $this->controller !== 'register' and $this->controller !== 'ajax' )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=reconfirm', 'front', 'register' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
/* Have required profile actions that need completing */
|
||||
else if ( \IPS\Settings::i()->quick_register AND !\IPS\Member::loggedIn()->members_bitoptions['profile_completed'] AND !\in_array( $this->controller, array( 'register', 'login', 'redirect', 'ajax', 'settings', 'checkout', 'pixabay', 'editor' ) ) AND $completion = \IPS\Member::loggedIn()->profileCompletion() AND \count( $completion['required'] ) )
|
||||
{
|
||||
foreach( $completion['required'] AS $id => $completed )
|
||||
{
|
||||
if ( $completed === FALSE )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=register&do=finish&_new=1", 'front', 'register' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Need to set up MFA... */
|
||||
if ( !\in_array( $this->controller, array( 'register', 'login', 'redirect', 'ajax', 'settings', 'embed' ) ) )
|
||||
{
|
||||
$haveAcceptableHandlers = FALSE;
|
||||
$haveConfiguredHandler = FALSE;
|
||||
foreach ( \IPS\MFA\MFAHandler::handlers() as $key => $handler )
|
||||
{
|
||||
if ( $handler->isEnabled() and $handler->memberCanUseHandler( \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
$haveAcceptableHandlers = TRUE;
|
||||
if ( $handler->memberHasConfiguredHandler( \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
$haveConfiguredHandler = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$haveConfiguredHandler and $haveAcceptableHandlers )
|
||||
{
|
||||
if ( \IPS\Settings::i()->mfa_required_groups == '*' or \IPS\Member::loggedIn()->inGroup( explode( ',', \IPS\Settings::i()->mfa_required_groups ) ) )
|
||||
{
|
||||
if ( \IPS\Settings::i()->mfa_required_prompt === 'immediate' )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&do=initialMfa', 'front', 'settings' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
}
|
||||
elseif ( \IPS\Settings::i()->mfa_optional_prompt === 'immediate' and !\IPS\Member::loggedIn()->members_bitoptions['security_questions_opt_out'] )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&do=initialMfa', 'front', 'settings' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Need to reset password */
|
||||
if ( $this->controller !== 'settings' AND ( !isset( \IPS\Request::i()->area ) OR \IPS\Request::i()->area !== 'password' ) )
|
||||
{
|
||||
foreach( \IPS\Login::methods() AS $method )
|
||||
{
|
||||
if ( $url = $method->forcePasswordResetUrl( \IPS\Member::loggedIn(), \IPS\Request::i()->url() ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
}
|
||||
}
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +219,10 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
{
|
||||
\IPS\Output::i()->error( 'requested_route_404', '2S160/5', 404, '' );
|
||||
}
|
||||
|
||||
|
||||
/* Set up isAnonymous variable for realtime */
|
||||
\IPS\Output::i()->jsVars['isAnonymous'] = (bool) \IPS\Member::loggedIn()->isOnlineAnonymously();
|
||||
|
||||
/* Stuff for output */
|
||||
if ( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
@@ -356,7 +291,7 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
if ( \IPS\Settings::i()->use_friendly_urls )
|
||||
{
|
||||
$url = \IPS\Request::i()->url();
|
||||
|
||||
|
||||
/* Redirect to the "correct" friendly URL if there is one */
|
||||
if ( !\IPS\Request::i()->isAjax() and mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'get' and !\IPS\ENFORCE_ACCESS )
|
||||
{
|
||||
@@ -368,13 +303,23 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
$correctUrl = $url->correctFriendlyUrl();
|
||||
}
|
||||
|
||||
/* If they are accessing "index.php/whatever", we want "index.php?/whatever */
|
||||
if ( !( $correctUrl instanceof \IPS\Http\Url ) and $url instanceof \IPS\Http\Url\Internal and mb_strpos( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], '/index.php/' ) !== FALSE )
|
||||
|
||||
if ( !( $correctUrl instanceof \IPS\Http\Url ) and $url instanceof \IPS\Http\Url\Internal )
|
||||
{
|
||||
$pathFromBaseUrl = ltrim( mb_substr( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], mb_strlen( \IPS\Http\Url::internal('')->data[ \IPS\Http\Url::COMPONENT_PATH ] ) ), '/' );
|
||||
if ( mb_substr( $pathFromBaseUrl, 0, 10 ) === 'index.php/' )
|
||||
|
||||
/* If they are accessing "index.php/whatever", we want "index.php?/whatever */
|
||||
if ( mb_strpos( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], '/index.php/' ) !== FALSE )
|
||||
{
|
||||
$correctUrl = \IPS\Http\Url\Friendly::friendlyUrlFromComponent( 0, trim( mb_substr( $pathFromBaseUrl, 10 ), '/' ), $url->queryString );
|
||||
if ( mb_substr( $pathFromBaseUrl, 0, 10 ) === 'index.php/' )
|
||||
{
|
||||
$correctUrl = \IPS\Http\Url\Friendly::friendlyUrlFromComponent( 0, trim( mb_substr( $pathFromBaseUrl, 10 ), '/' ), $url->queryString );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If necessary, return any special cases like the robots.txt file */
|
||||
$this->customResponse( $pathFromBaseUrl );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,16 +396,20 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
protected function checkCached()
|
||||
{
|
||||
/* If this is a guest and there's a full cached page, we can serve that */
|
||||
if( mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'get' and !isset( \IPS\Request::i()->csrfKey ) and !isset( \IPS\Request::i()->_mfaLogin ) and !\IPS\Session\Front::loggedIn() and !isset( \IPS\Request::i()->cookie['noCache'] ) and \IPS\CACHE_PAGE_TIMEOUT )
|
||||
if( mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'get' AND !isset( \IPS\Request::i()->csrfKey ) AND !isset( \IPS\Request::i()->_mfaLogin ) AND !\IPS\Session\Front::loggedIn() AND !isset( \IPS\Request::i()->cookie['noCache'] ) AND \IPS\CACHE_PAGE_TIMEOUT )
|
||||
{
|
||||
/* Check whether a 304 Not modified response is appropriate */
|
||||
if( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) AND ( new \IPS\DateTime( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) )->getTimestamp() > ( time() - \IPS\CACHE_PAGE_TIMEOUT ) )
|
||||
try
|
||||
{
|
||||
/* This is intentionally using PHP methods to avoid database connections */
|
||||
$this->destruct = false;
|
||||
header('HTTP/1.1 304 Not Modified' );
|
||||
exit;
|
||||
if( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) AND ( new \IPS\DateTime( \rtrim( $_SERVER['HTTP_IF_MODIFIED_SINCE'], ';' ) ) )->getTimestamp() > ( time() - \IPS\CACHE_PAGE_TIMEOUT ) )
|
||||
{
|
||||
/* This is intentionally using PHP methods to avoid database connections */
|
||||
$this->destruct = false;
|
||||
header('HTTP/1.1 304 Not Modified' );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
/* Only check the output cache if it is enabled */
|
||||
if( empty( \IPS\OUTPUT_CACHE_METHOD ) OR ( !empty( \IPS\OUTPUT_CACHE_METHOD ) AND \IPS\OUTPUT_CACHE_METHOD == 'None' ) )
|
||||
@@ -660,18 +609,24 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
}
|
||||
}
|
||||
|
||||
/* Do things if we're actively using the easy theme editor */
|
||||
\IPS\Theme::easyModePreOutput();
|
||||
|
||||
/* Meta tags */
|
||||
\IPS\Output::i()->buildMetaTags();
|
||||
|
||||
/* Check MFA */
|
||||
$this->checkMfa();
|
||||
|
||||
/* Check Alerts */
|
||||
$this->checkAlerts();
|
||||
|
||||
/* Finish */
|
||||
parent::finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check MFA to see if we need to supply a code
|
||||
* Check MFA to see if we need to supply a code. If the member elected to cancel, cancel (and redirect) here
|
||||
*
|
||||
* @param boolean $return Return any HTML (true) or add to Output (false)
|
||||
*
|
||||
@@ -685,6 +640,37 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
$device = \IPS\Member\Device::loadOrCreate( $member, FALSE );
|
||||
if ( $output = \IPS\MFA\MFAHandler::accessToArea( 'core', $device->known ? 'AuthenticateFrontKnown' : 'AuthenticateFront', \IPS\Request::i()->url(), $member ) )
|
||||
{
|
||||
/* Did we just cancel? */
|
||||
if ( \IPS\Request::i()->_mfaCancel and ( ! \IPS\Member::loggedIn()->member_id or ( \IPS\Member::loggedIn()->member_id === $member->member_id ) ) )
|
||||
{
|
||||
/* We don't need this until we re-enter the MFA flow again */
|
||||
unset( $_SESSION['processing2FA'] );
|
||||
|
||||
/* Is MFA required for this member? */
|
||||
$mfaRequired = \IPS\Settings::i()->mfa_required_groups === '*' or $member->inGroup( explode( ',', \IPS\Settings::i()->mfa_required_groups ) );
|
||||
|
||||
/* Does this member require MFA upon login? */
|
||||
$logout = \IPS\Settings::i()->mfa_required_prompt === 'immediate' and $mfaRequired;
|
||||
|
||||
/* Can they see this page without MFA? */
|
||||
if ( !$mfaRequired OR ( $logout and $this->application->allowGuestAccess( $this->module, $this->controller, \IPS\Request::i()->do ) ) )
|
||||
{
|
||||
$redirectUrl = \IPS\Request::i()->url()->stripQueryString([ '_mfaCancel', '_mfaLogin', '_fromLogin', 'csrfKey' ]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$redirectUrl = \IPS\Http\Url::internal( '' );
|
||||
}
|
||||
|
||||
if ( $logout )
|
||||
{
|
||||
\IPS\Login::logout( $redirectUrl );
|
||||
$redirectUrl = $redirectUrl->setQueryString( '_fromLogout', 1 );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $redirectUrl );
|
||||
}
|
||||
|
||||
if ( $return )
|
||||
{
|
||||
return $output;
|
||||
@@ -699,6 +685,103 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a robots.txt file if configured to do so
|
||||
*
|
||||
* @param string $pathFromBaseUrl
|
||||
*/
|
||||
public function customResponse( string $pathFromBaseUrl )
|
||||
{
|
||||
if ( $pathFromBaseUrl === 'robots.txt' )
|
||||
{
|
||||
$this->robotsTxt();
|
||||
}
|
||||
else if ( \IPS\core\IndexNow::i()->isEnabled() AND $pathFromBaseUrl === \IPS\core\IndexNow::i()->getKeyFileName() )
|
||||
{
|
||||
$this->indexNow();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IndexNow key.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function indexNow()
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( \IPS\core\IndexNow::i()->getKeyfileContent(), 200, 'text/plain' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the robots.txt files
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function robotsTxt()
|
||||
{
|
||||
if ( \IPS\Settings::i()->robots_txt == 'default' )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( static::robotsTxtRules(), 200, 'text/plain' );
|
||||
}
|
||||
else if ( \IPS\Settings::i()->robots_txt != 'off' )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( \IPS\Settings::i()->robots_txt, 200, 'text/plain' );
|
||||
}
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the text for the robots.txt file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function robotsTxtRules(): string
|
||||
{
|
||||
$path = str_replace( '//', '/', '/' . trim( str_replace( 'robots.txt', '', \IPS\Http\Url::createFromString( \IPS\Http\Url::baseUrl() )->data[ \IPS\Http\Url::COMPONENT_PATH ] ), '/' ) . '/' );
|
||||
|
||||
$content = <<<FILE
|
||||
# Rules for Invision Community (https://invisioncommunity.com)
|
||||
User-Agent: *
|
||||
# Block pages with no unique content
|
||||
Disallow: {$path}startTopic/
|
||||
Disallow: {$path}discover/unread/
|
||||
Disallow: {$path}markallread/
|
||||
Disallow: {$path}staff/
|
||||
Disallow: {$path}online/
|
||||
Disallow: {$path}discover/
|
||||
Disallow: {$path}leaderboard/
|
||||
Disallow: {$path}search/
|
||||
Disallow: {$path}*?advancedSearchForm=
|
||||
Disallow: {$path}register/
|
||||
Disallow: {$path}lostpassword/
|
||||
Disallow: {$path}login/
|
||||
|
||||
# Block faceted pages and 301 redirect pages
|
||||
Disallow: {$path}*?sortby=
|
||||
Disallow: {$path}*?filter=
|
||||
Disallow: {$path}*?tab=
|
||||
Disallow: {$path}*?do=
|
||||
Disallow: {$path}*ref=
|
||||
Disallow: {$path}*?forumId*
|
||||
|
||||
# Block profile pages as these have little unique value, consume a lot of crawl time and contain hundreds of 301 links
|
||||
Disallow: {$path}profile/
|
||||
|
||||
FILE;
|
||||
|
||||
if ( \IPS\Settings::i()->sitemap_url )
|
||||
{
|
||||
$siteMapUrl = ( \IPS\Settings::i()->sitemap_url ) ? rtrim( \IPS\Settings::i()->sitemap_url, '/' ) : rtrim( \IPS\Settings::i()->base_url, '/' ) . '/sitemap.php';
|
||||
$content .= <<<FILE
|
||||
|
||||
# Sitemap URL
|
||||
Sitemap: {$siteMapUrl}
|
||||
FILE;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the basic javascript files every page needs
|
||||
*
|
||||
@@ -712,6 +795,10 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
if ( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->globalControllers[] = 'core.front.core.app';
|
||||
if ( \IPS\Settings::i()->core_datalayer_enabled )
|
||||
{
|
||||
\IPS\Output::i()->globalControllers[] = 'core.front.core.dataLayer';
|
||||
}
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front.js' ) );
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_core.js', 'core', 'front' ) );
|
||||
|
||||
@@ -777,4 +864,48 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do Member Check
|
||||
*
|
||||
* @return \IPS\Http\Url|NULL
|
||||
*/
|
||||
protected static function doMemberCheck(): ?\IPS\Http\Url
|
||||
{
|
||||
foreach( \IPS\Application::applications() AS $app )
|
||||
{
|
||||
if ( $url = $app->doMemberCheck() )
|
||||
{
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function checkAlerts()
|
||||
{
|
||||
/* Don't get in the way of validating members */
|
||||
if ( \IPS\Member::loggedIn()->members_bitoptions['validating'] )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't get in the way of the ModCP, registering, logging in, etc */
|
||||
$ignoreControllers = [ 'modcp', 'register', 'login', 'redirect' ];
|
||||
if( !\IPS\Request::i()->isAjax() and !\in_array( $this->controller, $ignoreControllers ) AND $alert = \IPS\core\Alerts\Alert::getNextAlertForMember( \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
$alert->viewed( \IPS\Member::loggedIn() );
|
||||
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/alerts.css', 'core', 'front' ) );
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'alerts', 'core', 'front' )->alertModal( $alert, $url = base64_encode( \IPS\Request::i()->url() ) );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user