User   A
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 373
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 59
dl 0
loc 373
rs 9.6
c 1
b 0
f 0
wmc 35

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getCreatedAt() 0 3 1
A getUpdatedAt() 0 3 1
A setName() 0 5 1
A getName() 0 3 1
A getGoogleAuthenticatorSecret() 0 3 1
A isGoogleTwoFactor() 0 3 1
A setEmailAuthCode() 0 3 1
A getEmailAuthCode() 0 3 1
A addClient() 0 5 1
A isEmailTwoFactor() 0 3 1
A getEntries() 0 3 1
A isEmailAuthEnabled() 0 3 1
A setConfig() 0 5 1
A getEmailAuthRecipient() 0 3 1
A setEmailTwoFactor() 0 3 1
A getClients() 0 3 1
A isGoogleAuthenticatorEnabled() 0 3 2
A isEqualTo() 0 3 1
A addEntry() 0 5 1
A setGoogleAuthenticatorSecret() 0 3 1
A getConfig() 0 3 1
A getGoogleAuthenticatorUsername() 0 3 1
A getBackupCodes() 0 3 1
A isBackupCode() 0 3 2
A invalidateBackupCode() 0 6 2
A setBackupCodes() 0 3 1
A findBackupCode() 0 11 3
A getFirstClient() 0 7 2
1
<?php
2
3
namespace Wallabag\UserBundle\Entity;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Doctrine\ORM\Mapping as ORM;
7
use FOS\UserBundle\Model\User as BaseUser;
8
use JMS\Serializer\Annotation\Accessor;
9
use JMS\Serializer\Annotation\Groups;
10
use JMS\Serializer\Annotation\XmlRoot;
11
use Scheb\TwoFactorBundle\Model\BackupCodeInterface;
12
use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface as EmailTwoFactorInterface;
13
use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface as GoogleTwoFactorInterface;
14
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
15
use Symfony\Component\Security\Core\User\UserInterface;
16
use Wallabag\ApiBundle\Entity\Client;
17
use Wallabag\CoreBundle\Entity\Config;
18
use Wallabag\CoreBundle\Entity\Entry;
19
use Wallabag\CoreBundle\Helper\EntityTimestampsTrait;
20
21
/**
22
 * User.
23
 *
24
 * @XmlRoot("user")
25
 * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository")
26
 * @ORM\Table(name="`user`")
27
 * @ORM\HasLifecycleCallbacks()
28
 *
29
 * @UniqueEntity("email")
30
 * @UniqueEntity("username")
31
 */
32
class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorInterface, BackupCodeInterface
33
{
34
    use EntityTimestampsTrait;
35
36
    /** @Serializer\XmlAttribute */
37
    /**
38
     * @var int
39
     *
40
     * @ORM\Column(name="id", type="integer")
41
     * @ORM\Id
42
     * @ORM\GeneratedValue(strategy="AUTO")
43
     *
44
     * @Groups({"user_api", "user_api_with_client"})
45
     */
46
    protected $id;
47
48
    /**
49
     * @var string
50
     *
51
     * @ORM\Column(name="name", type="text", nullable=true)
52
     *
53
     * @Groups({"user_api", "user_api_with_client"})
54
     */
55
    protected $name;
56
57
    /**
58
     * @var string
59
     *
60
     * @Groups({"user_api", "user_api_with_client"})
61
     */
62
    protected $username;
63
64
    /**
65
     * @var string
66
     *
67
     * @Groups({"user_api", "user_api_with_client"})
68
     */
69
    protected $email;
70
71
    /**
72
     * @var \DateTime
73
     *
74
     * @ORM\Column(name="created_at", type="datetime")
75
     *
76
     * @Groups({"user_api", "user_api_with_client"})
77
     */
78
    protected $createdAt;
79
80
    /**
81
     * @var \DateTime
82
     *
83
     * @ORM\Column(name="updated_at", type="datetime")
84
     *
85
     * @Groups({"user_api", "user_api_with_client"})
86
     */
87
    protected $updatedAt;
88
89
    /**
90
     * @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\Entry", mappedBy="user", cascade={"remove"})
91
     */
92
    protected $entries;
93
94
    /**
95
     * @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user", cascade={"remove"})
96
     */
97
    protected $config;
98
99
    /**
100
     * @var ArrayCollection
101
     *
102
     * @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\SiteCredential", mappedBy="user", cascade={"remove"})
103
     */
104
    protected $siteCredentials;
105
106
    /**
107
     * @var ArrayCollection
108
     *
109
     * @ORM\OneToMany(targetEntity="Wallabag\ApiBundle\Entity\Client", mappedBy="user", cascade={"remove"})
110
     */
111
    protected $clients;
112
113
    /**
114
     * @see getFirstClient() below
115
     *
116
     * @Groups({"user_api_with_client"})
117
     * @Accessor(getter="getFirstClient")
118
     */
119
    protected $default_client;
120
121
    /**
122
     * @ORM\Column(type="integer", nullable=true)
123
     */
124
    private $authCode;
125
126
    /**
127
     * @ORM\Column(name="googleAuthenticatorSecret", type="string", nullable=true)
128
     */
129
    private $googleAuthenticatorSecret;
130
131
    /**
132
     * @ORM\Column(type="json_array", nullable=true)
133
     */
134
    private $backupCodes;
135
136
    /**
137
     * @var bool
138
     *
139
     * @ORM\Column(type="boolean")
140
     */
141
    private $emailTwoFactor = false;
142
143
    public function __construct()
144
    {
145
        parent::__construct();
146
        $this->entries = new ArrayCollection();
147
        $this->roles = ['ROLE_USER'];
148
    }
149
150
    /**
151
     * Set name.
152
     *
153
     * @param string $name
154
     *
155
     * @return User
156
     */
157
    public function setName($name)
158
    {
159
        $this->name = $name;
160
161
        return $this;
162
    }
163
164
    /**
165
     * Get name.
166
     *
167
     * @return string
168
     */
169
    public function getName()
170
    {
171
        return $this->name;
172
    }
173
174
    /**
175
     * @return \DateTime
176
     */
177
    public function getCreatedAt()
178
    {
179
        return $this->createdAt;
180
    }
181
182
    /**
183
     * @return \DateTime
184
     */
185
    public function getUpdatedAt()
186
    {
187
        return $this->updatedAt;
188
    }
189
190
    /**
191
     * @return User
192
     */
193
    public function addEntry(Entry $entry)
194
    {
195
        $this->entries[] = $entry;
196
197
        return $this;
198
    }
199
200
    /**
201
     * @return ArrayCollection<Entry>
202
     */
203
    public function getEntries()
204
    {
205
        return $this->entries;
206
    }
207
208
    public function isEqualTo(UserInterface $user)
209
    {
210
        return $this->username === $user->getUsername();
211
    }
212
213
    /**
214
     * Set config.
215
     *
216
     * @param Config $config
217
     *
218
     * @return User
219
     */
220
    public function setConfig(Config $config = null)
221
    {
222
        $this->config = $config;
223
224
        return $this;
225
    }
226
227
    /**
228
     * Get config.
229
     *
230
     * @return Config
231
     */
232
    public function getConfig()
233
    {
234
        return $this->config;
235
    }
236
237
    /**
238
     * @return bool
239
     */
240
    public function isEmailTwoFactor()
241
    {
242
        return $this->emailTwoFactor;
243
    }
244
245
    /**
246
     * @param bool $emailTwoFactor
247
     */
248
    public function setEmailTwoFactor($emailTwoFactor)
249
    {
250
        $this->emailTwoFactor = $emailTwoFactor;
251
    }
252
253
    /**
254
     * Used in the user config form to be "like" the email option.
255
     */
256
    public function isGoogleTwoFactor()
257
    {
258
        return $this->isGoogleAuthenticatorEnabled();
259
    }
260
261
    /**
262
     * {@inheritdoc}
263
     */
264
    public function isEmailAuthEnabled(): bool
265
    {
266
        return $this->emailTwoFactor;
267
    }
268
269
    /**
270
     * {@inheritdoc}
271
     */
272
    public function getEmailAuthCode(): string
273
    {
274
        return $this->authCode;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->authCode could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
275
    }
276
277
    /**
278
     * {@inheritdoc}
279
     */
280
    public function setEmailAuthCode(string $authCode): void
281
    {
282
        $this->authCode = $authCode;
0 ignored issues
show
Documentation Bug introduced by
It seems like $authCode of type string is incompatible with the declared type integer|null of property $authCode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
283
    }
284
285
    /**
286
     * {@inheritdoc}
287
     */
288
    public function getEmailAuthRecipient(): string
289
    {
290
        return $this->email;
291
    }
292
293
    /**
294
     * {@inheritdoc}
295
     */
296
    public function isGoogleAuthenticatorEnabled(): bool
297
    {
298
        return $this->googleAuthenticatorSecret ? true : false;
299
    }
300
301
    /**
302
     * {@inheritdoc}
303
     */
304
    public function getGoogleAuthenticatorUsername(): string
305
    {
306
        return $this->username;
307
    }
308
309
    /**
310
     * {@inheritdoc}
311
     */
312
    public function getGoogleAuthenticatorSecret(): string
313
    {
314
        return $this->googleAuthenticatorSecret;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->googleAuthenticatorSecret could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
315
    }
316
317
    /**
318
     * {@inheritdoc}
319
     */
320
    public function setGoogleAuthenticatorSecret(?string $googleAuthenticatorSecret): void
321
    {
322
        $this->googleAuthenticatorSecret = $googleAuthenticatorSecret;
323
    }
324
325
    public function setBackupCodes(array $codes = null)
326
    {
327
        $this->backupCodes = $codes;
328
    }
329
330
    public function getBackupCodes()
331
    {
332
        return $this->backupCodes;
333
    }
334
335
    /**
336
     * {@inheritdoc}
337
     */
338
    public function isBackupCode(string $code): bool
339
    {
340
        return false === $this->findBackupCode($code) ? false : true;
341
    }
342
343
    /**
344
     * {@inheritdoc}
345
     */
346
    public function invalidateBackupCode(string $code): void
347
    {
348
        $key = $this->findBackupCode($code);
349
350
        if (false !== $key) {
351
            unset($this->backupCodes[$key]);
352
        }
353
    }
354
355
    /**
356
     * @return User
357
     */
358
    public function addClient(Client $client)
359
    {
360
        $this->clients[] = $client;
361
362
        return $this;
363
    }
364
365
    /**
366
     * @return ArrayCollection<Entry>
367
     */
368
    public function getClients()
369
    {
370
        return $this->clients;
371
    }
372
373
    /**
374
     * Only used by the API when creating a new user it'll also return the first client (which was also created at the same time).
375
     *
376
     * @return Client|false
377
     */
378
    public function getFirstClient()
379
    {
380
        if (!empty($this->clients)) {
381
            return $this->clients->first();
382
        }
383
384
        return false;
385
    }
386
387
    /**
388
     * Try to find a backup code from the list of backup codes of the current user.
389
     *
390
     * @param string $code Given code from the user
391
     *
392
     * @return string|false
393
     */
394
    private function findBackupCode(string $code)
395
    {
396
        foreach ($this->backupCodes as $key => $backupCode) {
397
            // backup code are hashed using `password_hash`
398
            // see ConfigController->otpAppAction
399
            if (password_verify($code, $backupCode)) {
400
                return $key;
401
            }
402
        }
403
404
        return false;
405
    }
406
}
407