소스 검색

#1187 Core changes

RomanL 8 년 전
부모
커밋
81990525ea

+ 108 - 6
inc/classes/BxDolAccount.php

@@ -86,11 +86,75 @@ class BxDolAccount extends BxDolFactory implements iBxDolSingleton
      */
     public function isConfirmed($iAccountId = false)
     {
-        if (!getParam('sys_email_confirmation')) // if email_confirmation procedure is disabled, always return true
+        $sConfirmationType = getParam('sys_account_confirmation_type');
+        if ($sConfirmationType == BX_ACCOUNT_CONFIRMATION_NONE) 
+            return true;
+        
+        $a = $this->getInfo((int)$iAccountId);
+        
+        switch ($sConfirmationType) {
+            case BX_ACCOUNT_CONFIRMATION_EMAIL:
+                if ($a['email_confirmed'])
+                    return true;
+                break;
+            case BX_ACCOUNT_CONFIRMATION_PHONE:
+                if ($a['phone_confirmed'])
+                    return true;
+                break;
+            case BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE:
+                if ($a['email_confirmed'] && $a['phone_confirmed'])
+                    return true;
+                break;
+        }
+        return false;
+    }
+    
+    public function ConfirmationStatus($iAccountId = false)
+    {
+        $a = $this->getInfo((int)$iAccountId);
+        $sTmp = $a['email_confirmed'] . $a['phone_confirmed'];
+        switch ($sTmp) {
+            case '01':
+                return BX_ACCOUNT_CONFIRMATION_PHONE;
+            case '10':
+                return BX_ACCOUNT_CONFIRMATION_EMAIL;
+            case '11':
+                return BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE;
+        }
+        return BX_ACCOUNT_CONFIRMATION_NONE;
+    }
+    
+    public function isConfirmedEmail($iAccountId = false)
+    {
+        if (!self::isNeedConfirmEmail())
             return true;
         $a = $this->getInfo((int)$iAccountId);
         return $a['email_confirmed'] ? true : false;
     }
+    
+    public function isConfirmedPhone($iAccountId = false)
+    {
+        if (!self::isNeedConfirmPhone())
+            return true;
+        $a = $this->getInfo((int)$iAccountId);
+        return $a['phone_confirmed'] ? true : false;
+    }
+    
+    static public function isNeedConfirmEmail()
+    {
+        if (getParam('sys_account_confirmation_type') == BX_ACCOUNT_CONFIRMATION_EMAIL || getParam('sys_account_confirmation_type') == BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE) 
+            return true;
+        return false;
+    }
+    
+    static public function isNeedConfirmPhone()
+    {
+        if (getParam('sys_account_confirmation_type') == BX_ACCOUNT_CONFIRMATION_PHONE || getParam('sys_account_confirmation_type') == BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE) 
+            return true;
+        return false;
+    }
+    
+    //
 
     /**
      * Set account email to confirmed or unconfirmed
@@ -102,17 +166,50 @@ class BxDolAccount extends BxDolFactory implements iBxDolSingleton
     {
         $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
 
-        if (!$isConfirmed && $isAutoSendConfrmationEmail && getParam('sys_email_confirmation')) // if email_confirmation procedure is enabled - send email confirmation letter
+        if (!$isConfirmed && $isAutoSendConfrmationEmail && self::isNeedConfirmEmail()) // if email_confirmation procedure is enabled - send email confirmation letter
             $this->sendConfirmationEmail($iId);
 
         if ($this->_oQuery->updateEmailConfirmed($isConfirmed, $iId)) {
             $this->_aInfo = false;
-            bx_alert('account', $isConfirmed ? 'confirm' : 'unconfirm', $iId);
+            bx_alert('account', $this->isConfirmed() ? 'confirm' : 'unconfirm', $iId);
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Set account phone to confirmed or unconfirmed
+     * @param  int  $isConfirmed - false: mark phone as unconfirmed, true: as confirmed
+     * @param  int  $iAccountId  - optional account id
+     * @return true on success or false on error
+     */
+    public function updatePhoneConfirmed($isConfirmed, $iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        
+        if ($this->_oQuery->updatePhoneConfirmed($isConfirmed, $iId)) {
+            $this->_aInfo = false;
+            bx_alert('account', $this->isConfirmed() ? 'confirm' : 'unconfirm', $iId);
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Set account phone
+     * @param  string  $sPhone - phone number
+     * @param  int  $iAccountId  - optional account id
+     * @return true on success or false on error
+     */
+    public function updatePhone($sPhone, $iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        if ($this->_oQuery->updatePhone($sPhone, $iId)) {
+            bx_alert('account', 'set_phone', $iId);
             return true;
         }
         return false;
     }
-
     /**
      * Switch context automatically to the first available profile
      * @param $iProfileIdFilterOut profile ID to exclude from the list of possible profiles
@@ -399,10 +496,15 @@ class BxDolAccount extends BxDolFactory implements iBxDolSingleton
      */
     public function addInformerPermanentMessages ($oInformer)
     {
-        if (!$this->isConfirmed()) {
+        if (!$this->isConfirmedEmail()) {
             $sUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=confirm-email') . '&resend=1';
             $aAccountInfo = $this->getInfo();
-            $oInformer->add('sys-account-unconfirmed', _t('_sys_txt_account_unconfirmed', $sUrl, $aAccountInfo['email']), BX_INFORMER_ALERT);
+            $oInformer->add('sys-account-unconfirmed-email', _t('_sys_txt_account_unconfirmed_email', $sUrl, $aAccountInfo['email']), BX_INFORMER_ALERT);
+        }
+		if (!$this->isConfirmedPhone()) {
+            $sUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=confirm-phone') . '';
+            $aAccountInfo = $this->getInfo();
+            $oInformer->add('sys-account-unconfirmed-phone', _t('_sys_txt_account_unconfirmed_phone', $sUrl), BX_INFORMER_ALERT);
         }
     }
 

+ 31 - 0
inc/classes/BxDolAccountQuery.php

@@ -77,6 +77,14 @@ class BxDolAccountQuery extends BxDolDb implements iBxDolSingleton
     {
         return (int)$this->_getFieldByField('id', 'email', $sEmail);
     }
+    
+    /**
+     * get account id by phone
+     */
+    public function getIdByPhone($sPhone)
+    {
+        return (int)$this->_getFieldByField('id', 'phone', $sPhone);
+    }
 
     /**
      * get account id by id
@@ -198,6 +206,29 @@ class BxDolAccountQuery extends BxDolDb implements iBxDolSingleton
     {
         return $this->_updateField ($iID, 'email_confirmed', $isConfirmed ? 1 : 0);
     }
+    
+    /**
+     * Update 'phone_confirmed' field.
+     * @param  int    $isConfirmed - 0: mark phone as unconfirmed, 1: as confirmed
+     * @param  int    $iID         - account id
+     * @return number of affected rows
+     */
+    public function updatePhoneConfirmed($isConfirmed, $iID)
+    {
+        return $this->_updateField ($iID, 'phone_confirmed', $isConfirmed ? 1 : 0);
+    }
+    
+    /**
+     * Update 'phone' field.
+     * @param  int    $sPhone - phone number
+     * @param  int    $iID         - account id
+     * @return number of affected rows
+     */
+    public function updatePhone($sPhone, $iID)
+    {
+        $sSql = $this->prepare("UPDATE `sys_accounts` SET `phone` = ?, `phone_confirmed` = 0 WHERE `id` = ? LIMIT 1", $sPhone, $iID);
+        return $this->query($sSql);
+    }
 
     /**
      * Get account field by specified field name and value.

+ 63 - 0
inc/classes/BxDolTwilio.php

@@ -0,0 +1,63 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolTwilio extends BxDolDb implements iBxDolSingleton
+{
+    protected $_sSid;
+    protected $_sToken;
+    protected $_sFromNumber;
+    
+    protected function __construct()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
+
+        parent::__construct();
+
+        $this->_sSid = getParam('sys_twilio_gate_sid');
+        $this->_sToken = getParam('sys_twilio_gate_token');
+        $this->_sFromNumber = getParam('sys_twilio_gate_from_number');
+    }
+
+    /**
+     * Prevent cloning the instance
+     */
+    public function __clone()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
+    }
+
+    /**
+     * Get singleton instance of the class
+     */
+    public static function getInstance()
+    {
+        if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+            $GLOBALS['bxDolClasses'][__CLASS__] = new BxDolTwilio();
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+    
+    public function SendSms($sTo, $sMessage, $sFrom = '')
+    {
+        try{
+            require_once BX_DIRECTORY_PATH_PLUGINS . 'Twilio/autoload.php'; // Loads the library
+            $client = new Twilio\Rest\Client($this->_sSid, $this->_sToken);
+            $aParams = array('body' => $sMessage, 'from' => $sFrom != '' ? $sFrom : $this->_sFromNumber);
+            $client->messages->create($sTo, $aParams);
+            return true;
+        }
+        catch (Exception $oException) {
+            return false;
+        }
+    }
+}
+
+/** @} */

+ 9 - 0
inc/params.inc.php

@@ -76,6 +76,15 @@ define('BX_PROFILE_STATUS_SUSPENDED', 'suspended'); ///< profile status - suspen
 define('BX_PROFILE_STATUS_ACTIVE', 'active'); ///< profile status - active, profile is active on the site
 define('BX_PROFILE_STATUS_PENDING', 'pending'); ///< profile status - pending, default method of approving is manual approving
 
+//--- Account settings ---//
+define('BX_ACCOUNT_SESSION_KEY_FOR_2FA_LOGIN_ACCOUNT_ID', '2FA_LOGIN_ACCOUNT_ID');
+define('BX_ACCOUNT_SESSION_KEY_FOR_2FA_LOGIN_IS_REMEMBER', '2FA_LOGIN_IS_REMEMBER');
+define('BX_ACCOUNT_SESSION_KEY_FOR_PHONE_ACTIVATEION_CODE', 'PHONE_ACTIVATEION_CODE');
+define('BX_ACCOUNT_CONFIRMATION_NONE', 'none');
+define('BX_ACCOUNT_CONFIRMATION_EMAIL', 'email');
+define('BX_ACCOUNT_CONFIRMATION_PHONE', 'phone');
+define('BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE', 'email_and_phone');
+
 //--- Include files needed for basic functionality ---//
 require_once(BX_DIRECTORY_PATH_CLASSES . 'BxDol.php');
 require_once(BX_DIRECTORY_PATH_INC . 'utils.inc.php');

+ 62 - 8
install/sql/system.sql

@@ -280,7 +280,6 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `ex
 (@iCategoryId, 'sys_template_cache_image_enable', '_adm_stg_cpt_option_sys_template_cache_image_enable', '', 'checkbox', '', '', '', 20),
 (@iCategoryId, 'sys_template_cache_image_max_size', '_adm_stg_cpt_option_sys_template_cache_image_max_size', '5', 'digit', '', '', '', 21),
 
-(@iCategoryId, 'sys_email_confirmation', '_adm_stg_cpt_option_sys_email_confirmation', 'on', 'checkbox', '', '', '', 30),
 (@iCategoryId, 'sys_email_attachable_email_templates', '_adm_stg_cpt_option_sys_email_attachable_email_templates', '', 'digit', '', '', '', 31),
 
 (@iCategoryId, 'sys_redirect_after_account_added', '_adm_stg_cpt_option_sys_redirect_after_account_added', 'page.php?i=account-profile-switcher&register=1', 'digit', '', '', '', 40),
@@ -465,6 +464,8 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `ex
 (@iCategoryId, 'sys_account_online_time', '_adm_stg_cpt_option_sys_account_online_time', '5', 'digit', '', 'Avail', '_adm_stg_err_option_sys_account_online_time', 1),
 (@iCategoryId, 'sys_account_autoapproval', '_adm_stg_cpt_option_sys_account_autoapproval', 'on', 'checkbox', '', '', '', 10),
 (@iCategoryId, 'sys_account_activation_letter', '_adm_stg_cpt_option_sys_account_activation_letter', '', 'checkbox', '', '', '', 11),
+(@iCategoryId, 'sys_account_confirmation_type', '_adm_stg_cpt_option_sys_account_confirmation_type', 'email', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:22:"get_confirmation_types";s:5:"class";s:18:"BaseServiceAccount";}', '', '', 12),
+(@iCategoryId, 'sys_account_activation_2fa_enable', '_adm_stg_cpt_option_sys_account_2fa_enable', '', 'checkbox', '', '', '', 13),
 (@iCategoryId, 'sys_account_auto_profile_creation', '_adm_stg_cpt_option_sys_account_auto_profile_creation', 'on', 'checkbox', '', '', '', 15),
 (@iCategoryId, 'sys_account_default_profile_type', '_adm_stg_cpt_option_sys_account_default_profile_type', '', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:17:"get_profile_types";s:5:"class";s:20:"TemplServiceProfiles";}', '', '', 20),
 (@iCategoryId, 'sys_account_limit_profiles_number', '_adm_stg_cpt_option_sys_account_limit_profiles_number', '0', 'digit', '', '', '', 21);
@@ -505,6 +506,18 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `ex
 
 (@iCategoryId, 'sys_push_queue_send_per_start', '_adm_stg_cpt_option_sys_push_queue_send_per_start', '500',  'digit', '', '', '', 10);
 
+
+--
+-- CATEGORY: Twilio gate settings
+--
+INSERT INTO `sys_options_categories`(`type_id`, `name`, `caption`, `hidden`, `order`) VALUES (@iTypeId, 'twilio_gate', '_adm_stg_cpt_category_twilio_gate', 0, 18);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'sys_twilio_gate_sid', '_adm_stg_cpt_option_sys_twilio_gate_sid', '', 'digit', '', '', '', 1),
+(@iCategoryId, 'sys_twilio_gate_token', '_adm_stg_cpt_option_sys_twilio_gate_token', '', 'digit', '', '', '', 2),
+(@iCategoryId, 'sys_twilio_gate_from_number', '_adm_stg_cpt_option_sys_twilio_gate_from_number', '', 'digit', '', '', '', 3);
+
 --
 -- Table structure for table `sys_options_mixes`
 --
@@ -877,6 +890,8 @@ CREATE TABLE `sys_accounts` (
   `name` varchar(255) NOT NULL,
   `email` varchar(255) NOT NULL,
   `email_confirmed` tinyint(4) NOT NULL DEFAULT '0',
+  `phone` varchar(255) NOT NULL,
+  `phone_confirmed` tinyint(4) NOT NULL DEFAULT '0',
   `receive_updates` tinyint(4) NOT NULL DEFAULT '1',
   `receive_news` tinyint(4) NOT NULL DEFAULT '1',
   `password` varchar(40) NOT NULL,
@@ -2721,10 +2736,11 @@ CREATE TABLE IF NOT EXISTS `sys_objects_form` (
 );
 
 INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
-('sys_login', 'system', '_sys_form_login', 'member.php', 'a:3:{s:2:"id";s:14:"sys-form-login";s:6:"action";s:10:"member.php";s:8:"onsubmit";s:31:"return validateLoginForm(this);";}', 'role', '', '', '', '', '', 0, 1, 'BxTemplFormLogin', ''),
+('sys_login', 'system', '_sys_form_login', 'member.php', 'a:3:{s:2:"id";s:14:"sys-form-login";s:6:"action";s:10:"member.php";s:8:"onsubmit";s:31:"return validateLoginForm(this);";}', 'a:3:{i:0;s:4:"role";i:1;s:10:"do_sendsms";i:2;s:12:"do_checkcode";}', '', '', '', '', 'a:1:{s:14:"checker_helper";s:24:"BxFormLoginCheckerHelper";}', 0, 1, 'BxTemplFormLogin', ''),
 ('sys_account', 'system', '_sys_form_account', '', '', 'do_submit', 'sys_accounts', 'id', '', '', 'a:1:{s:14:"checker_helper";s:26:"BxFormAccountCheckerHelper";}', 0, 1, 'BxTemplFormAccount', ''),
 ('sys_forgot_password', 'system', '_sys_form_forgot_password', '', '', 'do_submit', '', '', '', '', 'a:1:{s:14:"checker_helper";s:33:"BxFormForgotPasswordCheckerHelper";}', 0, 1, 'BxTemplFormForgotPassword', ''),
 ('sys_confirm_email', 'system', '_sys_form_confirm_email', '', '', 'do_submit', '', '', '', '', 'a:1:{s:14:"checker_helper";s:31:"BxFormConfirmEmailCheckerHelper";}', 0, 1, 'BxTemplFormConfirmEmail', ''),
+('sys_confirm_phone', 'system', '_sys_form_confirm_phone', '', '', 'a:2:{i:0;s:9:"do_submit";i:1;s:10:"do_sendsms";}', '', '', '', '', 'a:1:{s:14:"checker_helper";s:31:"BxFormConfirmPhoneCheckerHelper";}', 0, 1, 'BxTemplFormConfirmPhone', ''),
 ('sys_unsubscribe', 'system', '_sys_form_unsubscribe', '', '', 'do_submit', 'sys_accounts', 'id', '', '', '', 0, 1, 'BxTemplFormAccount', ''),
 ('sys_comment', 'system', '_sys_form_comment', 'cmts.php', 'a:3:{s:2:"id";s:17:"cmt-%s-form-%s-%d";s:4:"name";s:17:"cmt-%s-form-%s-%d";s:5:"class";s:14:"cmt-post-reply";}', 'cmt_submit', '', 'cmt_id', '', '', '', 0, 1, 'BxTemplCmtsForm', ''),
 ('sys_report', 'system', '_sys_form_report', 'report.php', 'a:3:{s:2:"id";s:0:"";s:4:"name";s:0:"";s:5:"class";s:17:"bx-report-do-form";}', 'submit', '', 'id', '', '', '', 0, 1, '', '');
@@ -2742,12 +2758,16 @@ CREATE TABLE IF NOT EXISTS `sys_form_displays` (
 
 INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
 ('sys_login', 'system', 'sys_login', '_sys_form_display_login', 0),
+('sys_login_step2', 'system', 'sys_login', '_sys_form_display_login_step2', 0),
+('sys_login_step3', 'system', 'sys_login', '_sys_form_display_login_step3', 0),
 ('sys_account_create', 'system', 'sys_account', '_sys_form_display_account_create', 0),
 ('sys_account_settings_email', 'system', 'sys_account', '_sys_form_display_account_settings_email', 0),
 ('sys_account_settings_pwd', 'system', 'sys_account', '_sys_form_display_account_settings_password', 0),
 ('sys_account_settings_info', 'system', 'sys_account', '_sys_form_display_account_settings_info', 0),
 ('sys_account_settings_del_account', 'system', 'sys_account', '_sys_form_display_account_settings_delete', 0),
 ('sys_forgot_password', 'system', 'sys_forgot_password', '_sys_form_display_forgot_password', 0),
+('sys_confirm_phone_set_phone', 'system', 'sys_confirm_phone', '_sys_form_display_confirm_phone_set_phone', 0),
+('sys_confirm_phone_confirmation', 'system', 'sys_confirm_phone', '_sys_form_display_confirm_phone_confirmation', 0),
 ('sys_confirm_email', 'system', 'sys_confirm_email', '_sys_form_display_confirm_email', 0),
 ('sys_unsubscribe_updates', 'system', 'sys_unsubscribe', '_sys_form_display_unsubscribe_updates', 0),
 ('sys_unsubscribe_news', 'system', 'sys_unsubscribe', '_sys_form_display_unsubscribe_news', 0),
@@ -2794,6 +2814,10 @@ INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `c
 ('sys_login', 'system', 'rememberMe', '1', '', 0, 'switcher', '_sys_form_login_input_caption_system_remember_me', '_sys_form_login_input_remember_me', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('sys_login', 'system', 'login', '_sys_form_login_input_submit', '', 0, 'submit', '_sys_form_login_input_caption_system_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 ('sys_login', 'system', 'submit_text', '', '', 0, 'custom', '_sys_form_login_input_caption_system_submit_text', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('sys_login', 'system', 'phone', '', '', 0, 'text', '_sys_form_login_input_caption_system_phone', '_sys_form_login_input_phone', '', 1, 0, 0, '', '', '', 'PhoneExist', '', '_sys_form_login_input_phone_error_format', 'Xss', '', 1, 0),
+('sys_login', 'system', 'code', '', '', 0, 'text', '_sys_form_login_input_caption_system_code', '_sys_form_login_input_code', '', 1, 0, 0, '', '', '', 'CodeExist', '', '_sys_form_login_input_code_error_empty', 'Xss', '', 0, 0),
+('sys_login', 'system', 'do_checkcode', '_sys_form_login_input_checkcode', '', 0, 'submit', '_sys_form_login_input_caption_system_checkcode', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('sys_login', 'system', 'do_sendsms', '_sys_form_login_input_sendsms', '', 0, 'submit', '_sys_form_login_input_caption_system_sendsms', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 
 ('sys_account', 'system', 'email', '', '', 0, 'text', '_sys_form_login_input_caption_system_email', '_sys_form_account_input_email', '', 1, 0, 0, '', '', '', 'EmailUniq', '', '_sys_form_account_input_email_error', 'Xss', '', 0, 0),
 ('sys_account', 'system', 'password', '', '', 0, 'password', '_sys_form_login_input_caption_system_password', '_sys_form_account_input_password', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:6;s:3:"max";i:1024;}', '_sys_form_account_input_password_error', '', '', 0, 0),
@@ -2808,13 +2832,19 @@ INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `c
 ('sys_account', 'system', 'receive_news', '1', '', 1, 'switcher', '_sys_form_login_input_caption_system_receive_news', '_sys_form_account_input_receive_news', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
 ('sys_account', 'system', 'agreement', '', '', 0, 'custom', '_sys_form_login_input_caption_system_agreement', '_sys_form_account_input_agreement', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 
-('sys_forgot_password', 'system', 'email', '', '', 0, 'text', '_sys_form_forgot_password_input_caption_system_email', '_sys_form_forgot_password_input_email', '', 1, 0, 0, '', '', '', 'EmailExist', '', '_sys_form_account_input_email_error', 'Xss', '', 0, 0),
+('sys_forgot_password', 'system', 'email', '', '', 0, 'text', '_sys_form_forgot_password_input_caption_system_email', '_sys_form_forgot_password_input_email', '', 1, 0, 0, '', '', '', 'EmailExistOrEmpty', '', '_sys_form_account_input_email_error', 'Xss', '', 0, 0),
+('sys_forgot_password', 'system', 'phone', '', '', 0, 'text', '_sys_form_forgot_password_input_caption_system_phone', '_sys_form_forgot_password_input_phone', '', 1, 0, 0, '', '', '', 'PhoneExistOrEmpty', '', '_sys_form_account_input_phone_error', 'Xss', '', 0, 0),
 ('sys_forgot_password', 'system', 'captcha', '', '', 0, 'captcha', '_sys_form_login_input_caption_system_captcha', '_sys_form_account_input_captcha', '', 1, 0, 0, '', '', '', 'Captcha', '', '_sys_form_account_input_captcha_error', '', '', 0, 0),
 ('sys_forgot_password', 'system', 'do_submit', '_sys_form_forgot_password_input_submit', '', 0, 'submit', '_sys_form_forgot_password_input_caption_system_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 
 ('sys_confirm_email', 'system', 'code', '', '', 0, 'text', '_sys_form_confirm_email_input_caption_system_code', '_sys_form_confirm_email_input_code', '', 1, 0, 0, '', '', '', 'CodeExist', '', '_sys_form_confirm_email_input_code_error', 'Xss', '', 0, 0),
 ('sys_confirm_email', 'system', 'do_submit', '_sys_form_confirm_email_input_submit', '', 0, 'submit', '_sys_form_confirm_email_input_caption_system_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 
+('sys_confirm_phone', 'system', 'phone', '', '', 0, 'text', '_sys_form_confirm_phone_input_caption_system_phone', '_sys_form_confirm_phone_input_phone', '', 1, 0, 0, '', '', '', 'PhoneUniq', '', '_sys_form_confirm_phone_input_phone_error_format', 'Xss', '', 1, 0),
+('sys_confirm_phone', 'system', 'code', '', '', 0, 'text', '_sys_form_confirm_phone_input_caption_system_code', '_sys_form_confirm_phone_confirmation_input_code', '', 1, 0, 0, '', '', '', 'CodeExist', '', '_sys_form_confirm_phone_input_code_error_empty', 'Xss', '', 0, 0),
+('sys_confirm_phone', 'system', 'do_submit', '_sys_form_confirm_phone_input_submit', '', 0, 'submit', '_sys_form_confirm_phone_input_caption_system_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('sys_confirm_phone', 'system', 'do_sendsms', '_sys_form_confirm_phone_input_sendsms', '', 0, 'submit', '_sys_form_confirm_phone_input_caption_system_do_sendsms', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+
 ('sys_unsubscribe', 'system', 'id', '', '', 0, 'hidden', '_sys_form_unsubscribe_input_caption_system_id', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 ('sys_unsubscribe', 'system', 'code', '', '', 0, 'hidden', '_sys_form_unsubscribe_input_caption_system_code', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 ('sys_unsubscribe', 'system', 'receive_updates', '1', '', 0, 'switcher', '_sys_form_unsubscribe_input_caption_system_receive_updates', '_sys_form_unsubscribe_input_receive_updates', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
@@ -2851,7 +2881,6 @@ CREATE TABLE IF NOT EXISTS `sys_form_display_inputs` (
 );
 
 INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
-
 ('sys_login', 'role', 2147483647, 1, 1),
 ('sys_login', 'relocate', 2147483647, 1, 2),
 ('sys_login', 'ID', 2147483647, 1, 3),
@@ -2860,11 +2889,20 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('sys_login', 'login', 2147483647, 1, 6),
 ('sys_login', 'submit_text', 2147483647, 1, 7),
 
+('sys_login_step2', 'phone', 2147483647, 1, 1),
+('sys_login_step2', 'do_sendsms', 2147483647, 1, 2),
+('sys_login_step2', 'relocate', 2147483647, 1, 3),
+
+('sys_login_step3', 'code', 2147483647, 1, 1),
+('sys_login_step3', 'do_checkcode', 2147483647, 1, 2),
+('sys_login_step3', 'relocate', 2147483647, 1, 3),
+
 ('sys_account_create', 'name', 2147483647, 1, 1),
 ('sys_account_create', 'email', 2147483647, 1, 2),
 ('sys_account_create', 'password', 2147483647, 1, 3),
-('sys_account_create', 'receive_news', 2147483647, 1, 4),
-('sys_account_create', 'do_submit', 2147483647, 1, 5),
+('sys_account_create', 'phone', 2147483647, 1, 4),
+('sys_account_create', 'receive_news', 2147483647, 1, 5),
+('sys_account_create', 'do_submit', 2147483647, 1, 6),
 ('sys_account_create', 'agreement', 2147483647, 1, 7),
 
 ('sys_account_settings_email', 'email', 2147483647, 1, 1),
@@ -2887,12 +2925,19 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('sys_account_settings_info', 'do_submit', 2147483647, 1, 2),
 
 ('sys_forgot_password', 'email', 2147483647, 1, 1),
-('sys_forgot_password', 'captcha', 2147483647, 1, 2),
-('sys_forgot_password', 'do_submit', 2147483647, 1, 3),
+('sys_forgot_password', 'phone', 2147483647, 1, 2),
+('sys_forgot_password', 'captcha', 2147483647, 1, 3),
+('sys_forgot_password', 'do_submit', 2147483647, 1, 4),
 
 ('sys_confirm_email', 'code', 2147483647, 1, 1),
 ('sys_confirm_email', 'do_submit', 2147483647, 1, 2),
 
+('sys_confirm_phone_set_phone', 'phone', 2147483647, 1, 1),
+('sys_confirm_phone_set_phone', 'do_sendsms', 2147483647, 1, 2),
+
+('sys_confirm_phone_confirmation', 'code', 2147483647, 1, 1),
+('sys_confirm_phone_confirmation', 'do_submit', 2147483647, 1, 2),
+
 ('sys_unsubscribe_updates', 'id', 2147483647, 1, 1),
 ('sys_unsubscribe_updates', 'code', 2147483647, 1, 2),
 ('sys_unsubscribe_updates', 'receive_updates', 2147483647, 1, 3),
@@ -3970,8 +4015,11 @@ INSERT INTO `sys_objects_page` (`object`, `uri`, `title_system`, `title`, `modul
 ('sys_dashboard', 'dashboard', '_sys_page_title_system_dashboard', '_sys_page_title_dashboard', 'system', 12, 2147483646, 1, 'page.php?i=dashboard', '', '', '', 0, 1, 0, 'BxTemplPageDashboard', ''),
 ('sys_create_account', 'create-account', '_sys_page_title_system_create_account', '_sys_page_title_create_account', 'system', 5, 2147483647, 1, 'page.php?i=create-account', '', '', '', 0, 1, 0, '', ''),
 ('sys_login', 'login', '_sys_page_title_system_login', '_sys_page_title_login', 'system', 5, 2147483647, 1, 'page.php?i=login', '', '', '', 0, 1, 0, '', ''),
+('sys_login_step2', 'login-step2', '_sys_page_title_system_login_step2', '_sys_page_title_login_step2', 'system', 5, 2147483647, 1, 'page.php?i=login-step2', '', '', '', 0, 1, 0, '', ''),
+('sys_login_step3', 'login-step3', '_sys_page_title_system_login_step3', '_sys_page_title_login_step3', 'system', 5, 2147483647, 1, 'page.php?i=login-step3', '', '', '', 0, 1, 0, '', ''),
 ('sys_forgot_password', 'forgot-password', '_sys_page_title_system_forgot_password', '_sys_page_title_forgot_password', 'system', 5, 2147483647, 1, 'page.php?i=forgot-password', '', '', '', 0, 1, 0, '', ''),
 ('sys_confirm_email', 'confirm-email', '_sys_page_title_system_confirm_email', '_sys_page_title_confirm_email', 'system', 5, 2147483647, 1, 'page.php?i=confirm-email', '', '', '', 0, 1, 0, '', ''),
+('sys_confirm_phone', 'confirm-phone', '_sys_page_title_system_confirm_phone', '_sys_page_title_confirm_phone', 'system', 5, 2147483647, 1, 'page.php?i=confirm-phone', '', '', '', 0, 1, 0, '', ''),
 ('sys_account_settings_email', 'account-settings-email', '_sys_page_title_system_account_settings_email', '_sys_page_title_account_settings_email', 'system', 5, 2147483647, 1, 'member.php', '', '', '', 0, 1, 0, 'BxTemplPageAccount', ''),
 ('sys_account_settings_pwd', 'account-settings-password', '_sys_page_title_system_account_settings_pwd', '_sys_page_title_account_settings_pwd', 'system', 5, 2147483647, 1, 'page.php?i=account-settings-pwd', '', '', '', 0, 1, 0, 'BxTemplPageAccount', ''),
 ('sys_account_settings_info', 'account-settings-info', '_sys_page_title_system_account_settings_info', '_sys_page_title_account_settings_info', 'system', 5, 2147483647, 1, 'page.php?i=account-settings-info', '', '', '', 0, 1, 0, 'BxTemplPageAccount', ''),
@@ -4088,10 +4136,16 @@ INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `
 
 ('sys_login', 0, 'system', '_sys_page_block_system_title_login_only', '_sys_page_block_title_login', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:15:\"login_form_only\";s:5:\"class\";s:17:\"TemplServiceLogin\";}', 0, 1, 1, 0),
 
+('sys_login_step2', 1, 'system', '_sys_page_block_system_title_login_step2', '_sys_page_block_title_login_step2', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:16:\"login_form_step2\";s:5:\"class\";s:17:\"TemplServiceLogin\";}', 0, 1, 1, 1),
+
+('sys_login_step3', 1, 'system', '_sys_page_block_system_title_login_step3', '_sys_page_block_title_login_step3', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:16:\"login_form_step3\";s:5:\"class\";s:17:\"TemplServiceLogin\";}', 0, 1, 1, 1),
+
 ('sys_forgot_password', 1, 'system', '', '_sys_page_block_title_forgot_password', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:15:"forgot_password";s:6:"params";a:0:{}s:5:"class";s:19:"TemplServiceAccount";}', 0, 1, 1, 1),
 
 ('sys_confirm_email', 1, 'system', '', '_sys_page_block_title_confirm_email', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:18:"email_confirmation";s:6:"params";a:0:{}s:5:"class";s:19:"TemplServiceAccount";}', 0, 1, 1, 1),
 
+('sys_confirm_phone', 1, 'system', '', '_sys_page_block_title_confirm_phone', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:18:"phone_confirmation";s:6:"params";a:0:{}s:5:"class";s:19:"TemplServiceAccount";}', 0, 1, 1, 1),
+
 ('sys_account_settings_email', 1, 'system', '', '_sys_page_block_title_account_settings_email', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:22:"account_settings_email";s:6:"params";a:0:{}s:5:"class";s:19:"TemplServiceAccount";}', 0, 1, 1, 1),
 
 ('sys_account_settings_pwd', 1, 'system', '', '_sys_page_block_title_account_settings_pwd', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:25:"account_settings_password";s:6:"params";a:0:{}s:5:"class";s:19:"TemplServiceAccount";}', 0, 1, 1, 1),

+ 25 - 16
member.php

@@ -29,23 +29,32 @@ if (isset($_POST['ID'])) { // login form is submitted
         echo $bLoginSuccess ? 'OK' : $oForm->getLoginError();
         exit;
 
-    } elseif ($bLoginSuccess) {
-    	$sId = trim($oForm->getCleanValue('ID'));
-
-        $oAccount = BxDolAccount::getInstance($sId);
-        $aAccount = bx_login($oAccount->id(), ($oForm->getCleanValue('rememberMe') ? true : false));
-
-        $sUrlRelocate = $oForm->getCleanValue('relocate');
-        if (!$sUrlRelocate || 0 !== strncmp($sUrlRelocate, BX_DOL_URL_ROOT, strlen(BX_DOL_URL_ROOT)))
-            $sUrlRelocate = BX_DOL_ROLE_ADMIN == $oForm->getRole() ? BX_DOL_URL_STUDIO . 'launcher.php' : BX_DOL_URL_ROOT . 'member.php';
-
-        BxDolTemplate::getInstance()->setPageNameIndex (BX_PAGE_TRANSITION);
-        BxDolTemplate::getInstance()->setPageHeader (_t('_Please Wait'));
-        BxDolTemplate::getInstance()->setPageContent ('page_main_code', MsgBox(_t('_Please Wait')));
-        BxDolTemplate::getInstance()->setPageContent ('url_relocate', bx_html_attribute($sUrlRelocate, BX_ESCAPE_STR_QUOTE));
-
-        BxDolTemplate::getInstance()->getPageCode();
+    } 
+    elseif ($bLoginSuccess) {
+        if (getParam('sys_account_activation_2fa_enable') == 'on'){
+            $oSession = BxDolSession::getInstance();
+            $oSession->setValue(BX_ACCOUNT_SESSION_KEY_FOR_2FA_LOGIN_ACCOUNT_ID, trim($oForm->getCleanValue('ID')));
+            $oSession->setValue(BX_ACCOUNT_SESSION_KEY_FOR_2FA_LOGIN_IS_REMEMBER, ($oForm->getCleanValue('rememberMe') ? true : false));
+            header('Location: ' . BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=login-step2'));
+        }
+        else{
+    	    $sId = trim($oForm->getCleanValue('ID'));
+
+            $oAccount = BxDolAccount::getInstance($sId);
+            $aAccount = bx_login($oAccount->id(), ($oForm->getCleanValue('rememberMe') ? true : false));
+
+            $sUrlRelocate = $oForm->getCleanValue('relocate');
+            if (!$sUrlRelocate || 0 !== strncmp($sUrlRelocate, BX_DOL_URL_ROOT, strlen(BX_DOL_URL_ROOT)))
+                $sUrlRelocate = BX_DOL_ROLE_ADMIN == $oForm->getRole() ? BX_DOL_URL_STUDIO . 'launcher.php' : BX_DOL_URL_ROOT . 'member.php';
+
+            BxDolTemplate::getInstance()->setPageNameIndex (BX_PAGE_TRANSITION);
+            BxDolTemplate::getInstance()->setPageHeader (_t('_Please Wait'));
+            BxDolTemplate::getInstance()->setPageContent ('page_main_code', MsgBox(_t('_Please Wait')));
+            BxDolTemplate::getInstance()->setPageContent ('url_relocate', bx_html_attribute($sUrlRelocate, BX_ESCAPE_STR_QUOTE));
+
+            BxDolTemplate::getInstance()->getPageCode();
         exit;
+        }
     }
 
 }

+ 9 - 0
modules/boonex/accounts/classes/BxAccntGridAdministration.php

@@ -254,6 +254,15 @@ class BxAccntGridAdministration extends BxBaseModProfileGridAdministration
     protected function _getCellLogged($mixedValue, $sKey, $aField, $aRow)
     {
         return parent::_getCellDefault(bx_time_js($mixedValue), $sKey, $aField, $aRow);
+    }    
+    
+    protected function _getCellIsConfirmed($mixedValue, $sKey, $aField, $aRow)
+    {
+        $oAccount = BxDolAccount::getInstance($aRow['id']);
+        $s = "";
+        if ($oAccount)
+            $s = $oAccount->ConfirmationStatus();
+        return parent::_getCellDefault(_t('_bx_accnt_grid_confirmation_status_' . $s), $sKey, $aField, $aRow);
     }
 
     protected function _isCheckboxDisabled($aRow)

+ 6 - 1
modules/boonex/accounts/install/langs/en.xml

@@ -44,7 +44,7 @@
     <string name="_bx_accnt_grid_column_title_adm_email"><![CDATA[Email]]></string>
   <string name="_bx_accnt_grid_column_title_adm_ip"><![CDATA[IP]]></string>
   
-  <string name="_bx_accnt_grid_column_title_adm_email_confirmed"><![CDATA[Email Confirmed]]></string>
+  <string name="_bx_accnt_grid_column_title_adm_is_confirmed"><![CDATA[Confirmed]]></string>
     <string name="_bx_accnt_grid_column_title_adm_profiles"><![CDATA[Profiles]]></string>
     <string name="_bx_accnt_grid_column_title_adm_logged"><![CDATA[Last Online]]></string>
     <string name="_bx_accnt_grid_action_title_adm_activate"><![CDATA[Activate]]></string>
@@ -58,6 +58,11 @@
     <string name="_bx_accnt_grid_action_err_delete"><![CDATA[Cannot delete the selected account(s).]]></string>
     <string name="_bx_accnt_grid_action_err_perform"><![CDATA[Cannot perform the action for selected account(s).]]></string>
 
+    <string name="_bx_accnt_grid_confirmation_status_none"><![CDATA[No]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_email"><![CDATA[Email]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_phone"><![CDATA[Phone]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_email_and_phone"><![CDATA[All]]></string>
+
 	<string name="_bx_accnt_txt_more"><![CDATA[{0} more]]></string>
 	<string name="_bx_accnt_txt_see_more"><![CDATA[See more]]></string>
 	<string name="_bx_accnt_txt_copy_to_clipboard"><![CDATA[Copy to Clipboard]]></string>

+ 2 - 2
modules/boonex/accounts/install/sql/enable.sql

@@ -55,14 +55,14 @@ INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
 
 -- GRIDS: administration
 INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
-('bx_accounts_administration', 'Sql', 'SELECT `ta`.*, `tp`.`status` AS `status` FROM `sys_accounts` AS `ta` LEFT JOIN `sys_profiles` AS `tp` ON `ta`.`id`=`tp`.`account_id` AND `tp`.`type`=''system'' WHERE 1 ', 'sys_accounts', 'id', 'logged', 'status', '', 20, NULL, 'start', '', 'name,email,ip', '', 'like', 'email_confirmed,logged', '', 192, 'BxAccntGridAdministration', 'modules/boonex/accounts/classes/BxAccntGridAdministration.php');
+('bx_accounts_administration', 'Sql', 'SELECT `ta`.*, `tp`.`status` AS `status` FROM `sys_accounts` AS `ta` LEFT JOIN `sys_profiles` AS `tp` ON `ta`.`id`=`tp`.`account_id` AND `tp`.`type`=''system'' WHERE 1 ', 'sys_accounts', 'id', 'logged', 'status', '', 20, NULL, 'start', '', 'name,email,ip,phone', '', 'like', 'email_confirmed,logged', '', 192, 'BxAccntGridAdministration', 'modules/boonex/accounts/classes/BxAccntGridAdministration.php');
 
 INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
 ('bx_accounts_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
 ('bx_accounts_administration', 'switcher', '_bx_accnt_grid_column_title_adm_active', '6%', 0, '', '', 2),
 ('bx_accounts_administration', 'name', '_bx_accnt_grid_column_title_adm_name', '22%', 0, '22', '', 3),
 ('bx_accounts_administration', 'email', '_bx_accnt_grid_column_title_adm_email', '22%', 0, '22', '', 4),
-('bx_accounts_administration', 'email_confirmed', '_bx_accnt_grid_column_title_adm_email_confirmed', '5%', 0, '', '', 5),
+('bx_accounts_administration', 'is_confirmed', '_bx_accnt_grid_column_title_adm_is_confirmed', '5%', 0, '', '', 5),
 ('bx_accounts_administration', 'profiles', '_bx_accnt_grid_column_title_adm_profiles', '22%', 0, '22', '', 5),
 ('bx_accounts_administration', 'logged', '_bx_accnt_grid_column_title_adm_logged', '15%', 0, '15', '', 7),
 ('bx_accounts_administration', 'actions', '', '6%', 0, '', '', 8);

+ 21 - 0
modules/boonex/decorous/data/template/system/scripts/BxTemplFormConfirmPhone.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxBaseFormConfirmPhone
+ */
+class BxTemplFormConfirmPhone extends BxBaseFormConfirmPhone
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+    }
+}
+
+/** @} */

+ 76 - 2
modules/boonex/english/data/langs/system/en.xml

@@ -1230,6 +1230,7 @@
 	<string name="_adm_stg_cpt_category_storage"><![CDATA[Storage]]></string>
 	<string name="_adm_stg_cpt_category_system"><![CDATA[System]]></string>
 	<string name="_adm_stg_cpt_category_templates"><![CDATA[Templates]]></string>
+	<string name="_adm_stg_cpt_category_twilio_gate"><![CDATA[Twilio gate]]></string>
 	<string name="_adm_stg_cpt_option_currency_code"><![CDATA[Currency code (for checkout system)]]></string>
 	<string name="_adm_stg_err_option_currency_code"><![CDATA[Cannot be empty.]]></string>
 	<string name="_adm_stg_cpt_option_currency_sign"><![CDATA[Currency sign (for display purposes only)]]></string>
@@ -1254,6 +1255,8 @@
     <string name="_adm_stg_cpt_option_site_tour_studio"><![CDATA[Studio home page tour]]></string>
     <string name="_adm_stg_cpt_option_add_to_mobile_homepage"><![CDATA[Add to mobile homepage widget]]></string>
 	<string name="_adm_stg_cpt_option_sys_account_activation_letter"><![CDATA[Enable account activation letter]]></string>
+	<string name="_adm_stg_cpt_option_sys_account_confirmation_type"><![CDATA[Account is confirmed when]]></string>
+	<string name="_adm_stg_cpt_option_sys_account_2fa_enable"><![CDATA[Enable 2FA]]></string>
 	<string name="_adm_stg_cpt_option_sys_account_autoapproval"><![CDATA[Automatic account activation after creation]]></string>
 	<string name="_adm_stg_cpt_option_sys_account_auto_profile_creation"><![CDATA[Automatic profile creation from account name]]></string>
 	<string name="_adm_stg_cpt_option_sys_account_online_time"><![CDATA[Online status timeframe (minutes)]]></string>
@@ -1268,7 +1271,6 @@
 	<string name="_adm_stg_cpt_option_sys_cache_memcache_host"><![CDATA[Memcached server host]]></string>
 	<string name="_adm_stg_cpt_option_sys_cache_memcache_port"><![CDATA[Memcached server port]]></string>
 	<string name="_adm_stg_cpt_option_sys_captcha_default"><![CDATA[Сaptcha object]]></string>
-	<string name="_adm_stg_cpt_option_sys_email_confirmation"><![CDATA[Enable email confirmation]]></string>
 	<string name="_adm_stg_cpt_option_sys_email_attachable_email_templates"><![CDATA[Attachable email templates list]]></string>
 	<string name="_adm_stg_cpt_option_sys_db_cache_enable"><![CDATA[Enable DB cache]]></string>
 	<string name="_adm_stg_cpt_option_sys_db_cache_engine"><![CDATA[DB cache engine (other than File option may require custom server setup)]]></string>
@@ -1299,6 +1301,9 @@
 	<string name="_adm_stg_cpt_option_sys_per_page_search_keyword_plural"><![CDATA[Number of items in Site Search results]]></string>
 	<string name="_adm_stg_cpt_option_sys_push_app_id"><![CDATA[OneSignal App ID]]></string>
     <string name="_adm_stg_cpt_option_sys_push_rest_api"><![CDATA[REST API Key]]></string>
+	<string name="_adm_stg_cpt_option_sys_twilio_gate_sid"><![CDATA[Account SID]]></string>
+	<string name="_adm_stg_cpt_option_sys_twilio_gate_token"><![CDATA[Auth token]]></string>
+	<string name="_adm_stg_cpt_option_sys_twilio_gate_from_number"><![CDATA[Default 'From' number fror SMS]]></string>
     <string name="_adm_stg_cpt_option_sys_push_short_name"><![CDATA[Short name (required only for http sites. It must match the Subdomain you entered on the Web Push settings on the OneSignal dashboard)]]></string>
     <string name="_adm_stg_cpt_option_sys_push_safari_id"><![CDATA[Apple Safari Web ID on the Web Push settings]]></string>
     <string name="_adm_stg_cpt_option_sys_push_queue_send_per_start"><![CDATA[Number of messages to send from Push queue per run]]></string>
@@ -1552,6 +1557,10 @@
 	<string name="_sys_access_denied_to_private_content"><![CDATA[Access denied. This is private content.]]></string>
 	<string name="_sys_actions"><![CDATA[Actions]]></string>
 	<string name="_sys_active"><![CDATA[Active]]></string>
+	<string name="_sys_acc_confirmation_type_none"><![CDATA[No confirmation]]></string>
+	<string name="_sys_acc_confirmation_type_email"><![CDATA[email is confirmed]]></string>
+	<string name="_sys_acc_confirmation_type_phone"><![CDATA[phone is confirmed]]></string>
+	<string name="_sys_acc_confirmation_type_email_and_phone"><![CDATA[email and phone are confirmed]]></string>
 	<string name="_sys_acl_action_account"><![CDATA[You didn't created any profiles, so you can't '{1}'.]]></string>
 	<string name="_sys_acl_action_chart_view"><![CDATA[View charts]]></string>
 	<string name="_sys_acl_action_chart_view_desc"><![CDATA[View statistical charts]]></string>
@@ -1898,6 +1907,20 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_form_confirm_email_input_code"><![CDATA[Verification Code]]></string>
 	<string name="_sys_form_confirm_email_input_code_error"><![CDATA[Verification code is invalid or expired, please login to your account and resend verification email.]]></string>
 	<string name="_sys_form_confirm_email_input_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_confirm_phone"><![CDATA[Phone Confirmation]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_phone"><![CDATA[Phone]]></string>
+	<string name="_sys_form_confirm_phone_input_phone"><![CDATA[Phone]]></string>
+	<string name="_sys_form_confirm_phone_input_phone_error_format"><![CDATA[Wrong phone number, allowed digits only and start from '+']]></string>
+	<string name="_sys_form_confirm_phone_input_phone_error_not_unique"><![CDATA[This phone is already used by someone.]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_code"><![CDATA[Code]]></string>
+	<string name="_sys_form_confirm_phone_confirmation_input_code"><![CDATA[Code]]></string>
+	<string name="_sys_form_confirm_phone_input_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_do_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_confirm_phone_input_sendsms"><![CDATA[Send Sms]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_do_sendsms"><![CDATA[Send Sms]]></string>
+	<string name="_sys_form_confirm_phone_input_code_error_empty"><![CDATA[Cannot be empty.]]></string>
+	<string name="_sys_form_confirm_phone_input_code_error_invalid"><![CDATA[Wrong verification code. Please, repeat code or <a href="{0}">change phone number and repeat from the beginning</a>.]]></string>
+	<string name="_sys_form_account_input_phone_error"><![CDATA[Phone is not valid]]></string>
 	<string name="_sys_form_display_account_create"><![CDATA[Create Account]]></string>
 	<string name="_sys_form_display_account_settings_delete"><![CDATA[Delete Account]]></string>
 	<string name="_sys_form_display_account_settings_email"><![CDATA[Email Settings]]></string>
@@ -1906,16 +1929,25 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_form_display_comment_edit"><![CDATA[Comment From Edit]]></string>
 	<string name="_sys_form_display_comment_post"><![CDATA[Comment From Post]]></string>
 	<string name="_sys_form_display_confirm_email"><![CDATA[Email Confirmation]]></string>
+	<string name="_sys_form_display_confirm_phone_set_phone"><![CDATA[Set phone]]></string>
+	<string name="_sys_form_display_confirm_phone_confirmation"><![CDATA[Phone confirmation]]></string>
 	<string name="_sys_form_display_forgot_password"><![CDATA[Forgot Password]]></string>
 	<string name="_sys_form_display_login"><![CDATA[Log in]]></string>
+	<string name="_sys_form_display_login_step2"><![CDATA[Log in - step 2]]></string>
+	<string name="_sys_form_display_login_step3"><![CDATA[Log in - step 3]]></string>
 	<string name="_sys_form_display_report_post"><![CDATA[Report From Post]]></string>
 	<string name="_sys_form_display_unsubscribe_news"><![CDATA[Unsubscribe From Newsletters]]></string>
 	<string name="_sys_form_display_unsubscribe_updates"><![CDATA[Unsubscribe From Updates]]></string>
 	<string name="_sys_form_forgot_password"><![CDATA[Forgot Password]]></string>
 	<string name="_sys_form_forgot_password_email_not_recognized"><![CDATA[This email doesn't belong to any account. Please make sure that it is typed correctly.]]></string>
+	<string name="_sys_form_forgot_password_phone_not_recognized"><![CDATA[This phone doesn't belong to any account. Please make sure that it is typed correctly.]]></string>
+	<string name="_sys_form_forgot_password_phone_error_format"><![CDATA[Wrong phone number, allowed digits only and start from '+']]></string>
+	<string name="_sys_form_forgot_password_phone_and_email_empty_error"><![CDATA[Please, fill phone or email field]]></string>
 	<string name="_sys_form_forgot_password_input_caption_system_do_submit"><![CDATA[Submit]]></string>
 	<string name="_sys_form_forgot_password_input_caption_system_email"><![CDATA[Email]]></string>
 	<string name="_sys_form_forgot_password_input_email"><![CDATA[Email]]></string>
+	<string name="_sys_form_forgot_password_input_caption_system_phone"><![CDATA[Phone]]></string>
+	<string name="_sys_form_forgot_password_input_phone"><![CDATA[Phone]]></string>
 	<string name="_sys_form_forgot_password_input_submit"><![CDATA[Submit]]></string>
 	<string name="_sys_form_input_age"><![CDATA[Age]]></string>
 	<string name="_sys_form_input_sys_location"><![CDATA[Location]]></string>
@@ -1923,6 +1955,8 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_form_login"><![CDATA[Log in]]></string>
 	<string name="_sys_form_login_input_caption_system_agreement"><![CDATA[Agreement]]></string>
 	<string name="_sys_form_login_input_caption_system_captcha"><![CDATA[Captcha]]></string>
+	<string name="_sys_form_login_input_caption_system_checkcode"><![CDATA[Submit]]></string>
+	<string name="_sys_form_login_input_caption_system_code"><![CDATA[de from SMS]]></string>
 	<string name="_sys_form_login_input_caption_system_delete_confirm"><![CDATA[Confirm Delete]]></string>
 	<string name="_sys_form_login_input_caption_system_delete_content"><![CDATA[Delete with Content]]></string>
 	<string name="_sys_form_login_input_caption_system_do_submit"><![CDATA[Sign up]]></string>
@@ -1931,18 +1965,29 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_form_login_input_caption_system_name"><![CDATA[Account name]]></string>
 	<string name="_sys_form_login_input_caption_system_password"><![CDATA[Password]]></string>
 	<string name="_sys_form_login_input_caption_system_password_confirm"><![CDATA[Confirm Password]]></string>
+	<string name="_sys_form_login_input_caption_system_phone"><![CDATA[Phone]]></string>
 	<string name="_sys_form_login_input_caption_system_password_current"><![CDATA[Current Password]]></string>
 	<string name="_sys_form_login_input_caption_system_receive_news"><![CDATA[Receive News]]></string>
 	<string name="_sys_form_login_input_caption_system_receive_updates"><![CDATA[Receive Updates]]></string>
 	<string name="_sys_form_login_input_caption_system_relocate"><![CDATA[Relocate]]></string>
 	<string name="_sys_form_login_input_caption_system_remember_me"><![CDATA[Remember me]]></string>
 	<string name="_sys_form_login_input_caption_system_role"><![CDATA[Role]]></string>
+	<string name="_sys_form_login_input_caption_system_sendsms"><![CDATA[Send SMS]]></string>
 	<string name="_sys_form_login_input_caption_system_submit"><![CDATA[Submit]]></string>
 	<string name="_sys_form_login_input_caption_system_submit_text"><![CDATA[Submit Text]]></string>
+	<string name="_sys_form_login_input_code"><![CDATA[Code from SMS]]></string>
+	<string name="_sys_form_login_input_checkcode"><![CDATA[Submit]]></string>
 	<string name="_sys_form_login_input_email"><![CDATA[Email]]></string>
 	<string name="_sys_form_login_input_password"><![CDATA[Password]]></string>
+	<string name="_sys_form_login_input_phone"><![CDATA[Phone]]></string>
 	<string name="_sys_form_login_input_remember_me"><![CDATA[Remember me]]></string>
+	<string name="_sys_form_login_input_sendsms"><![CDATA[Send SMS]]></string>
 	<string name="_sys_form_login_input_submit"><![CDATA[Log in]]></string>
+	<string name="_sys_form_login_input_code_error_empty"><![CDATA[Cannot be empty.]]></string>
+	<string name="_sys_form_login_input_phone_error_format"><![CDATA[Wrong phone number, allowed digits only and start from '+']]></string>
+	<string name="_sys_form_login_input_phone_error_not_unique"><![CDATA[This phone is already used by someone.]]></string>
+	<string name="_sys_form_login_input_code_error_invalid"><![CDATA[Wrong verification code. Please, repeat code or <a href="{0}">change phone number and repeat from the beginning</a>.]]></string>
+	
 	<string name="_sys_form_paceholder_profiles_suggestions"><![CDATA[Type name here...]]></string>
 	<string name="_sys_form_report"><![CDATA[Report]]></string>
 	<string name="_sys_form_report_input_caption_submit"><![CDATA[Post]]></string>
@@ -2279,13 +2324,18 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_page_block_title_chart_growth"><![CDATA[Growth Charts]]></string>
 	<string name="_sys_page_block_title_chart_stats"><![CDATA[Content]]></string>
 	<string name="_sys_page_block_title_confirm_email"><![CDATA[Email Confirmation]]></string>
+	<string name="_sys_page_block_title_confirm_phone"><![CDATA[Phone Confirmation]]></string>
 	<string name="_sys_page_block_title_create_account"><![CDATA[Sign up]]></string>
 	<string name="_sys_page_block_title_dashboard"><![CDATA[Dashboard]]></string>
 	<string name="_sys_page_block_title_homepage_menu"><![CDATA[Content modules menu]]></string>
 	<string name="_sys_page_block_title_forgot_password"><![CDATA[Forgot Password]]></string>
 	<string name="_sys_page_block_system_title_login"><![CDATA[Log in with Sign up link]]></string>
+	<string name="_sys_page_block_system_title_login_step2"><![CDATA[Log in - step2]]></string>
+	<string name="_sys_page_block_system_title_login_step3"><![CDATA[Log in - step3]]></string>
 	<string name="_sys_page_block_system_title_login_only"><![CDATA[Log in]]></string>
 	<string name="_sys_page_block_title_login"><![CDATA[Log in]]></string>
+	<string name="_sys_page_block_title_login_step2"><![CDATA[Log in - step 2]]></string>
+	<string name="_sys_page_block_title_login_step3"><![CDATA[Log in - step 3]]></string>
 	<string name="_sys_page_block_title_manage_tools"><![CDATA[Manage]]></string>
 	<string name="_sys_page_block_title_privacy"><![CDATA[Privacy Policy]]></string>
 	<string name="_sys_page_block_title_profile_stats"><![CDATA[Profile stats]]></string>
@@ -2308,11 +2358,14 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_page_title_account_settings_pwd"><![CDATA[Change Password]]></string>
 	<string name="_sys_page_title_add_content"><![CDATA[Add Content]]></string>
 	<string name="_sys_page_title_confirm_email"><![CDATA[Email Confirmation]]></string>
+	<string name="_sys_page_title_confirm_phone"><![CDATA[Phone Confirmation]]></string>
 	<string name="_sys_page_title_create_account"><![CDATA[Sign up]]></string>
 	<string name="_sys_page_title_dashboard"><![CDATA[Dashboard]]></string>
 	<string name="_sys_page_title_forgot_password"><![CDATA[Forgot Password]]></string>
 	<string name="_sys_page_title_home"><![CDATA[{site_title} :: Homepage]]></string>
 	<string name="_sys_page_title_login"><![CDATA[Log in]]></string>
+	<string name="_sys_page_title_login_step2"><![CDATA[Log in - step 2]]></string>
+	<string name="_sys_page_title_login_step3"><![CDATA[Log in - step 3]]></string>
 	<string name="_sys_page_title_privacy"><![CDATA[Privacy Policy]]></string>
 	<string name="_sys_page_title_terms"><![CDATA[Terms of Service]]></string>
 	<string name="_sys_page_title_system_about"><![CDATA[About]]></string>
@@ -2323,11 +2376,14 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_page_title_system_account_settings_pwd"><![CDATA[Change Password]]></string>
 	<string name="_sys_page_title_system_add_content"><![CDATA[Add Content]]></string>
 	<string name="_sys_page_title_system_confirm_email"><![CDATA[Email Confirmation]]></string>
+	<string name="_sys_page_title_system_confirm_phone"><![CDATA[Phone Confirmation]]></string>
 	<string name="_sys_page_title_system_create_account"><![CDATA[Sign up]]></string>
 	<string name="_sys_page_title_system_dashboard"><![CDATA[Dashboard]]></string>
 	<string name="_sys_page_title_system_forgot_password"><![CDATA[Forgot Password]]></string>
 	<string name="_sys_page_title_system_home"><![CDATA[Homepage]]></string>
 	<string name="_sys_page_title_system_login"><![CDATA[Log in]]></string>
+	<string name="_sys_page_title_system_login_step2"><![CDATA[Log in - step 2]]></string>
+	<string name="_sys_page_title_system_login_step3"><![CDATA[Log in - step 3]]></string>
 	<string name="_sys_page_title_system_privacy"><![CDATA[Privacy Policy]]></string>
 	<string name="_sys_page_title_system_terms"><![CDATA[Terms of Service]]></string>
 	<string name="_sys_page_title_system_unsubscribe_news"><![CDATA[Unsubscribe From Newsletters]]></string>
@@ -2456,7 +2512,8 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_txt_account_profile_context_change_suggestion"><![CDATA[This is your profile, you can <a href="{0}">change your current profile</a> to this profile]]></string>
 	<string name="_sys_txt_account_profile_context_changed_success"><![CDATA[Current profile has been successfully changed to: <b>{0}</b>]]></string>
 	<string name="_sys_txt_account_suspended"><![CDATA[Your account is suspended.]]></string>
-	<string name="_sys_txt_account_unconfirmed"><![CDATA[Your email address is unconfirmed. Please, check your email ({1}) for a confirmation letter and click email confirmation link. Can't find the letter? Check your SPAM folder or <a href="{0}">send the verification letter again</a>.]]></string>
+	<string name="_sys_txt_account_unconfirmed_email"><![CDATA[Your email address is unconfirmed. Please, check your email ({1}) for a confirmation letter and click email confirmation link. Can't find the letter? Check your SPAM folder or <a href="{0}">send the verification letter again</a>.]]></string>
+	<string name="_sys_txt_account_unconfirmed_phone"><![CDATA[Your phone is unconfirmed. Please, confirm it on <a href="{0}">verification page</a>.]]></string>
 	<string name="_sys_txt_account_profile_system"><![CDATA[Please <a href="{0}">create a profile</a> to start using the site.]]></string>
 	<string name="_sys_txt_captcha_not_available"><![CDATA[CAPTCHA not available]]></string>
     <string name="_sys_txt_change_image"><![CDATA[Change Picture]]></string>
@@ -2467,6 +2524,15 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_txt_confirm_email_sent"><![CDATA[Email verification letter was sent, please check your inbox.]]></string>
 	<string name="_sys_txt_confirm_email_sent_failed"><![CDATA[Error occurred, please report error to site administrator.]]></string>
 	<string name="_sys_txt_confirm_email_success"><![CDATA[You email address was successfully confirmed.]]></string>
+	
+	<string name="_sys_txt_confirm_phone_already_confirmed"><![CDATA[Your phone is already confirmed.]]></string>
+	<string name="_sys_txt_confirm_phone_set_phone_error_occured"><![CDATA[Error occurred, please try to login to your account and repeat verification.]]></string>
+	<string name="_sys_txt_confirm_phone_send_sms_error_occured"><![CDATA[Error occurred, please report error to site administrator.]]></string>
+	<string name="_sys_txt_confirm_phone_sms_text"><![CDATA[Your phone's verification code is {0}.]]></string>
+	<string name="_sys_txt_confirm_phone_confirm_success"><![CDATA[Your phone is confirmed successfully.]]></string>
+	<string name="_sys_txt_confirm_phone_set_phone_desc_set_phone"><![CDATA[Please enter phone number for seinding verification SMS.]]></string>
+	<string name="_sys_txt_confirm_phone_set_phone_desc_phone_confirmation"><![CDATA[Please enter verification code from SMS.]]></string>
+	
     <string name="_sys_txt_current_picture"><![CDATA[Current Picture]]></string>
 	<string name="_sys_txt_data_successfully_submitted"><![CDATA[Done]]></string>
     <string name="_sys_txt_delete"><![CDATA[Delete]]></string>
@@ -2485,9 +2551,13 @@ If it is not enabled then please consider implement this optimization, since it
     <string name="_sys_txt_field_updated"><![CDATA[Updated:]]></string>
 	<string name="_sys_txt_forgot_pasword"><![CDATA[Forgot password?]]></string>
 	<string name="_sys_txt_forgot_pasword_check_email"><![CDATA[Email was sent, please follow instructions in the email message.]]></string>
+	<string name="_sys_txt_forgot_pasword_check_phone"><![CDATA[Sms was sent, please follow instructions in the sms.]]></string>
 	<string name="_sys_txt_forgot_pasword_desc"><![CDATA[Enter your account email address to get a password-reset link.]]></string>
+	<string name="_sys_txt_forgot_pasword_by_both_desc"><![CDATA[Enter your account email address or phone to get a password-reset link.]]></string>
+	<string name="_sys_txt_forgot_pasword_by_phone_desc"><![CDATA[Enter your account phone to get a password-reset link.]]></string>
 	<string name="_sys_txt_forgot_pasword_email_send_failed"><![CDATA[Email send failed, please try again later.]]></string>
     <string name="_sys_txt_forgot_pasword_error_occured"><![CDATA[Error occurred, please report error to the site administrator.]]></string>
+	<string name="_sys_txt_forgot_pasword_sms_text"><![CDATA[Click the link below to reset your password {0}]]></string>
     
     <string name="_sys_txt_form_entry_input_picture_delete"><![CDATA[Delete]]></string>
     <string name="_sys_txt_form_entry_input_picture_insert"><![CDATA[Insert to Post]]></string>
@@ -2497,6 +2567,10 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_txt_form_submission_error_csrf_expired"><![CDATA[Token expired. Please try again.]]></string>
 
     <string name="_sys_txt_homepage_cover"><![CDATA[Unity is strength... when there is teamwork and collaboration, wonderful things can be achieved.<br /><button class="bx-btn bx-hide-when-logged-in bx-def-margin-top" onclick="document.location='{0}'">Join Now!</button>]]></string>
+	<string name="_sys_txt_login_2fa_description"><![CDATA[Two-Factor Authentication is Enabled In addition to your username and password, you'll need to enter a verification code that we'll send you.]]></string>
+	<string name="_sys_txt_login_2fa_description2"><![CDATA[Please enter verification code from SMS.]]></string>
+	<string name="_sys_txt_login_2fa_sms_text"><![CDATA[Your verification code is {0}.]]></string>
+	<string name="_sys_txt_login_2fa_sms_error_occured"><![CDATA[Error occurred, please report error to site administrator.]]></string>
     <string name="_sys_txt_join_description"><![CDATA[Already a member? <a href="{0}">Log in.</a>]]></string>
 	<string name="_sys_txt_login_description"><![CDATA[Not a member yet? <a href="{0}">Sign up.</a>]]></string>
 	<string name="_sys_txt_login_error"><![CDATA[Entered email or password is incorrect. Please try again.]]></string>

+ 21 - 0
modules/boonex/ocean/data/template/system/scripts/BxTemplFormConfirmPhone.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxBaseFormConfirmPhone
+ */
+class BxTemplFormConfirmPhone extends BxBaseFormConfirmPhone
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+    }
+}
+
+/** @} */

+ 21 - 0
modules/boonex/protean/data/template/system/scripts/BxTemplFormConfirmPhone.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxBaseFormConfirmPhone
+ */
+class BxTemplFormConfirmPhone extends BxBaseFormConfirmPhone
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+    }
+}
+
+/** @} */

+ 6 - 1
modules/boonex/russian/data/langs/bx_accounts/ru.xml

@@ -39,7 +39,7 @@
     <string name="_bx_accnt_grid_column_title_adm_name"><![CDATA[Имя]]></string>
     <string name="_bx_accnt_grid_column_title_adm_email"><![CDATA[Имейл]]></string>
   <string name="_bx_accnt_grid_column_title_adm_ip"><![CDATA[IP]]></string>
-    <string name="_bx_accnt_grid_column_title_adm_email_confirmed"><![CDATA[Имейл подтверждён]]></string>
+    <string name="_bx_accnt_grid_column_title_adm_is_confirmed"><![CDATA[Подтверждён]]></string>
     <string name="_bx_accnt_grid_column_title_adm_profiles"><![CDATA[Профили]]></string>
     <string name="_bx_accnt_grid_column_title_adm_logged"><![CDATA[Последнее посещение]]></string>
     <string name="_bx_accnt_grid_action_title_adm_activate"><![CDATA[Активировать]]></string>
@@ -53,6 +53,11 @@
     <string name="_bx_accnt_grid_action_err_delete"><![CDATA[Невозможно удалить выбранный(ные) аккаунт(ы).]]></string>
     <string name="_bx_accnt_grid_action_err_perform"><![CDATA[Невозможно выполнить действие для выбранного(ных) аккаунта(ов).]]></string>
 
+    <string name="_bx_accnt_grid_confirmation_status_none"><![CDATA[Нет]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_email"><![CDATA[Email]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_phone"><![CDATA[Телефон]]></string>
+    <string name="_bx_accnt_grid_confirmation_status_email_and_phone"><![CDATA[Все]]></string>
+
 	<string name="_bx_accnt_txt_more"><![CDATA[{0} ещё]]></string>
 	<string name="_bx_accnt_txt_see_more"><![CDATA[Ещё]]></string>
 	<string name="_bx_accnt_txt_copy_to_clipboard"><![CDATA[Скопировать]]></string>

+ 78 - 4
modules/boonex/russian/data/langs/system/ru.xml

@@ -1228,6 +1228,7 @@
 	<string name="_adm_stg_cpt_category_storage"><![CDATA[Дисковое пространство]]></string>
 	<string name="_adm_stg_cpt_category_system"><![CDATA[Система]]></string>
 	<string name="_adm_stg_cpt_category_templates"><![CDATA[Темы]]></string>
+	<string name="_adm_stg_cpt_category_twilio_gate"><![CDATA[Twilio]]></string>
 	<string name="_adm_stg_cpt_option_currency_code"><![CDATA[Код валюты (для платёжных систем)]]></string>
 	<string name="_adm_stg_err_option_currency_code"><![CDATA[Не должно быть пустым.]]></string>
 	<string name="_adm_stg_cpt_option_currency_sign"><![CDATA[Знак валюты (только для отображения)]]></string>
@@ -1252,6 +1253,8 @@
     <string name="_adm_stg_cpt_option_site_tour_studio"><![CDATA[Экскурсия по главной странице Студии]]></string>
     <string name="_adm_stg_cpt_option_add_to_mobile_homepage"><![CDATA[Компонент для добавления сайта на мобильное устройство]]></string>
 	<string name="_adm_stg_cpt_option_sys_account_activation_letter"><![CDATA[Включить сообщение об активации аккаунта]]></string>
+	<string name="_adm_stg_cpt_option_sys_account_confirmation_type"><![CDATA[Аккаунт подтвержден когда]]></string>
+	<string name="_adm_stg_cpt_option_sys_account_2fa_enable"><![CDATA[Включить двухфакторную аутентификацию]]></string>
     <string name="_adm_stg_cpt_option_sys_account_autoapproval"><![CDATA[Автоматическая активация аккаунта после создания]]></string>
     <string name="_adm_stg_cpt_option_sys_account_auto_profile_creation"><![CDATA[Автоматическое создание профайла из аккаунта]]></string>
 	<string name="_adm_stg_cpt_option_sys_account_online_time"><![CDATA[Временные рамки статуса "онлайн" (минуты)]]></string>
@@ -1266,7 +1269,6 @@
 	<string name="_adm_stg_cpt_option_sys_cache_memcache_host"><![CDATA[Memcached - адрес сервера]]></string>
 	<string name="_adm_stg_cpt_option_sys_cache_memcache_port"><![CDATA[Memcached - порт сервера]]></string>
 	<string name="_adm_stg_cpt_option_sys_captcha_default"><![CDATA[Объект CAPTCHA]]></string>
-	<string name="_adm_stg_cpt_option_sys_email_confirmation"><![CDATA[Задействовать подтверждение эл. адреса]]></string>
 	<string name="_adm_stg_cpt_option_sys_email_attachable_email_templates"><![CDATA[Список присоединяемых имейл темплейтов]]></string>
 	<string name="_adm_stg_cpt_option_sys_db_cache_enable"><![CDATA[Задействовать кэш БД]]></string>
 	<string name="_adm_stg_cpt_option_sys_db_cache_engine"><![CDATA[Кэш-движок для БД (значение, отличное от File, может потребовать дополнительной настройки сервера)]]></string>
@@ -1297,6 +1299,9 @@
     <string name="_adm_stg_cpt_option_sys_per_page_search_keyword_plural"><![CDATA[Число элементов на странице в результатах поиска по сайту]]></string>
     <string name="_adm_stg_cpt_option_sys_push_app_id"><![CDATA[OneSignal App ID]]></string>
     <string name="_adm_stg_cpt_option_sys_push_rest_api"><![CDATA[REST API Key]]></string>
+	<string name="_adm_stg_cpt_option_sys_twilio_gate_sid"><![CDATA[Account SID]]></string>
+	<string name="_adm_stg_cpt_option_sys_twilio_gate_token"><![CDATA[Auth token]]></string>
+	<string name="_adm_stg_cpt_option_sys_twilio_gate_from_number"><![CDATA[Номер для отправки SMS по умолчанию]]></string>
     <string name="_adm_stg_cpt_option_sys_push_short_name"><![CDATA[Короткое имя (требуется только если у вас https сайт. Оно должно совпадать с поддоменом, введёным, в настройках пуш оповещений на OneSignal)]]></string>
     <string name="_adm_stg_cpt_option_sys_push_safari_id"><![CDATA[Apple Safari Web ID в натройках Web Push]]></string>
     <string name="_adm_stg_cpt_option_sys_push_queue_send_per_start"><![CDATA[Количество сообщенией, отправляемое из Push очереди при каждом запуске]]></string>    
@@ -1550,6 +1555,10 @@
 	<string name="_sys_access_denied_to_private_content"><![CDATA[Доступ запрещён. Это приватное содержимое.]]></string>
 	<string name="_sys_actions"><![CDATA[Действия]]></string>
 	<string name="_sys_active"><![CDATA[Активный]]></string>
+	<string name="_sys_acc_confirmation_type_none"><![CDATA[Нет подтверждения]]></string>
+	<string name="_sys_acc_confirmation_type_email"><![CDATA[email подтвержден]]></string>
+	<string name="_sys_acc_confirmation_type_phone"><![CDATA[телефон подтвержден]]></string>
+	<string name="_sys_acc_confirmation_type_email_and_phone"><![CDATA[email и телефон подтвержден]]></string>
 	<string name="_sys_acl_action_account"><![CDATA[Вы не создали ни одного профиля, поэтому Вы не можете '{1}'.]]></string>
 	<string name="_sys_acl_action_chart_view"><![CDATA[Диаграммы - Просматривать]]></string>
     <string name="_sys_acl_action_chart_view_desc"><![CDATA[Просматривать статистические диаграммы]]></string>
@@ -1874,6 +1883,7 @@
 	<string name="_sys_form_account_input_password_current"><![CDATA[Текущий пароль]]></string>
 	<string name="_sys_form_account_input_password_current_error"><![CDATA[Неправильный текущий пароль. Введите пароль, который Вы используете для доступа к этому сайту.]]></string>
 	<string name="_sys_form_account_input_password_error"><![CDATA[Пароль должен иметь как минимум 6 символов.]]></string>
+	<string name="_sys_form_account_input_phone_error"><![CDATA[Это обязательное поле.]]></string>
 	<string name="_sys_form_account_input_receive_news"><![CDATA[Получать новости]]></string>
 	<string name="_sys_form_account_input_receive_updates"><![CDATA[Получать обновления сайта]]></string>
 	<string name="_sys_form_account_input_submit"><![CDATA[Отправить]]></string>
@@ -1897,6 +1907,19 @@
 	<string name="_sys_form_confirm_email_input_code"><![CDATA[Код верификации]]></string>
 	<string name="_sys_form_confirm_email_input_code_error"><![CDATA[Код верификации неправилен или просрочен. Зайдите в свой аккаунт и запросите письмо верификации.]]></string>
 	<string name="_sys_form_confirm_email_input_submit"><![CDATA[Выполнить]]></string>
+	<string name="_sys_form_confirm_phone"><![CDATA[Подтверждение телефона]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_phone"><![CDATA[Телефон]]></string>
+	<string name="_sys_form_confirm_phone_input_phone"><![CDATA[Телефон]]></string>
+	<string name="_sys_form_confirm_phone_input_phone_error_format"><![CDATA[Телефон должен содержать только цифры и начинаться с '+']]></string>
+	<string name="_sys_form_confirm_phone_input_phone_error_not_unique"><![CDATA[Этот телефон уже кем-то используется]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_code"><![CDATA[Код]]></string>
+	<string name="_sys_form_confirm_phone_confirmation_input_code"><![CDATA[Код]]></string>
+	<string name="_sys_form_confirm_phone_input_submit"><![CDATA[Выполнить]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_do_submit"><![CDATA[Выполнить]]></string>
+	<string name="_sys_form_confirm_phone_input_sendsms"><![CDATA[Отправить Sms]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_do_sendsms"><![CDATA[Отправить Sms]]></string>
+	<string name="_sys_form_confirm_phone_input_code_error_empty"><![CDATA[Обязательное поле.]]></string>
+	<string name="_sys_form_confirm_phone_input_code_error_invalid"><![CDATA[Неправильный код проверки. Пожалуйста, повторите код или  <a href="{0}">измените телефонный номер и начните сначала</a>.</a>]]></string>
 	<string name="_sys_form_display_account_create"><![CDATA[Создать аккаунт]]></string>
 	<string name="_sys_form_display_account_settings_delete"><![CDATA[Удалить аккаунт]]></string>
 	<string name="_sys_form_display_account_settings_email"><![CDATA[Настройки имейла]]></string>
@@ -1905,16 +1928,25 @@
 	<string name="_sys_form_display_comment_edit"><![CDATA[Редактировать форму комментария]]></string>
 	<string name="_sys_form_display_comment_post"><![CDATA[Разместить форму комментария]]></string>
 	<string name="_sys_form_display_confirm_email"><![CDATA[Подтверждение имейла]]></string>
+	<string name="_sys_form_display_confirm_phone_set_phone"><![CDATA[Задание телефона]]></string>
+	<string name="_sys_form_display_confirm_phone_confirmation"><![CDATA[Подтверждение телефона]]></string>
 	<string name="_sys_form_display_forgot_password"><![CDATA[Забыли пароль?]]></string>
 	<string name="_sys_form_display_login"><![CDATA[Войти]]></string>
+	<string name="_sys_form_display_login_step2"><![CDATA[Войти - шаг 2]]></string>
+	<string name="_sys_form_display_login_step3"><![CDATA[Войти - шаг 3]]></string>
 	<string name="_sys_form_display_report_post"><![CDATA[Форма добавления жалобы]]></string>
 	<string name="_sys_form_display_unsubscribe_news"><![CDATA[Отписаться от новостей]]></string>
 	<string name="_sys_form_display_unsubscribe_updates"><![CDATA[Отписаться от обновлений]]></string>
 	<string name="_sys_form_forgot_password"><![CDATA[Забыли пароль?]]></string>
 	<string name="_sys_form_forgot_password_email_not_recognized"><![CDATA[Этот эл. адрес не принадлежит ни одному аккаунту. Удостоверьтесь, что он введён правильно.]]></string>
+	<string name="_sys_form_forgot_password_phone_not_recognized"><![CDATA[Этот телефон не принадлежит ни одному аккаунту. Удостоверьтесь, что он введён правильно.]]></string>
+	<string name="_sys_form_forgot_password_phone_error_format"><![CDATA[Телефон должен содержать только цифры и начинаться с '+']]></string>
+	<string name="_sys_form_forgot_password_phone_and_email_empty_error"><![CDATA[Нужно ввести либо телефон, либо емайл]]></string>
 	<string name="_sys_form_forgot_password_input_caption_system_do_submit"><![CDATA[Выполнить]]></string>
 	<string name="_sys_form_forgot_password_input_caption_system_email"><![CDATA[Имейл]]></string>
 	<string name="_sys_form_forgot_password_input_email"><![CDATA[Имейл]]></string>
+	<string name="_sys_form_forgot_password_input_caption_system_phone"><![CDATA[Телефон]]></string>
+	<string name="_sys_form_forgot_password_input_phone"><![CDATA[Телефон]]></string>
 	<string name="_sys_form_forgot_password_input_submit"><![CDATA[Выполнить]]></string>
 	<string name="_sys_form_input_age"><![CDATA[Возраст]]></string>
 	<string name="_sys_form_input_sys_location"><![CDATA[Расположение]]></string>
@@ -1922,6 +1954,8 @@
 	<string name="_sys_form_login"><![CDATA[Вход]]></string>
 	<string name="_sys_form_login_input_caption_system_agreement"><![CDATA[Соглашение]]></string>
 	<string name="_sys_form_login_input_caption_system_captcha"><![CDATA[Капча]]></string>
+	<string name="_sys_form_login_input_caption_system_checkcode"><![CDATA[Выполнить]]></string>
+	<string name="_sys_form_login_input_caption_system_code"><![CDATA[Код из SMS]]></string>
 	<string name="_sys_form_login_input_caption_system_delete_confirm"><![CDATA[Подтвердить удаление]]></string>
 	<string name="_sys_form_login_input_caption_system_delete_content"><![CDATA[Удалить с контентом]]></string>
 	<string name="_sys_form_login_input_caption_system_do_submit"><![CDATA[Присоединиться]]></string>
@@ -1931,17 +1965,28 @@
 	<string name="_sys_form_login_input_caption_system_password"><![CDATA[Пароль]]></string>
 	<string name="_sys_form_login_input_caption_system_password_confirm"><![CDATA[Подтвердить пароль]]></string>
 	<string name="_sys_form_login_input_caption_system_password_current"><![CDATA[Текущий пароль]]></string>
+	<string name="_sys_form_login_input_caption_system_phone"><![CDATA[Телефон]]></string>
 	<string name="_sys_form_login_input_caption_system_receive_news"><![CDATA[Получать новости]]></string>
 	<string name="_sys_form_login_input_caption_system_receive_updates"><![CDATA[Получать обновления]]></string>
 	<string name="_sys_form_login_input_caption_system_relocate"><![CDATA[Переместить]]></string>
 	<string name="_sys_form_login_input_caption_system_remember_me"><![CDATA[Запомнить меня]]></string>
 	<string name="_sys_form_login_input_caption_system_role"><![CDATA[Роль]]></string>
+	<string name="_sys_form_login_input_caption_system_sendsms"><![CDATA[Отправить Sms]]></string>
 	<string name="_sys_form_login_input_caption_system_submit"><![CDATA[Выполнить]]></string>
 	<string name="_sys_form_login_input_caption_system_submit_text"><![CDATA[Текст отправки]]></string>
+	<string name="_sys_form_login_input_checkcode"><![CDATA[Выполнить]]></string>
+	<string name="_sys_form_login_input_code"><![CDATA[Код из SMS]]></string>
 	<string name="_sys_form_login_input_email"><![CDATA[Имейл]]></string>
 	<string name="_sys_form_login_input_password"><![CDATA[Пароль]]></string>
+	<string name="_sys_form_login_input_phone"><![CDATA[Телефон]]></string>
 	<string name="_sys_form_login_input_remember_me"><![CDATA[Запомнить меня]]></string>
+	<string name="_sys_form_login_input_sendsms"><![CDATA[Отправить Sms]]></string>
 	<string name="_sys_form_login_input_submit"><![CDATA[Вход]]></string>
+	<string name="_sys_form_login_input_code_error_empty"><![CDATA[Обязательное поле.]]></string>
+	<string name="_sys_form_login_input_phone_error_format"><![CDATA[Телефон должен содержать только цифры и начинаться с '+']]></string>
+	<string name="_sys_form_login_input_phone_error_not_unique"><![CDATA[Этот телефон уже кем-то используется]]></string>
+	<string name="_sys_form_login_input_code_error_invalid"><![CDATA[Неправильный код проверки. Пожалуйста, повторите код или  <a href="{0}">измените телефонный номер и начните сначала</a>.</a>]]></string>
+	
 	<string name="_sys_form_paceholder_profiles_suggestions"><![CDATA[Введите имя...]]></string>
 	<string name="_sys_form_report"><![CDATA[Пожаловаться]]></string>
 	<string name="_sys_form_report_input_caption_submit"><![CDATA[Пожаловаться]]></string>
@@ -2278,13 +2323,18 @@
     <string name="_sys_page_block_title_chart_growth"><![CDATA[Диаграммы развития]]></string>
     <string name="_sys_page_block_title_chart_stats"><![CDATA[Содержимое]]></string>    
 	<string name="_sys_page_block_title_confirm_email"><![CDATA[Имейл - Подтверждение]]></string>
+	<string name="_sys_page_block_title_confirm_phone"><![CDATA[Телефон - Подтверждение]]></string>
 	<string name="_sys_page_block_title_create_account"><![CDATA[Присоединиться]]></string>
 	<string name="_sys_page_block_title_dashboard"><![CDATA[Панель]]></string>
     <string name="_sys_page_block_title_homepage_menu"><![CDATA[Меню модулей с содержимым]]></string>
 	<string name="_sys_page_block_title_forgot_password"><![CDATA[Забыли пароль]]></string>
 	<string name="_sys_page_block_system_title_login"><![CDATA[Вход с линкой регистрации]]></string>
+	<string name="_sys_page_block_system_title_login_step2"><![CDATA[Вход - шаг 2]]></string>
+	<string name="_sys_page_block_system_title_login_step3"><![CDATA[Вход - шаг 3]]></string>
 	<string name="_sys_page_block_system_title_login_only"><![CDATA[Вход]]></string>
 	<string name="_sys_page_block_title_login"><![CDATA[Вход]]></string>
+	<string name="_sys_page_block_title_login_step2"><![CDATA[Вход - шаг 2]]></string>
+	<string name="_sys_page_block_title_login_step3"><![CDATA[Вход - шаг 3]]></string>
 	<string name="_sys_page_block_title_manage_tools"><![CDATA[Управление]]></string>
 	<string name="_sys_page_block_title_privacy"><![CDATA[Политика конфиденциальности]]></string>
 	<string name="_sys_page_block_title_profile_stats"><![CDATA[Профиль - Статистика]]></string>
@@ -2307,11 +2357,14 @@
 	<string name="_sys_page_title_account_settings_pwd"><![CDATA[Изменить пароль]]></string>
 	<string name="_sys_page_title_add_content"><![CDATA[Добавить содержимое]]></string>
 	<string name="_sys_page_title_confirm_email"><![CDATA[Имейл - Подтверждение]]></string>
+	<string name="_sys_page_title_confirm_phone"><![CDATA[Телефон - Подтверждение]]></string>
 	<string name="_sys_page_title_create_account"><![CDATA[Присоединиться]]></string>
 	<string name="_sys_page_title_dashboard"><![CDATA[Панель]]></string>
 	<string name="_sys_page_title_forgot_password"><![CDATA[Забыли пароль]]></string>
 	<string name="_sys_page_title_home"><![CDATA[{site_title} :: Домашняя страница]]></string>
 	<string name="_sys_page_title_login"><![CDATA[Вход]]></string>
+	<string name="_sys_page_title_login_step2"><![CDATA[Вход - шаг 2]]></string>
+	<string name="_sys_page_title_login_step3"><![CDATA[Вход - шаг 3]]></string>
 	<string name="_sys_page_title_privacy"><![CDATA[Политика конфиденциальности]]></string>
 	<string name="_sys_page_title_terms"><![CDATA[Правила пользования]]></string>
 	<string name="_sys_page_title_system_about"><![CDATA[Об...]]></string>
@@ -2322,11 +2375,14 @@
 	<string name="_sys_page_title_system_account_settings_pwd"><![CDATA[Изменить пароль]]></string>
 	<string name="_sys_page_title_system_add_content"><![CDATA[Добавить содержимое]]></string>
 	<string name="_sys_page_title_system_confirm_email"><![CDATA[Имейл подтверждение]]></string>
+	<string name="_sys_page_title_system_confirm_phone"><![CDATA[Подтверждение телефона]]></string>
 	<string name="_sys_page_title_system_create_account"><![CDATA[Присоединиться]]></string>
 	<string name="_sys_page_title_system_dashboard"><![CDATA[Панель]]></string>
 	<string name="_sys_page_title_system_forgot_password"><![CDATA[Забыли пароль]]></string>
 	<string name="_sys_page_title_system_home"><![CDATA[Домашняя страница]]></string>
 	<string name="_sys_page_title_system_login"><![CDATA[Вход]]></string>
+	<string name="_sys_page_title_system_login_step2"><![CDATA[Вход - шаг2]]></string>
+	<string name="_sys_page_title_system_login_step3"><![CDATA[Вход - шаг3]]></string>
 	<string name="_sys_page_title_system_privacy"><![CDATA[Политика конфиденциальности]]></string>
 	<string name="_sys_page_title_system_terms"><![CDATA[Правила пользования]]></string>
 	<string name="_sys_page_title_system_unsubscribe_news"><![CDATA[Отписаться от новостей]]></string>
@@ -2456,7 +2512,8 @@
 	<string name="_sys_txt_account_profile_context_change_suggestion"><![CDATA[Это Ваш профиль, Вы можете <a href="{0}">изменить свой текущий профиль</a> на этот]]></string>
 	<string name="_sys_txt_account_profile_context_changed_success"><![CDATA[Текущий профиль удачно изменён на: <b>{0}</b>]]></string>
 	<string name="_sys_txt_account_suspended"><![CDATA[Ваш аккаунт заблокирован.]]></string>
-	<string name="_sys_txt_account_unconfirmed"><![CDATA[Ваш имейл не подтверждён. Пожалуйста, проверьте свой эл. ящик ({1}) на наличие письма подтверждения и перейдите по ссылке в нём. <br />Не можете найти письмо? Проверьте папку "спам" или <a href="{0}">снова запросите письмо верификации</a>.]]></string>
+	<string name="_sys_txt_account_unconfirmed_email"><![CDATA[Ваш имейл не подтверждён. Пожалуйста, проверьте свой эл. ящик ({1}) на наличие письма подтверждения и перейдите по ссылке в нём. <br />Не можете найти письмо? Проверьте папку "спам" или <a href="{0}">снова запросите письмо верификации</a>.]]></string>
+	<string name="_sys_txt_account_unconfirmed_phone"><![CDATA[Ваш телефон не подтверждён. Пожалуйста, подвердите его на  <a href="{0}">странице верификации</a>.]]></string>
 	<string name="_sys_txt_account_profile_system"><![CDATA[Пожалуйста, <a href="{0}">создайте профиль</a>, чтобы начать пользоваться сайтом.]]></string>
 	<string name="_sys_txt_captcha_not_available"><![CDATA[CAPTCHA недоступна]]></string>
     <string name="_sys_txt_change_image"><![CDATA[Изменить картинку]]></string>
@@ -2467,6 +2524,15 @@
 	<string name="_sys_txt_confirm_email_sent"><![CDATA[Письмо верификации было отослано, пожалуйста, проверьте свой эл. ящик.]]></string>
 	<string name="_sys_txt_confirm_email_sent_failed"><![CDATA[Произошла ошибка, пожалуйста, уведомите о ней администратора сайта.]]></string>
 	<string name="_sys_txt_confirm_email_success"><![CDATA[Ваш эл. адрес был удачно подтверждён.]]></string>
+	
+	<string name="_sys_txt_confirm_phone_already_confirmed"><![CDATA[Ваш телефон уже подтверждён.]]></string>
+	<string name="_sys_txt_confirm_phone_set_phone_error_occured"><![CDATA[Произошла ошибка, пожалуйста, войдите в свой аккаунт и снова перейдите на страничку верификации.]]></string>
+	<string name="_sys_txt_confirm_phone_send_sms_error_occured"><![CDATA[Произошла ошибка, пожалуйста, уведомите о ней администратора сайта.]]></string>
+	<string name="_sys_txt_confirm_phone_sms_text"><![CDATA[Ваш код проверки телефона - {0}.]]></string>
+	<string name="_sys_txt_confirm_phone_confirm_success"><![CDATA[Ваш телефон успешно подтверждён.]]></string>
+	<string name="_sys_txt_confirm_phone_set_phone_desc_set_phone"><![CDATA[Пожалуйста, введите телефонный номер на который будет отправлено SMS с кодом подтверждения.]]></string>
+	<string name="_sys_txt_confirm_phone_set_phone_desc_phone_confirmation"><![CDATA[Пожалуйста, введите код проверки из SMS]]></string>
+	
     <string name="_sys_txt_current_picture"><![CDATA[Текущая картинка]]></string>
 	<string name="_sys_txt_data_successfully_submitted"><![CDATA[Выполнено]]></string>
     <string name="_sys_txt_delete"><![CDATA[Удалить]]></string>
@@ -2483,10 +2549,14 @@
 	<string name="_sys_txt_error_entry_update"><![CDATA[Ошибка обновления элемента]]></string>
 	<string name="_sys_txt_error_occured"><![CDATA[Произошла ошибка]]></string>
 	<string name="_sys_txt_forgot_pasword"><![CDATA[Забыли пароль?]]></string>
-	<string name="_sys_txt_forgot_pasword_check_email"><![CDATA[Имейл отослан, подалуйста, следуйте инструкциям в нём.]]></string>
+	<string name="_sys_txt_forgot_pasword_check_email"><![CDATA[Имейл отослан, пожалуйста, следуйте инструкциям в нём.]]></string>
+	<string name="_sys_txt_forgot_pasword_check_phone"><![CDATA[Sms отослан, подалуйста, следуйте инструкциям в нём.]]></string>
 	<string name="_sys_txt_forgot_pasword_desc"><![CDATA[Введите эл. адрес своего аккаунта, чтобы запросить ссылку на изменение пароля.]]></string>
+	<string name="_sys_txt_forgot_pasword_by_both_desc"><![CDATA[Введите эл. адрес или телефон своего аккаунта, чтобы запросить ссылку на изменение пароля.]]></string>
+	<string name="_sys_txt_forgot_pasword_by_phone_desc"><![CDATA[Введите телефон своего аккаунта, чтобы запросить ссылку на изменение пароля.]]></string>
 	<string name="_sys_txt_forgot_pasword_email_send_failed"><![CDATA[Не удалось отослать имейл, пожалуйста, попытайтесь позднее.]]></string>
 	<string name="_sys_txt_forgot_pasword_error_occured"><![CDATA[Произошла ошибка, пожалуйста, уведомите о ней администратора сайта.]]></string>
+	<string name="_sys_txt_forgot_pasword_sms_text"><![CDATA[Чтобы восстановить пароль нажмите на ссылку {0}]]></string>
 
     <string name="_sys_txt_form_entry_input_picture_delete"><![CDATA[Удалить]]></string>
     <string name="_sys_txt_form_entry_input_picture_insert"><![CDATA[Вставить в сообщение]]></string>
@@ -2496,7 +2566,11 @@
 	<string name="_sys_txt_form_submission_error_csrf_expired"><![CDATA[Маркер устарел. Пожалуйста попробуйте снова.]]></string>
 
     <string name="_sys_txt_homepage_cover"><![CDATA[Сплоченность людей — нерушимая крепость.<br /><button class="bx-btn bx-hide-when-logged-in bx-def-margin-top" onclick="document.location='{0}'">Присоедениться!</button>]]></string>
-    <string name="_sys_txt_join_description"><![CDATA[Уже зарегистрировались? <a href="{0}">Заходите.</a>]]></string>
+    <string name="_sys_txt_login_2fa_description"><![CDATA[Двухэтапная авторизация включена. В дополнении к имайлу и паролю, Вам нужно будет ввести код проверки, который мы вышлем вам в SMS.]]></string>
+	<string name="_sys_txt_login_2fa_description2"><![CDATA[Пожалуйста, введите код проверки из SMS.]]></string>
+	<string name="_sys_txt_login_2fa_sms_text"><![CDATA[Ваш код проверки {0}.]]></string>
+	<string name="_sys_txt_login_2fa_sms_error_occured"><![CDATA[Произошла ошибка, пожалуйста, уведомите о ней администратора сайта.]]></string>
+	<string name="_sys_txt_join_description"><![CDATA[Уже зарегистрировались? <a href="{0}">Заходите.</a>]]></string>
 	<string name="_sys_txt_login_description"><![CDATA[Ещё нет аккаунта? <a href="{0}">Зарегистрируйтесь.</a>]]></string>
 	<string name="_sys_txt_login_error"><![CDATA[Введённый имейл или пароль неправильны. Пожалуйста, попытайтесь снова.]]></string>
 	<string name="_sys_txt_login_invalid_role"><![CDATA[Доступ запрещён]]></string>

+ 1 - 1
template/scripts/BxBaseAccountForms.php

@@ -126,7 +126,7 @@ class BxBaseAccountForms extends BxDolProfileForms
 
         // if email_confirmation procedure is enabled - send email confirmation letter
         $oAccount = BxDolAccount::getInstance($iAccountId);
-        if (getParam('sys_email_confirmation') && $oAccount && !$oAccount->isConfirmed())
+        if (BxDolAccount::isNeedConfirmEmail() && $oAccount && !$oAccount->isConfirmedEmail())
             $oAccount->sendConfirmationEmail($iAccountId);
 
         // add account and content association

+ 5 - 0
template/scripts/BxBaseFormAccount.php

@@ -74,6 +74,7 @@ class BxBaseFormAccount extends BxTemplFormView
     static $FIELD_CHANGED = 'changed';
     static $FIELD_IP = 'ip';
     static $FIELD_REFFERED = 'reffered';
+	static $FIELD_PHONE = 'phone';
 
     protected $_bSetPendingApproval = false;
 
@@ -110,6 +111,9 @@ class BxBaseFormAccount extends BxTemplFormView
     {
     	$sEmail = isset($aValsToAdd[self::$FIELD_EMAIL]) ? $aValsToAdd[self::$FIELD_EMAIL] : $this->getCleanValue(self::$FIELD_EMAIL);
     	$sEmail = trim(strtolower($sEmail));
+		
+		$sPhone = isset($aValsToAdd[self::$FIELD_PHONE]) ? $aValsToAdd[self::$FIELD_PHONE] : $this->getCleanValue(self::$FIELD_PHONE);
+    	$sPhone = trim(strtolower($sPhone));
     	
         $sPwd = isset($aValsToAdd[self::$FIELD_PASSWORD]) ? $aValsToAdd[self::$FIELD_PASSWORD] : $this->getCleanValue(self::$FIELD_PASSWORD);
         $sSalt = genRndSalt();
@@ -123,6 +127,7 @@ class BxBaseFormAccount extends BxTemplFormView
             self::$FIELD_CHANGED => time(),
             self::$FIELD_IP => getVisitorIP(),
             self::$FIELD_REFFERED => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
+			self::$FIELD_PHONE => $sPhone,
         ));
         return parent::insert ($aValsToAdd, $isIgnore);
     }

+ 58 - 0
template/scripts/BxBaseFormConfirmPhone.php

@@ -0,0 +1,58 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaBaseView UNA Base Representation Classes
+ * @{
+ */
+
+bx_import('BxTemplFormView');
+
+class BxFormConfirmPhoneCheckerHelper extends BxDolFormCheckerHelper
+{
+    /**
+     * Check if key exists or wrong format
+     */
+    function checkPhoneUniq($s)
+    {
+        $s = trim($s);
+        if(!preg_match("/^\+[0-9\s]*$/", $s)) {
+            return _t('_sys_form_confirm_phone_input_phone_error_format');
+        }
+        
+        $oAccount = BxDolAccount::getInstance();
+        if ($oAccount) { // user is logged in
+            $aAccountInfo = $oAccount->getInfo();
+            if ($s == $aAccountInfo['phone']) // don't check phone for uniq, if it wasn't changed
+                return true;
+        }
+        
+        return BxDolAccountQuery::getInstance()->getIdByPhone($s) ? _t('_sys_form_confirm_phone_input_phone_error_not_unique') : true;
+    }
+    
+    function checkCodeExist($s)
+    {
+        $s = trim($s);
+        if($s == '') {
+            return _t('_sys_form_confirm_phone_input_code_error_empty');
+        }
+        
+        $oSession = BxDolSession::getInstance();
+        return $oSession->getValue(BX_ACCOUNT_SESSION_KEY_FOR_PHONE_ACTIVATEION_CODE) != $s ? _t('_sys_form_confirm_phone_input_code_error_invalid', BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=confirm-phone') . '?step=1') : true;
+    }
+}
+
+/**
+ * Phone Confirmation Form.
+ */
+class BxBaseFormConfirmPhone extends BxTemplFormView
+{
+    public function __construct($aInfo, $oTemplate)
+    {
+        parent::__construct($aInfo, $oTemplate);
+    }
+
+}
+
+/** @} */

+ 38 - 1
template/scripts/BxBaseFormForgotPassword.php

@@ -12,15 +12,52 @@ bx_import('BxTemplFormView');
 class BxFormForgotPasswordCheckerHelper extends BxDolFormCheckerHelper
 {
     /**
-     * Check if email is uniq.
+     * Check if email is exists.
      */
     function checkEmailExist ($s)
+    {        
+        if (!$this->checkEmail($s))
+            return false;
+
+        return BxDolAccountQuery::getInstance()->getIdByEmail($s) ? true : _t('_sys_form_forgot_password_email_not_recognized');
+    }
+    
+    function checkEmailExistOrEmpty ($s)
     {
+        if (trim($s) == '')
+            return true;
+        
         if (!$this->checkEmail($s))
             return false;
 
         return BxDolAccountQuery::getInstance()->getIdByEmail($s) ? true : _t('_sys_form_forgot_password_email_not_recognized');
     }
+	
+	/**
+     * Check if phone is exists.
+     */
+    function checkPhoneExist ($s)
+    {
+        $s = trim($s);
+        if(!preg_match("/^\+[0-9\s]*$/", $s)) {
+            return _t('_sys_form_forgot_password_phone_error_format');
+        }
+
+        return BxDolAccountQuery::getInstance()->getIdByPhone($s) ? true : _t('_sys_form_forgot_password_phone_not_recognized');
+    }
+    
+    function checkPhoneExistOrEmpty ($s)
+    {
+        if (trim($s) == '')
+            return true;
+        
+        $s = trim($s);
+        if(!preg_match("/^\+[0-9\s]*$/", $s)) {
+            return _t('_sys_form_forgot_password_phone_error_format');
+        }
+
+        return BxDolAccountQuery::getInstance()->getIdByPhone($s) ? true : _t('_sys_form_forgot_password_phone_not_recognized');
+    }
 
 }
 

+ 45 - 7
template/scripts/BxBaseFormLogin.php

@@ -7,6 +7,40 @@
  * @{
  */
 
+class BxFormLoginCheckerHelper extends BxDolFormCheckerHelper
+{
+    /**
+     * Check if key exists or wrong format
+     */
+    function checkPhoneExist($s)
+    {
+        $s = trim($s);
+        if(!preg_match("/^\+[0-9\s]*$/", $s)) {
+            return _t('_sys_form_login_input_phone_error_format');
+        }
+        $oSession = BxDolSession::getInstance();
+        $oAccount = BxDolAccount::getInstance($oSession->getValue(BX_ACCOUNT_SESSION_KEY_FOR_2FA_LOGIN_ACCOUNT_ID));
+        if ($oAccount) { // user is logged in
+            $aAccountInfo = $oAccount->getInfo();
+            if ($s == $aAccountInfo['phone']) // don't check phone for uniq, if it wasn't changed
+                return true;
+        }
+        
+        return BxDolAccountQuery::getInstance()->getIdByPhone($s) ? _t('_sys_form_login_input_phone_error_not_unique') : true;       
+    }
+
+    function checkCodeExist($s)
+    {
+        $s = trim($s);
+        if($s == '') {
+            return _t('_sys_form_login_input_code_error_empty');
+        }
+       
+        $oSession = BxDolSession::getInstance();
+        return $oSession->getValue(BX_ACCOUNT_SESSION_KEY_FOR_PHONE_ACTIVATEION_CODE) != $s ? _t('_sys_form_login_input_code_error_invalid', BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=login-step2')) : true;          
+    }   
+}
+
 /**
  * Login Form.
  */
@@ -41,15 +75,20 @@ class BxBaseFormLogin extends BxTemplFormView
 
     function isValid ()
     {
-        if (!parent::isValid ())
+        $bIsValid = parent::isValid ();
+        if (! $bIsValid)
             return false;
-
+        
 		$sId = trim($this->getCleanValue('ID'));
 		$sPassword = $this->getCleanValue('Password');
-
-        $sErrorString = bx_check_password($sId, $sPassword, $this->getRole());
-        $this->_setCustomError ($sErrorString);
-        return $sErrorString ? false : true;
+        if ($sId != ''){
+            $sErrorString = bx_check_password($sId, $sPassword, $this->getRole());
+            $this->_setCustomError ($sErrorString);
+            return $sErrorString ? false : true;
+        }
+        else{
+            return $bIsValid;
+        }
     }
 
     protected function genCustomInputSubmitText ($aInput)
@@ -77,5 +116,4 @@ class BxBaseFormLogin extends BxTemplFormView
         $this->aInputs['ID']['error'] = $s;
     }
 }
-
 /** @} */

+ 152 - 26
template/scripts/BxBaseServiceAccount.php

@@ -10,6 +10,7 @@
 /**
  * System service for creating system profile functionality.
  */
+
 class BxBaseServiceAccount extends BxDol
 {
     protected $_oAccountForms;
@@ -96,6 +97,19 @@ class BxBaseServiceAccount extends BxDol
     {
         return $this->_unsubscribeForm('sys_unsubscribe_updates');
     }
+    
+    /**
+     * Display confirmation statuses list
+     */
+    public function serviceGetConfirmationTypes()
+    {
+        $aResult = array();
+        $aChoices = array(BX_ACCOUNT_CONFIRMATION_NONE, BX_ACCOUNT_CONFIRMATION_EMAIL, BX_ACCOUNT_CONFIRMATION_PHONE, BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE);
+        foreach($aChoices as $sChoice)
+            $aResult[$sChoice] = _t('_sys_acc_confirmation_type_' . $sChoice);
+        
+        return $aResult;
+    }
 
     protected function _unsubscribeForm($sDisplay)
     {
@@ -140,13 +154,13 @@ class BxBaseServiceAccount extends BxDol
         // if user is logged in and email is confirmed then just display a message
         if (isLogged()) {
             $oAccount = BxDolAccount::getInstance();
-            if ($oAccount->isConfirmed())
+            if ($oAccount->isConfirmedEmail())
                 return MsgBox(_t("_sys_txt_confirm_email_already_confirmed"));
         }
 
         // if confirmation code is provided in the URL - perform email confirmation right away
-        if (!empty($_GET['code']))
-            return $this->confirmEmail(bx_process_input($_GET['code']));
+        if (bx_get('code') !== false)
+            return $this->confirmEmail(bx_process_input(bx_get('code')));
 
         // if user requested to resend verification letter then send letter and display message
         if (bx_process_input(bx_get('resend')) && isLogged()) {
@@ -178,6 +192,73 @@ class BxBaseServiceAccount extends BxDol
 
         return '<div class="bx-def-padding-sec-bottom">' . _t("_sys_txt_confirm_email_desc") . '</div>' . $oForm->getCode();
     }
+    
+    /**
+     * Display phone confirmation forms, if confirmation code is provided then try to confirm profile
+     */
+    public function servicePhoneConfirmation($sMsg = false)
+    {
+        // if user is logged in and phone is confirmed then just display a message
+        if (isLogged()) {
+            $oAccount = BxDolAccount::getInstance();
+            if ($oAccount->isConfirmedPhone())
+                return MsgBox(_t("_sys_txt_confirm_phone_already_confirmed"));
+            
+            $iStep = 1;
+            $a = $oAccount->getInfo();
+            $sPhoneNumber = $a['phone'];
+            
+            $oSession = BxDolSession::getInstance();           
+            if ($sPhoneNumber != "" && $oSession->isValue(BX_ACCOUNT_SESSION_KEY_FOR_PHONE_ACTIVATEION_CODE)){
+                 $iStep = 2;
+            }
+        
+            if (bx_get('step'))
+                $iStep = (int)bx_get('step');
+        
+            // show and process phone set form
+            if ($iStep == 1){
+                $oForm = BxDolForm::getObjectInstance('sys_confirm_phone', 'sys_confirm_phone_set_phone');
+                if (!$oForm)
+                    return MsgBox(_t("_sys_txt_confirm_phone_set_phone_error_occured"));
+            
+                $oForm->initChecker(array('phone' => $sPhoneNumber));
+                if ($oForm->isSubmittedAndValid()) {
+                    $oAccount->updatePhone(trim($oForm->getCleanValue('phone')));
+                    $sActivationCode = rand(1000, 9999);
+                    $sActivationText =_t('_sys_txt_confirm_phone_sms_text', $sActivationCode);
+                    $ret = null;
+                    bx_alert('account', 'before_confirm_phone_send_sms', $oAccount->id(), bx_get_logged_profile_id(), array('phone_number' => $sPhoneNumber, 'sms_text' => $sActivationText, 'override_result' => &$ret));
+                    if ($ret === null) 
+                    {
+                        $oTwilio = BxDolTwilio::getInstance();
+                        if(!$oTwilio->SendSms($sPhoneNumber,  $sActivationText)){
+                            return MsgBox(_t("_sys_txt_confirm_phone_send_sms_error_occured"));
+                        }
+                    }
+
+                    $oSession->setValue(BX_ACCOUNT_SESSION_KEY_FOR_PHONE_ACTIVATEION_CODE, $sActivationCode);
+                    header('Location: ' . BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=confirm-phone'));
+                } 
+                return '<div class="bx-def-padding-sec-bottom">' . _t("_sys_txt_confirm_phone_set_phone_desc_set_phone") . '</div>' .$oForm->getCode();
+            }
+        
+            if ($iStep == 2){
+                $oForm = BxDolForm::getObjectInstance('sys_confirm_phone', 'sys_confirm_phone_confirmation');
+                if (!$oForm)
+                    return MsgBox(_t("_sys_txt_confirm_phone_set_phone_confirmation_occured"));
+            
+                $oForm->initChecker();
+            
+                if ($oForm->isSubmittedAndValid()) {
+                    $oAccount->updatePhoneConfirmed(true);
+                    $oSession->unsetValue(BX_ACCOUNT_SESSION_KEY_FOR_PHONE_ACTIVATEION_CODE);
+                    return MsgBox(_t("_sys_txt_confirm_phone_confirm_success"));
+                } 
+                return '<div class="bx-def-padding-sec-bottom">' . _t("_sys_txt_confirm_phone_set_phone_desc_phone_confirmation") . '</div>' .$oForm->getCode();
+            }
+        }
+    }
 
     /**
      * Perform email confirmation
@@ -236,42 +317,87 @@ class BxBaseServiceAccount extends BxDol
         if (!$oForm)
             return '';
 
+        $bNeedCheckEmailAndPhone = true;
+        $sCaptionKey = "_sys_txt_forgot_pasword_by_both_desc";
+        if (BxDolAccount::isNeedConfirmPhone()){
+            if (!BxDolAccount::isNeedConfirmEmail()){
+                unset($oForm->aInputs['email']);
+                $sCaptionKey = "_sys_txt_forgot_pasword_by_phone_desc";
+                $oForm->aInputs['phone']['checker']['func'] = 'PhoneExist';
+                $bNeedCheckEmailAndPhone = false;
+            }
+        }
+        else{
+            if (BxDolAccount::isNeedConfirmEmail()){
+                unset($oForm->aInputs['phone']);
+                $sCaptionKey = "_sys_txt_forgot_pasword_desc";
+                $oForm->aInputs['email']['checker']['func'] = 'EmailExist';
+                $bNeedCheckEmailAndPhone = false;
+            }
+        }
+        
         $oForm->initChecker();
 
-        if ( $oForm->isSubmittedAndValid() ) {
-
+        $bShowErrorEmptyBoth = false;
+        if ($oForm->isSubmitted() && $bNeedCheckEmailAndPhone && $oForm->getCleanValue('phone') == '' && $oForm->getCleanValue('email') == ''){
+            $bShowErrorEmptyBoth = true;
+            $oForm->setValid(false);
+        }
+        
+        if ($oForm->isSubmittedAndValid()) {
             $oKey = BxDolKey::getInstance();
             if (!$oKey) {
-
                 $sResultMsg = MsgBox(_t("_sys_txt_forgot_pasword_error_occured"));
-
-            } else {
-
+            } 
+            else {
                 $sEmail = $oForm->getCleanValue('email');
-                $iAccountId = $this->_oAccountQuery->getIdByEmail($sEmail);
+                $sPhone = $oForm->getCleanValue('phone');
+                
+                if (isset($oForm->aInputs['email']) &&  $sEmail != '')
+                {
+                    $iAccountId = $this->_oAccountQuery->getIdByEmail($sEmail);
 
-                $aPlus['key'] = $oKey->getNewKey(array('email' => $sEmail));
-                $aPlus['forgot_password_url'] = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=forgot-password') . '&key=' . $aPlus['key'];
+                    $aPlus['key'] = $oKey->getNewKey(array('email' => $sEmail));
+                    $aPlus['forgot_password_url'] = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=forgot-password', array('key' => $aPlus['key']));
 
-                $aTemplate = BxDolEmailTemplates::getInstance() -> parseTemplate('t_Forgot', $aPlus, $iAccountId);
+                    $aTemplate = BxDolEmailTemplates::getInstance() -> parseTemplate('t_Forgot', $aPlus, $iAccountId);
 
-                if ($aTemplate && sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, $aPlus, BX_EMAIL_SYSTEM))
-                    $sResultMsg = MsgBox(_t("_sys_txt_forgot_pasword_check_email"));
-                else
-                    $sResultMsg = MsgBox(_t("_sys_txt_forgot_pasword_email_send_failed"));
-
-                $sForm = '';
+                    if ($aTemplate && sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, $aPlus, BX_EMAIL_SYSTEM))
+                        $sResultMsg = MsgBox(_t("_sys_txt_forgot_pasword_check_email"));
+                    else
+                        $sResultMsg = MsgBox(_t("_sys_txt_forgot_pasword_email_send_failed"));
 
+                    $sForm = '';
+                }
+                
+                if (isset($oForm->aInputs['phone']) &&  $sPhone != ''){   
+                    $iAccountId = $this->_oAccountQuery->getIdByPhone($sPhone);
+                    $aAccountInfo = $this->_oAccountQuery->getInfoById($iAccountId);
+                    
+                    $aPlus['key'] = $oKey->getNewKey(array('email' => $aAccountInfo['email']));
+                    $aPlus['forgot_password_url'] = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=forgot-password', array('key' => $aPlus['key']));
+
+                    $sSmsText = _t('_sys_txt_forgot_pasword_sms_text', $aPlus['forgot_password_url']);
+                    
+                    $ret = null;
+                    bx_alert('account', 'before_forgot_password_send_sms', $aAccountInfo['id'], false, array('phone_number' => $sPhone, 'sms_text' => $sSmsText, 'override_result' => &$ret));
+                    if ($ret === null) 
+                    {
+                        $oTwilio = BxDolTwilio::getInstance();
+                        if($oTwilio->SendSms($sPhone,  $sSmsText))
+                            $sResultMsg = MsgBox(_t("_sys_txt_forgot_pasword_check_phone"));
+                        else
+                            $sResultMsg = MsgBox(_t("_sys_txt_forgot_pasword_error_occured"));
+                    }
+                    $sForm = '';
+                }
             }
-
-        } else {
-
-            $sResultMsg = _t("_sys_txt_forgot_pasword_desc");
+        } 
+        else {
+            $sResultMsg = _t($sCaptionKey);
             $sForm = $oForm->getCode();
-
         }
-
-        return '<div class="bx-def-padding-sec-bottom">' . $sResultMsg . '</div>' . $sForm;
+        return '<div class="bx-def-padding-sec-bottom">' . $sResultMsg . '</div>' . $sForm . ($bShowErrorEmptyBoth ? '<div class="bx-form-warn">' . _t("_sys_form_forgot_password_phone_and_email_empty_error") . '</div>' : '');
     }
 
     /**

+ 68 - 0
template/scripts/BxBaseServiceLogin.php

@@ -104,7 +104,75 @@ class BxBaseServiceLogin extends BxDol
         return $sCustomHtmlBefore . $sAuth . $sFormCode . $sCustomHtmlAfter . $sJoinText;
 
     }
+    
+    public function serviceLoginFormStep2 ()
+    {
+        if(isLogged())
+            return false;
 
+        $oSession = BxDolSession::getInstance();
+        $iAccountId = $oSession->getValue(BX_ACCOUNT_SESSION_KEY_FOR_2FA_LOGIN_ACCOUNT_ID);
+        if ($iAccountId == '')
+            return false;
+
+        $oForm = BxDolForm::getObjectInstance('sys_login', 'sys_login_step2');
+        $oForm->aFormAttrs['action'] = '';
+        
+        $oAccount = BxDolAccount::getInstance($iAccountId);
+        $a = $oAccount->getInfo($iAccountId);
+        $sPhoneNumber = trim($a['phone']);
+            
+        $oForm->initChecker(array('phone' => $sPhoneNumber));
+        if ($oForm->isSubmittedAndValid()) {
+            $sNewPhoneNumber = trim($oForm->getCleanValue('phone'));
+            if ($sPhoneNumber != $sNewPhoneNumber)
+                $oAccount->updatePhone($sNewPhoneNumber);
+            $sActivationCode = rand(1000, 9999);
+            $sActivationText =_t('_sys_txt_login_2fa_sms_text', $sActivationCode);
+            $ret = null;
+            bx_alert('account', 'before_2fa_send_sms', $oAccount->id(), false, array('phone_number' => $sPhoneNumber, 'sms_text' => $sActivationText, 'override_result' => &$ret));
+            if ($ret === null) 
+            {
+                $oTwilio = BxDolTwilio::getInstance();
+                if(!$oTwilio->SendSms($sPhoneNumber,  $sActivationText)){
+                    return MsgBox(_t('_sys_txt_login_2fa_sms_error_occured'));
+                }
+            }
+            $oSession = BxDolSession::getInstance();
+            $oSession->setValue(BX_ACCOUNT_SESSION_KEY_FOR_PHONE_ACTIVATEION_CODE, $sActivationCode);
+            header('Location: ' . BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=login-step3'));
+        }
+        return '<div class="bx-def-padding-sec-bottom">' . _t("_sys_txt_login_2fa_description") . '</div>' .$oForm->getCode();
+    }
+    
+    public function serviceLoginFormStep3 ()
+    {
+        if(isLogged())
+            return false;
+        $oForm = BxDolForm::getObjectInstance('sys_login', 'sys_login_step3');
+        $oForm->aFormAttrs['action'] = '';
+        $oForm->initChecker();
+        
+        if ($oForm->isSubmittedAndValid()) {
+            $oSession = BxDolSession::getInstance();
+            $oSession->unsetValue(BX_ACCOUNT_SESSION_KEY_FOR_PHONE_ACTIVATEION_CODE);
+            $iAccountId = $oSession->getValue(BX_ACCOUNT_SESSION_KEY_FOR_2FA_LOGIN_ACCOUNT_ID);
+            $oAccount = BxDolAccount::getInstance($iAccountId);
+            $aAccount = bx_login($oAccount->id(), $oSession->getValue(BX_ACCOUNT_SESSION_KEY_FOR_2FA_LOGIN_IS_REMEMBER));
+           
+            $sUrlRelocate = $oForm->getCleanValue('relocate');
+            if (!$sUrlRelocate || 0 !== strncmp($sUrlRelocate, BX_DOL_URL_ROOT, strlen(BX_DOL_URL_ROOT)))
+                $sUrlRelocate = BX_DOL_ROLE_ADMIN == $oForm->getRole() ? BX_DOL_URL_STUDIO . 'launcher.php' : BX_DOL_URL_ROOT . 'member.php';
+            
+            BxDolTemplate::getInstance()->setPageNameIndex (BX_PAGE_TRANSITION);
+            BxDolTemplate::getInstance()->setPageHeader (_t('_Please Wait'));
+            BxDolTemplate::getInstance()->setPageContent ('page_main_code', MsgBox(_t('_Please Wait')));
+            BxDolTemplate::getInstance()->setPageContent ('url_relocate', bx_html_attribute($sUrlRelocate, BX_ESCAPE_STR_QUOTE));
+            
+            header('Location: ' . $sUrlRelocate);
+        } 
+        return '<div class="bx-def-padding-sec-bottom">' . _t("_sys_txt_login_2fa_description2") . '</div>' .$oForm->getCode();
+    }
 }
 
 /** @} */