‪TYPO3CMS  ‪main
RecoveryCodes.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
23 
30 {
31  private const ‪MIN_LENGTH = 8;
32 
34 
35  public function ‪__construct(protected readonly string $mode)
36  {
37  $this->passwordHashFactory = GeneralUtility::makeInstance(PasswordHashFactory::class);
38  }
39 
43  public function ‪generateRecoveryCodes(): array
44  {
45  $plainCodes = $this->‪generatePlainRecoveryCodes();
46  return array_combine($plainCodes, $this->‪generatedHashedRecoveryCodes($plainCodes));
47  }
48 
54  public function ‪generatePlainRecoveryCodes(int $length = 8, int $quantity = 8): array
55  {
56  if ($length < self::MIN_LENGTH) {
57  throw new \InvalidArgumentException(
58  $length . ' is not allowed as length for recovery codes. Must be at least ' . self::MIN_LENGTH,
59  1613666803
60  );
61  }
62 
63  $codes = [];
64  $random = GeneralUtility::makeInstance(Random::class);
65 
66  while ($quantity >= 1 && count($codes) < $quantity) {
67  $number = (int)hexdec($random->generateRandomHexString(16));
68  // We only want to work with positive integers
69  if ($number < 0) {
70  continue;
71  }
72  // Create a $length long string from the random number
73  $code = str_pad((string)($number % (10 ** $length)), $length, '0', STR_PAD_LEFT);
74  // Prevent duplicate codes which is however very unlikely to happen
75  if (!in_array($code, $codes, true)) {
76  $codes[] = $code;
77  }
78  }
79 
80  return $codes;
81  }
82 
86  public function ‪generatedHashedRecoveryCodes(array $codes): array
87  {
88  // Use the current default hash instance for hashing the recovery codes
89  $hashInstance = $this->passwordHashFactory->getDefaultHashInstance($this->mode);
90 
91  foreach ($codes as &$code) {
92  $code = $hashInstance->getHashedPassword($code);
93  }
94  unset($code);
95  return $codes;
96  }
97 
102  public function ‪verifyRecoveryCode(string $recoveryCode, array &$codes): bool
103  {
104  if ($codes === []) {
105  return false;
106  }
107 
108  // Get the hash instance which was initially used to generate these codes.
109  // This could differ from the current default hash instance. We however only need
110  // to check the first code since recovery codes can not be generated individually.
111  $hasInstance = $this->passwordHashFactory->get(reset($codes), $this->mode);
112 
113  foreach ($codes as $key => $code) {
114  // Compare hashed codes
115  if ($hasInstance->checkPassword($recoveryCode, $code)) {
116  // Unset the matching code
117  unset($codes[$key]);
118  return true;
119  }
120  }
121  return false;
122  }
123 }
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory
Definition: PasswordHashFactory.php:27
‪TYPO3\CMS\Core\Authentication\Mfa\Provider\RecoveryCodes
Definition: RecoveryCodes.php:30
‪TYPO3\CMS\Core\Authentication\Mfa\Provider
Definition: RecoveryCodes.php:18
‪TYPO3\CMS\Core\Authentication\Mfa\Provider\RecoveryCodes\verifyRecoveryCode
‪verifyRecoveryCode(string $recoveryCode, array &$codes)
Definition: RecoveryCodes.php:102
‪TYPO3\CMS\Core\Authentication\Mfa\Provider\RecoveryCodes\generatePlainRecoveryCodes
‪string[] generatePlainRecoveryCodes(int $length=8, int $quantity=8)
Definition: RecoveryCodes.php:54
‪TYPO3\CMS\Core\Authentication\Mfa\Provider\RecoveryCodes\__construct
‪__construct(protected readonly string $mode)
Definition: RecoveryCodes.php:35
‪TYPO3\CMS\Core\Authentication\Mfa\Provider\RecoveryCodes\$passwordHashFactory
‪PasswordHashFactory $passwordHashFactory
Definition: RecoveryCodes.php:33
‪TYPO3\CMS\Core\Authentication\Mfa\Provider\RecoveryCodes\generatedHashedRecoveryCodes
‪generatedHashedRecoveryCodes(array $codes)
Definition: RecoveryCodes.php:86
‪TYPO3\CMS\Core\Authentication\Mfa\Provider\RecoveryCodes\MIN_LENGTH
‪const MIN_LENGTH
Definition: RecoveryCodes.php:31
‪TYPO3\CMS\Core\Crypto\Random
Definition: Random.php:27
‪TYPO3\CMS\Core\Authentication\Mfa\Provider\RecoveryCodes\generateRecoveryCodes
‪generateRecoveryCodes()
Definition: RecoveryCodes.php:43
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52