Failed Conditions
Pull Request — oauthcreation (#531)
by Simon
06:20
created

U2FCredentialProvider::authenticate()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 2
dl 0
loc 26
rs 9.504
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 DateTimeImmutable;
12
use u2flib_server\Error;
13
use u2flib_server\U2F;
14
use Waca\DataObjects\User;
15
use Waca\Exceptions\ApplicationLogicException;
16
use Waca\PdoDatabase;
17
use Waca\SiteConfiguration;
18
use Waca\WebRequest;
19
20
class U2FCredentialProvider extends CredentialProviderBase
21
{
22
    /** @var U2F */
23
    private $u2f;
24
25
    /**
26
     * U2FCredentialProvider 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, 'u2f');
34
35
        $appId = 'https://' . WebRequest::httpHost();
36
        $this->u2f = new U2F($appId);
37
    }
38
39
    /**
40
     * Validates a user-provided credential
41
     *
42
     * @param User   $user The user to test the authentication against
43
     * @param string $data The raw credential data to be validated
44
     *
45
     * @return bool
46
     */
47
    public function authenticate(User $user, $data)
48
    {
49
        if (!is_array($data)) {
50
            return false;
51
        }
52
53
        list($authenticate, $request, $isU2F) = $data;
54
55
        if ($isU2F !== 'u2f') {
56
            return false;
57
        }
58
59
        $storedData = $this->getCredentialData($user->getId(), false);
60
        $registrations = json_decode($storedData->getData());
61
62
        try {
63
            $this->u2f->doAuthenticate($request, array($registrations), $authenticate);
64
        }
65
        catch (Error $ex) {
66
            return false;
67
        }
68
69
        // TODO: counter?
70
71
        return true;
72
    }
73
74
    public function enable(User $user, $request, $u2fData)
75
    {
76
        $registrationData = $this->u2f->doRegister($request, $u2fData);
77
78
        $storedData = $this->getCredentialData($user->getId(), true);
79
80
        if ($storedData === null) {
81
            throw new ApplicationLogicException('Credential data not found');
82
        }
83
84
        if ($storedData->getTimeout() > new DateTimeImmutable()) {
85
            $storedData->setData(json_encode($registrationData));
86
            $storedData->setDisabled(0);
87
            $storedData->setTimeout(null);
88
            $storedData->save();
89
        }
90
    }
91
92
    /**
93
     * @param User   $user   The user the credential belongs to
94
     * @param int    $factor The factor this credential provides
95
     * @param string $data   Unused here, due to multi-stage enrollment
96
     */
97
    public function setCredential(User $user, $factor, $data)
98
    {
99
        $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...
100
101
        if ($storedData !== null) {
102
            $storedData->delete();
103
        }
104
105
        $storedData = $this->createNewCredential($user);
106
107
        $storedData->setData(null);
108
        $storedData->setFactor($factor);
109
        $storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
110
        $storedData->setDisabled(1);
111
        $storedData->setPriority(4);
112
        $storedData->setVersion(1);
113
114
        $storedData->save();
115
    }
116
117 View Code Duplication
    public function isPartiallyEnrolled(User $user)
0 ignored issues
show
Duplication introduced by
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...
118
    {
119
        $storedData = $this->getCredentialData($user->getId(), true);
120
121
        if ($storedData->getTimeout() < new DateTimeImmutable()) {
122
            $storedData->delete();
123
124
            return false;
125
        }
126
127
        if ($storedData === null) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !($storedData === null);.
Loading history...
128
            return false;
129
        }
130
131
        return true;
132
    }
133
134
    public function getRegistrationData()
135
    {
136
        return $this->u2f->getRegisterData();
137
    }
138
139
    public function getAuthenticationData(User $user)
140
    {
141
        $storedData = $this->getCredentialData($user->getId(), false);
142
        $registrations = json_decode($storedData->getData());
143
144
        $authenticateData = $this->u2f->getAuthenticateData(array($registrations));
145
146
        return $authenticateData;
147
    }
148
}