Failed Conditions
Pull Request — oauthcreation (#531)
by Simon
18:38 queued 08:37
created

ScratchTokenCredentialProvider::authenticate()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 8
nop 2
dl 0
loc 33
rs 8.7697
c 0
b 0
f 0
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 Base32\Base32;
12
use Waca\DataObjects\User;
13
use Waca\Exceptions\ApplicationLogicException;
14
use Waca\Exceptions\OptimisticLockFailedException;
15
use Waca\PdoDatabase;
16
use Waca\Security\EncryptionHelper;
17
use Waca\SiteConfiguration;
18
19
class ScratchTokenCredentialProvider extends CredentialProviderBase
20
{
21
    /** @var EncryptionHelper */
22
    private $encryptionHelper;
23
    /** @var array the tokens generated in the last generation round. */
24
    private $generatedTokens;
25
26
    /**
27
     * ScratchTokenCredentialProvider constructor.
28
     *
29
     * @param PdoDatabase       $database
30
     * @param SiteConfiguration $configuration
31
     */
32
    public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
33
    {
34
        parent::__construct($database, $configuration, 'scratch');
35
        $this->encryptionHelper = new EncryptionHelper($configuration);
36
    }
37
38
    /**
39
     * Validates a user-provided credential
40
     *
41
     * @param User   $user The user to test the authentication against
42
     * @param string $data The raw credential data to be validated
43
     *
44
     * @return bool
45
     * @throws ApplicationLogicException|OptimisticLockFailedException
46
     */
47
    public function authenticate(User $user, $data)
48
    {
49
        if (is_array($data)) {
50
            return false;
51
        }
52
53
        $storedData = $this->getCredentialData($user->getId());
54
55
        if ($storedData === null) {
56
            throw new ApplicationLogicException('Credential data not found');
57
        }
58
59
        $scratchTokens = unserialize($this->encryptionHelper->decryptData($storedData->getData()));
60
61
        $usedToken = null;
62
        foreach ($scratchTokens as $scratchToken) {
63
            if (password_verify($data, $scratchToken)){
64
                $usedToken = $scratchToken;
65
                break;
66
            }
67
        }
68
69
        if($usedToken === null) {
70
            return false;
71
        }
72
73
        $scratchTokens = array_diff($scratchTokens, [$usedToken]);
74
75
        $storedData->setData($this->encryptionHelper->encryptData(serialize($scratchTokens)));
76
        $storedData->save();
77
78
        return true;
79
    }
80
81
    /**
82
     * @param User   $user   The user the credential belongs to
83
     * @param int    $factor The factor this credential provides
84
     * @param string $data   Unused.
85
     *
86
     * @throws OptimisticLockFailedException
87
     */
88
    public function setCredential(User $user, $factor, $data)
89
    {
90
        $plaintextScratch = array();
91
        $storedScratch = array();
92
        for ($i = 0; $i < 5; $i++) {
93
            $token = Base32::encode(openssl_random_pseudo_bytes(10));
94
            $plaintextScratch[] = $token;
95
96
            $storedScratch[] = password_hash(
97
                $token,
98
                PasswordCredentialProvider::PASSWORD_ALGO,
99
                array('cost' => PasswordCredentialProvider::PASSWORD_COST)
100
            );
101
        }
102
103
        $storedData = $this->getCredentialData($user->getId(), null);
0 ignored issues
show
Documentation introduced by
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...
104
105
        if ($storedData !== null) {
106
            $storedData->delete();
107
        }
108
109
        $storedData = $this->createNewCredential($user);
110
111
        $storedData->setData($this->encryptionHelper->encryptData(serialize($storedScratch)));
112
        $storedData->setFactor($factor);
113
        $storedData->setVersion(1);
114
        $storedData->setPriority(9);
115
116
        $storedData->save();
117
        $this->generatedTokens = $plaintextScratch;
118
    }
119
120
    /**
121
     * Gets the count of remaining valid tokens
122
     *
123
     * @param int $userId
124
     *
125
     * @return int
126
     */
127
    public function getRemaining($userId)
128
    {
129
        $storedData = $this->getCredentialData($userId);
130
131
        if ($storedData === null) {
132
            return 0;
133
        }
134
135
        $scratchTokens = unserialize($this->encryptionHelper->decryptData($storedData->getData()));
136
137
        return count($scratchTokens);
138
    }
139
140
    /**
141
     * @return array
142
     */
143
    public function getTokens()
144
    {
145
        if ($this->generatedTokens != null) {
146
            return $this->generatedTokens;
147
        }
148
149
        return array();
150
    }
151
}
152