diff --git a/docs/install.sql b/docs/install.sql index e3e983e..fa144ca 100644 --- a/docs/install.sql +++ b/docs/install.sql @@ -1,19 +1,23 @@ -CREATE TABLE `d3totp` ( - `OXID` CHAR(32) NOT NULL, - `OXUSERID` CHAR(32) NOT NULL, - `USETOTP` TINYINT(1) NOT NULL DEFAULT '0', - `SEED` VARCHAR(256) NOT NULL DEFAULT '0', - `BC1` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #1', - `BC2` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #2', - `BC3` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #3', - `BC4` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #4', - `BC5` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #5', - `BC6` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #6', - `BC7` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #7', - `BC8` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #8', - `BC9` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #9', - `BC10` VARCHAR(64) NOT NULL DEFAULT '0' COMMENT 'BackupCode #10', - PRIMARY KEY (`OXID`), - UNIQUE INDEX `OXUSERID` (`OXUSERID`) -) +CREATE TABLE IF NOT EXISTS `d3totp` ( + `OXID` CHAR(32) NOT NULL , + `OXUSERID` CHAR(32) NOT NULL , + `USETOTP` TINYINT(1) NOT NULL DEFAULT 0, + `SEED` VARCHAR(256) NOT NULL , + `OXTIMESTAMP` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Timestamp', + PRIMARY KEY (`OXID`) , + UNIQUE KEY `OXUSERID` (`OXUSERID`) +) +ENGINE=InnoDB +COMMENT='totp setting'; + +CREATE TABLE IF NOT EXISTS `d3totp_backupcodes` ( + `OXID` CHAR(32) NOT NULL , + `OXUSERID` CHAR(32) NOT NULL COMMENT 'user id', + `BACKUPCODE` VARCHAR(64) NOT NULL COMMENT 'BackupCode', + `OXTIMESTAMP` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Timestamp', + PRIMARY KEY (`OXID`) , + KEY `OXUSERID` (`OXUSERID`) , + KEY `BACKUPCODE` (`BACKUPCODE`) +) ENGINE=InnoDB +COMMENT='totp backup codes'; diff --git a/docs/update.sql b/docs/update.sql index 892dc86..59daeac 100644 --- a/docs/update.sql +++ b/docs/update.sql @@ -1 +1 @@ -# no update instructions available \ No newline at end of file +# no update instructions available diff --git a/src/Application/Controller/Admin/d3user_totp.php b/src/Application/Controller/Admin/d3user_totp.php index 2e8a1c1..530a26e 100644 --- a/src/Application/Controller/Admin/d3user_totp.php +++ b/src/Application/Controller/Admin/d3user_totp.php @@ -16,11 +16,11 @@ namespace D3\Totp\Application\Controller\Admin; use D3\Totp\Application\Model\d3totp; +use D3\Totp\Application\Model\Exceptions\d3backupcodelist; use D3\Totp\Modules\Application\Model\d3_totp_user; -use Doctrine\DBAL\DBALException; +use Exception; use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController; use OxidEsales\Eshop\Application\Model\User; -use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Exception\StandardException; use OxidEsales\Eshop\Core\Registry; @@ -30,10 +30,10 @@ class d3user_totp extends AdminDetailsController protected $_sThisTemplate = 'd3user_totp.tpl'; + public $aBackupCodes = array(); + /** * @return string - * @throws DBALException - * @throws DatabaseConnectionException */ public function render() { @@ -60,7 +60,7 @@ class d3user_totp extends AdminDetailsController } /** - * @throws \Exception + * @throws Exception */ public function save() { @@ -74,6 +74,7 @@ class d3user_totp extends AdminDetailsController /** @var d3_totp_user $oUser */ $oUser = oxNew(User::class); $oUser->load($this->getEditObjectId()); + if (false == $oUser->isSamePassword($pwd)) { $oException = oxNew(StandardException::class, 'D3_TOTP_ERROR_PWDONTPASS'); throw $oException; @@ -81,6 +82,7 @@ class d3user_totp extends AdminDetailsController /** @var d3totp $oTotp */ $oTotp = oxNew(d3totp::class); + $oTotpBackupCodes = oxNew(d3backupcodelist::class); if ($aParams['d3totp__oxid']) { $oTotp->load($aParams['d3totp__oxid']); } else { @@ -91,11 +93,12 @@ class d3user_totp extends AdminDetailsController $oTotp->saveSecret($seed); $oTotp->assign($aParams); $oTotp->verify($otp, $seed); - $this->addTplParam('aBackupCodes', $oTotp->generateBackupCodes()); + $oTotpBackupCodes->generateBackupCodes($this->getEditObjectId()); $oTotp->setId(); } $oTotp->save(); - } catch (\Exception $oExcp) { + $oTotpBackupCodes->save(); + } catch (Exception $oExcp) { $this->_sSaveError = $oExcp->getMessage(); } } @@ -111,4 +114,20 @@ class d3user_totp extends AdminDetailsController $oTotp->delete(); } } + + /** + * @param $aCodes + */ + public function setBackupCodes($aCodes) + { + $this->aBackupCodes = $aCodes; + } + + /** + * @return string + */ + public function getBackupCodes() + { + return implode(PHP_EOL, $this->aBackupCodes); + } } \ No newline at end of file diff --git a/src/Application/Model/Exceptions/d3backupcodelist.php b/src/Application/Model/Exceptions/d3backupcodelist.php new file mode 100644 index 0000000..eaa4af4 --- /dev/null +++ b/src/Application/Model/Exceptions/d3backupcodelist.php @@ -0,0 +1,118 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\Totp\Application\Model\Exceptions; + +use D3\Totp\Application\Controller\Admin\d3user_totp; +use D3\Totp\Application\Model\d3backupcode; +use Exception; +use OxidEsales\Eshop\Core\DatabaseProvider; +use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; +use OxidEsales\Eshop\Core\Model\ListModel; +use OxidEsales\Eshop\Core\Registry; + +class d3backupcodelist extends ListModel +{ + protected $_sObjectsInListName = d3backupcode::class; + + /** + * Core table name + * + * @var string + */ + protected $_sCoreTable = 'd3totp_backupcodes'; + + protected $_backupCodes = array(); + + /** + * @param $sUserId + * @throws DatabaseConnectionException + */ + public function generateBackupCodes($sUserId) + { + $this->deleteAllFromUser($sUserId); + + for ($i = 1; $i <= 10; $i++) { + $oBackupCode = oxNew(d3backupcode::class); + $this->_backupCodes[] = $oBackupCode->generateCode($sUserId); + $this->offsetSet(md5(rand()), $oBackupCode); + } + + /** @var d3user_totp $oActView */ + $oActView = Registry::getConfig()->getActiveView(); + $oActView->setBackupCodes($this->_backupCodes); + } + + /** + * @throws Exception + */ + public function save() + { + /** @var d3backupcode $oBackupCode */ + foreach ($this->getArray() as $oBackupCode) { + $oBackupCode->save(); + } + } + + /** + * @return d3backupcode + */ + public function getBaseObject() + { + /** @var d3backupcode $object */ + $object = parent::getBaseObject(); + + return $object; + } + + /** + * @param $totp + * @return bool + * @throws DatabaseConnectionException + */ + public function verify($totp) + { + $oDb = DatabaseProvider::getDb(); + + $query = "SELECT oxid FROM ".$this->getBaseObject()->getViewName(). + " WHERE ".$oDb->quoteIdentifier('backupcode')." = ".$oDb->quote($this->getBaseObject()->d3EncodeBC($totp))." AND ". + $oDb->quoteIdentifier("oxuserid") ." = ".$oDb->quote($this->getUser()->getId()); + + $sVerify = $oDb->getOne($query); + + $this->getBaseObject()->delete($sVerify); + + return (bool) $sVerify; + } + + /** + * @param $sUserId + * @throws DatabaseConnectionException + */ + public function deleteAllFromUser($sUserId) + { + $oDb = DatabaseProvider::getDb(); + + $query = "SELECT OXID FROM ".$oDb->quoteIdentifier($this->getBaseObject()->getCoreTableName()). + " WHERE ".$oDb->quoteIdentifier('oxuserid')." = ".$oDb->quote($sUserId); + + $this->selectString($query); + + /** @var d3backupcode $oBackupCode */ + foreach ($this->getArray() as $oBackupCode) { + $oBackupCode->delete(); + } + } +} \ No newline at end of file diff --git a/src/Application/Model/Exceptions/d3totp_wrongOtpException.php b/src/Application/Model/Exceptions/d3totp_wrongOtpException.php index 051da9f..e21e854 100644 --- a/src/Application/Model/Exceptions/d3totp_wrongOtpException.php +++ b/src/Application/Model/Exceptions/d3totp_wrongOtpException.php @@ -17,6 +17,7 @@ namespace D3\Totp\Application\Model\Exceptions; +use Exception; use OxidEsales\Eshop\Core\Exception\StandardException; class d3totp_wrongOtpException extends StandardException @@ -26,9 +27,9 @@ class d3totp_wrongOtpException extends StandardException * * @param string $sMessage exception message * @param integer $iCode exception code - * @param \Exception|null $previous previous exception + * @param Exception|null $previous previous exception */ - public function __construct($sMessage = "D3_TOTP_ERROR_UNVALID", $iCode = 0, \Exception $previous = null) + public function __construct($sMessage = "D3_TOTP_ERROR_UNVALID", $iCode = 0, Exception $previous = null) { parent::__construct($sMessage, $iCode, $previous); } diff --git a/src/Application/Model/d3backupcode.php b/src/Application/Model/d3backupcode.php new file mode 100644 index 0000000..1caa013 --- /dev/null +++ b/src/Application/Model/d3backupcode.php @@ -0,0 +1,62 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\Totp\Application\Model; + +use OxidEsales\Eshop\Core\DatabaseProvider; +use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; +use OxidEsales\Eshop\Core\Model\BaseModel; +use RandomLib\Factory; +use RandomLib\Generator; + +class d3backupcode extends BaseModel +{ + protected $_sCoreTable = 'd3totp_backupcodes'; + + /** + * @param $sUserId + * @return string + * @throws DatabaseConnectionException + */ + public function generateCode($sUserId) + { + $factory = new Factory(); + $generator = $factory->getLowStrengthGenerator(); + + $sCode = $generator->generateString(6, Generator::CHAR_DIGITS); + $this->assign( + array( + 'oxuserid' => $sUserId, + 'backupcode' => $this->d3EncodeBC($sCode), + ) + ); + + return $sCode; + } + + /** + * @param $code + * @return false|string + * @throws DatabaseConnectionException + */ + public function d3EncodeBC($code) + { + $oDb = DatabaseProvider::getDb(); + $salt = $this->getUser()->getFieldData('oxpasssalt'); + $sSelect = "SELECT BINARY MD5( CONCAT( " . $oDb->quote($code) . ", UNHEX( ".$oDb->quote($salt)." ) ) )"; + + return $oDb->getOne($sSelect); + } +} \ No newline at end of file diff --git a/src/Application/Model/d3totp.php b/src/Application/Model/d3totp.php index 0b24665..83a843b 100644 --- a/src/Application/Model/d3totp.php +++ b/src/Application/Model/d3totp.php @@ -18,6 +18,7 @@ namespace D3\Totp\Application\Model; use BaconQrCode\Renderer\Image\Svg; use BaconQrCode\Writer; use D3\ModCfg\Application\Model\d3database; +use D3\Totp\Application\Model\Exceptions\d3backupcodelist; use D3\Totp\Application\Model\Exceptions\d3totp_wrongOtpException; use Doctrine\DBAL\DBALException; use OTPHP\TOTP; @@ -26,8 +27,6 @@ use OxidEsales\Eshop\Core\DatabaseProvider; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Model\BaseModel; use OxidEsales\Eshop\Core\Registry; -use RandomLib\Factory; -use RandomLib\Generator; class d3totp extends BaseModel { @@ -37,7 +36,6 @@ class d3totp extends BaseModel public $userId; public $totp; protected $timeWindow = 2; - protected $_backupCodes = array(); /** * d3totp constructor. @@ -119,28 +117,6 @@ class d3totp extends BaseModel return null; } - /** - * @return array - * @throws DatabaseConnectionException - */ - public function generateBackupCodes() - { - $factory = new Factory(); - $generator = $factory->getLowStrengthGenerator(); - - for ($i = 1; $i <= 10; $i++) { - $sCode = $generator->generateString(6, Generator::CHAR_DIGITS); - $this->_backupCodes[] = $sCode; - $this->assign( - array( - 'bc'.$i => $this->d3EncodeBC($sCode) - ) - ); - } - - return $this->_backupCodes; - } - /** * @param $seed * @return TOTP @@ -206,20 +182,6 @@ class d3totp extends BaseModel ); } - /** - * @param $code - * @return false|string - * @throws DatabaseConnectionException - */ - public function d3EncodeBC($code) - { - $oDb = DatabaseProvider::getDb(); - $salt = $this->getUser()->getFieldData('oxpasssalt'); - $sSelect = "SELECT BINARY MD5( CONCAT( " . $oDb->quote($code) . ", UNHEX( ".$oDb->quote($salt)." ) ) )"; - - return $oDb->getOne($sSelect); - } - /** * @param $totp * @param $seed @@ -231,14 +193,9 @@ class d3totp extends BaseModel { $blVerify = $this->getTotp($seed)->verify($totp, null, $this->timeWindow); if (false == $blVerify) { - $oDb = DatabaseProvider::getDb(); - $aFields = array('bc1', 'bc2', 'bc3', 'bc4', 'bc5', 'bc6', 'bc7', 'bc8', 'bc9', 'bc10'); - - $query = "SELECT 1 FROM ".$this->getViewName(). - " WHERE ".$oDb->quote($this->d3EncodeBC($totp))." IN (".implode(', ', array_map([$oDb, 'quoteIdentifier'], $aFields)).") AND ". - $oDb->quoteIdentifier("oxuserid") ." = ".$oDb->quote($this->getUser()->getId()); - - $blVerify = (bool) $oDb->getOne($query); + /** @var d3backupcodelist $oBC */ + $oBC = oxNew(d3backupcodelist::class); + $blVerify = $oBC->verify($totp); if (false == $blVerify) { $oException = oxNew(d3totp_wrongOtpException::class); @@ -283,4 +240,19 @@ class d3totp extends BaseModel return false; } + + /** + * @param null $oxid + * @return bool + * @throws DatabaseConnectionException + */ + public function delete($oxid = null) + { + $oBackupCodeList = oxNew(d3backupcodelist::class); + $oBackupCodeList->deleteAllFromUser($this->getFieldData('oxuserid')); + + $blDelete = parent::delete(); + + return $blDelete; + } } \ No newline at end of file diff --git a/src/Application/views/admin/de/d3totp_lang.php b/src/Application/views/admin/de/d3totp_lang.php index bd8c346..3801970 100644 --- a/src/Application/views/admin/de/d3totp_lang.php +++ b/src/Application/views/admin/de/d3totp_lang.php @@ -41,7 +41,7 @@ $aLang = [ 'D3_TOTP_REGISTERDELETE_DESC' => 'Um die Registrierung zu ändern, löschen Sie diese bitte vorerst. Sie können sofort im Anschluss eine neue Registrierung anlegen.
Wenn Sie die Registrierung löschen, ist das Konto nicht mehr durch die Zweifaktorauthentisierung geschützt.', 'D3_TOTP_BACKUPCODES' => 'Backup-Codes', - 'D3_TOTP_BACKUPCODES_DESC' => 'Mit diesen Backup-Codes können Sie sich anmelden, wenn die Generierung des Einmalpasswortes nicht möglich ist (z.B. Gerät verloren oder neu installiert). Sie können dann die Einstellungen zur Verwendung der 2-Faktor-Autetizierung aändern oder einen neuen Zugang erstellen. Speichern Sie sich diese Codes bitte in diesem Moment sicher ab. Nach Verlassen dieser Seite können diese Codes nicht erneut angezeigt werden.', + 'D3_TOTP_BACKUPCODES_DESC' => 'Mit diesen Backup-Codes können Sie sich anmelden, wenn die Generierung des Einmalpasswortes nicht möglich ist (z.B. Gerät verloren oder neu installiert). Sie können dann die Einstellungen zur Verwendung der 2-Faktor-Authentisierung ändern oder einen neuen Zugang erstellen. Speichern Sie sich diese Codes bitte in diesem Moment sicher ab. Nach Verlassen dieser Seite können diese Codes nicht erneut angezeigt werden.', 'D3_TOTP_SAVE' => 'Speichern', diff --git a/src/Application/views/admin/tpl/d3user_totp.tpl b/src/Application/views/admin/tpl/d3user_totp.tpl index 759cd96..f0ad81a 100644 --- a/src/Application/views/admin/tpl/d3user_totp.tpl +++ b/src/Application/views/admin/tpl/d3user_totp.tpl @@ -29,7 +29,7 @@ [{if $sSaveError}] - +
@@ -38,10 +38,10 @@ [{/if}] [{if $oxid && $oxid != '-1'}] -
[{oxmultilang ident=$sSaveError}]
+
-
- + -
+ [{block name="user_d3user_totp_form1"}] [{if false == $totp->getId()}] @@ -80,8 +80,8 @@
- +
+ [{block name="user_d3user_totp_form2"}] [{if false == $totp->getId()}] @@ -124,7 +124,7 @@ [{else}] - [{if $aBackupCodes}] + [{if $oView->getBackupCodes()}] [{/if}] diff --git a/src/Setup/Installation.php b/src/Setup/Installation.php index 37ec5d1..d5b709e 100644 --- a/src/Setup/Installation.php +++ b/src/Setup/Installation.php @@ -27,6 +27,8 @@ class Installation extends d3install_updatebase protected $_aUpdateMethods = array( array('check' => 'doesTotpTableNotExist', 'do' => 'addTotpTable'), + array('check' => 'doesTotpBCTableNotExist', + 'do' => 'addTotpBCTable'), array('check' => 'checkFields', 'do' => 'fixFields'), array('check' => 'checkIndizes', @@ -76,103 +78,54 @@ class Installation extends d3install_updatebase 'sExtra' => '', 'blMultilang' => false, ), - 'BC1' => array( + 'OXTIMESTAMP' => array( 'sTableName' => 'd3totp', - 'sFieldName' => 'BC1', - 'sType' => 'VARCHAR(64)', + 'sFieldName' => 'OXTIMESTAMP', + 'sType' => 'TIMESTAMP', 'blNull' => false, - 'sDefault' => false, - 'sComment' => 'BackupCode #1', + 'sDefault' => 'CURRENT_TIMESTAMP', + 'sComment' => 'Timestamp', 'sExtra' => '', 'blMultilang' => false, ), - 'BC2' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC2', - 'sType' => 'VARCHAR(64)', + + 'bc_OXID' => array( + 'sTableName' => 'd3totp_backupcodes', + 'sFieldName' => 'OXID', + 'sType' => 'CHAR(32)', 'blNull' => false, 'sDefault' => false, - 'sComment' => 'BackupCode #2', + 'sComment' => '', 'sExtra' => '', 'blMultilang' => false, ), - 'BC3' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC3', - 'sType' => 'VARCHAR(64)', + 'bc_OXUSERID' => array( + 'sTableName' => 'd3totp_backupcodes', + 'sFieldName' => 'OXUSERID', + 'sType' => 'CHAR(32)', 'blNull' => false, 'sDefault' => false, - 'sComment' => 'BackupCode #3', + 'sComment' => 'user id', 'sExtra' => '', 'blMultilang' => false, ), - 'BC4' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC4', + 'bc_BACKUPCODE' => array( + 'sTableName' => 'd3totp_backupcodes', + 'sFieldName' => 'BACKUPCODE', 'sType' => 'VARCHAR(64)', 'blNull' => false, 'sDefault' => false, - 'sComment' => 'BackupCode #4', + 'sComment' => 'BackupCode', 'sExtra' => '', 'blMultilang' => false, ), - 'BC5' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC5', - 'sType' => 'VARCHAR(64)', + 'bc_OXTIMESTAMP' => array( + 'sTableName' => 'd3totp_backupcodes', + 'sFieldName' => 'OXTIMESTAMP', + 'sType' => 'TIMESTAMP', 'blNull' => false, - 'sDefault' => false, - 'sComment' => 'BackupCode #5', - 'sExtra' => '', - 'blMultilang' => false, - ), - 'BC6' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC6', - 'sType' => 'VARCHAR(64)', - 'blNull' => false, - 'sDefault' => false, - 'sComment' => 'BackupCode #6', - 'sExtra' => '', - 'blMultilang' => false, - ), - 'BC7' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC7', - 'sType' => 'VARCHAR(64)', - 'blNull' => false, - 'sDefault' => false, - 'sComment' => 'BackupCode #7', - 'sExtra' => '', - 'blMultilang' => false, - ), - 'BC8' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC8', - 'sType' => 'VARCHAR(64)', - 'blNull' => false, - 'sDefault' => false, - 'sComment' => 'BackupCode #8', - 'sExtra' => '', - 'blMultilang' => false, - ), - 'BC9' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC9', - 'sType' => 'VARCHAR(64)', - 'blNull' => false, - 'sDefault' => false, - 'sComment' => 'BackupCode #9', - 'sExtra' => '', - 'blMultilang' => false, - ), - 'BC10' => array( - 'sTableName' => 'd3totp', - 'sFieldName' => 'BC10', - 'sType' => 'VARCHAR(64)', - 'blNull' => false, - 'sDefault' => false, - 'sComment' => 'BackupCode #10', + 'sDefault' => 'CURRENT_TIMESTAMP', + 'sComment' => 'Timestamp', 'sExtra' => '', 'blMultilang' => false, ) @@ -194,7 +147,31 @@ class Installation extends d3install_updatebase 'aFields' => array( 'OXUSERID' => 'OXUSERID', ), - ) + ), + 'bc_OXID' => array( + 'sTableName' => 'd3totp_backupcodes', + 'sType' => d3database::INDEX_TYPE_PRIMARY, + 'sName' => 'PRIMARY', + 'aFields' => array( + 'OXID' => 'OXID', + ), + ), + 'bc_OXUSERID' => array( + 'sTableName' => 'd3totp_backupcodes', + 'sType' => d3database::INDEX_TYPE_INDEX, + 'sName' => 'OXUSERID', + 'aFields' => array( + 'OXUSERID' => 'OXUSERID', + ), + ), + 'bc_BACKUPCODE' => array( + 'sTableName' => 'd3totp_backupcodes', + 'sType' => d3database::INDEX_TYPE_INDEX, + 'sName' => 'BACKUPCODE', + 'aFields' => array( + 'BACKUPCODE' => 'BACKUPCODE', + ), + ), ); protected $_aRefreshMetaModuleIds = array('d3totp'); @@ -233,4 +210,39 @@ class Installation extends d3install_updatebase return $blRet; } + + /** + * @return bool + * @throws DBALException + * @throws DatabaseConnectionException + * @throws DatabaseErrorException + */ + public function doesTotpBCTableNotExist() + { + return $this->_checkTableNotExist('d3totp_backupcodes'); + } + + /** + * @return bool + * @throws ConnectionException + * @throws DBALException + * @throws DatabaseConnectionException + * @throws DatabaseErrorException + */ + public function addTotpBCTable() + { + $blRet = false; + if ($this->doesTotpBCTableNotExist()) { + $this->setInitialExecMethod(__METHOD__); + $blRet = $this->_addTable2( + 'd3totp_backupcodes', + $this->aFields, + $this->aIndizes, + 'totp backup codes', + 'InnoDB' + ); + } + + return $blRet; + } } \ No newline at end of file
@@ -136,10 +136,7 @@

- +