improve code style

This commit is contained in:
Daniel Seifert 2024-09-21 23:53:58 +02:00
parent ceaa9daf90
commit 30e13cb0dc
Signed by: DanielS
GPG Key ID: 6A513E13AEE66170
28 changed files with 408 additions and 198 deletions

View File

@ -1,13 +1,42 @@
<?php <?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
$finder = PhpCsFixer\Finder::create() $finder = PhpCsFixer\Finder::create()
->in(__DIR__) ->in(__DIR__)
; ;
$fileHeaderComment = <<<EOF
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
https://www.d3data.de
@copyright (C) D3 Data Development (Inh. Thomas Dartsch)
@author D3 Data Development - Daniel Seifert <info@shopmodule.com>
@link https://www.oxidmodule.com
EOF;
$config = new PhpCsFixer\Config(); $config = new PhpCsFixer\Config();
return $config->setRules([ return $config->setRules([
'@PHP73Migration' => true, 'header_comment' => [
'@PSR12' => true 'header' => $fileHeaderComment,
]) 'comment_type' => 'PHPDoc',
'location' => 'after_open'
],
'@PHP80Migration' => true,
'@PSR12' => true
])
->setFinder($finder) ->setFinder($finder)
; ;

View File

@ -1,5 +1,16 @@
<?php <?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1); declare(strict_types=1);
namespace D3\Totp\Application\Controller\Admin; namespace D3\Totp\Application\Controller\Admin;
@ -27,7 +38,12 @@ class d3force_2fa extends d3user_totp
return parent::render(); return parent::render();
} }
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws ModuleSettingNotFountException
* @throws NotFoundExceptionInterface
*/
protected function authorize(): bool protected function authorize(): bool
{ {
$userID = $this->d3TotpGetSessionObject()->getVariable(d3totp_conf::OXID_ADMIN_AUTH); $userID = $this->d3TotpGetSessionObject()->getVariable(d3totp_conf::OXID_ADMIN_AUTH);

View File

@ -22,13 +22,16 @@ use D3\Totp\Application\Model\d3totp_conf;
use D3\Totp\Application\Model\Exceptions\d3totp_wrongOtpException; use D3\Totp\Application\Model\Exceptions\d3totp_wrongOtpException;
use D3\Totp\Modules\Application\Controller\Admin\d3_totp_LoginController; use D3\Totp\Modules\Application\Controller\Admin\d3_totp_LoginController;
use D3\Totp\Modules\Application\Model\d3_totp_user; use D3\Totp\Modules\Application\Model\d3_totp_user;
use Doctrine\DBAL\Driver\Exception;
use Doctrine\DBAL\Exception as DBALException;
use OxidEsales\Eshop\Application\Controller\Admin\AdminController; use OxidEsales\Eshop\Application\Controller\Admin\AdminController;
use OxidEsales\Eshop\Application\Controller\Admin\LoginController; use OxidEsales\Eshop\Application\Controller\Admin\LoginController;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
use OxidEsales\Eshop\Core\Utils; use OxidEsales\Eshop\Core\Utils;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class d3totpadminlogin extends AdminController class d3totpadminlogin extends AdminController
@ -44,16 +47,19 @@ class d3totpadminlogin extends AdminController
} }
/** /**
* @return d3totp|mixed * @return d3totp
*/ */
public function d3TotpGetTotpObject() public function d3TotpGetTotpObject(): d3totp
{ {
return oxNew(d3totp::class); return oxNew(d3totp::class);
} }
/** /**
* @return bool * @return bool
* @throws DatabaseConnectionException * @throws Exception
* @throws DBALException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
protected function isTotpIsNotRequired(): bool protected function isTotpIsNotRequired(): bool
{ {
@ -79,7 +85,10 @@ class d3totpadminlogin extends AdminController
/** /**
* @return string * @return string
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws Exception
* @throws NotFoundExceptionInterface
* @throws DBALException
*/ */
public function render(): string public function render(): string
{ {
@ -109,7 +118,10 @@ class d3totpadminlogin extends AdminController
/** /**
* @return string|void * @return string|void
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws Exception
* @throws NotFoundExceptionInterface
* @throws DBALException
*/ */
public function getBackupCodeCountMessage() public function getBackupCodeCountMessage()
{ {
@ -140,16 +152,21 @@ class d3totpadminlogin extends AdminController
} }
/** /**
* @return User * @return d3_totp_user
*/ */
public function d3TotpGetUserObject(): User public function d3TotpGetUserObject(): User
{ {
return oxNew(User::class); /** @var d3_totp_user $user */
$user = oxNew(User::class);
return $user;
} }
/** /**
* @return string|void * @return string|void
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws DBALException
* @throws Exception
* @throws NotFoundExceptionInterface
*/ */
public function checklogin() public function checklogin()
{ {
@ -192,7 +209,10 @@ class d3totpadminlogin extends AdminController
* @param string|null $sTotp * @param string|null $sTotp
* @param d3totp $totp * @param d3totp $totp
* @return bool * @return bool
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws Exception
* @throws NotFoundExceptionInterface
* @throws DBALException
* @throws d3totp_wrongOtpException * @throws d3totp_wrongOtpException
*/ */
public function d3TotpHasValidTotp(string $sTotp = null, d3totp $totp): bool public function d3TotpHasValidTotp(string $sTotp = null, d3totp $totp): bool

View File

@ -25,7 +25,6 @@ use Doctrine\DBAL\Driver\Exception as DBALDriverException;
use Exception; use Exception;
use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController; use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\UtilsView; use OxidEsales\Eshop\Core\UtilsView;
use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerExceptionInterface;
@ -122,7 +121,8 @@ class d3user_totp extends AdminDetailsController
} }
/** /**
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
public function delete(): void public function delete(): void
{ {

View File

@ -17,7 +17,9 @@ namespace D3\Totp\Application\Controller;
use D3\Totp\Application\Model\d3backupcodelist; use D3\Totp\Application\Model\d3backupcodelist;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use Doctrine\DBAL\Driver\Exception;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
trait OtpManagementControllerTrait trait OtpManagementControllerTrait
{ {
@ -47,7 +49,10 @@ trait OtpManagementControllerTrait
/** /**
* @return int * @return int
* @throws DatabaseConnectionException * @throws Exception
* @throws \Doctrine\DBAL\Exception
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
public function getAvailableBackupCodeCount(): int public function getAvailableBackupCodeCount(): int
{ {
@ -62,4 +67,4 @@ trait OtpManagementControllerTrait
{ {
return oxNew(d3totp::class); return oxNew(d3totp::class);
} }
} }

View File

@ -23,7 +23,6 @@ use D3\Totp\Modules\Application\Model\d3_totp_user;
use Exception; use Exception;
use OxidEsales\Eshop\Application\Controller\AccountController; use OxidEsales\Eshop\Application\Controller\AccountController;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\UtilsView; use OxidEsales\Eshop\Core\UtilsView;
use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerExceptionInterface;
@ -51,14 +50,18 @@ class d3_account_totp extends AccountController
return $this->getUser()->getId(); return $this->getUser()->getId();
} }
/**
* @return void
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws \Doctrine\DBAL\Driver\Exception
*/
public function create(): void public function create(): void
{ {
if (Registry::getRequest()->getRequestEscapedParameter('totp_use') === '1') { if (Registry::getRequest()->getRequestEscapedParameter('totp_use') === '1') {
try { try {
/** @var d3_totp_user $oUser */ /** @var d3_totp_user $oUser */
$oUser = $this->getUser(); $oUser = $this->getUser();
/** @var d3totp $oTotp */
$oTotp = $this->getTotpObject(); $oTotp = $this->getTotpObject();
Assert::that($oTotp->checkIfAlreadyExist($this->getCurrentUserId()))->false('D3_TOTP_ALREADY_EXIST'); Assert::that($oTotp->checkIfAlreadyExist($this->getCurrentUserId()))->false('D3_TOTP_ALREADY_EXIST');
@ -94,11 +97,10 @@ class d3_account_totp extends AccountController
} }
/** /**
* @throws DatabaseConnectionException
* @throws \Doctrine\DBAL\Driver\Exception
* @throws \Doctrine\DBAL\Exception
* @throws ContainerExceptionInterface * @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface * @throws NotFoundExceptionInterface
* @throws \Doctrine\DBAL\Driver\Exception
* @throws \Doctrine\DBAL\Exception
*/ */
public function delete(): void public function delete(): void
{ {

View File

@ -18,16 +18,18 @@ namespace D3\Totp\Application\Controller;
use D3\Totp\Application\Model\Constants; use D3\Totp\Application\Model\Constants;
use D3\Totp\Application\Model\d3backupcodelist; use D3\Totp\Application\Model\d3backupcodelist;
use D3\Totp\Application\Model\d3totp_conf; use D3\Totp\Application\Model\d3totp_conf;
use Doctrine\DBAL\Driver\Exception;
use OxidEsales\Eshop\Application\Controller\FrontendController; use OxidEsales\Eshop\Application\Controller\FrontendController;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Utils; use OxidEsales\Eshop\Core\Utils;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class d3totplogin extends FrontendController class d3totplogin extends FrontendController
{ {
protected $_sThisTemplate = '@'.Constants::OXID_MODULE_ID.'/tpl/d3totplogin'; protected $_sThisTemplate = '@'.Constants::OXID_MODULE_ID.'/tpl/d3totplogin';
public function render() public function render(): string
{ {
if (!Registry::getSession()->hasVariable(d3totp_conf::SESSION_CURRENTUSER)) { if (!Registry::getSession()->hasVariable(d3totp_conf::SESSION_CURRENTUSER)) {
$this->getUtils()->redirect('index.php?cl=start', false); $this->getUtils()->redirect('index.php?cl=start', false);
@ -48,7 +50,10 @@ class d3totplogin extends FrontendController
/** /**
* @return string|void * @return string|void
* @throws DatabaseConnectionException * @throws Exception
* @throws \Doctrine\DBAL\Exception
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
public function getBackupCodeCountMessage() public function getBackupCodeCountMessage()
{ {
@ -72,7 +77,7 @@ class d3totplogin extends FrontendController
return oxNew(d3backupcodelist::class); return oxNew(d3backupcodelist::class);
} }
public function getPreviousClass() public function getPreviousClass(): string
{ {
return Registry::getSession()->getVariable(d3totp_conf::SESSION_CURRENTCLASS); return Registry::getSession()->getVariable(d3totp_conf::SESSION_CURRENTCLASS);
} }
@ -101,7 +106,7 @@ class d3totplogin extends FrontendController
* *
* @return array * @return array
*/ */
public function getBreadCrumb() public function getBreadCrumb(): array
{ {
$aPaths = []; $aPaths = [];
$aPath = []; $aPath = [];

View File

@ -1,5 +1,16 @@
<?php <?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1); declare(strict_types=1);
namespace D3\Totp\Application\Factory; namespace D3\Totp\Application\Factory;
@ -12,14 +23,15 @@ use BaconQrCode\Renderer\RendererStyle\RendererStyle; // v2.0.0
class BaconQrCodeFactory class BaconQrCodeFactory
{ {
/** /**
* @param int $size
* @return RendererInterface * @return RendererInterface
*/ */
public static function renderer($size) public static function renderer(int $size): RendererInterface
{ {
return self::v200($size); return self::v200($size);
} }
private static function v200($size) private static function v200(int $size): RendererInterface
{ {
return oxNew( return oxNew(
ImageRenderer::class, ImageRenderer::class,

View File

@ -1,10 +1,8 @@
<?php <?php
/** /**
* Copyright (c) D3 Data Development (Inh. Thomas Dartsch) * For the full copyright and license information, please view the LICENSE
* * file that was distributed with this source code.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* *
* https://www.d3data.de * https://www.d3data.de
* *

View File

@ -24,7 +24,7 @@ class d3RandomGenerator extends Rand
/** /**
* @return string * @return string
*/ */
public static function getRandomTotpBackupCode() public static function getRandomTotpBackupCode(): string
{ {
return self::getString(6, self::CHAR_DIGITS); return self::getString(6, self::CHAR_DIGITS);
} }

View File

@ -16,56 +16,65 @@ declare(strict_types=1);
namespace D3\Totp\Application\Model; namespace D3\Totp\Application\Model;
use D3\Totp\Modules\Application\Model\d3_totp_user; use D3\Totp\Modules\Application\Model\d3_totp_user;
use Doctrine\DBAL\Driver\Exception;
use Doctrine\DBAL\Query\QueryBuilder;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Model\BaseModel; use OxidEsales\Eshop\Core\Model\BaseModel;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class d3backupcode extends BaseModel class d3backupcode extends BaseModel
{ {
protected $_sCoreTable = 'd3totp_backupcodes'; protected $_sCoreTable = 'd3totp_backupcodes';
/** /**
* @param $sUserId * @param string $sUserId
* @return string * @return string
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws Exception
* @throws NotFoundExceptionInterface
* @throws \Doctrine\DBAL\Exception
*/ */
public function generateCode($sUserId) public function generateCode(string $sUserId): string
{ {
$sCode = $this->getRandomTotpBackupCode(); $sCode = $this->getRandomTotpBackupCode();
$this->assign( $this->assign([
[ 'oxuserid' => $sUserId,
'oxuserid' => $sUserId, 'backupcode' => $this->d3EncodeBC($sCode, $sUserId),
'backupcode' => $this->d3EncodeBC($sCode, $sUserId), ]);
]
);
return $sCode; return $sCode;
} }
public function getRandomTotpBackupCode() public function getRandomTotpBackupCode(): string
{ {
return d3RandomGenerator::getRandomTotpBackupCode(); return d3RandomGenerator::getRandomTotpBackupCode();
} }
/** /**
* @param $code * @param string $code
* @param $sUserId * @param string $sUserId
* @return false|string * @return string
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws Exception
* @throws NotFoundExceptionInterface
* @throws \Doctrine\DBAL\Exception
*/ */
public function d3EncodeBC($code, $sUserId) public function d3EncodeBC(string $code, string $sUserId): string
{ {
$oDb = DatabaseProvider::getDb();
$oUser = $this->d3TotpGetUserObject(); $oUser = $this->d3TotpGetUserObject();
$oUser->load($sUserId); $oUser->load($sUserId);
$salt = $oUser->getFieldData('oxpasssalt'); $salt = $oUser->getFieldData('oxpasssalt');
$sSelect = "SELECT BINARY MD5( CONCAT( " . $oDb->quote($code) . ", UNHEX( ".$oDb->quote($salt)." ) ) )";
return $oDb->getOne($sSelect); $qb = $this->getQueryBuilder();
$qb->select('BINARY MD5( CONCAT('.$qb->createNamedParameter($code).', UNHEX('.$qb->createNamedParameter($salt).')))');
return $qb->execute()->fetchOne();
} }
public function d3GetUser() public function d3GetUser(): User
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = $this->getUser(); $user = $this->getUser();
@ -84,8 +93,18 @@ class d3backupcode extends BaseModel
/** /**
* @return User * @return User
*/ */
public function d3TotpGetUserObject() public function d3TotpGetUserObject(): User
{ {
return oxNew(User::class); return oxNew(User::class);
} }
/**
* @return QueryBuilder
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getQueryBuilder(): QueryBuilder
{
return ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
}
} }

View File

@ -16,32 +16,36 @@ declare(strict_types=1);
namespace D3\Totp\Application\Model; namespace D3\Totp\Application\Model;
use D3\Totp\Application\Controller\Admin\d3user_totp; use D3\Totp\Application\Controller\Admin\d3user_totp;
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Query\QueryBuilder;
use Exception; use Exception;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Config; use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface;
use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Model\ListModel; use OxidEsales\Eshop\Core\Model\ListModel;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class d3backupcodelist extends ListModel class d3backupcodelist extends ListModel
{ {
protected $_sObjectsInListName = d3backupcode::class; protected $_sObjectsInListName = d3backupcode::class;
/** /** @var string */
* Core table name
*
* @var string
*/
protected $_sCoreTable = 'd3totp_backupcodes'; protected $_sCoreTable = 'd3totp_backupcodes';
protected $_backupCodes = []; protected array $_backupCodes = [];
/** /**
* @param $sUserId * @param string $sUserId
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws DBALDriverException
* @throws DBALException
*/ */
public function generateBackupCodes($sUserId) public function generateBackupCodes(string $sUserId): void
{ {
$this->deleteAllFromUser($sUserId); $this->deleteAllFromUser($sUserId);
@ -59,7 +63,7 @@ class d3backupcodelist extends ListModel
/** /**
* @return d3backupcode * @return d3backupcode
*/ */
public function getD3BackupCodeObject() public function getD3BackupCodeObject(): d3backupcode
{ {
return oxNew(d3backupcode::class); return oxNew(d3backupcode::class);
} }
@ -67,7 +71,7 @@ class d3backupcodelist extends ListModel
/** /**
* @return Config * @return Config
*/ */
public function d3GetConfig() public function d3GetConfig(): Config
{ {
return Registry::getConfig(); return Registry::getConfig();
} }
@ -75,7 +79,7 @@ class d3backupcodelist extends ListModel
/** /**
* @throws Exception * @throws Exception
*/ */
public function save() public function save(): void
{ {
/** @var d3backupcode $oBackupCode */ /** @var d3backupcode $oBackupCode */
foreach ($this->getArray() as $oBackupCode) { foreach ($this->getArray() as $oBackupCode) {
@ -86,7 +90,7 @@ class d3backupcodelist extends ListModel
/** /**
* @return d3backupcode * @return d3backupcode
*/ */
public function getBaseObject() public function getBaseObject(): d3backupcode
{ {
/** @var d3backupcode $object */ /** @var d3backupcode $object */
$object = parent::getBaseObject(); $object = parent::getBaseObject();
@ -95,19 +99,32 @@ class d3backupcodelist extends ListModel
} }
/** /**
* @param $totp * @param string $totp
* @return bool * @return bool
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws DBALDriverException
* @throws DBALException
*/ */
public function verify($totp) public function verify(string $totp): bool
{ {
$oDb = $this->d3GetDb(); $qb = $this->getQueryBuilder();
$qb->select('oxid')
->from($this->getBaseObject()->getViewName())
->where(
$qb->expr()->and(
$qb->expr()->eq(
'backupcode',
$qb->createNamedParameter($this->getBaseObject()->d3EncodeBC($totp, $this->d3GetUser()->getId()))
),
$qb->expr()->eq(
'oxuserid',
$qb->createNamedParameter($this->d3GetUser()->getId())
)
)
);
$query = "SELECT oxid FROM ".$this->getBaseObject()->getViewName(). $sVerify = $qb->execute()->fetchOne();
" WHERE ".$oDb->quoteIdentifier('backupcode')." = ".$oDb->quote($this->getBaseObject()->d3EncodeBC($totp, $this->d3GetUser()->getId()))." AND ".
$oDb->quoteIdentifier("oxuserid") ." = ".$oDb->quote($this->d3GetUser()->getId());
$sVerify = $oDb->getOne($query);
if ($sVerify) { if ($sVerify) {
$this->getBaseObject()->delete($sVerify); $this->getBaseObject()->delete($sVerify);
@ -117,26 +134,23 @@ class d3backupcodelist extends ListModel
} }
/** /**
* @return DatabaseInterface * @param string $sUserId
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
public function d3GetDb() public function deleteAllFromUser(string $sUserId): void
{ {
return DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC); $qb = $this->getQueryBuilder();
} $qb->select('oxid')
->from($this->getBaseObject()->getCoreTableName())
->where(
$qb->expr()->eq(
'oxuserid',
$qb->createNamedParameter($sUserId)
)
);
/** $this->selectString($qb->getSQL(), $qb->getParameters());
* @param $sUserId
* @throws DatabaseConnectionException
*/
public function deleteAllFromUser($sUserId)
{
$oDb = $this->d3GetDb();
$query = "SELECT OXID FROM ".$oDb->quoteIdentifier($this->getBaseObject()->getCoreTableName()).
" WHERE ".$oDb->quoteIdentifier('oxuserid')." = ".$oDb->quote($sUserId);
$this->selectString($query);
/** @var d3backupcode $oBackupCode */ /** @var d3backupcode $oBackupCode */
foreach ($this->getArray() as $oBackupCode) { foreach ($this->getArray() as $oBackupCode) {
@ -145,22 +159,40 @@ class d3backupcodelist extends ListModel
} }
/** /**
* @param $sUserId * @param string $sUserId
* @return int * @return int
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws DBALDriverException
* @throws DBALException
*/ */
public function getAvailableCodeCount($sUserId) public function getAvailableCodeCount(string $sUserId): int
{ {
$oDb = $this->d3GetDb(); $qb = $this->getQueryBuilder();
$qb->select('count(*)')
->from($this->getBaseObject()->getViewName())
->where(
$qb->expr()->eq(
'oxuserid',
$qb->createNamedParameter($sUserId)
)
);
$query = "SELECT count(*) FROM ".$oDb->quoteIdentifier($this->getBaseObject()->getViewName()). return (int) $qb->execute()->fetchOne();
" WHERE ".$oDb->quoteIdentifier('oxuserid')." = ".$oDb->quote($sUserId);
return (int) $oDb->getOne($query);
} }
public function d3GetUser() public function d3GetUser(): User
{ {
return $this->getBaseObject()->d3GetUser(); return $this->getBaseObject()->d3GetUser();
} }
/**
* @return QueryBuilder
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getQueryBuilder(): QueryBuilder
{
return ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
}
} }

View File

@ -25,7 +25,6 @@ use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Query\QueryBuilder;
use OTPHP\TOTP; use OTPHP\TOTP;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Model\BaseModel; use OxidEsales\Eshop\Core\Model\BaseModel;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory; use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
@ -54,13 +53,13 @@ class d3totp extends BaseModel
} }
/** /**
* @param $userId * @param string $userId
* @throws ContainerExceptionInterface * @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception
* @throws DBALException * @throws DBALException
* @throws Exception
* @throws NotFoundExceptionInterface
*/ */
public function loadByUserId($userId): void public function loadByUserId(string $userId): void
{ {
$this->userId = $userId; $this->userId = $userId;
@ -69,7 +68,6 @@ class d3totp extends BaseModel
->executeQuery() ->executeQuery()
->fetchOne() ->fetchOne()
) { ) {
/** @var QueryBuilder $qb */
$qb = $this->getQueryBuilder(); $qb = $this->getQueryBuilder();
$qb->select('oxid') $qb->select('oxid')
->from($this->getViewName()) ->from($this->getViewName())
@ -82,14 +80,14 @@ class d3totp extends BaseModel
} }
/** /**
* @param $userId * @param string $userId
* @return bool * @return bool
* @throws ContainerExceptionInterface * @throws ContainerExceptionInterface
* @throws DBALException * @throws DBALException
* @throws Exception * @throws Exception
* @throws NotFoundExceptionInterface * @throws NotFoundExceptionInterface
*/ */
public function checkIfAlreadyExist($userId): bool public function checkIfAlreadyExist(string $userId): bool
{ {
$qb = $this->getQueryBuilder(); $qb = $this->getQueryBuilder();
$qb->select('1') $qb->select('1')
@ -98,6 +96,7 @@ class d3totp extends BaseModel
$qb->expr()->eq('oxuserid', $qb->createNamedParameter($userId)) $qb->expr()->eq('oxuserid', $qb->createNamedParameter($userId))
) )
->setMaxResults(1); ->setMaxResults(1);
return (bool) $qb->execute()->fetchOne(); return (bool) $qb->execute()->fetchOne();
} }
@ -177,10 +176,10 @@ class d3totp extends BaseModel
} }
/** /**
* @param $seed * @param string|null $seed
* @return TOTP * @return TOTP
*/ */
public function getTotp($seed = null): TOTP public function getTotp(string $seed = null): TOTP
{ {
if (null == $this->totp) { if (null == $this->totp) {
$this->totp = TOTP::create($seed ?: $this->getSavedSecret()); $this->totp = TOTP::create($seed ?: $this->getSavedSecret());
@ -220,9 +219,9 @@ class d3totp extends BaseModel
} }
/** /**
* @param $seed * @param string $seed
*/ */
public function saveSecret($seed): void public function saveSecret(string $seed): void
{ {
$this->assign([ $this->assign([
'seed' => $this->encrypt($seed), 'seed' => $this->encrypt($seed),
@ -230,13 +229,16 @@ class d3totp extends BaseModel
} }
/** /**
* @param $totp * @param string $totp
* @param $seed * @param string|null $seed
* @return bool * @return bool
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws DBALException
* @throws d3totp_wrongOtpException * @throws d3totp_wrongOtpException
* @throws NotFoundExceptionInterface
* @throws Exception
*/ */
public function verify($totp, $seed = null): bool public function verify(string $totp, string $seed = null): bool
{ {
$blNotVerified = $this->getTotp($seed)->verify($totp, null, $this->timeWindow) == false; $blNotVerified = $this->getTotp($seed)->verify($totp, null, $this->timeWindow) == false;
@ -245,10 +247,14 @@ class d3totp extends BaseModel
$blNotVerified = $oBC->verify($totp) == false; $blNotVerified = $oBC->verify($totp) == false;
if ($blNotVerified) { if ($blNotVerified) {
throw oxNew(d3totp_wrongOtpException::class); /** @var d3totp_wrongOtpException $exception */
$exception = oxNew(d3totp_wrongOtpException::class);
throw $exception;
} }
} elseif ($blNotVerified && $seed !== null) { } elseif ($blNotVerified && $seed !== null) {
throw oxNew(d3totp_wrongOtpException::class); /** @var d3totp_wrongOtpException $exception */
$exception = oxNew(d3totp_wrongOtpException::class);
throw $exception;
} }
return !$blNotVerified; return !$blNotVerified;
@ -263,12 +269,12 @@ class d3totp extends BaseModel
} }
/** /**
* @param $plaintext * @param string $plaintext
* @return string * @return string
*/ */
public function encrypt($plaintext): string public function encrypt(string $plaintext): string
{ {
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC"); $ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen); $iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, self::ENC_KEY, OPENSSL_RAW_DATA, $iv); $ciphertext_raw = openssl_encrypt($plaintext, $cipher, self::ENC_KEY, OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, self::ENC_KEY, true); $hmac = hash_hmac('sha256', $ciphertext_raw, self::ENC_KEY, true);
@ -276,16 +282,16 @@ class d3totp extends BaseModel
} }
/** /**
* @param $ciphertext * @param string $ciphertext
* @return false|string * @return false|string
*/ */
public function decrypt($ciphertext): false|string public function decrypt(string $ciphertext): false|string
{ {
$c = $this->d3Base64_decode($ciphertext); $c = $this->d3Base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC"); $ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
$iv = substr($c, 0, $ivlen); $iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32); $hmac = substr($c, $ivlen, $sha2len = 32);
$ciphertext_raw = substr($c, $ivlen+$sha2len); $ciphertext_raw = substr($c, $ivlen + $sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, self::ENC_KEY, OPENSSL_RAW_DATA, $iv); $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, self::ENC_KEY, OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, self::ENC_KEY, true); $calcmac = hash_hmac('sha256', $ciphertext_raw, self::ENC_KEY, true);
if (hash_equals($hmac, $calcmac)) { // PHP 5.6+ compute attack-safe comparison if (hash_equals($hmac, $calcmac)) { // PHP 5.6+ compute attack-safe comparison
@ -297,18 +303,19 @@ class d3totp extends BaseModel
/** /**
* required for unit tests * required for unit tests
* @param $source * @param string $source
* @return bool|string * @return string
*/ */
public function d3Base64_decode($source): bool|string public function d3Base64_decode(string $source): string
{ {
return base64_decode($source); return base64_decode($source);
} }
/** /**
* @param null|string $oxid * @param string|null $oxid
* @return bool * @return bool
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/ */
public function delete($oxid = null): bool public function delete($oxid = null): bool
{ {

View File

@ -24,7 +24,6 @@ use Doctrine\DBAL\Driver\Exception;
use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Exception as DBALException;
use InvalidArgumentException; use InvalidArgumentException;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
use OxidEsales\Eshop\Core\Utils; use OxidEsales\Eshop\Core\Utils;
@ -38,7 +37,10 @@ class d3_totp_UserComponent extends d3_totp_UserComponent_parent
* @param User $oUser * @param User $oUser
* *
* @return string * @return string
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws DBALException
* @throws Exception
* @throws NotFoundExceptionInterface
*/ */
protected function afterLogin($oUser) protected function afterLogin($oUser)
{ {
@ -68,7 +70,8 @@ class d3_totp_UserComponent extends d3_totp_UserComponent_parent
$sUrl = Registry::getConfig()->getShopHomeUrl() . 'cl=d3totplogin'; $sUrl = Registry::getConfig()->getShopHomeUrl() . 'cl=d3totplogin';
$this->d3TotpGetUtils()->redirect($sUrl, false); $this->d3TotpGetUtils()->redirect($sUrl, false);
} }
} catch (InvalidArgumentException) {} } catch (InvalidArgumentException) {
}
return parent::afterLogin($oUser); return parent::afterLogin($oUser);
} }
@ -83,10 +86,9 @@ class d3_totp_UserComponent extends d3_totp_UserComponent_parent
/** /**
* @return false|string * @return false|string
* @throws DatabaseConnectionException
* @throws Exception
* @throws DBALException
* @throws ContainerExceptionInterface * @throws ContainerExceptionInterface
* @throws DBALException
* @throws Exception
* @throws NotFoundExceptionInterface * @throws NotFoundExceptionInterface
*/ */
public function d3TotpCheckTotpLogin(): false|string public function d3TotpCheckTotpLogin(): false|string
@ -148,7 +150,7 @@ class d3_totp_UserComponent extends d3_totp_UserComponent_parent
* @param d3totp $totp * @param d3totp $totp
* @return bool * @return bool
*/ */
public function d3TotpIsNoTotpOrNoLogin($totp): bool public function d3TotpIsNoTotpOrNoLogin(d3totp $totp): bool
{ {
return false == Registry::getSession()->getVariable(d3totp_conf::SESSION_CURRENTUSER) return false == Registry::getSession()->getVariable(d3totp_conf::SESSION_CURRENTUSER)
|| false == $totp->isActive(); || false == $totp->isActive();
@ -158,10 +160,13 @@ class d3_totp_UserComponent extends d3_totp_UserComponent_parent
* @param string $sTotp * @param string $sTotp
* @param d3totp $totp * @param d3totp $totp
* @return bool * @return bool
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws DBALException
* @throws Exception
* @throws NotFoundExceptionInterface
* @throws d3totp_wrongOtpException * @throws d3totp_wrongOtpException
*/ */
public function d3TotpHasValidTotp($sTotp, $totp): bool public function d3TotpHasValidTotp(string $sTotp, d3totp $totp): bool
{ {
return Registry::getSession()->getVariable(d3totp_conf::SESSION_AUTH) || return Registry::getSession()->getVariable(d3totp_conf::SESSION_AUTH) ||
$totp->verify($sTotp); $totp->verify($sTotp);

View File

@ -18,9 +18,6 @@ namespace D3\Totp\Modules\Application\Controller\Admin;
use D3\TestingTools\Production\IsMockable; use D3\TestingTools\Production\IsMockable;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use D3\Totp\Application\Model\d3totp_conf; use D3\Totp\Application\Model\d3totp_conf;
use D3\Totp\Modules\Application\Model\d3_totp_user;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Language; use OxidEsales\Eshop\Core\Language;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
@ -48,7 +45,6 @@ class d3_totp_LoginController extends d3_totp_LoginController_parent
/** /**
* @return mixed|string * @return mixed|string
* @throws DatabaseConnectionException
*/ */
public function checklogin() public function checklogin()
{ {
@ -74,13 +70,13 @@ class d3_totp_LoginController extends d3_totp_LoginController_parent
$aProfiles = $this->d3TotpGetSession()->getVariable("aAdminProfiles"); $aProfiles = $this->d3TotpGetSession()->getVariable("aAdminProfiles");
if ($aProfiles && isset($aProfiles[$sProfile])) { if ($aProfiles && isset($aProfiles[$sProfile])) {
// setting cookie to store last locally used profile // setting cookie to store last locally used profile
$myUtilsServer->setOxCookie("oxidadminprofile", $sProfile . "@" . implode("@", $aProfiles[$sProfile]), time() + 31536000, "/"); $myUtilsServer->setOxCookie("oxidadminprofile", $sProfile . "@" . implode("@", $aProfiles[$sProfile]), time() + 31536000);
$this->d3TotpGetSession()->setVariable("profile", $aProfiles[$sProfile]); $this->d3TotpGetSession()->setVariable("profile", $aProfiles[$sProfile]);
$this->d3TotpGetSession()->deleteVariable(d3totp_conf::SESSION_ADMIN_PROFILE); $this->d3TotpGetSession()->deleteVariable(d3totp_conf::SESSION_ADMIN_PROFILE);
} }
} else { } else {
//deleting cookie info, as setting profile to default //deleting cookie info, as setting profile to default
$myUtilsServer->setOxCookie("oxidadminprofile", "", time() - 3600, "/"); $myUtilsServer->setOxCookie("oxidadminprofile", "", time() - 3600);
} }
$this->d3totpAfterLoginSetLanguage(); $this->d3totpAfterLoginSetLanguage();
@ -97,7 +93,7 @@ class d3_totp_LoginController extends d3_totp_LoginController_parent
$iLang = key($aLanguages); $iLang = key($aLanguages);
} }
$myUtilsServer->setOxCookie("oxidadminlanguage", $aLanguages[$iLang]->abbr, time() + 31536000, "/"); $myUtilsServer->setOxCookie("oxidadminlanguage", $aLanguages[$iLang]->abbr, time() + 31536000);
$this->d3TotpGetLangObject()->setTplLanguage($iLang); $this->d3TotpGetLangObject()->setTplLanguage($iLang);
} }

View File

@ -18,20 +18,25 @@ namespace D3\Totp\Modules\Application\Controller;
use D3\TestingTools\Production\IsMockable; use D3\TestingTools\Production\IsMockable;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use D3\Totp\Application\Model\d3totp_conf; use D3\Totp\Application\Model\d3totp_conf;
use Doctrine\DBAL\Driver\Exception;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
trait d3_totp_getUserTrait trait d3_totp_getUserTrait
{ {
use IsMockable; use IsMockable;
/** /**
* @return bool|object|User * @return false|User
* @throws DatabaseConnectionException * @throws ContainerExceptionInterface
* @throws Exception
* @throws NotFoundExceptionInterface
* @throws \Doctrine\DBAL\Exception
*/ */
public function getUser() public function getUser(): false|User
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = $this->d3CallMockableFunction([$this->parentClass, 'getUser']); $user = $this->d3CallMockableFunction([$this->parentClass, 'getUser']);
@ -55,7 +60,7 @@ trait d3_totp_getUserTrait
/** /**
* @return d3totp * @return d3totp
*/ */
public function d3GetTotpObject() public function d3GetTotpObject(): d3totp
{ {
return oxNew(d3totp::class); return oxNew(d3totp::class);
} }
@ -63,7 +68,7 @@ trait d3_totp_getUserTrait
/** /**
* @return Session * @return Session
*/ */
public function d3TotpGetSessionObject() public function d3TotpGetSessionObject(): Session
{ {
return Registry::getSession(); return Registry::getSession();
} }

View File

@ -18,9 +18,8 @@ namespace D3\Totp\Modules\Core;
use D3\Totp\Application\Model\Constants; use D3\Totp\Application\Model\Constants;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use D3\Totp\Application\Model\d3totp_conf; use D3\Totp\Application\Model\d3totp_conf;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\Exception;
use OxidEsales\Eshop\Core\Config; use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory; use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
@ -34,8 +33,11 @@ class d3_totp_utils extends d3_totp_utils_parent
{ {
/** /**
* @return bool * @return bool
* @throws DBALException * @throws ContainerExceptionInterface
* @throws DatabaseConnectionException * @throws ModuleSettingNotFountException
* @throws NotFoundExceptionInterface
* @throws Exception
* @throws \Doctrine\DBAL\Exception
*/ */
public function checkAccessRights() public function checkAccessRights()
{ {
@ -43,7 +45,6 @@ class d3_totp_utils extends d3_totp_utils_parent
$blAuth = $this->d3AuthHook($blAuth); $blAuth = $this->d3AuthHook($blAuth);
$userID = $this->d3TotpGetSessionObject()->getVariable(d3totp_conf::OXID_ADMIN_AUTH); $userID = $this->d3TotpGetSessionObject()->getVariable(d3totp_conf::OXID_ADMIN_AUTH);
$totpAuth = (bool) $this->d3TotpGetSessionObject()->getVariable(d3totp_conf::SESSION_ADMIN_AUTH); $totpAuth = (bool) $this->d3TotpGetSessionObject()->getVariable(d3totp_conf::SESSION_ADMIN_AUTH);
/** @var d3totp $totp */
$totp = $this->d3GetTotpObject(); $totp = $this->d3GetTotpObject();
$totp->loadByUserId($userID); $totp->loadByUserId($userID);

View File

@ -19,15 +19,26 @@ use D3\TestingTools\Production\IsMockable;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use D3\Totp\Application\Model\d3totp_conf; use D3\Totp\Application\Model\d3totp_conf;
use D3\Totp\Modules\Application\Model\d3_totp_user; use D3\Totp\Modules\Application\Model\d3_totp_user;
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
use Doctrine\DBAL\Exception as DBALException;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
use OxidEsales\Eshop\Core\Utils; use OxidEsales\Eshop\Core\Utils;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class totpSystemEventHandler extends totpSystemEventHandler_parent class totpSystemEventHandler extends totpSystemEventHandler_parent
{ {
use IsMockable; use IsMockable;
/**
* @return void
* @throws ContainerExceptionInterface
* @throws DBALDriverException
* @throws DBALException
* @throws NotFoundExceptionInterface
*/
public function onAdminLogin() public function onAdminLogin()
{ {
$this->d3RequestTotp(); $this->d3RequestTotp();
@ -35,7 +46,14 @@ class totpSystemEventHandler extends totpSystemEventHandler_parent
$this->d3CallMockableFunction([totpSystemEventHandler_parent::class, 'onAdminLogin']); $this->d3CallMockableFunction([totpSystemEventHandler_parent::class, 'onAdminLogin']);
} }
protected function d3requestTotp() /**
* @return void
* @throws DBALDriverException
* @throws DBALException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function d3requestTotp(): void
{ {
$totp = $this->d3GetTotpObject(); $totp = $this->d3GetTotpObject();
$userId = $this->d3TotpGetSession()->getVariable(d3totp_conf::OXID_ADMIN_AUTH); $userId = $this->d3TotpGetSession()->getVariable(d3totp_conf::OXID_ADMIN_AUTH);
@ -86,7 +104,7 @@ class totpSystemEventHandler extends totpSystemEventHandler_parent
* @param d3totp $totp * @param d3totp $totp
* @return bool * @return bool
*/ */
public function d3TotpLoginMissing($totp) public function d3TotpLoginMissing(d3totp $totp)
{ {
return $totp->isActive() return $totp->isActive()
&& false == $this->d3TotpGetSession()->getVariable(d3totp_conf::SESSION_ADMIN_AUTH); && false == $this->d3TotpGetSession()->getVariable(d3totp_conf::SESSION_ADMIN_AUTH);

View File

@ -3,7 +3,7 @@
# 2-factor authentication (one-time password) for OXID eShop # 2-factor authentication (one-time password) for OXID eShop
This module provides a 2-factor authentication (time-dependent one-time password / TOTP) for login in front- and backend in addition to user name and password. This module provides a 2-factor authentication (time-dependent one-time password / TOTP) for login in front- and backend in addition to username and password.
## Features ## Features
@ -48,7 +48,7 @@ The necessary configuration can be found in the same area in the "Settings" tab.
## Changelog ## Changelog
See [CHANGELOG](CHANGELOG.md) for further informations. See [CHANGELOG](CHANGELOG.md) for further information.
## Contributing ## Contributing

View File

@ -32,13 +32,13 @@ use Psr\Container\NotFoundExceptionInterface;
class Actions class Actions
{ {
public array $seo_de = [ public array $seo_de = [
'2-faktor-authentisierung/' '2-faktor-authentisierung/',
]; ];
public array $seo_en = [ public array $seo_en = [
'en/2-factor-authentication/' 'en/2-factor-authentication/',
]; ];
public array $stdClassName = [ public array $stdClassName = [
'd3_account_totp' 'd3_account_totp',
]; ];
/** /**
@ -112,7 +112,7 @@ class Actions
return true; return true;
} }
protected function hasSeoUrl($item, $langId): bool protected function hasSeoUrl(string $item, int $langId): bool
{ {
$seoEncoder = oxNew(SeoEncoder::class); $seoEncoder = oxNew(SeoEncoder::class);
$seoUrl = $seoEncoder->getStaticUrl( $seoUrl = $seoEncoder->getStaticUrl(

View File

@ -15,16 +15,14 @@ declare(strict_types=1);
namespace D3\Totp\Setup; namespace D3\Totp\Setup;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use Exception;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
class Events class Events
{ {
/** /**
* @return void * @return void
* @throws DatabaseConnectionException * @throws Exception
* @throws DatabaseErrorException
*/ */
public static function onActivate(): void public static function onActivate(): void
{ {
@ -38,7 +36,7 @@ class Events
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public static function onDeactivate() public static function onDeactivate(): void
{ {
} }
} }

View File

@ -1,5 +1,16 @@
<?php <?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
namespace D3\Totp\tests\unit\Application\Controller\Admin; namespace D3\Totp\tests\unit\Application\Controller\Admin;
use D3\Totp\Application\Controller\Admin\d3force_2fa; use D3\Totp\Application\Controller\Admin\d3force_2fa;

View File

@ -1,5 +1,16 @@
<?php <?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
namespace D3\Totp\tests\unit\Application\Factory; namespace D3\Totp\tests\unit\Application\Factory;
use BaconQrCode\Renderer\ImageRenderer; use BaconQrCode\Renderer\ImageRenderer;

View File

@ -271,7 +271,7 @@ class d3_totp_LoginControllerTest extends d3TotpUnitTestCase
public function d3TotpLoginMissingTestDataProvider(): array public function d3TotpLoginMissingTestDataProvider(): array
{ {
return [ return [
'totp not active, not logged in'=> [false, false, false], 'totp not active, not logged in' => [false, false, false],
'totp active, logged in' => [true, true, false], 'totp active, logged in' => [true, true, false],
'totp active, not logged in' => [true, false, true], 'totp active, not logged in' => [true, false, true],
'totp not active, logged in' => [false, true, false], 'totp not active, logged in' => [false, true, false],

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.

View File

@ -49,6 +49,7 @@
"beberlei/assert": "^v3.3.2" "beberlei/assert": "^v3.3.2"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit" : "^10.5",
"friendsofphp/php-cs-fixer": "^3.9", "friendsofphp/php-cs-fixer": "^3.9",
"phpstan/phpstan": "^1.8", "phpstan/phpstan": "^1.8",
"boxblinkracer/phpunuhi": "^1.12" "boxblinkracer/phpunuhi": "^1.12"

View File

@ -1,5 +1,16 @@
<?php <?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1); declare(strict_types=1);
namespace D3\Totp\Migrations; namespace D3\Totp\Migrations;
@ -14,7 +25,7 @@ use Doctrine\Migrations\AbstractMigration;
final class Version20240905232017 extends AbstractMigration final class Version20240905232017 extends AbstractMigration
{ {
public function getDescription() : string public function getDescription(): string
{ {
return 'Extend Database by missing OTP tables and missing columns.'; return 'Extend Database by missing OTP tables and missing columns.';
} }
@ -22,7 +33,7 @@ final class Version20240905232017 extends AbstractMigration
/** /**
* @throws Exception * @throws Exception
*/ */
public function up(Schema $schema) : void public function up(Schema $schema): void
{ {
$this->connection->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string'); $this->connection->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
@ -79,9 +90,9 @@ final class Version20240905232017 extends AbstractMigration
->setDefault('CURRENT_TIMESTAMP'); ->setDefault('CURRENT_TIMESTAMP');
} }
$table->hasPrimaryKey() ?:$table->setPrimaryKey(['oxid']); $table->hasPrimaryKey() ?: $table->setPrimaryKey(['oxid']);
if($table->hasIndex('OXUSERID') === false){ if ($table->hasIndex('OXUSERID') === false) {
$table->addUniqueIndex(['OXUSERID'], 'OXUSERID'); $table->addUniqueIndex(['OXUSERID'], 'OXUSERID');
} }
} }
@ -129,18 +140,18 @@ final class Version20240905232017 extends AbstractMigration
->setDefault('CURRENT_TIMESTAMP'); ->setDefault('CURRENT_TIMESTAMP');
} }
$table->hasPrimaryKey() ?:$table->setPrimaryKey(['oxid']); $table->hasPrimaryKey() ?: $table->setPrimaryKey(['oxid']);
if($table->hasIndex('OXUSERID') === false){ if ($table->hasIndex('OXUSERID') === false) {
$table->addIndex(['OXUSERID'], 'OXUSERID'); $table->addIndex(['OXUSERID'], 'OXUSERID');
} }
if($table->hasIndex('BACKUPCODE') === false){ if ($table->hasIndex('BACKUPCODE') === false) {
$table->addIndex(['BACKUPCODE'], 'BACKUPCODE'); $table->addIndex(['BACKUPCODE'], 'BACKUPCODE');
} }
} }
public function down(Schema $schema) : void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs // this down() migration is auto-generated, please modify it to your needs
} }

View File

@ -1,14 +1,21 @@
parameters: parameters:
scanFiles: scanFiles:
- src/IntelliSenseHelper.php - IntelliSenseHelper.php
- ../../oxid-esales/oxideshop-ce/source/bootstrap.php
- ../../oxid-esales/oxideshop-ce/source/oxfunctions.php - ../../oxid-esales/oxideshop-ce/source/oxfunctions.php
- ../../oxid-esales/oxideshop-ce/source/overridablefunctions.php
paths: paths:
- src - .
level: 5 excludePaths:
phpVersion: 70300 - .php-cs-fixer.php
- rector.php
- Tests
level: 6
phpVersion: 80300
ignoreErrors: ignoreErrors:
- '#Call to method getFieldData\(\) on an unknown class oxShop.#' - '#Return type [()a-z]* of method .*getBreadCrumb\(\) should be compatible with return type [()a-z]* of method\s*.*getBreadCrumb\(\)#'
- '#Return type \(array\) of method D3\\Totp\\Application\\Controller\\d3totplogin::getBreadCrumb\(\) should be compatible with return type \(null\) of method OxidEsales\\EshopCommunity\\Application\\Controller\\FrontendController::getBreadCrumb\(\)#' - '#Unable to resolve the template type T in call to function oxNew#'
- '#Parameter \#\d+ \$value of method OxidEsales\\EshopCommunity\\Core\\Config::setConfigParam\(\) expects string, (true|false) given.#' - '#(Property|Method) D3\\Totp\\Modules\\.* has no (return type|type) specified.#'
- identifier: missingType.iterableValue
parallel: parallel:
processTimeout: 900.0 processTimeout: 900.0