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

+71 -15
View File
@@ -2,9 +2,9 @@
/**
* @brief AJAX actions
* @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 04 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -26,7 +26,7 @@ class _ajax extends \IPS\Dispatcher\Controller
/**
* Find Member
*
* @retun void
* @return void
*/
public function findMember()
{
@@ -57,8 +57,8 @@ class _ajax extends \IPS\Dispatcher\Controller
$results[] = array(
'id' => $member->member_id,
'value' => $member->name,
'name' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? $member->group['prefix'] . htmlspecialchars( $member->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) . $member->group['suffix'] : htmlspecialchars( $member->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'extra' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? $member->email : $member->groupName,
'name' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? $member->group['prefix'] . htmlspecialchars( $member->name, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) . $member->group['suffix'] : htmlspecialchars( $member->name, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'extra' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? htmlspecialchars( $member->email, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) : $member->groupName,
'photo' => (string) $member->photo,
);
}
@@ -83,6 +83,10 @@ class _ajax extends \IPS\Dispatcher\Controller
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('form_required') );
}
elseif ( mb_strlen( $name ) < \IPS\Settings::i()->min_user_name_length )
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack( 'form_minlength', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->min_user_name_length ) ) ) );
}
elseif ( mb_strlen( $name ) > \IPS\Settings::i()->max_user_name_length )
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack( 'form_maxlength', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->max_user_name_length ) ) ) );
@@ -102,10 +106,12 @@ class _ajax extends \IPS\Dispatcher\Controller
if ( \IPS\Member::loggedIn()->isAdmin() )
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('member_name_exists_admin', FALSE, array( 'sprintf' => array( $k ) ) ) );
break;
}
else
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('member_name_exists') );
break;
}
}
}
@@ -119,6 +125,7 @@ class _ajax extends \IPS\Dispatcher\Controller
if( preg_match( '/^' . str_replace( '\*', '.*', preg_quote( $bannedName, '/' ) ) . '$/i', $name ) )
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('form_name_banned') );
break;
}
}
}
@@ -167,6 +174,19 @@ class _ajax extends \IPS\Dispatcher\Controller
}
}
/* Check it's not banned */
if ( $result == array( 'result' => 'ok' ) )
{
foreach( \IPS\Db::i()->select( 'ban_content', 'core_banfilters', array("ban_type=?", 'email') ) as $bannedEmail )
{
if( preg_match( '/^' . str_replace( '\*', '.*', preg_quote( $bannedEmail, '/' ) ) . '$/i', $email ) )
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('form_email_banned') );
break;
}
}
}
\IPS\Output::i()->json( $result );
}
@@ -204,19 +224,21 @@ class _ajax extends \IPS\Dispatcher\Controller
switch ( \IPS\Request::i()->time )
{
case 'week':
$where[] = array( 'rep_date>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1W' ) )->getTimestamp() );
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1W' ) )->getTimestamp() );
$timeframe = 'week';
break;
case 'month':
$where[] = array( 'rep_date>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1M' ) )->getTimestamp() );
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1M' ) )->getTimestamp() );
$timeframe = 'month';
break;
case 'year':
$where[] = array( 'rep_date>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1Y' ) )->getTimestamp() );
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1Y' ) )->getTimestamp() );
$timeframe = 'year';
break;
}
$topContributors = iterator_to_array( \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', $where, 'rep DESC', $limit, 'member' )->setKeyField('member')->setValueField('rep') );
$innerQuery = \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', $where, NULL, NULL, 'member' );
$topContributors = iterator_to_array( \IPS\Db::i()->select( 'member, rep', array( $innerQuery, 'in' ), NULL, 'rep DESC', $limit )->setKeyField('member')->setValueField('rep') );
}
else
{
@@ -237,6 +259,7 @@ class _ajax extends \IPS\Dispatcher\Controller
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'block_topContributors' );
\IPS\Output::i()->output = $output;
}
}
@@ -261,7 +284,7 @@ class _ajax extends \IPS\Dispatcher\Controller
/**
* Instant Notifications
*
* @retun void
* @return void
*/
public function instantNotifications()
{
@@ -272,7 +295,7 @@ class _ajax extends \IPS\Dispatcher\Controller
return;
}
/* Get the intitial counts */
/* Get the initial counts */
$return = array( 'notifications' => array( 'count' => \IPS\Member::loggedIn()->notification_cnt, 'data' => array() ), 'messages' => array( 'count' => \IPS\Member::loggedIn()->msg_count_new, 'data' => array() ) );
/* If there's new notifications, get the actual data */
@@ -280,15 +303,29 @@ class _ajax extends \IPS\Dispatcher\Controller
{
$notificationsDifference = $return['notifications']['count'] - \IPS\Request::i()->notifications;
/* Cap at 200 to prevent DOSing the server when there are like 1000+ notifications to send */
if( $notificationsDifference > 200 )
{
$notificationsDifference = 200;
}
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_notifications', array( 'member=? AND ( read_time IS NULL OR read_time<? )', \IPS\Member::loggedIn()->member_id, time() ), 'updated_time DESC', $notificationsDifference ), 'IPS\Notification\Inline' ) as $notification )
{
$data = $notification->getData();
/* It is possible that the content has been removed after the iterator has started but before we fetch the data */
try
{
$data = $notification->getData();
}
catch( \OutOfRangeException $e )
{
continue;
}
$return['notifications']['data'][] = array(
'id' => $notification->id,
'title' => $data['title'],
'title' => htmlspecialchars( $data['title'], \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'url' => (string) $data['url'],
'content' => isset( $data['content'] ) ? $data['content'] : NULL,
'content' => isset( $data['content'] ) ? htmlspecialchars( $data['content'], \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : NULL,
'date' => $notification->updated_time->getTimestamp(),
'author_photo' => $data['author'] ? $data['author']->photo : NULL
);
@@ -309,7 +346,7 @@ class _ajax extends \IPS\Dispatcher\Controller
$return['messages']['data'][] = array(
'id' => $conversation->id,
'title' => $conversation->title,
'title' => htmlspecialchars( $conversation->title, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'url' => (string) $conversation->url()->setQueryString( 'latest', 1 ),
'message' => $message->truncated(),
'date' => $message->mapped('date'),
@@ -322,4 +359,23 @@ class _ajax extends \IPS\Dispatcher\Controller
/* And return */
\IPS\Output::i()->json( $return );
}
/**
* Returns score in json indicating the strength of a password
*
* @return void
*/
public function passwordStrength()
{
/* The value comes urlencoded so we need to decode so length is correct (and not using a percent-encoded value) */
$password = urldecode( \IPS\Request::i()->input );
require_once \IPS\ROOT_PATH . "/system/3rd_party/phpass/phpass.php";
$phpass = new \PasswordStrength();
$response = array( 'result' => 'ok', 'score' => $phpass->classify( $password ), 'granular' => $phpass->calculate( $password ) );
\IPS\Output::i()->json( $response );
}
}
@@ -2,9 +2,9 @@
/**
* @brief Announcement
* @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 09 Oct 2013
* @version SVN_VERSION_NUMBER
*/
@@ -46,6 +46,11 @@ class _announcement extends \IPS\Content\Controller
{
\IPS\Output::i()->error( 'announcement_missing', '2C199/1', 404, '' );
}
if ( !$announcement->canView() )
{
\IPS\Output::i()->error( 'node_error_no_perm', '2C199/2', 403, '' );
}
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=announcement&id=' . $announcement->id, NULL, 'announcement', $announcement->seo_title ), array(), 'loc_viewing_announcement', array( $announcement->title => FALSE ) );
@@ -2,9 +2,9 @@
/**
* @brief My Attachments Controller
* @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 22 Jul 2013
* @version SVN_VERSION_NUMBER
*/
@@ -64,36 +64,6 @@ class _attachments extends \IPS\Dispatcher\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('myAttachments')->template( (string) $table, \IPS\Db::i()->select( 'SUM(attach_filesize)', 'core_attachments', array( 'attach_member_id=?', \IPS\Member::loggedIn()->member_id ) )->first(), \IPS\Db::i()->select( 'COUNT(*)', 'core_attachments', array( 'attach_member_id=?', \IPS\Member::loggedIn()->member_id ) )->first() );
}
/**
* Lookup
*
* @return void
*/
public function lookup()
{
/* Load and check permission */
try
{
$attachment = \IPS\Db::i()->select( '*', 'core_attachments', array( 'attach_id=?', \IPS\Request::i()->id ) )->first();
}
catch ( \UnderflowException $e )
{
\IPS\Output::i()->error( 'node_error', '2C229/6', 404, '' );
}
/* Check it belongs to us */
if ( $attachment['attach_member_id'] !== \IPS\Member::loggedIn()->member_id or !\IPS\Member::loggedIn()->group['gbw_delete_attachments'] )
{
\IPS\Output::i()->error( 'no_module_permission', '2C229/7', 403, '' );
}
/* Display */
\IPS\Output::i()->title = $attachment['attach_file'];
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=system&controller=attachments', 'front', 'attachments' ), \IPS\Member::loggedIn()->language()->addToStack('my_attachments') );
\IPS\Output::i()->breadcrumb[] = array( NULL, $attachment['attach_file'] );
\IPS\Output::i()->output = $this->_getLocations( $attachment['attach_id'] );
}
/**
* Delete
*
@@ -103,6 +73,9 @@ class _attachments extends \IPS\Dispatcher\Controller
{
/* Security check */
\IPS\Session::i()->csrfCheck();
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Load and check permission */
try
@@ -152,6 +125,5 @@ class _attachments extends \IPS\Dispatcher\Controller
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=attachments', 'front', 'attachments' ) );
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief "Content" functions Controller
* @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 29 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -44,10 +44,9 @@ class _content extends \IPS\Dispatcher\Controller
try
{
$item = $class::load( \IPS\Request::i()->content_id );
$commentClass = $class::$commentClass;
$comment = $commentClass::load( \IPS\Request::i()->content_commentid );
$item = $comment->item();
}
catch( \OutOfRangeException $ex )
{
@@ -55,7 +54,7 @@ class _content extends \IPS\Dispatcher\Controller
}
/* Make sure we have permission to see this */
if ( ( $comment->item()->tid == $item->tid ) AND $item->canView() AND $comment->canView() )
if ( $item->canView() AND $comment->canView() )
{
\IPS\Output::i()->redirect( $comment->url() );
}
@@ -64,5 +63,4 @@ class _content extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'node_error', '2S226/4', 404, '' );
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief Designer mode controller
* @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 07 Aug 2013
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Editor AJAX functions Controller
* @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 29 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -23,6 +23,17 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _editor extends \IPS\Dispatcher\Controller
{
/**
* Preview iframe
*
* @return void
*/
protected function preview()
{
$output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->preview( \IPS\Request::i()->editor_id );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $output ) );
}
/**
* Link Dialog
*
@@ -41,7 +52,7 @@ class _editor extends \IPS\Dispatcher\Controller
protected function code()
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'codemirror/codemirror.css', 'core', 'interface' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->code( \IPS\Request::i()->val, \IPS\Request::i()->editorId, md5( uniqid() ), \IPS\Request::i()->lang ?: 'html' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->code( \IPS\Request::i()->val, \IPS\Request::i()->editorId, md5( uniqid() ), \IPS\Request::i()->lang ?: '' );
}
/**
@@ -53,21 +64,23 @@ class _editor extends \IPS\Dispatcher\Controller
{
$maxImageDims = \IPS\Settings::i()->attachment_image_size ? explode( 'x', \IPS\Settings::i()->attachment_image_size ) : array( 1000, 750 );
$maxWidth = ( \IPS\Request::i()->actualWidth < $maxImageDims[0] ) ? \IPS\Request::i()->actualWidth : $maxImageDims[0];
$maxHeight = ( \IPS\Request::i()->actualHeight < $maxImageDims[1] ) ? \IPS\Request::i()->actualHeight : $maxImageDims[1];
$ratio = round( \IPS\Request::i()->height / \IPS\Request::i()->width, 2 );
$maxHeight = ( \IPS\Request::i()->actualHeight < $maxImageDims[1] ) ? \IPS\Request::i()->actualHeight : $maxImageDims[1];
$ratioH = round( \IPS\Request::i()->height / \IPS\Request::i()->width, 2 );
$ratioW = round( \IPS\Request::i()->width / \IPS\Request::i()->height, 2 );
if ( \IPS\Request::i()->width > $maxWidth )
{
\IPS\Request::i()->width = $maxWidth;
\IPS\Request::i()->height = floor( \IPS\Request::i()->width * $ratio );
\IPS\Request::i()->height = floor( \IPS\Request::i()->width * $ratioH );
}
if ( \IPS\Request::i()->height > $maxHeight )
{
\IPS\Request::i()->height = $maxHeight;
\IPS\Request::i()->width = floor( \IPS\Request::i()->height * $ratio );
\IPS\Request::i()->width = floor( \IPS\Request::i()->height * $ratioW );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->image( \IPS\Request::i()->editorId, \IPS\Request::i()->width, \IPS\Request::i()->height, $maxWidth, $maxHeight, \IPS\Request::i()->float, \IPS\Request::i()->link, $ratio );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->image( \IPS\Request::i()->editorId, \IPS\Request::i()->width, \IPS\Request::i()->height, $maxWidth, $maxHeight, \IPS\Request::i()->float, \IPS\Request::i()->link, $ratioW, $ratioH, urldecode( \IPS\Request::i()->imageAlt ) );
}
/**
@@ -77,48 +90,87 @@ class _editor extends \IPS\Dispatcher\Controller
*/
protected function validateLink()
{
/* CSRF check */
\IPS\Session::i()->csrfCheck();
/* Have we recently checked and validated this link? */
$cacheKey = md5( \IPS\Request::i()->url . (bool) \IPS\Request::i()->noEmbed . (bool) \IPS\Request::i()->image . \IPS\Member::loggedIn()->language()->id );
try
{
$title = NULL;
$isEmbed = FALSE;
$url = \IPS\Request::i()->url;
if ( !\IPS\Request::i()->noEmbed and !\IPS\Request::i()->image and $embed = \IPS\Text\Parser::embeddableMedia( $url ) )
$cachedResult = \IPS\Data\Cache::i()->getWithExpire( $cacheKey, TRUE );
\IPS\Output::i()->json( $cachedResult );
}
catch( \OutOfRangeException $e ){}
/* Fetch the result and cache it, then return it */
try
{
$title = NULL;
$isEmbed = FALSE;
$url = \IPS\Http\Url::createFromString( \IPS\Request::i()->url, TRUE, TRUE );
$embed = NULL;
$error = NULL;
if ( !\IPS\Request::i()->noEmbed )
{
$insert = $embed;
$isEmbed = TRUE;
}
else
{
$response = \IPS\Http\Url::external( $url )->request()->get();
if ( \IPS\Request::i()->image and isset( $response->httpHeaders['Content-Type'] ) and mb_substr( $response->httpHeaders['Content-Type'], 0, 6 ) === 'image/' )
{
$insert = "<img src='{$url}' class='ipsImage'>";
}
else
try
{
if ( \IPS\Request::i()->image )
{
throw new \DomainException;
}
if ( \IPS\Request::i()->title )
{
$title = \IPS\Request::i()->title;
}
elseif ( isset( $response->httpHeaders['Content-Type'] ) and mb_substr( $response->httpHeaders['Content-Type'], 0, 9 ) === 'text/html' and preg_match( '/<title>(.+)<\/title>/', $response, $matches ) and isset( $matches[1] ) )
{
$title = $matches[1];
$embed = \IPS\Text\Parser::_imageEmbed( $url, FALSE, TRUE );
}
else
{
$title = $url;
$embed = \IPS\Text\Parser::embeddableMedia( $url );
}
$insert = "<a href='{$url}' ipsNoEmbed='true'>{$title}</a>";
}
catch( \UnexpectedValueException $e )
{
switch( $e->getMessage() )
{
case 'embed__fail_404':
$error = \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage(), FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->get( 'embed__fail_' . $e->getCode() ) ) ) );
break;
case 'embed__fail_403':
$error = \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage(), FALSE, array( 'sprintf' => array( $url->data['host'], \IPS\Member::loggedIn()->language()->get( 'embed__fail_' . $e->getCode() ) ) ) );
break;
case 'embed__fail_500':
$error = \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage(), FALSE, array( 'sprintf' => array( $url->data['host'] ) ) );
break;
default:
$error = \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage() );
break;
}
}
catch ( \Exception $e ){ }
}
\IPS\Output::i()->json( array( 'preview' => trim( $insert ), 'title' => $title, 'embed' => $isEmbed ) );
if ( $embed OR $error )
{
$insert = $embed;
$isEmbed = $error ? FALSE : TRUE;
}
else
{
$title = \IPS\Request::i()->title ?: $url;
$insert = "<a href='{$url}' ipsNoEmbed='true'>{$title}</a>";
}
$result = array( 'preview' => trim( $insert ), 'title' => $title, 'embed' => $isEmbed, 'errorMessage' => $error ? \IPS\Member::loggedIn()->language()->addToStack( 'embed_failure_message', FALSE, array( 'sprintf' => array( $error ) ) ) : NULL );
if( $error )
{
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $result['errorMessage'] );
\IPS\Log::debug( $url . "\n" . $result['errorMessage'], 'embed_failure' );
}
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, $result, \IPS\DateTime::create()->add( new\DateInterval( 'PT10S' ) ), TRUE );
\IPS\Output::i()->json( $result );
}
catch ( \Exception $e )
{
@@ -184,13 +236,13 @@ class _editor extends \IPS\Dispatcher\Controller
$mediaSources[] = $k;
}
}
/* Work out what tab we're on */
if ( !\IPS\Request::i()->tab )
{
if( !count( $mediaSources ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C270/1', 403, '' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->myMedia( \IPS\Request::i()->editorId, $mediaSources, NULL, NULL, NULL );
return;
}
$sources = $mediaSources;
@@ -268,9 +320,12 @@ class _editor extends \IPS\Dispatcher\Controller
protected function mention()
{
$results = '';
foreach ( \IPS\Db::i()->select( '*', 'core_members', array( "name LIKE CONCAT( ?, '%' )", mb_strtolower( \IPS\Request::i()->input ) ), 'name', 10 ) as $row )
if ( mb_strlen( \IPS\Request::i()->input ) > 0 )
{
$results .= \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->mentionRow( \IPS\Member::constructFromData( $row ) );
foreach ( \IPS\Db::i()->select( '*', 'core_members', array( "name LIKE CONCAT( ?, '%' )", mb_strtolower( \IPS\Request::i()->input ) ), 'name', 10 ) as $row )
{
$results .= \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->mentionRow( \IPS\Member::constructFromData( $row ) );
}
}
\IPS\Output::i()->sendOutput( $results );
@@ -2,9 +2,9 @@
/**
* @brief Embed iframe display
* @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 15 Sep 2014
* @version SVN_VERSION_NUMBER
*/
@@ -29,7 +29,32 @@ class _embed extends \IPS\Content\Controller
* @return void
*/
protected function manage()
{
\IPS\Output::i()->sendOutput( \IPS\Text\Parser::embeddableMedia( \IPS\Request::i()->url, TRUE ), 200 );
{
/* Check cache */
$cacheKey = 'embed_' . md5( \IPS\Request::i()->url );
try
{
$return = \IPS\Data\Cache::i()->getWithExpire( $cacheKey, TRUE );
}
/* Not in cache - fetch */
catch ( \OutOfRangeException $e )
{
try
{
$return = \IPS\Text\Parser::embeddableMedia( \IPS\Http\Url::createFromString( \IPS\Request::i()->url, FALSE, TRUE ), TRUE );
}
catch( \UnexpectedValueException $e )
{
$return = '';
}
/* And cache */
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, $return, \IPS\DateTime::create()->add( new \DateInterval('P1D') ), TRUE );
}
/* Output */
$js = \IPS\Output::i()->js( 'js/embedHandler.js', 'core', 'interface' );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->embedExternal( $return, $js ), 200 );
}
}
@@ -2,9 +2,9 @@
/**
* @brief My followed content
* @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 16 Apr 2014
* @version SVN_VERSION_NUMBER
*/
@@ -109,6 +109,11 @@ class _followed extends \IPS\Dispatcher\Controller
else
{
/* Display */
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/followedcontent_responsive.css' ) );
}
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_system.js', 'core' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu_followed_content');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
@@ -2,9 +2,9 @@
/**
* @brief Guidelines
* @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 02 Sept 2013
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Ignore Preferences
* @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 20 Aug 2013
* @version SVN_VERSION_NUMBER
*/
@@ -106,7 +106,7 @@ class _ignore extends \IPS\Dispatcher\Controller
/* Display */
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('ignored_users') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('ignored_users');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->ignore( $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'system' ), 'ignoreForm' ) ), (string) $table );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->ignore( $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'system' ), 'ignoreForm' ) ), (string) $table, ( isset( \IPS\Request::i()->id ) ? \IPS\Request::i()->id : 0 ) );
}
/**
@@ -120,12 +120,13 @@ class _ignore extends \IPS\Dispatcher\Controller
try
{
$member = \IPS\Member::load( \IPS\Request::i()->name, 'name' );
/* We have to html_entity_decode because the javascript code sends the encoded name here */
$member = \IPS\Member::load( html_entity_decode( \IPS\Request::i()->name, ENT_QUOTES, 'UTF-8' ), 'name' );
/* If \IPS\Member::load() cannot find a member, it just creates a new guest object, never throwing the exception */
if ( !$member->member_id )
{
throw new \OutOfRangeException( 'user_does_not_exist' );
throw new \OutOfRangeException( 'cannot_ignore_no_user' );
}
if ( $member->member_id == \IPS\Member::loggedIn()->member_id )
@@ -133,7 +134,7 @@ class _ignore extends \IPS\Dispatcher\Controller
throw new \InvalidArgumentException( 'cannot_ignore_self' );
}
if ( $member->group['gbw_cannot_be_ignored'] )
if ( !$member->canBeIgnored() )
{
throw new \InvalidArgumentException( 'cannot_ignore_that_member' );
}
@@ -153,11 +154,7 @@ class _ignore extends \IPS\Dispatcher\Controller
\IPS\Output::i()->json( $data );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->json( $e->getMessage(), 404 );
}
catch( \InvalidArgumentException $e )
catch( \Exception $e )
{
\IPS\Output::i()->json( array( 'error' => \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage() ) ), 403 );
}
@@ -177,7 +174,7 @@ class _ignore extends \IPS\Dispatcher\Controller
/* If \IPS\Member::load() cannot find a member, it just creates a new guest object, never throwing the exception */
if ( !$member->member_id )
{
throw new \OutOfRangeException( 'user_does_not_exist' );
throw new \OutOfRangeException( 'cannot_ignore_no_user' );
}
if ( $member->member_id == \IPS\Member::loggedIn()->member_id )
@@ -185,7 +182,7 @@ class _ignore extends \IPS\Dispatcher\Controller
throw new \InvalidArgumentException( 'cannot_ignore_self' );
}
if ( $member->group['gbw_cannot_be_ignored'] )
if ( !$member->canBeIgnored() )
{
throw new \InvalidArgumentException( 'cannot_ignore_that_member' );
}
@@ -229,11 +226,7 @@ class _ignore extends \IPS\Dispatcher\Controller
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('add_ignored_user');
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'system' ), 'ignoreEditForm' ) );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->json( $e->getMessage(), 404 );
}
catch( \InvalidArgumentException $e )
catch( \Exception $e )
{
\IPS\Output::i()->json( \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage() ), 403 );
}
@@ -248,6 +241,9 @@ class _ignore extends \IPS\Dispatcher\Controller
{
\IPS\Session::i()->csrfCheck();
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$member = \IPS\Member::load( \IPS\Request::i()->id );
@@ -283,6 +279,8 @@ class _ignore extends \IPS\Dispatcher\Controller
*/
protected function ignoreType()
{
\IPS\Session::i()->csrfCheck();
try
{
if ( !in_array( \IPS\Request::i()->type, \IPS\core\Ignore::types() ) )
@@ -294,7 +292,7 @@ class _ignore extends \IPS\Dispatcher\Controller
if ( !$member->member_id )
{
throw new \OutOfRangeException( 'user_does_not_exist' );
throw new \OutOfRangeException( 'cannot_ignore_no_user' );
}
if ( $member->member_id == \IPS\Member::loggedIn()->member_id )
@@ -302,7 +300,7 @@ class _ignore extends \IPS\Dispatcher\Controller
throw new \InvalidArgumentException( 'cannot_ignore_self' );
}
if ( $member->group['gbw_cannot_be_ignored'] )
if ( !$member->canBeIgnored() )
{
throw new \InvalidArgumentException( 'cannot_ignore_that_member' );
}
@@ -337,18 +335,8 @@ class _ignore extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=ignore", 'front', 'ignore' ), 'ignore_adjusted' );
}
}
catch( \OutOfRangeException $e )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'error' => 'user_does_not_exist' ), 404 );
}
else
{
\IPS\Output::i()->error( 'user_does_not_exist', '2C146/3', 404, '' );
}
}
catch( \InvalidArgumentException $e )
catch( \Exception $e )
{
if ( \IPS\Request::i()->isAjax() )
{
@@ -2,9 +2,9 @@
/**
* @brief Language Changer
* @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 17 Dec 2013
* @version SVN_VERSION_NUMBER
*/
+135 -44
View File
@@ -2,9 +2,9 @@
/**
* @brief Login
* @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 7 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -46,29 +46,13 @@ class _login extends \IPS\Dispatcher\Controller
$login = new \IPS\Login( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) );
/* Process */
$error = isset( \IPS\Request::i()->_err ) ? \IPS\Request::i()->_err : NULL;
$error = isset( \IPS\Request::i()->_err ) && \IPS\Member::loggedIn()->language()->checkKeyExists( \IPS\Request::i()->_err ) ? \IPS\Request::i()->_err : NULL;
try
{
$member = $login->authenticate();
if ( $member !== NULL )
{
$this->_doLogin( $member, $login->flags['signin_anonymous'], $login->flags['remember_me'] );
if ( \IPS\Request::i()->isAjax() )
{
$response = array( 'status' => 'success' );
if( !empty( \IPS\Request::i()->ref ) )
{
$response['redirect'] = \IPS\Request::i()->ref;
}
\IPS\Output::i()->json( $response );
}
else
{
\IPS\Output::i()->redirect( \IPS\Login::getDestination()->setQueryString( '_fromLogin', 1 ) );
}
$this->_doLogin( $member, $login->flags['signin_anonymous'], $login->flags['remember_me'], \IPS\Login::getDestination() );
}
}
catch ( \IPS\Login\Exception $e )
@@ -78,7 +62,12 @@ class _login extends \IPS\Dispatcher\Controller
$e->member = $e->member->member_id;
$_SESSION['linkAccounts'] = json_encode( $e );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' ) );
$linkUrl = \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' );
if ( isset( \IPS\Request::i()->ref ) )
{
$linkUrl = $linkUrl->setQueryString( 'ref', \IPS\Request::i()->ref );
}
\IPS\Output::i()->redirect( $linkUrl );
}
$error = $e->getMessage();
@@ -105,25 +94,43 @@ class _login extends \IPS\Dispatcher\Controller
/**
* Process the login
*
* @param \IPS\Member $member The member
* @param bool $anonymous If the login is anonymous
* @param bool $rememberMe If the "remember me" checkbox was checked
* @param \IPS\Member $member The member
* @param bool $anonymous If the login is anonymous
* @param bool $rememberMe If the "remember me" checkbox was checked
* @param \IPS\Http\Url $destination Where to redirect to
* @param bool $bypass2FA If true, will not perform 2FA check
* @return void
*/
protected function _doLogin( $member, $anonymous=FALSE, $rememberMe=TRUE )
protected function _doLogin( $member, $anonymous=FALSE, $rememberMe=TRUE, $destination=NULL, $bypass2FA=FALSE )
{
/* Get destination */
if ( !$destination )
{
$destination = \IPS\Http\Url::internal( '' );
}
/* Do we need to do 2FA? */
if ( !$bypass2FA and $output = \IPS\MFA\MFAHandler::accessToArea( 'core', 'AuthenticateFront', \IPS\Http\Url::internal( '' ), $member ) )
{
$_SESSION['processing2FA'] = array( 'memberId' => $member->member_id, 'anonymous' => $anonymous, 'remember' => $rememberMe, 'destination' => (string) $destination );
\IPS\Output::i()->redirect( $destination->setQueryString( '_mfaLogin', 1 ) );
}
/* Set anonymous cookie */
if ( $anonymous and !\IPS\Settings::i()->disable_anonymous )
{
\IPS\Session::i()->setAnon();
\IPS\Request::i()->setCookie( 'anon_login', 1 );
}
/* Log in */
\IPS\Session::i()->setMember( $member );
/* Set remember me cookie */
if ( $rememberMe )
{
$expire = new \IPS\DateTime;
$expire->add( new \DateInterval( 'P7D' ) );
$expire->add( new \DateInterval( 'P3M' ) );
\IPS\Request::i()->setCookie( 'member_id', $member->member_id, $expire );
\IPS\Request::i()->setCookie( 'pass_hash', $member->member_login_key, $expire );
@@ -133,7 +140,65 @@ class _login extends \IPS\Dispatcher\Controller
}
}
/* Member sync */
$member->memberSync( 'onLogin', array( \IPS\Login::getDestination() ) );
/* Redirect */
\IPS\Output::i()->redirect( $destination->setQueryString( '_fromLogin', 1 ), '', 303 );
}
/**
* MFA
*
* @return void
*/
protected function mfa()
{
/* Have we logged in? */
$member = NULL;
if ( isset( $_SESSION['processing2FA'] ) )
{
$member = \IPS\Member::load( $_SESSION['processing2FA']['memberId'] );
}
if ( !$member->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) );
}
/* Where do we want to go? */
$destination = NULL;
try
{
$destination = \IPS\Http\Url::createFromString( $_SESSION['processing2FA']['destination'] );
}
catch ( \Exception $e ) { }
/* Have we already done 2FA? */
$output = \IPS\MFA\MFAHandler::accessToArea( 'core', 'AuthenticateFront', \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=mfa', 'front', 'login' ), $member );
if ( !$output )
{
$this->_doLogin( $member, $_SESSION['processing2FA']['anonymous'], $_SESSION['processing2FA']['remember'], $destination, TRUE );
}
/* Nope, just send us where we want to go not logged in */
$qs = array( '_mfaLogin' => 1 );
if ( isset( \IPS\Request::i()->_mfa ) )
{
$qs['_mfa'] = \IPS\Request::i()->_mfa;
if ( isset( \IPS\Request::i()->_mfaMethod ) )
{
$qs['_mfaMethod'] = \IPS\Request::i()->_mfaMethod;
}
}
elseif ( isset( \IPS\Request::i()->mfa_auth ) )
{
$qs['mfa_auth'] = \IPS\Request::i()->mfa_auth;
}
elseif ( isset( \IPS\Request::i()->mfa_setup ) )
{
$qs['mfa_setup'] = \IPS\Request::i()->mfa_setup;
}
\IPS\Output::i()->redirect( $destination->setQueryString( $qs ) );
}
/**
@@ -156,7 +221,11 @@ class _login extends \IPS\Dispatcher\Controller
}
$form = new \IPS\Helpers\Form( 'link_accounts', 'login' );
$form->addDummy( 'email_address', isset( $details['email'] ) ? $details['email'] : $member->email );
if ( isset( \IPS\Request::i()->ref ) )
{
$form->hiddenValues['ref'] = \IPS\Request::i()->ref;
}
$form->addDummy( 'email_address', htmlspecialchars( isset( $details['email'] ) ? $details['email'] : $member->email, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'validateFor' => $member ) ) );
if ( $values = $form->values() )
{
@@ -166,9 +235,21 @@ class _login extends \IPS\Dispatcher\Controller
$class::link( $member, $details['details'] );
unset( $_SESSION['linkAccounts'] );
$this->_doLogin( $member );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
$destination = 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 )
{
$destination = $ref;
}
}
catch ( \Exception $e ) { }
}
$this->_doLogin( $member, FALSE, TRUE, $destination );
}
catch ( \IPS\Login\Exception $e )
{
@@ -191,22 +272,10 @@ class _login extends \IPS\Dispatcher\Controller
{
\IPS\Session::i()->csrfCheck();
\IPS\Request::i()->setCookie( 'member_id', NULL );
\IPS\Request::i()->setCookie( 'pass_hash', NULL );
\IPS\Request::i()->setCookie( 'anon_login', NULL );
foreach( \IPS\Request::i()->cookie as $name => $value )
{
if( mb_strpos( $name, "ipbforumpass_" ) !== FALSE )
{
\IPS\Request::i()->setCookie( $name, NULL );
}
}
if( !empty( $_SERVER['HTTP_REFERER'] ) )
{
$referrer = new \IPS\Http\Url( $_SERVER['HTTP_REFERER'] );
$redirectUrl = ( $referrer->isInternal and isset( $referrer->queryString['do'] ) and $referrer->queryString['do'] != 'validating' ) ? $referrer : \IPS\Http\Url::internal('');
$referrer = \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] );
$redirectUrl = ( $referrer instanceof \IPS\Http\Url\Internal and ( !isset( $referrer->queryString['do'] ) or $referrer->queryString['do'] != 'validating' ) ) ? $referrer : \IPS\Http\Url::internal('');
}
else
{
@@ -226,6 +295,28 @@ class _login extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( $redirectUrl );
}
\IPS\Request::i()->setCookie( 'member_id', NULL );
\IPS\Request::i()->setCookie( 'pass_hash', NULL );
\IPS\Request::i()->setCookie( 'anon_login', NULL );
foreach( \IPS\Request::i()->cookie as $name => $value )
{
if( mb_strpos( $name, "ipbforumpass_" ) !== FALSE )
{
\IPS\Request::i()->setCookie( $name, NULL );
}
}
/* Reset session global parameters */
$_SESSION = array();
/* We have to explicitly reset the session cookie
@link http://php.net/manual/en/function.session-destroy.php */
$params = session_get_cookie_params();
setcookie( session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] );
/* Then destroy the session itself */
session_destroy();
/* Login handler callback */
@@ -268,7 +359,7 @@ class _login extends \IPS\Dispatcher\Controller
/* Do it */
$_SESSION['logged_in_from'] = array( 'id' => $admin->member_id, 'name' => $admin->name );
$unique_id = md5( uniqid() );
$unique_id = \IPS\Login::generateRandomString();
$_SESSION['logged_in_as_key'] = $unique_id;
\IPS\Data\Store::i()->$unique_id = $member->member_id;
@@ -2,9 +2,9 @@
/**
* @brief Lost Password
* @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 26 Aug 2013
* @version SVN_VERSION_NUMBER
*/
@@ -32,7 +32,7 @@ class _lostpass extends \IPS\Dispatcher\Controller
{
/* Build the form */
$form = new \IPS\Helpers\Form( "lostpass", 'request_password' );
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array(), function( $val ){
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'bypassProfanity' => TRUE ), function( $val ){
/* Check email exists */
$member = \IPS\Member::load( $val, 'email' );
@@ -51,30 +51,52 @@ class _lostpass extends \IPS\Dispatcher\Controller
/* Load the member */
$member = \IPS\Member::load( $values['email_address'], 'email' );
/* Make a validation key */
$vid = md5( $member->members_pass_hash . uniqid( mt_rand(), TRUE ) );
/* Get rid of old entries for this member */
\IPS\DB::i()->delete( 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) );
/* Update the DB for this member. */
$validating = array(
'vid' => $vid,
'member_id' => $member->member_id,
'entry_date' => time(),
'lost_pass' => 1,
'ip_address' => $member->ip_address,
);
/* If we have an existing validation record, we can just reuse it */
$sendEmail = TRUE;
try
{
$existing = \IPS\Db::i()->select( array( 'vid', 'email_sent' ), 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) )->first();
$vid = $existing['vid'];
\IPS\Db::i()->insert( 'core_validating', $validating );
/* If we sent a lost password email within the last 15 minutes, don't send another one otherwise someone could be a nuisence */
if ( $existing['email_sent'] and $existing['email_sent'] > ( time() - 900 ) )
{
$sendEmail = FALSE;
}
else
{
\IPS\Db::i()->update( 'core_validating', array( 'email_sent' => time() ), array( 'vid=?', $vid ) );
}
}
catch ( \UnderflowException $e )
{
$vid = md5( $member->members_pass_hash . \IPS\Login::generateRandomString() );
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => $member->member_id,
'entry_date' => time(),
'lost_pass' => 1,
'ip_address' => $member->ip_address,
'email_sent' => time(),
) );
}
/* Send email */
\IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $vid ) )->send( $member );
if ( $sendEmail )
{
\IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
$message = "lost_pass_confirm";
}
else
{
$message = "lost_pass_too_soon";
}
/* Show confirmation page with further instructions */
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPassConfirm();
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPassConfirm( $message );
}
else
{
@@ -102,32 +124,33 @@ class _lostpass extends \IPS\Dispatcher\Controller
/* Show form for new password */
$form = new \IPS\Helpers\Form( "resetpass", 'save' );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array() ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'showMeter' => \IPS\Settings::i()->password_strength_meter ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password_confirm', NULL, TRUE, array( 'confirm' => 'password' ) ) );
/* Set new password */
if ( $values = $form->values() )
{
/* Get the member */
$member = \IPS\Member::load( $record['member_id'] );
$member->members_pass_salt = $member->generateSalt();
$member->members_pass_hash = $member->encryptedPassword( $values['password'] );
/* Reset the failed logins storage - we don't need to save because the login handler will do that for us later */
$member->failed_logins = array();
$member->save();
/* Now reset the member's password */
foreach ( \IPS\Login::handlers( TRUE ) as $handler )
{
/* We cannot update our password in some login handlers, that's ok */
try
{
$handler->changePassword( $member, $values['password'] );
}
catch( \BadMethodCallException $e ){}
}
/* Delete validating record and log in */
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) );
/* If the member doesn't have any other validating rows validate them */
try
{
$record = \IPS\Db::i()->select( '*', 'core_validating', array( 'member_id=?', $member->member_id ) )->first();
}
catch ( \UnderflowException $e )
{
$member->validate();
}
/* Log in and redirect */
\IPS\Session::i()->setMember( $member );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
}
@@ -2,9 +2,9 @@
/**
* @brief Mark site as read
* @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 19 May 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Live meta tag editor
* @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 4 Sept 2013
* @version SVN_VERSION_NUMBER
*/
@@ -50,8 +50,8 @@ class _metatags extends \IPS\Dispatcher\Controller
\IPS\Session::i()->csrfCheck();
/* Delete any existing database entries, as we are about to re-insert */
\IPS\DB::i()->delete( 'core_seo_meta', array( 'meta_url=?', \IPS\Request::i()->meta_url ) );
\IPS\DB::i()->delete( 'core_seo_meta', array( 'meta_url=?', trim( \IPS\Request::i()->meta_url, '/' ) ) );
\IPS\Db::i()->delete( 'core_seo_meta', array( 'meta_url=?', \IPS\Request::i()->meta_url ) );
\IPS\Db::i()->delete( 'core_seo_meta', array( 'meta_url=?', trim( \IPS\Request::i()->meta_url, '/' ) ) );
/* Start save array */
$save = array(
@@ -75,7 +75,7 @@ class _metatags extends \IPS\Dispatcher\Controller
$save['meta_tags'] = json_encode( $_tags );
\IPS\DB::i()->insert( 'core_seo_meta', $save );
\IPS\Db::i()->insert( 'core_seo_meta', $save );
unset( \IPS\Data\Store::i()->metaTags );
/* Send back to the page */
@@ -2,9 +2,9 @@
/**
* @brief Moderation
* @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 23 Jul 2013
* @version SVN_VERSION_NUMBER
*/
@@ -33,12 +33,23 @@ class _moderation extends \IPS\Dispatcher\Controller
\IPS\Session::i()->csrfCheck();
$member = \IPS\Member::load( \IPS\Request::i()->id );
$redirectTarget = ( \IPS\Request::i()->referrer ) ? \IPS\Http\Url::createFromString( urldecode( \IPS\Request::i()->referrer ), TRUE ) : $member->url();
if ( $member->member_id and $member->member_id != \IPS\Member::loggedIn()->member_id and \IPS\Member::loggedIn()->modPermission('can_flag_as_spammer') and !$member->modPermission() and !$member->isAdmin() )
{
if ( \IPS\Request::i()->s )
{
$member->flagAsSpammer();
\IPS\Session::i()->modLog( 'modlog__spammer_flagged', array( $member->name => FALSE ) );
$actions = explode( ',', \IPS\Settings::i()->spm_option );
/* Redirect to the users profile if we're deleting the content to avoid that the moderator sees a 404 error message */
if ( in_array( 'delete', $actions ) )
{
$redirectTarget = $member->url();
}
}
else
{
@@ -47,6 +58,6 @@ class _moderation extends \IPS\Dispatcher\Controller
}
}
\IPS\Output::i()->redirect( ( \IPS\Request::i()->referrer ) ? new \IPS\Http\Url( urldecode( \IPS\Request::i()->referrer ), TRUE ) : $member->url(), ( \IPS\Request::i()->s ) ? 'account_flagged' : 'account_unflagged');
\IPS\Output::i()->redirect( $redirectTarget, ( \IPS\Request::i()->s ) ? 'account_flagged' : 'account_unflagged');
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief Notification Settings Controller
* @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 27 Aug 2013
* @version SVN_VERSION_NUMBER
*/
@@ -57,28 +57,6 @@ class _notifications extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->json( array( 'data' => \IPS\Theme::i()->getTemplate( 'system' )->notificationsAjax( $notifications ) ) );
}
elseif ( isset( \IPS\Request::i()->format ) and \IPS\Request::i()->format === 'rss' )
{
$document = \IPS\Xml\Rss::newDocument( $urlObject, \IPS\Member::loggedIn()->language()->get('notifications'), sprintf( \IPS\Member::loggedIn()->language()->get( 'notifications_rss_desc' ), \IPS\Member::loggedIn()->name, \IPS\Settings::i()->board_name ) );
if ( count( $table->getRows() ) )
{
foreach ( $table->getRows() as $notification )
{
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $notification['data']['title'] );
if( isset( $notification['data']['content'] ) )
{
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $notification['data']['content'] );
}
$document->addItem( $notification['data']['title'], $notification['data']['url'], isset( $notification['data']['content'] ) ? $notification['data']['content'] : NULL, $notification['notification']->updated_time, $notification['notification']->id );
}
}
/* @note application/rss+xml is not a registered IANA mime-type so we need to stick with text/xml for RSS */
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml' );
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('notifications');
@@ -113,7 +91,8 @@ class _notifications extends \IPS\Dispatcher\Controller
$form->add( new \IPS\Helpers\Form\Radio( 'auto_track_type', \IPS\Member::loggedIn()->auto_follow['method'] ?: 'immediate', FALSE, array( 'options' => array(
'immediate' => \IPS\Member::loggedIn()->language()->addToStack('follow_type_immediate'),
'daily' => \IPS\Member::loggedIn()->language()->addToStack('follow_type_daily'),
'weekly' => \IPS\Member::loggedIn()->language()->addToStack('follow_type_weekly')
'weekly' => \IPS\Member::loggedIn()->language()->addToStack('follow_type_weekly'),
'none' => \IPS\Member::loggedIn()->language()->addToStack('follow_type_none')
) ), NULL, NULL, NULL, 'auto_track_type' ) );
/* Changed in 4.1: since email_notifications_once is new, combined show_pm_popup in and made a checkbox set for better organization */
$notificationPrefValues = array();
@@ -457,9 +436,12 @@ class _notifications extends \IPS\Dispatcher\Controller
$output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'system', 'core' ) ), 'followForm' ) );
/* @see http://community.invisionpower.com/4bugtrack/follow-button-adds-meta-title-and-link-tags-r3209/ */
if( \IPS\Request::i()->isAjax() ){
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( $output, 200, 'text/html', \IPS\Output::i()->httpHeaders );
} else {
}
else
{
\IPS\Output::i()->output = $output;
}
}
@@ -591,21 +573,21 @@ class _notifications extends \IPS\Dispatcher\Controller
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
$followers = $thing->followers( $class::FOLLOW_PUBLIC, array( 'none', 'immediate', 'daily', 'weekly' ), NULL, array( ( $thisPage - 1 ) * $perPage, $perPage ), 'name' );
$anonymous = $thing->followers( $class::FOLLOW_ANONYMOUS )->count( TRUE );
$title = $thing->name;
$title = $thing->mapped('title');
}
else
{
$thing = $class::load( \IPS\Request::i()->follow_id );
$followers = $thing->followers( $class::FOLLOW_PUBLIC, array( 'none', 'immediate', 'daily', 'weekly' ), NULL, array( ( $thisPage - 1 ) * $perPage, $perPage ), 'name' );
$anonymous = $thing->followers( $class::FOLLOW_ANONYMOUS )->count( TRUE );
$title = $thing->mapped('title');
$title = $thing->name;
}
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C154/6', 404, '' );
}
/* Display */
if ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->_infScroll ) )
{
@@ -614,12 +596,14 @@ class _notifications extends \IPS\Dispatcher\Controller
else
{
$url = \IPS\Http\Url::internal( "app=core&module=system&section=notifications&do=followers&follow_app=". \IPS\Request::i()->follow_app ."&follow_area=". \IPS\Request::i()->follow_area ."&follow_id=" . \IPS\Request::i()->follow_id . "&_infScroll=1" );
$removeAllUrl = \IPS\Http\Url::internal( "app=core&module=system&section=notifications&do=removeFollowers&follow_app=". \IPS\Request::i()->follow_app ."&follow_area=". \IPS\Request::i()->follow_area ."&follow_id=" . \IPS\Request::i()->follow_id )->csrf();
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $url, ceil( $followers->count( TRUE ) / $perPage ), $thisPage, $perPage, FALSE, 'followerPage' );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('item_followers', FALSE, array( 'sprintf' => array( $title ) ) );
\IPS\Output::i()->breadcrumb[] = array( $thing->url(), $title );
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('who_follows_this') );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->followers( $url, $pagination, $followers, $anonymous );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->followers( $url, $pagination, $followers, $anonymous, $removeAllUrl );
}
}
@@ -675,23 +659,42 @@ class _notifications extends \IPS\Dispatcher\Controller
{
if ( isset( \IPS\Request::i()->button_type ) && \IPS\Request::i()->button_type === 'search' )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->memberSearchFollowButton( \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id, $count );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'profile' )->memberSearchFollowButton( \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id, $count ) );
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->memberFollowButton( \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id, $count );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'profile' )->memberFollowButton( \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id, $count ) );
}
}
else
{
if ( \IPS\Request::i()->button_type == 'manage' )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->manageFollowButton( \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'system' )->manageFollowButton( \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id ) );
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->followButton( \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id, $count );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global' )->followButton( \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id, $count ) );
}
}
}
/**
* Remove all followers
*
* @return void
*/
protected function removeFollowers()
{
\IPS\Session::i()->csrfCheck();
if ( !\IPS\Member::loggedIn()->modPermission('can_remove_followers') )
{
\IPS\Output::i()->error( 'cant_remove_followers', '2C154/A', 403, 'cant_remove_followers_admin' );
}
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id ) );
\IPS\Output::i()->redirect( ( !empty( $_SERVER['HTTP_REFERER'] ) ) ? \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal( '' ), 'followers_removed' );
}
}
@@ -2,9 +2,9 @@
/**
* @brief A deliberately empty controller intended for use by plugins which need to add small actions
* @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 09 Aug 2013
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Poll View Voters Controller
* @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 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Privacy Policy
* @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 28 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief External redirector with key checks
* @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 12 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -24,31 +24,61 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
class _redirect extends \IPS\Dispatcher\Controller
{
/**
* Redirect the request appropriately
* Handle munged links
*
* @return void
*/
protected function manage()
{
/* First check the key to make sure this actually came from HTMLPurifier */
if ( \IPS\Request::i()->key == hash_hmac( "sha256", \IPS\Request::i()->url, md5( \IPS\Settings::i()->sql_pass . \IPS\Settings::i()->board_url . \IPS\Settings::i()->sql_database ) ) )
if ( \IPS\Login::compareHashes( hash_hmac( "sha256", \IPS\Request::i()->url, \IPS\Settings::i()->site_secret_key ), (string) \IPS\Request::i()->key ) )
{
/* Is it a resource? (image, etc.) */
/* Construct the URL */
$url = \IPS\Http\Url::external( \IPS\Request::i()->url );
/* If it's a resource (image, etc.), we pull the actual contents to prevent the referrer being exposed (which is an issue in the ACP where the session ID is private) */
if ( \IPS\Request::i()->resource )
{
/* If it's a resource, redirect without a message. Browsers should follow a location header for resources such as image fine. */
/* Note that this scenario is hit if we have <img src='munged url' /> */
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Request::i()->url ) );
/* Except if it's internal or localhost, we can't make a HTTP request to it because doing that would potentially allow access to secured resources because the server
thinks the request is internal. We don't need to worry about about things on this domain getting access to the referrer anyway */
if ( $url->isLocalhost() )
{
\IPS\Output::i()->redirect( $url, NULL, 303 );
}
/* For everything else, pull the contents... */
else
{
/* It can't be protocol relative */
if ( !$url->data['scheme'] )
{
$url = \IPS\Http\Url::external( 'http:' . \IPS\Request::i()->url );
}
/* Get the contents */
try
{
$response = \IPS\Http\Url::external( $url )->request( \IPS\DEFAULT_REQUEST_TIMEOUT )->get();
}
catch ( \Exception $e )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('') );
}
/* Send output - we only want to pass along the content and content type. We can't allow the response
to perform a redirect (which would cause the referrer to be exposed) and we don't want to pass
along any of their headers which could include setting cookies, etc. */
\IPS\Output::i()->sendOutput( $response->content, $response->httpResponseCode == 200 ? 200 : 404, isset( $response->httpHeaders['Content-Type'] ) ? $response->httpHeaders['Content-Type'] : 'unknown/unknown' );
}
}
/* For everything else, we'll do a 303 redirect */
else
{
/* Regular URL? Show a redirect page. */
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Request::i()->url ), \IPS\Member::loggedIn()->language()->addToStack('external_redirect'), 303, TRUE );
\IPS\Output::i()->redirect( $url, \IPS\Member::loggedIn()->language()->addToStack('external_redirect'), 303, TRUE );
}
}
/* If it doesn't validate, send the user to the index page */
else
{
/* Key did not validate, send the user to the index page */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('') );
}
}
@@ -2,9 +2,9 @@
/**
* @brief Register
* @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 3 July 2013
* @version SVN_VERSION_NUMBER
*/
@@ -60,15 +60,23 @@ class _register extends \IPS\Dispatcher\Controller
if( isset( $_SESSION['coppa_user'] ) )
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reg_awaiting_validation');
return \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->notCoppaValidated();
if ( \IPS\Settings::i()->minimum_age > 0 )
{
$message = \IPS\Member::loggedIn()->language()->addToStack( 'register_denied_age', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->minimum_age ) ) );
\IPS\Output::i()->error( $message, '2C223/7', 403, '' );
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reg_awaiting_validation');
return \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->notCoppaValidated();
}
}
/* Set up the step array */
$steps = array();
/* If coppa is enabled we need to add a birthday verification */
if ( \IPS\Settings::i()->use_coppa )
if ( \IPS\Settings::i()->use_coppa OR \IPS\Settings::i()->minimum_age > 0 )
{
$steps['coppa'] = function( $data )
{
@@ -78,7 +86,16 @@ class _register extends \IPS\Dispatcher\Controller
if( $values = $form->values() )
{
if( ( $values['bday']->diff( \IPS\DateTime::create() )->y < 13 ) )
/* Did we pass the minimum age requirement? */
if ( \IPS\Settings::i()->minimum_age > 0 AND $values['bday']->diff( \IPS\DateTime::create() )->y < \IPS\Settings::i()->minimum_age )
{
$_SESSION['coppa_user'] = TRUE;
$message = \IPS\Member::loggedIn()->language()->addToStack( 'register_denied_age', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->minimum_age ) ) );
\IPS\Output::i()->error( $message, '2C223/8', 403, '' );
}
/* We did, but we should check normal COPPA too */
else if( ( $values['bday']->diff( \IPS\DateTime::create() )->y < 13 ) )
{
$_SESSION['coppa_user'] = TRUE;
return \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->notCoppaValidated();
@@ -100,16 +117,18 @@ class _register extends \IPS\Dispatcher\Controller
/* Handle submissions */
if ( $values = $form->values() )
{
/* Create Member */
$member = \IPS\core\modules\front\system\register::_createMember( $values );
/* Custom Fields */
$profileFields = array();
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\REG ) as $group => $fields )
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::REG ) as $group => $fields )
{
foreach ( $fields as $id => $field )
{
if( $field->required and ( $values[ $field->name ] === NULL or !isset( $values[ $field->name ] ) ) )
{
\IPS\Output::i()->error( 'reg_required_fields', '1C223/5', 403, '' );
}
$profileFields[ "field_{$id}" ] = $field::stringValue( $values[ $field->name ] );
if ( $fields instanceof \IPS\Helpers\Form\Editor )
@@ -118,33 +137,46 @@ class _register extends \IPS\Dispatcher\Controller
}
}
}
\IPS\Db::i()->replace( 'core_pfields_content', array_merge( array( 'member_id' => $member->member_id ), $profileFields ) );
/* Email - We don't want to send if the new member is banned or we're not using email validation */
if( \IPS\Settings::i()->reg_auth_type != 'none' AND \IPS\Settings::i()->reg_auth_type != 'admin' AND !$member->members_bitoptions['bw_is_spammer'] )
if ( \IPS\Settings::i()->security_questions_enabled and ( \IPS\Settings::i()->security_questions_prompt === 'register' or ( \IPS\Settings::i()->security_questions_prompt === 'optional' and !$values['security_questions_optout_title'] ) ) )
{
\IPS\Email::buildFromTemplate( 'core', 'registration_validate', array( $member, \IPS\Db::i()->select( 'vid', 'core_validating', array( 'member_id=?', $member->member_id ) )->first() ) )->send( $member );
$answers = array();
foreach ( $values as $k => $v )
{
if ( preg_match( '/^security_question_q_(\d+)$/', $k, $matches ) )
{
if ( isset( $answers[ $v ] ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'security_questions_unique', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->security_questions_number ?: 3 ) ) );
break;
}
else
{
$answers[ $v ] = $v;
}
}
}
}
/* Notify the incoming mail address except if they're a spammer */
if( \IPS\Settings::i()->new_reg_notify && !$member->members_bitoptions['bw_is_spammer'] )
if ( !$form->error )
{
\IPS\Email::buildFromTemplate( 'core', 'registration_notify', array( $member, $profileFields ) )->send( \IPS\Settings::i()->email_in );
}
/* Log them in */
\IPS\Session::i()->setMember( $member );
$redirectUrl = \IPS\Login::getRegistrationDestination( $member );
/* Redirect */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'redirect' => (string) $redirectUrl ) );
}
else
{
\IPS\Output::i()->redirect( $redirectUrl );
/* Create Member */
$member = \IPS\core\modules\front\system\register::_createMember( $values, $profileFields );
/* Log them in */
\IPS\Session::i()->setMember( $member );
$redirectUrl = \IPS\Login::getRegistrationDestination( $member );
/* Redirect */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'redirect' => (string) $redirectUrl ) );
}
else
{
\IPS\Output::i()->redirect( $redirectUrl );
}
}
}
@@ -168,12 +200,12 @@ class _register extends \IPS\Dispatcher\Controller
/* Build the form */
$form = new \IPS\Helpers\Form( 'form', 'register_button', NULL, array( 'data-controller' => 'core.front.system.register') );
$form->add( new \IPS\Helpers\Form\Text( 'username', NULL, TRUE, array( 'accountUsername' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'accountEmail' => TRUE, 'maxLength' => 150 ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array() ) );
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'accountEmail' => TRUE, 'maxLength' => 150, 'bypassProfanity' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'showMeter' => \IPS\Settings::i()->password_strength_meter, 'checkStrength' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password_confirm', NULL, TRUE, array( 'confirm' => 'password' ) ) );
/* Profile fields */
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\REG ) as $group => $fields )
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::REG ) as $group => $fields )
{
foreach ( $fields as $field )
{
@@ -189,6 +221,54 @@ class _register extends \IPS\Dispatcher\Controller
}
catch ( \UnderflowException $e ) {}
/* Security Questions */
if ( \IPS\Settings::i()->security_questions_enabled and in_array( \IPS\Settings::i()->security_questions_prompt, array( 'register', 'optional' ) ) )
{
$numberOfQuestions = \IPS\Settings::i()->security_questions_number ?: 3;
$securityQuestions = array();
foreach ( \IPS\MFA\SecurityQuestions\Question::roots() as $securityQuestion )
{
$securityQuestions[ $securityQuestion->id ] = $securityQuestion->_title;
}
$form->addMessage( \IPS\Member::loggedIn()->language()->addToStack('security_questions_setup_blurb', FALSE, array( 'pluralize' => array( $numberOfQuestions ) ) ) );
if ( \IPS\Settings::i()->security_questions_prompt === 'optional' )
{
$securityOptoutToggles = array();
foreach ( range( 1, min( $numberOfQuestions, count( $securityQuestions ) ) ) as $i )
{
$securityOptoutToggles[] = 'security_question_q_' . $i;
$securityOptoutToggles[] = 'security_question_a_' . $i;
}
$optOutCheckbox = new \IPS\Helpers\Form\Checkbox( 'security_questions_optout_title', FALSE, FALSE, array( 'togglesOff' => $securityOptoutToggles ) );
if ( \IPS\Member::loggedIn()->language()->checkKeyExists('security_questions_opt_out_warning_value') )
{
$optOutCheckbox->description = \IPS\Member::loggedIn()->language()->addToStack('security_questions_opt_out_warning_value');
}
$form->add( $optOutCheckbox );
}
foreach ( range( 1, min( $numberOfQuestions, count( $securityQuestions ) ) ) as $i )
{
$securityValidation = function( $val ) {
if ( !$val and ( \IPS\Settings::i()->security_questions_prompt === 'register' or !isset( \IPS\Request::i()->security_questions_optout_title_checkbox ) ) )
{
throw new \DomainException('form_required');
}
};
$questionField = new \IPS\Helpers\Form\Select( 'security_question_q_' . $i, NULL, FALSE, array( 'options' => $securityQuestions ), $securityValidation, NULL, NULL, 'security_question_q_' . $i );
$questionField->label = \IPS\Member::loggedIn()->language()->addToStack('security_question_q');
$answerField = new \IPS\Helpers\Form\Text( 'security_question_a_' . $i, NULL, NULL, array(), $securityValidation, NULL, NULL, 'security_question_a_' . $i );
$answerField->label = \IPS\Member::loggedIn()->language()->addToStack('security_question_a');
$form->add( $questionField );
$form->add( $answerField );
}
$form->addSeparator();
}
/* Random Q&A */
if( $question )
{
@@ -280,10 +360,11 @@ class _register extends \IPS\Dispatcher\Controller
/**
* Create Member
*
* @param array $values Values from form
* @param array $values Values from form
* @param array $profileFields Profile field values from registration
* @return \IPS\Member
*/
public static function _createMember( $values )
public static function _createMember( $values, $profileFields )
{
/* Create */
$member = new \IPS\Member;
@@ -303,15 +384,50 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'spam_denied_account', '2S129/1', 403, '' );
}
}
/* Will we be validating? */
if ( \IPS\Settings::i()->reg_auth_type != 'none' )
/* Save */
$member->save();
/* Security Questions */
if ( \IPS\Settings::i()->security_questions_enabled and in_array( \IPS\Settings::i()->security_questions_prompt, array( 'register', 'optional' ) ) )
{
$member->members_bitoptions['validating'] = TRUE;
if ( $values['security_questions_optout_title'] )
{
$member->members_bitoptions['security_questions_opt_out'] = TRUE;
}
else
{
$answers = array();
foreach ( $values as $k => $v )
{
if ( preg_match( '/^security_question_q_(\d+)$/', $k, $matches ) )
{
$answers[ $v ] = array(
'answer_question_id' => $v,
'answer_member_id' => $member->member_id,
'answer_answer' => \IPS\Text\Encrypt::fromPlaintext( $values[ 'security_question_a_' . $matches[1] ] )->tag()
);
}
}
if ( count( $answers ) )
{
\IPS\Db::i()->insert( 'core_security_answers', $answers );
}
$member->members_bitoptions['has_security_answers'] = TRUE;
}
$member->save();
}
/* Save custom field values */
\IPS\Db::i()->replace( 'core_pfields_content', array_merge( array( 'member_id' => $member->member_id ), $profileFields ) );
/* Handle validation */
$member->postRegistration();
/* Save and return */
$member->save();
return $member;
}
@@ -370,6 +486,8 @@ class _register extends \IPS\Dispatcher\Controller
*/
protected function resend()
{
\IPS\Session::i()->csrfCheck();
$validating = \IPS\Db::i()->select( '*', 'core_validating', array( 'member_id=?', \IPS\Member::loggedIn()->member_id ) );
if ( !count( $validating ) )
@@ -379,7 +497,14 @@ class _register extends \IPS\Dispatcher\Controller
foreach( $validating as $reg )
{
\IPS\Email::buildFromTemplate( 'core', 'registration_validate', array( \IPS\Member::loggedIn(), $reg['vid'] ) )->send( \IPS\Member::loggedIn() );
if ( $reg['email_sent'] and $reg['email_sent'] > ( time() - 900 ) )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack('validation_email_rate_limit', FALSE, array( 'sprintf' => array( \IPS\DateTime::ts( $reg['email_sent'] )->relative( \IPS\DateTime::RELATIVE_FORMAT_LOWER ) ) ) ), '1C223/4', 429, '', array( 'Retry-After' => \IPS\DateTime::ts( $reg['email_sent'] )->add( new \DateInterval( 'PT15M' ) )->format('r') ) );
}
\IPS\Email::buildFromTemplate( 'core', $reg['email_chg'] ? 'email_change' : 'registration_validate', array( \IPS\Member::loggedIn(), $reg['vid'] ), \IPS\Email::TYPE_TRANSACTIONAL )->send( \IPS\Member::loggedIn() );
\IPS\Db::i()->update( 'core_validating', array( 'email_sent' => time() ), array( 'vid=?', $reg['vid'] ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=validating', 'front', 'register' ), 'reg_email_resent' );
@@ -394,6 +519,7 @@ class _register extends \IPS\Dispatcher\Controller
{
if( \IPS\Request::i()->vid AND \IPS\Request::i()->mid )
{
/* Load record */
try
{
$record = \IPS\Db::i()->select( '*', 'core_validating', array( 'vid=? AND member_id=? AND ( new_reg=? or email_chg=? )', \IPS\Request::i()->vid, \IPS\Request::i()->mid, 1, 1 ) )->first();
@@ -403,18 +529,26 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'validate_no_record', '2S129/2', 404, '' );
}
/* If we're using user validation, or this was anything other than a new registration (like an email change) we can go ahead and validate */
if( \IPS\Settings::i()->reg_auth_type == 'user' or $record['email_chg'] )
/* Validate */
$member = \IPS\Member::load( \IPS\Request::i()->mid );
if ( $record['new_reg'] )
{
\IPS\Member::load( \IPS\Request::i()->mid )->validate();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'validate_confirmation' );
$member->emailValidationConfirmed( $record );
}
/* Otherwise admin still needs to validate so we flag user validated */
else
{
\IPS\Db::i()->update( 'core_validating', array( 'user_verified' => TRUE ), array( 'member_id=?', \IPS\Request::i()->mid ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'validate_email_confirmation' );
$member->members_bitoptions['validating'] = FALSE;
$member->save();
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=?', $member->member_id ) );
/* Send a confirmation email */
\IPS\Email::buildFromTemplate( 'core', 'email_address_changed', array( $member, $record['prev_email'] ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $record['prev_email'], array(), array(), NULL, NULL, array( 'Reply-To' => \IPS\Settings::i()->email_in ) );
}
/* Log in and Redirect */
\IPS\Session::i()->setMember( $member );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'validate_email_confirmation' );
}
}
@@ -425,8 +559,22 @@ class _register extends \IPS\Dispatcher\Controller
*/
protected function complete()
{
/* Check we are an incomplete member */
if ( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) );
}
elseif ( \IPS\Member::loggedIn()->real_name and \IPS\Member::loggedIn()->email )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
}
/* Build the form */
$form = new \IPS\Helpers\Form( 'form', 'register_button' );
if ( isset( \IPS\Request::i()->ref ) )
{
$form->hiddenValues['ref'] = \IPS\Request::i()->ref;
}
if( !\IPS\Member::loggedIn()->real_name OR \IPS\Member::loggedIn()->name === \IPS\Member::loggedIn()->language()->get('guest') )
{
$form->add( new \IPS\Helpers\Form\Text( 'username', NULL, TRUE, array( 'accountUsername' => \IPS\Member::loggedIn() ) ) );
@@ -463,30 +611,19 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'spam_denied_account', '2S272/1', 403, '' );
}
}
/* If email validation is enabled add a validating record */
if( in_array( \IPS\Settings::i()->reg_auth_type, array( 'user', 'admin_user' ) ) )
{
$vid = md5( uniqid() );
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => \IPS\Member::loggedIn()->member_id,
'entry_date' => time(),
'new_reg' => 1,
'email_chg' => 0,
'user_verified' => FALSE,
'ip_address' => \IPS\Request::i()->ipAddress()
) );
\IPS\Member::loggedIn()->members_bitoptions['validating'] = TRUE;
}
}
/* Save */
\IPS\Member::loggedIn()->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
/* Handle validation */
\IPS\Member::loggedIn()->postRegistration( ( isset( $values['email_address'] ) ) ? FALSE : TRUE );
/* Set member as a full member in the session table */
\IPS\Session::i()->setType( \IPS\Session\Front::LOGIN_TYPE_MEMBER );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Login::getRegistrationDestination( \IPS\Member::loggedIn() ) );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reg_complete_details');
@@ -518,43 +655,55 @@ class _register extends \IPS\Dispatcher\Controller
/* Build the form */
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Email( 'new_email', '', TRUE, array( 'accountEmail' => TRUE ) ) );
$captcha = new \IPS\Helpers\Form\Captcha;
if ( (string) $captcha !== '' )
{
$form->add( $captcha );
}
/* Handle submissions */
if ( $values = $form->values() )
{
/* Change the email */
$oldEmail = \IPS\Member::loggedIn()->email;
foreach ( \IPS\Login::handlers( TRUE ) as $handler )
{
try
{
$handler->changeEmail( \IPS\Member::loggedIn(), \IPS\Member::loggedIn()->email, $values['new_email'] );
$handler->changeEmail( \IPS\Member::loggedIn(), $oldEmail, $values['new_email'] );
}
catch( \BadMethodCallException $e ) {}
}
/* Delete any pending validation emails */
if ( $pending['vid'] )
{
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=? AND ( new_reg=1 or email_chg=1 )', \IPS\Member::loggedIn()->member_id ) );
}
$vid = md5( uniqid() );
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => \IPS\Member::loggedIn()->member_id,
'entry_date' => time(),
'new_reg' => !$pending or $pending['new_reg'],
'email_chg' => $pending and $pending['email_chg'],
'user_verified' => ( \IPS\Settings::i()->reg_auth_type == 'admin' ) ?: FALSE,
'ip_address' => \IPS\Request::i()->ipAddress()
) );
\IPS\Member::loggedIn()->save();
\IPS\Email::buildFromTemplate( 'core', 'registration_validate', array( \IPS\Member::loggedIn(), $vid ) )->send( \IPS\Member::loggedIn() );
/* If email validation is required, do that... */
if ( in_array( \IPS\Settings::i()->reg_auth_type, array( 'user', 'admin_user' ) ) )
{
/* Delete any pending validation emails */
if ( $pending['vid'] )
{
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=? AND ( new_reg=1 or email_chg=1 )', \IPS\Member::loggedIn()->member_id ) );
}
$vid = \IPS\Login::generateRandomString();
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => \IPS\Member::loggedIn()->member_id,
'entry_date' => time(),
'new_reg' => !$pending or $pending['new_reg'],
'email_chg' => $pending and $pending['email_chg'],
'user_verified' => ( \IPS\Settings::i()->reg_auth_type == 'admin' ) ?: FALSE,
'ip_address' => \IPS\Request::i()->ipAddress(),
'email_sent' => time(),
) );
\IPS\Email::buildFromTemplate( 'core', $pending['email_chg'] ? 'email_change' : 'registration_validate', array( \IPS\Member::loggedIn(), $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( \IPS\Member::loggedIn() );
}
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
}
@@ -575,8 +724,46 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'no_module_permission', '2C223/1', 403, '' );
}
/* Delete Member */
\IPS\Member::loggedIn()->delete();
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete( 'reg_cancel', 'reg_cancel_confirm', 'reg_cancel' );
/* Log the user out. Previously, we immediately deleted the account however this has been changed to let the cleanup task handle this instead. */
\IPS\Request::i()->setCookie( 'member_id', NULL );
\IPS\Request::i()->setCookie( 'pass_hash', NULL );
\IPS\Request::i()->setCookie( 'anon_login', NULL );
foreach( \IPS\Request::i()->cookie as $name => $value )
{
if( mb_strpos( $name, "ipbforumpass_" ) !== FALSE )
{
\IPS\Request::i()->setCookie( $name, NULL );
}
}
/* Reset session global parameters */
$_SESSION = array();
/* We have to explicitly reset the session cookie
@link http://php.net/manual/en/function.session-destroy.php */
$params = session_get_cookie_params();
setcookie( session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] );
/* Then destroy the session itself */
session_destroy();
/* Member sync callback */
\IPS\Member::loggedIn()->memberSync( 'onLogout', array( \IPS\Http\Url::internal( '' ) ) );
/* Login handler callback */
foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler )
{
try
{
$handler->logoutAccount( \IPS\Member::loggedIn(), \IPS\Http\Url::internal( '' ) );
}
catch( \BadMethodCallException $e ) {}
}
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'reg_canceled' );
@@ -591,6 +778,10 @@ class _register extends \IPS\Dispatcher\Controller
{
/* Generate form */
$form = new \IPS\Helpers\Form;
if ( isset( \IPS\Request::i()->ref ) )
{
$form->hiddenValues['ref'] = \IPS\Request::i()->ref;
}
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Checkbox( 'reconfirm_checkbox', NULL, FALSE, array(), function( $val )
{
@@ -607,6 +798,19 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] = FALSE;
\IPS\Member::loggedIn()->save();
if ( isset( \IPS\Request::i()->ref ) )
{
try
{
$ref = \IPS\Http\Url\Friendly::createFromString( base64_decode( \IPS\Request::i()->ref ) );
if ( $ref instanceof \IPS\Http\Url\Internal )
{
\IPS\Output::i()->redirect( $ref );
}
}
catch ( \Exception $e ) { }
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('') );
}
@@ -2,9 +2,9 @@
/**
* @brief User CP Controller
* @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 10 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -54,11 +54,49 @@ class _settings extends \IPS\Dispatcher\Controller
{
$output = call_user_func( array( $this, "_{$area}" ) );
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('settings');
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('settings') );
if ( !\IPS\Request::i()->isAjax() )
{
if ( \IPS\Request::i()->service )
{
$area = "{$area}_" . \IPS\Request::i()->service;
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/settings.css' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/settings_responsive.css' ) );
}
if ( $output )
{
\IPS\Output::i()->output .= $this->_wrapOutputInTemplate( $area, $output );
}
}
elseif ( $output )
{
\IPS\Output::i()->output .= $output;
}
}
/**
* Wrap output in template
*
* @param string $area Active area
* @param string $output Output
* @return string
*/
protected function _wrapOutputInTemplate( $area, $output )
{
/* What can we do? */
$canChangeEmail = FALSE;
$canChangePassword = FALSE;
$canChangeUsername = FALSE;
$canConfigureMfa = FALSE;
foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler )
{
if ( \IPS\Member::loggedIn()->group['g_dname_changes'] and $handler->canChange( 'username', \IPS\Member::loggedIn() ) )
@@ -74,6 +112,14 @@ class _settings extends \IPS\Dispatcher\Controller
$canChangePassword = TRUE;
}
}
foreach ( \IPS\MFA\MFAHandler::handlers() as $handler )
{
if ( $handler->isEnabled() and $handler->memberCanUseHandler( \IPS\Member::loggedIn() ) )
{
$canConfigureMfa = TRUE;
break;
}
}
$sigLimits = explode( ":", \IPS\Member::loggedIn()->group['g_signature_limits'] );
$canChangeSignature = (bool) ( \IPS\Settings::i()->signatures_enabled && !$sigLimits[0] );
@@ -81,21 +127,8 @@ class _settings extends \IPS\Dispatcher\Controller
/* Add sync services */
$services = \IPS\core\ProfileSync\ProfileSyncAbstract::services();
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('settings');
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('settings') );
if ( !\IPS\Request::i()->isAjax() )
{
if ( \IPS\Request::i()->service )
{
$area = "{$area}_" . \IPS\Request::i()->service;
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->settings( $area, $output, $canChangeEmail, $canChangePassword, $canChangeUsername, $canChangeSignature, $services );
}
else
{
\IPS\Output::i()->output = $output;
}
/* Return */
return \IPS\Theme::i()->getTemplate( 'system' )->settings( $area, $output, $canChangeEmail, $canChangePassword, $canChangeUsername, $canChangeSignature, $services, $canConfigureMfa );
}
/**
@@ -127,6 +160,16 @@ class _settings extends \IPS\Dispatcher\Controller
return \IPS\Theme::i()->getTemplate( 'system' )->settingsEmail();
}
$mfaOutput = \IPS\MFA\MFAHandler::accessToArea( 'core', 'EmailChange', \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=password', 'front', 'settings_password' ) );
if ( $mfaOutput )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) );
}
\IPS\Output::i()->output = $mfaOutput;
}
/* Do we have any pending validation emails? */
try
{
@@ -139,20 +182,23 @@ class _settings extends \IPS\Dispatcher\Controller
/* Build the form */
$form = new \IPS\Helpers\Form;
$form->addDummy( 'current_email', \IPS\Member::loggedIn()->email );
$form->class = 'ipsForm_collapseTablet';
$form->addDummy( 'current_email', htmlspecialchars( \IPS\Member::loggedIn()->email, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) );
$form->add( new \IPS\Helpers\Form\Email( 'new_email', '', TRUE, array( 'accountEmail' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'current_password', '', TRUE, array( 'validateFor' => \IPS\Member::loggedIn() ) ) );
/* Handle submissions */
if ( $values = $form->values() )
if ( !$mfaOutput and $values = $form->values() )
{
$oldEmail = \IPS\Member::loggedIn()->email;
/* Change the email */
foreach ( \IPS\Login::handlers( TRUE ) as $handler )
{
/* We cannot update our email address in some login handlers, that's ok */
try
{
$handler->changeEmail( \IPS\Member::loggedIn(), \IPS\Member::loggedIn()->email, $values['new_email'] );
$handler->changeEmail( \IPS\Member::loggedIn(), $oldEmail, $values['new_email'] );
}
catch( \BadMethodCallException $e ){}
}
@@ -166,7 +212,7 @@ class _settings extends \IPS\Dispatcher\Controller
/* Send a validation email if we need to */
if ( \IPS\Settings::i()->reg_auth_type == 'user' or \IPS\Settings::i()->reg_auth_type == 'admin_user' )
{
$vid = md5( uniqid() );
$vid = \IPS\Login::generateRandomString();
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
@@ -174,13 +220,14 @@ class _settings extends \IPS\Dispatcher\Controller
'entry_date' => time(),
'email_chg' => TRUE,
'ip_address' => \IPS\Request::i()->ipAddress(),
'prev_email' => \IPS\Member::loggedIn()->email
'prev_email' => $oldEmail,
'email_sent' => time(),
) );
\IPS\Member::loggedIn()->members_bitoptions['validating'] = TRUE;
\IPS\Member::loggedIn()->save();
\IPS\Email::buildFromTemplate( 'core', 'email_change', array( \IPS\Member::loggedIn(), $vid ) )->send( \IPS\Member::loggedIn() );
\IPS\Email::buildFromTemplate( 'core', 'email_change', array( \IPS\Member::loggedIn(), $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( \IPS\Member::loggedIn() );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
}
@@ -188,6 +235,9 @@ class _settings extends \IPS\Dispatcher\Controller
/* Or just redirect */
else
{
/* Send a confirmation email */
\IPS\Email::buildFromTemplate( 'core', 'email_address_changed', array( \IPS\Member::loggedIn(), $oldEmail ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $oldEmail, array(), array(), NULL, NULL, array( 'Reply-To' => \IPS\Settings::i()->email_in ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=email', 'front', 'settings' ), 'email_changed' );
}
}
@@ -207,12 +257,23 @@ class _settings extends \IPS\Dispatcher\Controller
return \IPS\Theme::i()->getTemplate( 'system' )->settingsPassword();
}
$mfaOutput = \IPS\MFA\MFAHandler::accessToArea( 'core', 'PasswordChange', \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=password', 'front', 'settings_password' ) );
if ( $mfaOutput )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) );
}
\IPS\Output::i()->output = $mfaOutput;
}
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_collapseTablet';
$form->add( new \IPS\Helpers\Form\Password( 'current_password', '', TRUE, array( 'validateFor' => \IPS\Member::loggedIn() ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'new_password', '', TRUE ) );
$form->add( new \IPS\Helpers\Form\Password( 'new_password', '', TRUE, array( 'showMeter' => \IPS\Settings::i()->password_strength_meter ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'confirm_new_password', '', TRUE, array( 'confirm' => 'new_password' ) ) );
if ( $values = $form->values() )
if ( !$mfaOutput and $values = $form->values() )
{
foreach ( \IPS\Login::handlers( TRUE ) as $handler )
{
@@ -223,17 +284,383 @@ class _settings extends \IPS\Dispatcher\Controller
}
catch( \BadMethodCallException $e ){}
}
\IPS\Member::loggedIn()->members_pass_salt = \IPS\Member::loggedIn()->generateSalt();
\IPS\Member::loggedIn()->members_pass_hash = \IPS\Member::loggedIn()->encryptedPassword( $values['new_password'] );
\IPS\Member::loggedIn()->save();
/* If we have a pass_hash cookie, update it so we stay logged in on the next page load */
if( isset( \IPS\Request::i()->cookie['pass_hash'] ) )
{
$expire = new \IPS\DateTime;
$expire->add( new \DateInterval( 'P3M' ) );
\IPS\Request::i()->setCookie( 'pass_hash', \IPS\Member::loggedIn()->member_login_key, $expire );
}
/* Send a confirmation email */
\IPS\Email::buildFromTemplate( 'core', 'password_changed', array(), \IPS\Email::TYPE_TRANSACTIONAL )->send( \IPS\Member::loggedIn(), array(), array(), NULL, NULL, array( 'Reply-To' => \IPS\Settings::i()->email_in ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=password', 'front', 'settings' ), 'password_changed' );
}
return \IPS\Theme::i()->getTemplate( 'system' )->settingsPassword( $form );
}
/**
* MFA
*
* @return string
*/
protected function _mfa()
{
/* Validate password */
if ( !isset( $_SESSION['passwordValidatedForMfa'] ) )
{
$form = new \IPS\Helpers\Form( 'mfa_password', 'continue' );
$form->class = 'ipsForm_collapseTablet';
$form->add( new \IPS\Helpers\Form\Password( 'password', '', TRUE, array( 'validateFor' => \IPS\Member::loggedIn() ) ) );
if ( $form->values() )
{
$_SESSION['passwordValidatedForMfa'] = TRUE;
}
else
{
return \IPS\Theme::i()->getTemplate( 'system' )->settingsMfaPassword( $form );
}
}
/* Do MFA check */
$mfaOutput = \IPS\MFA\MFAHandler::accessToArea( 'core', 'SecurityQuestions', \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) );
if ( $mfaOutput )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) );
}
\IPS\Output::i()->output = $mfaOutput;
}
/* Show it */
$handlers = array();
foreach ( \IPS\MFA\MFAHandler::handlers() as $key => $handler )
{
if ( $handler->isEnabled() and $handler->memberCanUseHandler( \IPS\Member::loggedIn() ) )
{
$handlers[ $key ] = $handler;
}
}
return \IPS\Theme::i()->getTemplate( 'system' )->settingsMfa( $handlers );
}
/**
* Initial MFA Setup
*
* @return string
*/
protected function initialMfa()
{
$ref = \IPS\Http\Url::internal('');
if ( isset( \IPS\Request::i()->ref ) )
{
try
{
$ref = \IPS\Http\Url\Friendly::createFromString( base64_decode( \IPS\Request::i()->ref ) );
}
catch ( \Exception $e ) { }
}
$handlers = array();
foreach ( \IPS\MFA\MFAHandler::handlers() as $key => $handler )
{
if ( $handler->isEnabled() and $handler->memberCanUseHandler( \IPS\Member::loggedIn() ) )
{
$handlers[ $key ] = $handler;
}
}
if ( isset( \IPS\Request::i()->mfa_setup ) )
{
foreach ( $handlers as $key => $handler )
{
if ( ( count( $handlers ) == 1 ) or $key == \IPS\Request::i()->mfa_method )
{
if ( $handler->configurationScreenSubmit( \IPS\Member::loggedIn() ) )
{
$_SESSION['MFAAuthenticated'] = time();
\IPS\Output::i()->redirect( $ref );
}
}
}
}
foreach ( $handlers as $key => $handler )
{
if ( $handler->memberHasConfiguredHandler( \IPS\Member::loggedIn() ) )
{
\IPS\Output::i()->redirect( $ref );
}
}
if ( isset( \IPS\Request::i()->_mfa ) and \IPS\Request::i()->_mfa == 'optout' )
{
\IPS\Member::loggedIn()->members_bitoptions['security_questions_opt_out'] = TRUE;
\IPS\Member::loggedIn()->save();
\IPS\Output::i()->redirect( $ref );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reg_complete_details');
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( '2fa.css', 'core', 'global' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->mfaSetup( $handlers, \IPS\Member::loggedIn(), \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&do=initialMfa', 'front', 'settings' )->setQueryString( 'ref', base64_encode( $ref ) ) );
}
/**
* Enable MFA
*
* @return string
*/
protected function enableMfa()
{
/* Get the handler */
$handlers = \IPS\MFA\MFAHandler::handlers();
$key = \IPS\Request::i()->type;
if ( !isset( $handlers[ $key ] ) or !$handlers[ $key ]->isEnabled() or !$handlers[ $key ]->memberCanUseHandler( \IPS\Member::loggedIn() ) or \IPS\MFA\MFAHandler::accessToArea( 'core', 'SecurityQuestions', \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C122/M', 404, '' );
}
/* Include the CSS we'll need */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( '2fa.css', 'core', 'global' ) );
/* Show the list again as the backdrop */
\IPS\Output::i()->output = $this->_wrapOutputInTemplate( 'mfa', $this->_mfa() );
/* Did we just submit it? */
if ( isset( \IPS\Request::i()->mfa_setup ) and $handlers[ $key ]->configurationScreenSubmit( \IPS\Member::loggedIn() ) )
{
\IPS\Member::loggedIn()->members_bitoptions['security_questions_opt_out'] = FALSE;
\IPS\Member::loggedIn()->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) );
}
/* And put the configruation modal over the top */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('settings');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'system' )->settingsMfaSetup( $handlers[ $key ]->configurationScreen( \IPS\Member::loggedIn() ), \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa&do=enableMfa&type=' . $key, 'front', 'settings_mfa' ) );
}
/**
* Disable MFA
*
* @return string
*/
protected function disableMfa()
{
/* Get the handler */
$handlers = \IPS\MFA\MFAHandler::handlers();
$key = \IPS\Request::i()->type;
if ( !isset( $handlers[ $key ] ) or !$handlers[ $key ]->isEnabled() or !$handlers[ $key ]->memberCanUseHandler( \IPS\Member::loggedIn() ) or \IPS\MFA\MFAHandler::accessToArea( 'core', 'SecurityQuestions', \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C122/N', 404, '' );
}
/* Disable it */
$handlers[ $key ]->disableHandlerForMember( \IPS\Member::loggedIn() );
\IPS\Member::loggedIn()->save();
/* If we have now disabled everything, save that we have opted out */
if ( \IPS\Settings::i()->mfa_required_groups != '*' and !\IPS\Member::loggedIn()->inGroup( explode( ',', \IPS\Settings::i()->mfa_required_groups ) ) )
{
$enabledHandlers = FALSE;
foreach ( $handlers as $handler )
{
if ( $handler->memberHasConfiguredHandler( \IPS\Member::loggedIn() ) )
{
$enabledHandlers = TRUE;
break;
}
}
if ( !$enabledHandlers )
{
\IPS\Member::loggedIn()->members_bitoptions['security_questions_opt_out'] = TRUE;
\IPS\Member::loggedIn()->save();
}
}
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) );
}
/**
* Security Questions
*
* @return string
*/
protected function _securityquestions()
{
$handler = new \IPS\MFA\SecurityQuestions\Handler();
if ( !$handler->isEnabled() )
{
\IPS\Output::i()->error( 'requested_route_404', '2C122/J', 404, '' );
}
$url = \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=securityquestions', 'front', 'settings_securityquestions' );
if ( isset( \IPS\Request::i()->initial ) )
{
if ( isset( \IPS\Request::i()->ref ) )
{
$url = $url->setQueryString( 'ref', \IPS\Request::i()->ref );
}
if ( !$handler->memberCanUseHandler( \IPS\Member::loggedIn() ) or $handler->memberHasConfiguredHandler( \IPS\Member::loggedIn() ) )
{
$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 ) { }
}
\IPS\Output::i()->redirect( $ref ?: \IPS\Http\Url::internal( '' ) );
}
$url = $url->setQueryString( 'initial', 1 );
}
elseif ( $handler->memberHasConfiguredHandler( \IPS\Member::loggedIn() ) )
{
if ( isset( \IPS\Request::i()->_securityQuestionSetup ) )
{
return \IPS\Theme::i()->getTemplate( 'system', 'core' )->securityQuestionsFinished();
}
elseif ( $output = \IPS\MFA\MFAHandler::accessToArea( 'core', 'SecurityQuestions', $url ) )
{
return $output;
}
}
$output = $handler->configurationForm( \IPS\Member::loggedIn(), $url, !isset( \IPS\Request::i()->initial ) );
if ( isset( \IPS\Request::i()->initial ) )
{
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->output = $output;
return;
}
else
{
return $output;
}
}
/**
* MFA Email Recovery
*
* @return string
*/
protected function mfarecovery()
{
/* Who are we */
if ( isset( $_SESSION['processing2FA'] ) )
{
$member = \IPS\Member::load( $_SESSION['processing2FA']['memberId'] );
}
else
{
$member = \IPS\Member::loggedIn();
}
/* Can we use this? */
if ( !$member->member_id or !( ( $member->failed_mfa_attempts >= \IPS\Settings::i()->security_questions_tries and \IPS\Settings::i()->mfa_lockout_behaviour == 'email' ) or in_array( 'email', explode( ',', \IPS\Settings::i()->mfa_forgot_behaviour ) ) ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C122/L', 403, '' );
}
/* If we have an existing validation record, we can just reuse it */
$sendEmail = TRUE;
try
{
$existing = \IPS\Db::i()->select( array( 'vid', 'email_sent' ), 'core_validating', array( 'member_id=? AND forgot_security=1', $member->member_id ) )->first();
$vid = $existing['vid'];
/* If we sent an email within the last 15 minutes, don't send another one otherwise someone could be a nuisence */
if ( $existing['email_sent'] and $existing['email_sent'] > ( time() - 900 ) )
{
$sendEmail = FALSE;
}
else
{
\IPS\Db::i()->update( 'core_validating', array( 'email_sent' => time() ), array( 'vid=?', $vid ) );
}
}
catch ( \UnderflowException $e )
{
$vid = md5( $member->members_pass_hash . \IPS\Login::generateRandomString() );
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => $member->member_id,
'entry_date' => time(),
'forgot_security' => 1,
'ip_address' => \IPS\Request::i()->ipAddress(),
'email_sent' => time(),
) );
}
/* Send email */
if ( $sendEmail )
{
\IPS\Email::buildFromTemplate( 'core', 'mfaRecovery', array( $member, $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
$message = "mfa_recovery_email_sent";
}
else
{
$message = "mfa_recovery_email_already_sent";
}
/* Show confirmation page with further instructions */
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('mfa_account_recovery');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->mfaAccountRecovery( $message );
}
/**
* Validate MFA Email Recovery
*
* @return void
*/
protected function mfarecoveryvalidate()
{
/* Validate */
try
{
$record = \IPS\Db::i()->select( '*', 'core_validating', array( 'vid=? AND member_id=? AND forgot_security=1', \IPS\Request::i()->vid, \IPS\Request::i()->mid ) )->first();
}
catch ( \UnderflowException $e )
{
\IPS\Output::i()->error( 'mfa_recovery_no_validation_key', '2C122/K', 410, '' );
}
/* Remove all MFA */
$member = \IPS\Member::load( $record['member_id'] );
foreach ( \IPS\MFA\MFAHandler::handlers() as $key => $handler )
{
$handler->disableHandlerForMember( $member );
}
$member->failed_mfa_attempts = 0;
$member->save();
/* Delete validating record */
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=? AND forgot_security=1', $member->member_id ) );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
}
/**
* Username
*
@@ -290,7 +717,8 @@ class _settings extends \IPS\Dispatcher\Controller
{
/* Build form */
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Text( 'new_username', '', TRUE, array( 'accountUsername' => TRUE ) ) );
$form->class = 'ipsForm_collapseTablet';
$form->add( new \IPS\Helpers\Form\Text( 'new_username', '', TRUE, array( 'accountUsername' => \IPS\Member::loggedIn() ) ) );
/* Handle submissions */
if ( $values = $form->values() )
@@ -364,6 +792,7 @@ class _settings extends \IPS\Dispatcher\Controller
/* Build form */
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_collapseTablet';
$form->add( new \IPS\Helpers\Form\YesNo( 'view_sigs', \IPS\Member::loggedIn()->members_bitoptions['view_sigs'], FALSE ) );
$form->add( new \IPS\Helpers\Form\Editor( 'signature', \IPS\Member::loggedIn()->signature, FALSE, array( 'app' => 'core', 'key' => 'Signatures', 'autoSaveKey' => "frontsig-" .\IPS\Member::loggedIn()->member_id, 'attachIds' => array( \IPS\Member::loggedIn()->member_id ) ) ) );
@@ -373,8 +802,8 @@ class _settings extends \IPS\Dispatcher\Controller
if( $values['signature'] )
{
/* Check Limits */
$signature = new \DOMDocument;
$signature->loadHTML( $values['signature'] );
$signature = new \IPS\Xml\DOMDocument( '1.0', 'UTF-8' );
$signature->loadHTML( \IPS\Xml\DOMDocument::wrapHtml( $values['signature'] ) );
$errors = array();
@@ -383,11 +812,22 @@ class _settings extends \IPS\Dispatcher\Controller
{
$errors[] = \IPS\Member::loggedIn()->language()->addToStack('sig_num_links_exceeded');
}
/* Number of Images */
if ( is_numeric( $sigLimits[1] ) and $signature->getElementsByTagName('img')->length > $sigLimits[1] )
if ( is_numeric( $sigLimits[1] ) and $signature->getElementsByTagName('img')->length > 0 )
{
$errors[] = \IPS\Member::loggedIn()->language()->addToStack('sig_num_images_exceeded');
$imageCount = 0;
foreach ( $signature->getElementsByTagName('img') as $img )
{
if( !$img->hasAttribute("data-emoticon") )
{
$imageCount++;
}
}
if( $imageCount > $sigLimits[1] )
{
$errors[] = \IPS\Member::loggedIn()->language()->addToStack('sig_num_images_exceeded');
}
}
/* Size of images */
@@ -395,10 +835,29 @@ class _settings extends \IPS\Dispatcher\Controller
{
foreach ( $signature->getElementsByTagName('img') as $image )
{
$src = $image->getAttribute('src');
\IPS\Output::i()->parseFileObjectUrls( $src );
$attachId = $image->getAttribute('data-fileid');
$checkSrc = TRUE;
if( $attachId )
{
try
{
$attachment = \IPS\Db::i()->select( 'attach_location, attach_thumb_location', 'core_attachments', array( 'attach_id=?', $attachId ) )->first();
$imageProperties = \IPS\File::get( 'core_Attachment', $attachment['attach_thumb_location'] ?: $attachment['attach_location'] )->getImageDimensions();
$checkSrc = FALSE;
}
catch( \UnderflowException $e ){}
}
if( $checkSrc )
{
$src = $image->getAttribute('src');
\IPS\Output::i()->parseFileObjectUrls( $src );
$imageProperties = @getimagesize( $src );
}
$imageProperties = @getimagesize( $src );
if( is_array( $imageProperties ) AND count( $imageProperties ) )
{
if( $imageProperties[0] > $sigLimits[2] OR $imageProperties[1] > $sigLimits[3] )
@@ -408,13 +867,22 @@ class _settings extends \IPS\Dispatcher\Controller
}
else
{
$errors[] = \IPS\Member::loggedIn()->language()->addToStack( 'sig_imagenotretrievable' );
$errors[] = \IPS\Member::loggedIn()->language()->addToStack( 'sig_imagenotretrievable', FALSE, array( 'sprintf' => array( $src ) ) );
}
}
}
/* Lines */
if ( is_numeric( $sigLimits[5] ) and ( $signature->getElementsByTagName('p')->length + $signature->getElementsByTagName('br')->length ) > $sigLimits[5] )
$preBreaks = 0;
/* Make sure we are not trying to bypass the limit by using <pre> tags, which will not have <p> or <br> tags in its content */
foreach( $signature->getElementsByTagName('pre') AS $pre )
{
$content = nl2br( trim( $pre->nodeValue ) );
$preBreaks += count( explode( "<br />", $content ) );
}
if ( is_numeric( $sigLimits[5] ) and ( $signature->getElementsByTagName('p')->length + $signature->getElementsByTagName('br')->length + $preBreaks ) > $sigLimits[5] )
{
$errors[] = \IPS\Member::loggedIn()->language()->addToStack('sig_num_lines_exceeded');
}
@@ -463,6 +931,9 @@ class _settings extends \IPS\Dispatcher\Controller
}
elseif ( isset( \IPS\Request::i()->disassociate ) )
{
/* CSRF check */
\IPS\Session::i()->csrfCheck();
/* Check they have another way of signing in */
$isOkay = FALSE;
foreach ( \IPS\Login::handlers() as $handler )
@@ -490,30 +961,19 @@ class _settings extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Checkbox( 'profilesync_photo', $settings['photo'], FALSE, array( 'labelSprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $serviceName ) ) ) ) );
if ( method_exists( $obj, 'photo' ) )
{
$form->add( new \IPS\Helpers\Form\Checkbox( 'profilesync_photo', $settings['photo'], FALSE, array( 'labelSprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $serviceName ) ) ) ) );
}
if ( method_exists( $obj, 'cover' ) )
{
$form->add( new \IPS\Helpers\Form\Checkbox( 'profilesync_cover', $settings['cover'], FALSE, array( 'labelSprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $serviceName ) ) ) ) );
}
if ( method_exists( $obj, 'status' ) and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'members' ) ) and !\IPS\Member::loggedIn()->members_bitoptions['bw_no_status_update'] )
if ( $obj->canImportStatus( \IPS\Member::loggedIn() ) )
{
$options = array();
if ( !\IPS\Member::loggedIn()->group['gbw_no_status_import'] )
{
$options['import'] = \IPS\Member::loggedIn()->language()->addToStack('profilesync_import_status', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $serviceName ) ) ) );
}
if ( method_exists( $obj, 'exportStatus' ) )
{
$options['export'] = \IPS\Member::loggedIn()->language()->addToStack('profilesync_export_status', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $serviceName ) ) ) );
}
$options['none'] = \IPS\Member::loggedIn()->language()->addToStack('profilesync_status_none');
$form->add( new \IPS\Helpers\Form\Radio( 'profilesync_status', $settings['status'], FALSE, array(
'labelSprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $serviceName ) ),
'options' => $options,
'parse' => FALSE
) ) );
$form->add( new \IPS\Helpers\Form\Checkbox( 'profilesync_status', $settings['status'] == 'import', FALSE, array( 'labelSprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $serviceName ) ) ) ) );
}
if ( $values = $form->values() )
@@ -521,7 +981,7 @@ class _settings extends \IPS\Dispatcher\Controller
$obj->save( $values );
}
$photo = $obj->photo();
$photo = ( method_exists( $obj, 'photo' ) ) ? $obj->photo() : NULL;
return \IPS\Theme::i()->getTemplate( 'system' )->settingsProfileSync( $photo instanceof \IPS\File ? $photo->url : $photo, $headline, method_exists( $obj, 'status' ) ? $obj->status() : NULL, $form, $service, "profilesync__{$service}", ( $settings['photo'] or $settings['cover'] or $settings['status'] ) );
}
else
@@ -2,9 +2,9 @@
/**
* @brief Splash Controller
* @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 21 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Terms of Use
* @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 25 Sept 2013
* @version SVN_VERSION_NUMBER
*/
@@ -37,4 +37,41 @@ class _terms extends \IPS\Dispatcher\Controller
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->terms();
}
/**
* Dismiss Terms
*
* @return void
*/
protected function dismiss()
{
\IPS\Request::i()->setCookie( 'guestTermsDismissed', 1, NULL, FALSE );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'message' => \IPS\Member::loggedIn()->language()->addToStack( 'terms_dismissed' ) ) );
}
else
{
if ( isset( \IPS\Request::i()->ref ) )
{
try
{
$url = \IPS\Http\Url::createFromString( base64_decode( \IPS\Request::i()->ref ) );
}
catch( \IPS\Http\Url\Exception $e )
{
$url = NULL;
}
if ( $url instanceof \IPS\Http\Url\Internal )
{
\IPS\Output::i()->redirect( $url, 'terms_dismissed' );
}
}
/* Still here? Just redirect to the index */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'terms_dismissed' );
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief Theme Changer
* @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 17 Dec 2013
* @version SVN_VERSION_NUMBER
*/
@@ -58,6 +58,12 @@ class _theme extends \IPS\Dispatcher\Controller
\IPS\Request::i()->setCookie( 'vseThemeId', 0 );
}
if ( \IPS\Member::loggedIn()->members_bitoptions['bw_using_skin_gen'] )
{
\IPS\Member::loggedIn()->members_bitoptions['bw_using_skin_gen'] = 0;
\IPS\Member::loggedIn()->save();
}
\IPS\Output::i()->redirect( ( !empty( $_SERVER['HTTP_REFERER'] ) ) ? \IPS\Http\Url::external( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal( '' ) );
}
}
@@ -2,9 +2,9 @@
/**
* @brief Allow users to unsubscribe from site updates
* @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 12 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -44,7 +44,7 @@ class _unsubscribe extends \IPS\Dispatcher\Controller
}
/* Verify the key is correct */
if ( \IPS\Request::i()->key == md5( $member->email . ':' . $member->members_pass_hash ) )
if ( \IPS\Login::compareHashes( md5( $member->email . ':' . $member->members_pass_hash ), (string) \IPS\Request::i()->key ) )
{
/* Set the member not to receive future emails */
$member->allow_admin_mails = 0;
+15 -3
View File
@@ -2,9 +2,9 @@
/**
* @brief Visual Language Editor
* @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 27 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -63,6 +63,8 @@ class _vle extends \IPS\Dispatcher\Controller
*/
public function set()
{
\IPS\Session::i()->csrfCheck();
try
{
$word = \IPS\Db::i()->select( '*', 'core_sys_lang_words', array( 'lang_id=? AND word_key=?', \IPS\Member::loggedIn()->language()->id, \IPS\Request::i()->key ) )->first();
@@ -72,11 +74,20 @@ class _vle extends \IPS\Dispatcher\Controller
$word = NULL;
}
try
{
$application = \IPS\Application::load( $word['word_app'] );
}
catch ( \Exception $e )
{
return;
}
if ( $word !== NULL )
{
if ( $word['word_export'] )
{
\IPS\Db::i()->update( 'core_sys_lang_words', array( 'word_custom' => \IPS\Request::i()->value, 'word_custom_version' => \IPS\Application::load( $word['word_app'] )->long_version ), array( 'word_id=?', $word['word_id'] ) );
\IPS\Db::i()->update( 'core_sys_lang_words', array( 'word_custom' => \IPS\Request::i()->value, 'word_custom_version' => $application->long_version ), array( 'word_id=?', $word['word_id'] ) );
}
else
{
@@ -94,6 +105,7 @@ class _vle extends \IPS\Dispatcher\Controller
\IPS\Db::i()->insert( 'core_admin_logs', array(
'member_id' => \IPS\Member::loggedIn()->member_id,
'member_name' => \IPS\Member::loggedIn()->name,
'ctime' => time(),
'note' => json_encode( array( $word['word_key'] => FALSE, \IPS\Member::loggedIn()->language()->title => FALSE ) ),
'ip_address' => \IPS\Request::i()->ipAddress(),
@@ -2,9 +2,9 @@
/**
* @brief Visual Theme Editor
* @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 7 Nov 2013
* @version SVN_VERSION_NUMBER
*/
@@ -144,6 +144,8 @@ class _vse extends \IPS\Dispatcher\Controller
*/
public function close()
{
\IPS\Session::i()->csrfCheck();
/* Update the current member */
\IPS\Member::loggedIn()->members_bitoptions['bw_using_skin_gen'] = 0;
\IPS\Member::loggedIn()->save();
@@ -179,6 +181,8 @@ class _vse extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->json( 'NO_PERMISSION', 403 );
}
\IPS\Session::i()->csrfCheck();
$theme = null;
@@ -199,7 +203,7 @@ class _vse extends \IPS\Dispatcher\Controller
$theme->vseSave( \IPS\Request::i()->css, \IPS\Request::i()->customcss, \IPS\Request::i()->settings, \IPS\Request::i()->values );
\IPS\File::getClass('core_Theme')->deleteContainer( 'css_built_' . $this->id );
\IPS\File::getClass('core_Theme')->deleteContainer( 'css_built_' . $theme->id );
$theme->css_map = array();
$theme->save();
foreach( $theme->children() as $child )
@@ -2,9 +2,9 @@
/**
* @brief Member Warnings
* @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 18 Jul 2013
* @version SVN_VERSION_NUMBER
*/
@@ -172,6 +172,8 @@ class _warnings extends \IPS\Content\Controller
*/
protected function acknowledge()
{
\IPS\Session::i()->csrfCheck();
/* Load the member */
$member = \IPS\Member::load( \IPS\Request::i()->id );
if ( !$member->member_id )
@@ -197,21 +199,21 @@ class _warnings extends \IPS\Content\Controller
/* Acknowledge it */
$warning->acknowledged = TRUE;
$warning->save();
$member->members_bitoptions['unacknowledged_warnings'] = (bool) \IPS\Db::i()->select( 'COUNT(*)', 'core_members_warn_logs', array( "wl_member=? AND wl_acknowledged=0", $member->member_id ) )->first();
$member->members_bitoptions['unacknowledged_warnings'] = (bool) \IPS\Db::i()->select( 'COUNT(*)', 'core_members_warn_logs', array( "wl_member=? AND wl_acknowledged=0", $member->member_id ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
$member->save();
/* Redirect */
if ( isset( $_SERVER['HTTP_REFERER'] ) )
{
$url = new \IPS\Http\Url( $_SERVER['HTTP_REFERER'] );
if ( $url->isInternal )
$url = \IPS\Http\Url\Friendly::createFromString( $_SERVER['HTTP_REFERER'] );
if ( $url instanceof \IPS\Http\Url\Internal )
{
\IPS\Output::i()->redirect( $url );
return;
}
}
\IPS\Output::i()->redirect( $warning->url() );
\IPS\Output::i()->redirect( $warning->url() );
}
/**
@@ -275,6 +277,7 @@ class _warnings extends \IPS\Content\Controller
'points_override' => TRUE,
'remove' => $remove,
'remove_override' => TRUE,
'notes' => NULL,
) );
}
@@ -307,6 +310,7 @@ class _warnings extends \IPS\Content\Controller
'points_override' => $reason->points_override,
'remove' => $remove,
'remove_override' => $reason->remove_override,
'notes' => $reason->notes,
) );
}
@@ -317,6 +321,7 @@ class _warnings extends \IPS\Content\Controller
'points_override' => FALSE,
'remove' => $remove,
'remove_override' => FALSE,
'notes' => NULL,
) );
}
}
@@ -2,9 +2,9 @@
/**
* @brief Sidebar Widgets
* @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 19 Nov 2013
* @version SVN_VERSION_NUMBER
*/
@@ -237,6 +237,8 @@ class _widgets extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->error( 'invalid_widget_area', '3S172/2', 403, '' );
}
\IPS\Session::i()->csrfCheck();
$newOrder = array();
$seen = array();