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

U2FCredentialProvider   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 130
Duplicated Lines 12.31 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 16
loc 130
rs 10
c 0
b 0
f 0
wmc 15
lcom 1
cbo 6

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A authenticate() 0 26 4
A enable() 0 17 3
A setCredential() 0 19 2
A isPartiallyEnrolled() 16 16 3
A getRegistrationData() 0 4 1
A getAuthenticationData() 0 9 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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