enwikipedia-acc /
waca
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /****************************************************************************** |
||
| 3 | * Wikipedia Account Creation Assistance tool * |
||
| 4 | * * |
||
| 5 | * All code in this file is released into the public domain by the ACC * |
||
| 6 | * Development Team. Please see team.json for a list of contributors. * |
||
| 7 | ******************************************************************************/ |
||
| 8 | |||
| 9 | namespace Waca\Security\CredentialProviders; |
||
| 10 | |||
| 11 | use DateTimeImmutable; |
||
| 12 | use OTPHP\Factory; |
||
| 13 | use OTPHP\TOTP; |
||
| 14 | use Waca\DataObjects\User; |
||
| 15 | use Waca\Exceptions\ApplicationLogicException; |
||
| 16 | use Waca\PdoDatabase; |
||
| 17 | use Waca\Security\EncryptionHelper; |
||
| 18 | use Waca\SiteConfiguration; |
||
| 19 | |||
| 20 | class TotpCredentialProvider extends CredentialProviderBase |
||
| 21 | { |
||
| 22 | /** @var EncryptionHelper */ |
||
| 23 | private $encryptionHelper; |
||
| 24 | |||
| 25 | /** |
||
| 26 | * TotpCredentialProvider constructor. |
||
| 27 | * |
||
| 28 | * @param PdoDatabase $database |
||
| 29 | * @param SiteConfiguration $configuration |
||
| 30 | */ |
||
| 31 | public function __construct(PdoDatabase $database, SiteConfiguration $configuration) |
||
| 32 | { |
||
| 33 | parent::__construct($database, $configuration, 'totp'); |
||
| 34 | $this->encryptionHelper = new EncryptionHelper($configuration); |
||
| 35 | } |
||
| 36 | |||
| 37 | /** |
||
| 38 | * Validates a user-provided credential |
||
| 39 | * |
||
| 40 | * @param User $user The user to test the authentication against |
||
| 41 | * @param string $data The raw credential data to be validated |
||
| 42 | * |
||
| 43 | * @return bool |
||
| 44 | * @throws ApplicationLogicException |
||
| 45 | */ |
||
| 46 | public function authenticate(User $user, $data) |
||
| 47 | { |
||
| 48 | if (is_array($data)) { |
||
| 49 | return false; |
||
| 50 | } |
||
| 51 | |||
| 52 | $storedData = $this->getCredentialData($user->getId()); |
||
| 53 | |||
| 54 | if ($storedData === null) { |
||
| 55 | throw new ApplicationLogicException('Credential data not found'); |
||
| 56 | } |
||
| 57 | |||
| 58 | $provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData()); |
||
| 59 | $totp = Factory::loadFromProvisioningUri($provisioningUrl); |
||
| 60 | |||
| 61 | return $totp->verify($data, null, 2); |
||
| 62 | } |
||
| 63 | |||
| 64 | public function verifyEnable(User $user, $data) |
||
|
0 ignored issues
–
show
|
|||
| 65 | { |
||
| 66 | $storedData = $this->getCredentialData($user->getId(), true); |
||
| 67 | |||
| 68 | if ($storedData === null) { |
||
| 69 | throw new ApplicationLogicException('Credential data not found'); |
||
| 70 | } |
||
| 71 | |||
| 72 | $provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData()); |
||
| 73 | $totp = Factory::loadFromProvisioningUri($provisioningUrl); |
||
| 74 | |||
| 75 | $result = $totp->verify($data, null, 2); |
||
| 76 | |||
| 77 | if ($result && $storedData->getTimeout() > new DateTimeImmutable()) { |
||
| 78 | $storedData->setDisabled(0); |
||
| 79 | $storedData->setPriority(5); |
||
| 80 | $storedData->setTimeout(null); |
||
| 81 | $storedData->save(); |
||
| 82 | } |
||
| 83 | |||
| 84 | return $result; |
||
| 85 | } |
||
| 86 | |||
| 87 | /** |
||
| 88 | * @param User $user The user the credential belongs to |
||
| 89 | * @param int $factor The factor this credential provides |
||
| 90 | * @param string $data Unused here, due to there being no user-provided data. We provide the user with the secret. |
||
| 91 | */ |
||
| 92 | public function setCredential(User $user, $factor, $data) |
||
| 93 | { |
||
| 94 | $issuer = 'ACC - ' . $this->getConfiguration()->getIrcNotificationsInstance(); |
||
| 95 | $totp = new TOTP($user->getUsername()); |
||
| 96 | $totp->setIssuer($issuer); |
||
| 97 | |||
| 98 | $storedData = $this->getCredentialData($user->getId(), null); |
||
|
0 ignored issues
–
show
null is of type null, but the function expects a boolean.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
| 99 | |||
| 100 | if ($storedData !== null) { |
||
| 101 | $storedData->delete(); |
||
| 102 | } |
||
| 103 | |||
| 104 | $storedData = $this->createNewCredential($user); |
||
| 105 | |||
| 106 | $storedData->setData($this->encryptionHelper->encryptData($totp->getProvisioningUri())); |
||
| 107 | $storedData->setFactor($factor); |
||
| 108 | $storedData->setTimeout(new DateTimeImmutable('+ 1 hour')); |
||
| 109 | $storedData->setDisabled(1); |
||
| 110 | $storedData->setVersion(1); |
||
| 111 | |||
| 112 | $storedData->save(); |
||
| 113 | } |
||
| 114 | |||
| 115 | public function getProvisioningUrl(User $user) |
||
| 116 | { |
||
| 117 | $storedData = $this->getCredentialData($user->getId(), true); |
||
| 118 | |||
| 119 | if ($storedData->getTimeout() < new DateTimeImmutable()) { |
||
| 120 | $storedData->delete(); |
||
| 121 | $storedData = null; |
||
| 122 | } |
||
| 123 | |||
| 124 | if ($storedData === null) { |
||
| 125 | throw new ApplicationLogicException('Credential data not found'); |
||
| 126 | } |
||
| 127 | |||
| 128 | return $this->encryptionHelper->decryptData($storedData->getData()); |
||
| 129 | } |
||
| 130 | |||
| 131 | View Code Duplication | public function isPartiallyEnrolled(User $user) |
|
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 132 | { |
||
| 133 | $storedData = $this->getCredentialData($user->getId(), true); |
||
| 134 | |||
| 135 | if ($storedData->getTimeout() < new DateTimeImmutable()) { |
||
| 136 | $storedData->delete(); |
||
| 137 | |||
| 138 | return false; |
||
| 139 | } |
||
| 140 | |||
| 141 | if ($storedData === null) { |
||
|
0 ignored issues
–
show
|
|||
| 142 | return false; |
||
| 143 | } |
||
| 144 | |||
| 145 | return true; |
||
| 146 | } |
||
| 147 | |||
| 148 | public function getSecret(User $user) |
||
|
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a Loading history...
|
|||
| 149 | { |
||
| 150 | $totp = Factory::loadFromProvisioningUri($this->getProvisioningUrl($user)); |
||
| 151 | |||
| 152 | return $totp->getSecret(); |
||
| 153 | } |
||
| 154 | } |
Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a
@returnannotation as described here.