Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
@@ -11,21 +11,49 @@
|
||||
namespace IPS\MFA\SecurityQuestions;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use DomainException;
|
||||
use Exception;
|
||||
use IPS\core\modules\admin\settings\securityquestions;
|
||||
use IPS\Db;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\CheckboxSet;
|
||||
use IPS\Helpers\Form\Matrix;
|
||||
use IPS\Helpers\Form\Number;
|
||||
use IPS\Helpers\Form\Radio;
|
||||
use IPS\Helpers\Form\Select;
|
||||
use IPS\Helpers\Form\Text;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Group;
|
||||
use IPS\MFA\MFAHandler;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Settings;
|
||||
use IPS\Text\Encrypt;
|
||||
use IPS\Theme;
|
||||
use OutOfRangeException;
|
||||
use UnderflowException;
|
||||
use function count;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multi Factor Authentication Handler for Security Questions
|
||||
*/
|
||||
class _Handler extends \IPS\MFA\MFAHandler
|
||||
class Handler extends MFAHandler
|
||||
{
|
||||
/**
|
||||
* @brief Key
|
||||
*/
|
||||
protected $key = 'questions';
|
||||
protected string $key = 'questions';
|
||||
|
||||
/* !Setup */
|
||||
|
||||
@@ -34,29 +62,29 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled()
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return \IPS\Settings::i()->security_questions_enabled;
|
||||
return Settings::i()->security_questions_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Member *can* use this handler (even if they have not yet configured it)
|
||||
*
|
||||
* @param \IPS\Member $member Member to check
|
||||
* @param Member $member Member to check
|
||||
* @return bool
|
||||
*/
|
||||
public function memberCanUseHandler( \IPS\Member $member )
|
||||
public function memberCanUseHandler( Member $member ): bool
|
||||
{
|
||||
return \IPS\Settings::i()->security_questions_groups == '*' or $member->inGroup( explode( ',', \IPS\Settings::i()->security_questions_groups ) );
|
||||
return Settings::i()->security_questions_groups == '*' or $member->inGroup( explode( ',', Settings::i()->security_questions_groups ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Member has configured this handler
|
||||
*
|
||||
* @param \IPS\Member $member Member to check
|
||||
* @param Member $member Member to check
|
||||
* @return bool
|
||||
*/
|
||||
public function memberHasConfiguredHandler( \IPS\Member $member )
|
||||
public function memberHasConfiguredHandler( Member $member ): bool
|
||||
{
|
||||
return $member->members_bitoptions['has_security_answers'];
|
||||
}
|
||||
@@ -64,12 +92,12 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
/**
|
||||
* Show a setup screen
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param Member $member The member
|
||||
* @param bool $showingMultipleHandlers Set to TRUE if multiple options are being displayed
|
||||
* @param \IPS\Http\Url $url URL for page
|
||||
* @param Url $url URL for page
|
||||
* @return string
|
||||
*/
|
||||
public function configurationScreen( \IPS\Member $member, $showingMultipleHandlers, \IPS\Http\Url $url )
|
||||
public function configurationScreen( Member $member, bool $showingMultipleHandlers, Url $url ): string
|
||||
{
|
||||
$securityQuestions = array();
|
||||
foreach ( Question::roots() as $question )
|
||||
@@ -77,34 +105,34 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
$securityQuestions[ $question->id ] = $question->_title;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->securityQuestionsSetup( $securityQuestions, $showingMultipleHandlers );
|
||||
return Theme::i()->getTemplate( 'login', 'core', 'global' )->securityQuestionsSetup( $securityQuestions, $showingMultipleHandlers );
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit configuration screen. Return TRUE if was accepted
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param Member $member The member
|
||||
* @return bool
|
||||
*/
|
||||
public function configurationScreenSubmit( \IPS\Member $member )
|
||||
public function configurationScreenSubmit( Member $member ): bool
|
||||
{
|
||||
$answers = array();
|
||||
|
||||
$isReconfiguring = $this->memberHasConfiguredHandler( $member );
|
||||
|
||||
foreach ( \IPS\Request::i()->security_question as $k => $v )
|
||||
foreach ( Request::i()->security_question as $k => $v )
|
||||
{
|
||||
$answers[ $v ] = array(
|
||||
'answer_question_id' => $v,
|
||||
'answer_member_id' => $member->member_id,
|
||||
'answer_answer' => \IPS\Text\Encrypt::fromPlaintext( \IPS\Request::i()->security_answer[ $k ] )->tag()
|
||||
'answer_answer' => Encrypt::fromPlaintext( Request::i()->security_answer[ $k ] )->tag()
|
||||
);
|
||||
}
|
||||
|
||||
if ( \count( $answers ) >= \IPS\Settings::i()->security_questions_number )
|
||||
if ( count( $answers ) >= Settings::i()->security_questions_number )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_security_answers', array( 'answer_member_id=?', $member->member_id ) );
|
||||
\IPS\Db::i()->insert( 'core_security_answers', $answers );
|
||||
Db::i()->delete( 'core_security_answers', array( 'answer_member_id=?', $member->member_id ) );
|
||||
Db::i()->insert( 'core_security_answers', $answers );
|
||||
|
||||
$member->members_bitoptions['has_security_answers'] = TRUE;
|
||||
$member->save();
|
||||
@@ -123,59 +151,59 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
/**
|
||||
* Get the form for a member to authenticate
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param \IPS\Http\Url $url URL for page
|
||||
* @param Member $member The member
|
||||
* @param Url $url URL for page
|
||||
* @return string
|
||||
*/
|
||||
public function authenticationScreen( \IPS\Member $member, \IPS\Http\Url $url )
|
||||
public function authenticationScreen( Member $member, Url $url ): string
|
||||
{
|
||||
try
|
||||
{
|
||||
$chosenAnswer = \IPS\Db::i()->select( '*', 'core_security_answers', array( 'answer_member_id=? AND answer_is_chosen=1', $member->member_id ) )->first();
|
||||
$chosenAnswer = Db::i()->select( '*', 'core_security_answers', array( 'answer_member_id=? AND answer_is_chosen=1', $member->member_id ) )->first();
|
||||
$chosenQuestion = Question::load( $chosenAnswer['answer_question_id'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception $e )
|
||||
{
|
||||
$chosenQuestion = NULL;
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_security_answers', array( 'answer_member_id=?', $member->member_id ), 'RAND()' ) as $chosenAnswer )
|
||||
foreach ( Db::i()->select( '*', 'core_security_answers', array( 'answer_member_id=?', $member->member_id ), 'RAND()' ) as $chosenAnswer )
|
||||
{
|
||||
try
|
||||
{
|
||||
$chosenQuestion = Question::load( $chosenAnswer['answer_question_id'] );
|
||||
\IPS\Db::i()->update( 'core_security_answers', array( 'answer_is_chosen' => 1 ), array( 'answer_member_id=? AND answer_question_id=?', $member->member_id, $chosenQuestion->id ) );
|
||||
Db::i()->update( 'core_security_answers', array( 'answer_is_chosen' => 1 ), array( 'answer_member_id=? AND answer_question_id=?', $member->member_id, $chosenQuestion->id ) );
|
||||
break;
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
catch ( OutOfRangeException $e ) { }
|
||||
}
|
||||
if ( !$chosenQuestion )
|
||||
{
|
||||
return NULL;
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->securityQuestionsAuth( $chosenQuestion );
|
||||
return Theme::i()->getTemplate( 'login', 'core', 'global' )->securityQuestionsAuth( $chosenQuestion );
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit authentication screen. Return TRUE if was accepted
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @return string
|
||||
* @param Member $member The member
|
||||
* @return bool
|
||||
*/
|
||||
public function authenticationScreenSubmit( \IPS\Member $member )
|
||||
public function authenticationScreenSubmit( Member $member ): bool
|
||||
{
|
||||
try
|
||||
{
|
||||
$authenticated = \IPS\Request::i()->security_answer == \IPS\Text\Encrypt::fromTag( \IPS\Db::i()->select( 'answer_answer', 'core_security_answers', array( 'answer_member_id=? AND answer_is_chosen=1', $member->member_id ) )->first() )->decrypt();
|
||||
$authenticated = Request::i()->security_answer == Encrypt::fromTag( Db::i()->select( 'answer_answer', 'core_security_answers', array( 'answer_member_id=? AND answer_is_chosen=1', $member->member_id ) )->first() )->decrypt();
|
||||
|
||||
if( $authenticated )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_security_answers', array( 'answer_is_chosen' => 0 ), array( 'answer_member_id=? AND answer_is_chosen=?', $member->member_id, 1 ) );
|
||||
Db::i()->update( 'core_security_answers', array( 'answer_is_chosen' => 0 ), array( 'answer_member_id=? AND answer_is_chosen=?', $member->member_id, 1 ) );
|
||||
}
|
||||
|
||||
return $authenticated;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch ( UnderflowException $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -187,20 +215,20 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
* Toggle
|
||||
*
|
||||
* @param bool $enabled On/Off
|
||||
* @return bool
|
||||
* @return void
|
||||
*/
|
||||
public function toggle( $enabled )
|
||||
public function toggle( bool $enabled ) : void
|
||||
{
|
||||
if( $enabled )
|
||||
{
|
||||
/* Check we have some questions */
|
||||
if ( !count( \IPS\MFA\SecurityQuestions\Question::roots() ) )
|
||||
if ( !count( Question::roots() ) )
|
||||
{
|
||||
throw new \DomainException( 'no_questions' );
|
||||
throw new DomainException( 'no_questions' );
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Settings::i()->changeValues( array( 'security_questions_enabled' => $enabled ) );
|
||||
Settings::i()->changeValues( array( 'security_questions_enabled' => $enabled ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +236,7 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function acpSettings()
|
||||
public function acpSettings(): string
|
||||
{
|
||||
/* Init */
|
||||
$activeTabContents = '';
|
||||
@@ -216,21 +244,21 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
'settings' => 'security_question_settings',
|
||||
'questions' => 'security_questions_questions'
|
||||
);
|
||||
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'handlers';
|
||||
$activeTab = ( isset( Request::i()->tab ) and array_key_exists( Request::i()->tab, $tabs ) ) ? Request::i()->tab : 'handlers';
|
||||
|
||||
/* Settings Form */
|
||||
if ( $activeTab === 'settings' )
|
||||
{
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'security_questions_groups', \IPS\Settings::i()->security_questions_groups == '*' ? '*' : explode( ',', \IPS\Settings::i()->security_questions_groups ), FALSE, array(
|
||||
$form = new Form;
|
||||
$form->add( new CheckboxSet( 'security_questions_groups', Settings::i()->security_questions_groups == '*' ? '*' : explode( ',', Settings::i()->security_questions_groups ), FALSE, array(
|
||||
'multiple' => TRUE,
|
||||
'options' => array_combine( array_keys( \IPS\Member\Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups() ) ),
|
||||
'options' => array_combine( array_keys( Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, Group::groups() ) ),
|
||||
'unlimited' => '*',
|
||||
'unlimitedLang' => 'everyone',
|
||||
'impliedUnlimited' => TRUE
|
||||
), NULL, NULL, NULL, 'security_questions_groups' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'security_questions_prompt', \IPS\Settings::i()->security_questions_prompt, FALSE, array( 'options' => array( 'register' => 'security_questions_prompt_register', 'optional' => 'security_questions_prompt_optional', 'access' => 'security_questions_prompt_access' ) ), NULL, NULL, NULL, 'security_questions_prompt' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'security_questions_number', \IPS\Settings::i()->security_questions_number, FALSE, array( 'min' => 1, 'max' => \IPS\Db::i()->select( 'COUNT(*)', 'core_security_questions' )->first() ?: NULL ), NULL, NULL, NULL, 'security_questions_number' ) );
|
||||
$form->add( new Radio( 'security_questions_prompt', Settings::i()->security_questions_prompt, FALSE, array( 'options' => array( 'register' => 'security_questions_prompt_register', 'optional' => 'security_questions_prompt_optional', 'access' => 'security_questions_prompt_access' ) ), NULL, NULL, NULL, 'security_questions_prompt' ) );
|
||||
$form->add( new Number( 'security_questions_number', Settings::i()->security_questions_number, FALSE, array( 'min' => 1, 'max' => Db::i()->select( 'COUNT(*)', 'core_security_questions' )->first() ?: NULL ), NULL, NULL, NULL, 'security_questions_number' ) );
|
||||
|
||||
$form->addMessage('nexus_mfa_reset_answers');
|
||||
|
||||
@@ -238,8 +266,8 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
{
|
||||
$values['security_questions_groups'] = ( $values['security_questions_groups'] == '*' ) ? '*' : implode( ',', $values['security_questions_groups'] );
|
||||
$form->saveAsSettings( $values );
|
||||
\IPS\Session::i()->log( 'acplogs__mfa_handler_enabled', array( "mfa_questions_title" => TRUE ) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=mfa' ), 'saved' );
|
||||
Session::i()->log( 'acplogs__mfa_handler_enabled', array( "mfa_questions_title" => TRUE ) );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=mfa' ), 'saved' );
|
||||
}
|
||||
|
||||
$activeTabContents = (string) $form;
|
||||
@@ -248,49 +276,49 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
/* Questions table */
|
||||
else
|
||||
{
|
||||
$controller = new \IPS\core\modules\admin\settings\securityquestions;
|
||||
$controller = new securityquestions;
|
||||
$controller->execute();
|
||||
$activeTabContents = \IPS\Output::i()->output;
|
||||
$activeTabContents = Output::i()->output;
|
||||
}
|
||||
|
||||
|
||||
/* Output */
|
||||
if( \IPS\Request::i()->isAjax() )
|
||||
if( Request::i()->isAjax() )
|
||||
{
|
||||
return $activeTabContents;
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=settings&controller=mfa&tab=handlers&do=settings&key=questions" ) );
|
||||
return Theme::i()->getTemplate( 'global' )->tabs( $tabs, $activeTab, $activeTabContents, Url::internal( "app=core&module=settings&controller=mfa&tab=handlers&do=settings&key=questions" ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options when editing member account in ACP
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param Member $member The member
|
||||
* @return array
|
||||
*/
|
||||
public function acpConfiguration( \IPS\Member $member )
|
||||
public function acpConfiguration( Member $member ): array
|
||||
{
|
||||
$return = array();
|
||||
$return[] = new \IPS\Helpers\Form\YesNo( "mfa_{$this->key}_title", $this->memberHasConfiguredHandler( $member ), FALSE, array( 'togglesOn' => array( 'security_question_matrix' ) ) );
|
||||
$return[] = new YesNo( "mfa_{$this->key}_title", $this->memberHasConfiguredHandler( $member ), FALSE, array( 'togglesOn' => array( 'security_question_matrix' ) ) );
|
||||
|
||||
$securityQuestions = array();
|
||||
foreach ( \IPS\MFA\SecurityQuestions\Question::roots() as $question )
|
||||
foreach (Question::roots() as $question )
|
||||
{
|
||||
$securityQuestions[ $question->id ] = $question->_title;
|
||||
}
|
||||
|
||||
$matrix = new \IPS\Helpers\Form\Matrix('security_question_matrix');
|
||||
$matrix = new Matrix('security_question_matrix');
|
||||
$matrix->columns = array(
|
||||
'security_question_q' => function( $key, $value, $data ) use ( $securityQuestions )
|
||||
{
|
||||
return new \IPS\Helpers\Form\Select( $key, $value, FALSE, array( 'options' => $securityQuestions ) );
|
||||
return new Select( $key, $value, FALSE, array( 'options' => $securityQuestions ) );
|
||||
},
|
||||
'security_question_a' => function( $key, $value, $data )
|
||||
{
|
||||
return new \IPS\Helpers\Form\Text( $key, $value );
|
||||
return new Text( $key, $value );
|
||||
},
|
||||
);
|
||||
|
||||
@@ -298,7 +326,7 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
{
|
||||
$matrix->rows[] = array(
|
||||
'security_question_q' => $questionId,
|
||||
'security_question_a' => \IPS\Text\Encrypt::fromTag( $answer )->decrypt()
|
||||
'security_question_a' => Encrypt::fromTag( $answer )->decrypt()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -311,11 +339,11 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
/**
|
||||
* Save configuration when editing member account in ACP
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param array $values Values from form
|
||||
* @return array
|
||||
* @param Member $member The member
|
||||
* @param array $values Values from form
|
||||
* @return void
|
||||
*/
|
||||
public function acpConfigurationSave( \IPS\Member $member, $values )
|
||||
public function acpConfigurationSave( Member $member, array $values ): void
|
||||
{
|
||||
if ( isset( $values["mfa_{$this->key}_title"] ) and !$values["mfa_{$this->key}_title"] )
|
||||
{
|
||||
@@ -326,7 +354,7 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
return;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_security_answers', array( 'answer_member_id=?', $member->member_id ) );
|
||||
Db::i()->delete( 'core_security_answers', array( 'answer_member_id=?', $member->member_id ) );
|
||||
|
||||
$toInsert = array();
|
||||
|
||||
@@ -337,17 +365,17 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
$toInsert[ $row['security_question_q'] ] = array(
|
||||
'answer_question_id' => $row['security_question_q'],
|
||||
'answer_member_id' => $member->member_id,
|
||||
'answer_answer' => (string) \IPS\Text\Encrypt::fromPlaintext( $row['security_question_a'] )->tag()
|
||||
'answer_answer' => Encrypt::fromPlaintext( $row['security_question_a'] )->tag()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( \count( $toInsert ) )
|
||||
if ( count( $toInsert ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_security_answers', $toInsert );
|
||||
Db::i()->insert( 'core_security_answers', $toInsert );
|
||||
}
|
||||
|
||||
if ( \count( $toInsert ) >= \IPS\Settings::i()->security_questions_number )
|
||||
if ( count( $toInsert ) >= Settings::i()->security_questions_number )
|
||||
{
|
||||
$member->members_bitoptions['has_security_answers'] = TRUE;
|
||||
}
|
||||
@@ -362,12 +390,12 @@ class _Handler extends \IPS\MFA\MFAHandler
|
||||
/**
|
||||
* If member has configured this handler, disable it
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param Member $member The member
|
||||
* @return void
|
||||
*/
|
||||
public function disableHandlerForMember( \IPS\Member $member )
|
||||
public function disableHandlerForMember( Member $member ) : void
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_security_answers', array( 'answer_member_id=?', $member->member_id ) );
|
||||
Db::i()->delete( 'core_security_answers', array( 'answer_member_id=?', $member->member_id ) );
|
||||
$member->members_bitoptions['has_security_answers'] = FALSE;
|
||||
$member->save();
|
||||
|
||||
|
||||
@@ -11,56 +11,63 @@
|
||||
namespace IPS\MFA\SecurityQuestions;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Translatable;
|
||||
use IPS\Lang;
|
||||
use IPS\Node\Model;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Security Question Node
|
||||
*/
|
||||
class _Question extends \IPS\Node\Model
|
||||
class Question extends Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'core_security_questions';
|
||||
public static ?string $databaseTable = 'core_security_questions';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'question_';
|
||||
public static string $databasePrefix = 'question_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'order';
|
||||
public static ?string $databaseColumnOrder = 'order';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'security_questions';
|
||||
public static string $nodeTitle = 'security_questions';
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'security_question_';
|
||||
public static ?string $titleLangPrefix = 'security_question_';
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @param Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
public function form( Form &$form ) : void
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'security_question_title', NULL, TRUE, array( 'app' => 'core', 'key' => ( $this->id ? "security_question_{$this->id}" : NULL ) ) ) );
|
||||
$form->add( new Translatable( 'security_question_title', NULL, TRUE, array( 'app' => 'core', 'key' => ( $this->id ? "security_question_{$this->id}" : NULL ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,14 +76,14 @@ class _Question extends \IPS\Node\Model
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
public function formatFormValues( array $values ): array
|
||||
{
|
||||
if( !$this->id )
|
||||
{
|
||||
$this->save();
|
||||
}
|
||||
|
||||
\IPS\Lang::saveCustom( 'core', "security_question_{$this->id}", $values['security_question_title'] );
|
||||
Lang::saveCustom( 'core', "security_question_{$this->id}", $values['security_question_title'] );
|
||||
unset( $values['security_question_title'] );
|
||||
|
||||
return $values;
|
||||
|
||||
Reference in new issue
Block a user