![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/module-two-factor-auth/Model/Provider/Engine/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\TwoFactorAuth\Model\Provider\Engine; use Base32\Base32; use Endroid\QrCode\Color\Color; use Endroid\QrCode\Encoding\Encoding; use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh; use Endroid\QrCode\QrCode; use Endroid\QrCode\Writer\PngWriter; use Exception; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\DataObject; use Magento\Framework\Encryption\EncryptorInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Store\Model\StoreManagerInterface; use Magento\TwoFactorAuth\Api\EngineInterface; use Magento\TwoFactorAuth\Api\UserConfigManagerInterface; use Magento\TwoFactorAuth\Model\Provider\Engine\Google\TotpFactory; use Magento\User\Api\Data\UserInterface; use OTPHP\TOTPInterface; /** * Google authenticator engine * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Google implements EngineInterface { /** * Config path for the OTP window */ const XML_PATH_OTP_WINDOW = 'twofactorauth/google/otp_window'; /** * Engine code * * Must be the same as defined in di.xml */ public const CODE = 'google'; /** * @var UserConfigManagerInterface */ private $configManager; /** * @var StoreManagerInterface */ private $storeManager; /** * @var ScopeConfigInterface */ private $scopeConfig; /** * @var TOTPInterfaceFactory */ private $totpFactory; /** * @var EncryptorInterface */ private $encryptor; /** * @param StoreManagerInterface $storeManager * @param ScopeConfigInterface $scopeConfig * @param UserConfigManagerInterface $configManager * @param TotpFactory $totpFactory * @param EncryptorInterface $encryptor */ public function __construct( StoreManagerInterface $storeManager, ScopeConfigInterface $scopeConfig, UserConfigManagerInterface $configManager, TotpFactory $totpFactory, EncryptorInterface $encryptor ) { $this->configManager = $configManager; $this->storeManager = $storeManager; $this->scopeConfig = $scopeConfig; $this->totpFactory = $totpFactory; $this->encryptor = $encryptor; } /** * Generate random secret * * @return string * @throws Exception */ private function generateSecret(): string { $secret = random_bytes(128); // seed for iOS devices to avoid errors with barcode $seed = 'abcd'; return preg_replace('/[^A-Za-z0-9]/', '', Base32::encode($seed . $secret)); } /** * Get TOTP object * * @param UserInterface $user * @return TOTPInterface * @throws NoSuchEntityException */ private function getTotp(UserInterface $user): TOTPInterface { $secret = $this->getSecretCode($user); if (!$secret) { throw new NoSuchEntityException(__('Secret for user with ID#%1 was not found', $user->getId())); } $totp = $this->totpFactory->create($secret); return $totp; } /** * Get the secret code used for Google Authentication * * @param UserInterface $user * @return string|null * @throws NoSuchEntityException */ public function getSecretCode(UserInterface $user): ?string { $config = $this->configManager->getProviderConfig((int)$user->getId(), static::CODE); if (!isset($config['secret'])) { $config['secret'] = $this->generateSecret(); $this->setSharedSecret((int)$user->getId(), $config['secret']); return $config['secret']; } return $config['secret'] ? $this->encryptor->decrypt($config['secret']) : null; } /** * Set the secret used to generate OTP * * @param int $userId * @param string $secret * @throws NoSuchEntityException */ public function setSharedSecret(int $userId, string $secret): void { $this->configManager->addProviderConfig( $userId, static::CODE, ['secret' => $this->encryptor->encrypt($secret)] ); } /** * Get TFA provisioning URL * * @param UserInterface $user * @return string * @throws NoSuchEntityException */ private function getProvisioningUrl(UserInterface $user): string { $baseUrl = $this->storeManager->getStore()->getBaseUrl(); // @codingStandardsIgnoreStart $issuer = parse_url($baseUrl, PHP_URL_HOST); // @codingStandardsIgnoreEnd $totp = $this->getTotp($user); $totp->setLabel($user->getEmail()); $totp->setIssuer($issuer); return $totp->getProvisioningUri(); } /** * @inheritDoc */ public function verify(UserInterface $user, DataObject $request): bool { $token = $request->getData('tfa_code'); if (!$token) { return false; } $totp = $this->getTotp($user); $config = $this->configManager->getProviderConfig((int)$user->getId(), static::CODE); return $totp->verify( $token, null, $config['window'] ?? (int)$this->scopeConfig->getValue(self::XML_PATH_OTP_WINDOW) ?: null ); } /** * Render TFA QrCode * * @param UserInterface $user * * @return string * @throws Exception */ public function getQrCodeAsPng(UserInterface $user): string { // @codingStandardsIgnoreStart $qrCode = new QrCode($this->getProvisioningUrl($user)); $qrCode->setSize(400); $qrCode->setMargin(0); $qrCode->setErrorCorrectionLevel(new ErrorCorrectionLevelHigh()); $qrCode->setForegroundColor(new Color(0, 0, 0, 0)); $qrCode->setBackgroundColor(new Color(255, 255, 255, 0)); $qrCode->setEncoding(new Encoding('UTF-8')); $writer = new PngWriter(); $pngData = $writer->write($qrCode); // @codingStandardsIgnoreEnd return $pngData->getString(); } /** * @inheritDoc */ public function isEnabled(): bool { return true; } }