GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Storage::setYubiKeyId()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 9

Duplication

Lines 18
Ratio 100 %

Importance

Changes 0
Metric Value
dl 18
loc 18
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 2
1
<?php
2
3
/**
4
 * eduVPN - End-user friendly VPN.
5
 *
6
 * Copyright: 2016-2017, The Commons Conservancy eduVPN Programme
7
 * SPDX-License-Identifier: AGPL-3.0+
8
 */
9
10
namespace SURFnet\VPN\Server;
11
12
use DateTime;
13
use fkooman\OAuth\Client\AccessToken;
14
use fkooman\OAuth\Client\TokenStorageInterface;
15
use PDO;
16
use PDOException;
17
18
class Storage implements TokenStorageInterface
19
{
20
    /** @var \PDO */
21
    private $db;
22
23
    /** @var \DateTime */
24
    private $dateTime;
25
26
    public function __construct(PDO $db, DateTime $dateTime)
27
    {
28
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
29
        if ('sqlite' === $db->getAttribute(PDO::ATTR_DRIVER_NAME)) {
30
            $db->query('PRAGMA foreign_keys = ON');
31
        }
32
33
        $this->db = $db;
34
        $this->dateTime = $dateTime;
35
    }
36
37
    /**
38
     * @return array
39
     */
40
    public function getUsers()
41
    {
42
        $stmt = $this->db->prepare(
43
<<< 'SQL'
44
    SELECT
45
        user_id, 
46
        date_time,
47
        totp_secret,
48
        yubi_key_id,
49
        is_disabled
50
    FROM 
51
        users
52
SQL
53
        );
54
        $stmt->execute();
55
56
        $userList = [];
57
        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
58
            $userList[] = [
59
                'user_id' => $row['user_id'],
60
                'is_disabled' => (bool) $row['is_disabled'],
61
                'has_yubi_key_id' => !is_null($row['yubi_key_id']),
62
                'has_totp_secret' => !is_null($row['totp_secret']),
63
            ];
64
        }
65
66
        return $userList;
67
    }
68
69
    /**
70
     * @return array|false
71
     */
72 View Code Duplication
    public function getUserCertificateInfo($commonName)
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...
73
    {
74
        $stmt = $this->db->prepare(
75
<<< 'SQL'
76
    SELECT 
77
        u.user_id AS user_id, 
78
        u.is_disabled AS user_is_disabled,
79
        c.display_name AS display_name,
80
        c.is_disabled AS certificate_is_disabled 
81
    FROM 
82
        users u, certificates c 
83
    WHERE 
84
        u.user_id = c.user_id AND 
85
        c.common_name = :common_name
86
SQL
87
        );
88
89
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
90
        $stmt->execute();
91
92
        return $stmt->fetch(PDO::FETCH_ASSOC);
93
    }
94
95
    /**
96
     * @return string|null
97
     */
98 View Code Duplication
    public function getVootToken($userId)
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...
99
    {
100
        $this->addUser($userId);
101
        $stmt = $this->db->prepare(
102
<<< 'SQL'
103
    SELECT
104
        voot_token
105
    FROM 
106
        users
107
    WHERE 
108
        user_id = :user_id
109
SQL
110
        );
111
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
112
        $stmt->execute();
113
114
        return $stmt->fetchColumn();
115
    }
116
117
    public function setVootToken($userId, AccessToken $vootToken)
118
    {
119
        $this->addUser($userId);
120
        $stmt = $this->db->prepare(
121
<<< 'SQL'
122
    UPDATE
123
        users
124
    SET
125
        voot_token = :voot_token
126
    WHERE
127
        user_id = :user_id
128
SQL
129
        );
130
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
131
        $stmt->bindValue(':voot_token', $vootToken->toJson(), PDO::PARAM_STR);
132
133
        $stmt->execute();
134
    }
135
136
    /**
137
     * @return bool
138
     */
139 View Code Duplication
    public function hasVootToken($userId)
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...
140
    {
141
        $this->addUser($userId);
142
        $stmt = $this->db->prepare(
143
<<< 'SQL'
144
    SELECT
145
        voot_token
146
    FROM 
147
        users
148
    WHERE 
149
        user_id = :user_id
150
SQL
151
        );
152
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
153
        $stmt->execute();
154
155
        return !is_null($stmt->fetchColumn());
156
    }
157
158
    public function deleteVootToken($userId)
159
    {
160
        $this->addUser($userId);
161
        $stmt = $this->db->prepare(
162
<<< 'SQL'
163
    UPDATE
164
        users
165
    SET
166
        voot_token = NULL
167
    WHERE 
168
        user_id = :user_id
169
SQL
170
        );
171
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
172
173
        $stmt->execute();
174
    }
175
176
    /**
177
     * @return bool
178
     */
179 View Code Duplication
    public function hasTotpSecret($userId)
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...
180
    {
181
        $this->addUser($userId);
182
        $stmt = $this->db->prepare(
183
<<< 'SQL'
184
    SELECT
185
        totp_secret
186
    FROM 
187
        users
188
    WHERE 
189
        user_id = :user_id
190
SQL
191
        );
192
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
193
        $stmt->execute();
194
195
        return !is_null($stmt->fetchColumn());
196
    }
197
198
    /**
199
     * @return string|null
200
     */
201 View Code Duplication
    public function getTotpSecret($userId)
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...
202
    {
203
        $this->addUser($userId);
204
        $stmt = $this->db->prepare(
205
<<< 'SQL'
206
    SELECT
207
        totp_secret
208
    FROM 
209
        users
210
    WHERE 
211
        user_id = :user_id
212
SQL
213
        );
214
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
215
        $stmt->execute();
216
217
        return $stmt->fetchColumn();
218
    }
219
220 View Code Duplication
    public function setTotpSecret($userId, $totpSecret)
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...
221
    {
222
        $this->addUser($userId);
223
        $stmt = $this->db->prepare(
224
<<< 'SQL'
225
    UPDATE
226
        users
227
    SET
228
        totp_secret = :totp_secret
229
    WHERE
230
        user_id = :user_id
231
SQL
232
        );
233
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
234
        $stmt->bindValue(':totp_secret', $totpSecret, PDO::PARAM_STR);
235
236
        $stmt->execute();
237
    }
238
239 View Code Duplication
    public function deleteTotpSecret($userId)
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...
240
    {
241
        $this->addUser($userId);
242
        $stmt = $this->db->prepare(
243
<<< 'SQL'
244
    UPDATE
245
        users
246
    SET
247
        totp_secret = NULL
248
    WHERE 
249
        user_id = :user_id
250
SQL
251
        );
252
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
253
        $stmt->execute();
254
    }
255
256 View Code Duplication
    public function setYubiKeyId($userId, $yubiKeyId)
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...
257
    {
258
        $this->addUser($userId);
259
        $stmt = $this->db->prepare(
260
<<< 'SQL'
261
    UPDATE
262
        users
263
    SET
264
        yubi_key_id = :yubi_key_id
265
    WHERE
266
        user_id = :user_id
267
SQL
268
        );
269
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
270
        $stmt->bindValue(':yubi_key_id', $yubiKeyId, PDO::PARAM_STR);
271
272
        $stmt->execute();
273
    }
274
275
    /**
276
     * @return bool
277
     */
278 View Code Duplication
    public function hasYubiKeyId($userId)
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...
279
    {
280
        $this->addUser($userId);
281
        $stmt = $this->db->prepare(
282
<<< 'SQL'
283
    SELECT
284
        yubi_key_id
285
    FROM 
286
        users
287
    WHERE 
288
        user_id = :user_id
289
SQL
290
        );
291
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
292
        $stmt->execute();
293
294
        return !is_null($stmt->fetchColumn());
295
    }
296
297
    /**
298
     * @return string|null
299
     */
300 View Code Duplication
    public function getYubiKeyId($userId)
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...
301
    {
302
        $this->addUser($userId);
303
        $stmt = $this->db->prepare(
304
<<< 'SQL'
305
    SELECT
306
        yubi_key_id
307
    FROM 
308
        users
309
    WHERE 
310
        user_id = :user_id
311
SQL
312
        );
313
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
314
        $stmt->execute();
315
316
        return $stmt->fetchColumn();
317
    }
318
319 View Code Duplication
    public function deleteYubiKeyId($userId)
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...
320
    {
321
        $this->addUser($userId);
322
        $stmt = $this->db->prepare(
323
<<< 'SQL'
324
    UPDATE
325
        users
326
    SET
327
        yubi_key_id = NULL
328
    WHERE 
329
        user_id = :user_id
330
SQL
331
        );
332
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
333
        $stmt->execute();
334
    }
335
336 View Code Duplication
    public function deleteUser($userId)
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...
337
    {
338
        $this->addUser($userId);
339
        $stmt = $this->db->prepare(
340
<<< 'SQL'
341
    DELETE FROM 
342
        users 
343
    WHERE 
344
        user_id = :user_id
345
SQL
346
        );
347
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
348
        $stmt->execute();
349
    }
350
351 View Code Duplication
    public function addCertificate($userId, $commonName, $displayName, DateTime $validFrom, DateTime $validTo)
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...
352
    {
353
        $this->addUser($userId);
354
        $stmt = $this->db->prepare(
355
<<< 'SQL'
356
    INSERT INTO certificates 
357
        (common_name, user_id, display_name, valid_from, valid_to)
358
    VALUES
359
        (:common_name, :user_id, :display_name, :valid_from, :valid_to)
360
SQL
361
        );
362
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
363
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
364
        $stmt->bindValue(':display_name', $displayName, PDO::PARAM_STR);
365
        $stmt->bindValue(':valid_from', $validFrom->format('Y-m-d H:i:s'), PDO::PARAM_STR);
366
        $stmt->bindValue(':valid_to', $validTo->format('Y-m-d H:i:s'), PDO::PARAM_STR);
367
        $stmt->execute();
368
    }
369
370
    /**
371
     * @return array
372
     */
373
    public function getCertificates($userId)
374
    {
375
        $this->addUser($userId);
376
        $stmt = $this->db->prepare(
377
<<< 'SQL'
378
    SELECT
379
        common_name, 
380
        display_name, 
381
        valid_from, 
382
        valid_to, 
383
        is_disabled
384
    FROM 
385
        certificates
386
    WHERE 
387
        user_id = :user_id
388
SQL
389
        );
390
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
391
        $stmt->execute();
392
393
        $certificateList = [];
394
        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
395
            $row['is_disabled'] = (bool) $row['is_disabled'];
396
            $certificateList[] = $row;
397
        }
398
399
        return $certificateList;
400
    }
401
402
    public function disableCertificate($commonName)
403
    {
404
        $stmt = $this->db->prepare(
405
<<< 'SQL'
406
    UPDATE 
407
        certificates 
408
    SET 
409
        is_disabled = 1 
410
    WHERE
411
        common_name = :common_name
412
SQL
413
        );
414
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
415
        $stmt->execute();
416
    }
417
418
    public function deleteCertificate($commonName)
419
    {
420
        $stmt = $this->db->prepare(
421
<<< 'SQL'
422
    DELETE FROM 
423
        certificates 
424
    WHERE 
425
        common_name = :common_name
426
SQL
427
        );
428
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
429
        $stmt->execute();
430
    }
431
432
    public function enableCertificate($commonName)
433
    {
434
        $stmt = $this->db->prepare(
435
<<< 'SQL'
436
    UPDATE 
437
        certificates 
438
    SET 
439
        is_disabled = 0 
440
    WHERE 
441
        common_name = :common_name
442
SQL
443
        );
444
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
445
        $stmt->execute();
446
    }
447
448 View Code Duplication
    public function disableUser($userId)
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...
449
    {
450
        $this->addUser($userId);
451
        $stmt = $this->db->prepare(
452
<<< 'SQL'
453
    UPDATE
454
        users 
455
    SET 
456
        is_disabled = 1 
457
    WHERE 
458
        user_id = :user_id
459
SQL
460
        );
461
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
462
        $stmt->execute();
463
    }
464
465
    public function enableUser($userId)
466
    {
467
        $this->addUser($userId);
468
        $stmt = $this->db->prepare(
469
<<< 'SQL'
470
    UPDATE
471
        users 
472
    SET 
473
        is_disabled = 0 
474
    WHERE 
475
        user_id = :user_id
476
SQL
477
        );
478
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
479
        $stmt->execute();
480
    }
481
482
    /**
483
     * @return bool
484
     */
485 View Code Duplication
    public function isDisabledUser($userId)
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...
486
    {
487
        $this->addUser($userId);
488
        $stmt = $this->db->prepare(
489
<<< 'SQL'
490
    SELECT
491
        is_disabled
492
    FROM 
493
        users
494
    WHERE 
495
        user_id = :user_id 
496
SQL
497
        );
498
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
499
        $stmt->execute();
500
501
        return (bool) $stmt->fetchColumn();
502
    }
503
504
    /**
505
     * @return array
506
     */
507
    public function getAllLogEntries()
508
    {
509
        $stmt = $this->db->prepare(
510
<<< 'SQL'
511
    SELECT 
512
        user_id,
513
        common_name, 
514
        connected_at, 
515
        disconnected_at, 
516
        bytes_transferred
517
    FROM 
518
        connection_log
519
    WHERE
520
        disconnected_at IS NOT NULL
521
    ORDER BY
522
        connected_at
523
SQL
524
        );
525
526
        $stmt->execute();
527
528
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
529
    }
530
531 View Code Duplication
    public function clientConnect($profileId, $commonName, $ip4, $ip6, DateTime $connectedAt)
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...
532
    {
533
        // this query is so complex, because we want to store the user_id in the
534
        // log as well, not just the common_name... the user may delete the
535
        // certificate, or the user account may be deleted...
536
        $stmt = $this->db->prepare(
537
<<< 'SQL'
538
    INSERT INTO connection_log 
539
        (
540
            user_id,
541
            profile_id,
542
            common_name,
543
            ip4,
544
            ip6,
545
            connected_at
546
        ) 
547
    VALUES
548
        (
549
            (
550
                SELECT
551
                    u.user_id
552
                FROM 
553
                    users u, certificates c
554
                WHERE
555
                    u.user_id = c.user_id
556
                AND
557
                    c.common_name = :common_name
558
            ),                
559
            :profile_id, 
560
            :common_name,
561
            :ip4,
562
            :ip6,
563
            :connected_at
564
        )
565
SQL
566
        );
567
568
        $stmt->bindValue(':profile_id', $profileId, PDO::PARAM_STR);
569
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
570
        $stmt->bindValue(':ip4', $ip4, PDO::PARAM_STR);
571
        $stmt->bindValue(':ip6', $ip6, PDO::PARAM_STR);
572
        $stmt->bindValue(':connected_at', $connectedAt->format('Y-m-d H:i:s'), PDO::PARAM_STR);
573
        $stmt->execute();
574
    }
575
576
    public function clientDisconnect($profileId, $commonName, $ip4, $ip6, DateTime $connectedAt, DateTime $disconnectedAt, $bytesTransferred)
577
    {
578
        $stmt = $this->db->prepare(
579
<<< 'SQL'
580
    UPDATE 
581
        connection_log
582
    SET 
583
        disconnected_at = :disconnected_at, 
584
        bytes_transferred = :bytes_transferred
585
    WHERE 
586
        profile_id = :profile_id 
587
    AND
588
        common_name = :common_name 
589
    AND
590
        ip4 = :ip4 
591
    AND
592
        ip6 = :ip6 
593
    AND
594
        connected_at = :connected_at
595
SQL
596
        );
597
598
        $stmt->bindValue(':profile_id', $profileId, PDO::PARAM_STR);
599
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
600
        $stmt->bindValue(':ip4', $ip4, PDO::PARAM_STR);
601
        $stmt->bindValue(':ip6', $ip6, PDO::PARAM_STR);
602
        $stmt->bindValue(':connected_at', $connectedAt->format('Y-m-d H:i:s'), PDO::PARAM_STR);
603
        $stmt->bindValue(':disconnected_at', $disconnectedAt->format('Y-m-d H:i:s'), PDO::PARAM_STR);
604
        $stmt->bindValue(':bytes_transferred', $bytesTransferred, PDO::PARAM_INT);
605
        $stmt->execute();
606
    }
607
608
    /**
609
     * @return array|false
610
     */
611 View Code Duplication
    public function getLogEntry(DateTime $dateTime, $ipAddress)
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...
612
    {
613
        $stmt = $this->db->prepare(
614
<<< 'SQL'
615
    SELECT 
616
        user_id,
617
        profile_id, 
618
        common_name, 
619
        ip4, 
620
        ip6, 
621
        connected_at, 
622
        disconnected_at
623
    FROM
624
        connection_log
625
    WHERE
626
        (ip4 = :ip_address OR ip6 = :ip_address)
627
    AND 
628
        connected_at < :date_time
629
    AND 
630
        (disconnected_at > :date_time OR disconnected_at IS NULL)
631
SQL
632
        );
633
        $stmt->bindValue(':ip_address', $ipAddress, PDO::PARAM_STR);
634
        $stmt->bindValue(':date_time', $dateTime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
635
        $stmt->execute();
636
637
        // XXX can this also contain multiple results? I don't think so, but
638
        // make sure!
639
        return $stmt->fetch(PDO::FETCH_ASSOC);
640
    }
641
642
    /**
643
     * @return int
644
     */
645 View Code Duplication
    public function getTotpAttemptCount($userId)
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...
646
    {
647
        $this->addUser($userId);
648
        $stmt = $this->db->prepare(
649
<<< 'SQL'
650
        SELECT
651
            COUNT(*)
652
        FROM 
653
            totp_log
654
        WHERE user_id = :user_id
655
SQL
656
        );
657
658
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
659
        $stmt->execute();
660
661
        return (int) $stmt->fetchColumn();
662
    }
663
664
    /**
665
     * @return bool true if recording succeeds, false if it cannot due to replay
666
     */
667
    public function recordTotpKey($userId, $totpKey)
668
    {
669
        $this->addUser($userId);
670
        $stmt = $this->db->prepare(
671
<<< 'SQL'
672
    INSERT INTO totp_log 
673
        (user_id, totp_key, date_time)
674
    VALUES
675
        (:user_id, :totp_key, :date_time)
676
SQL
677
        );
678
679
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
680
        $stmt->bindValue(':totp_key', $totpKey, PDO::PARAM_STR);
681
        $stmt->bindValue(':date_time', $this->dateTime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
682
683
        try {
684
            $stmt->execute();
685
        } catch (PDOException $e) {
686
            // unable to record the TOTP, most likely replay
687
            return false;
688
        }
689
690
        return true;
691
    }
692
693 View Code Duplication
    public function cleanConnectionLog(DateTime $dateTime)
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...
694
    {
695
        $stmt = $this->db->prepare(
696
<<< 'SQL'
697
    DELETE FROM
698
        connection_log
699
    WHERE
700
        connected_at < :date_time
701
    AND
702
        disconnected_at IS NOT NULL
703
SQL
704
        );
705
706
        $stmt->bindValue(':date_time', $dateTime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
707
708
        return $stmt->execute();
709
    }
710
711 View Code Duplication
    public function cleanUserMessages(DateTime $dateTime)
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...
712
    {
713
        $stmt = $this->db->prepare(
714
<<< 'SQL'
715
    DELETE FROM
716
        user_messages
717
    WHERE
718
        date_time < :date_time
719
SQL
720
        );
721
722
        $stmt->bindValue(':date_time', $dateTime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
723
724
        return $stmt->execute();
725
    }
726
727 View Code Duplication
    public function cleanTotpLog(DateTime $dateTime)
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...
728
    {
729
        $stmt = $this->db->prepare(
730
<<< 'SQL'
731
    DELETE FROM 
732
        totp_log
733
    WHERE 
734
        date_time < :date_time
735
SQL
736
        );
737
738
        $stmt->bindValue(':date_time', $dateTime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
739
740
        return $stmt->execute();
741
    }
742
743
    /**
744
     * @return array
745
     */
746 View Code Duplication
    public function systemMessages($type)
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...
747
    {
748
        $stmt = $this->db->prepare(
749
<<< 'SQL'
750
    SELECT
751
        id, message, date_time 
752
    FROM 
753
        system_messages
754
    WHERE
755
        type = :type
756
SQL
757
        );
758
759
        $stmt->bindValue(':type', $type, PDO::PARAM_STR);
760
        $stmt->execute();
761
762
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
763
    }
764
765
    public function addSystemMessage($type, $message)
766
    {
767
        $stmt = $this->db->prepare(
768
<<< 'SQL'
769
    INSERT INTO system_messages 
770
        (type, message, date_time) 
771
    VALUES
772
        (:type, :message, :date_time)
773
SQL
774
        );
775
776
        $stmt->bindValue(':type', $type, PDO::PARAM_STR);
777
        $stmt->bindValue(':message', $message, PDO::PARAM_STR);
778
        $stmt->bindValue(':date_time', $this->dateTime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
779
        $stmt->execute();
780
    }
781
782
    public function deleteSystemMessage($messageId)
783
    {
784
        $stmt = $this->db->prepare(
785
<<< 'SQL'
786
    DELETE FROM 
787
        system_messages
788
    WHERE id = :message_id
789
SQL
790
        );
791
792
        $stmt->bindValue(':message_id', $messageId, PDO::PARAM_INT);
793
        $stmt->execute();
794
    }
795
796
    /**
797
     * @return array
798
     */
799 View Code Duplication
    public function userMessages($userId)
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...
800
    {
801
        $this->addUser($userId);
802
        $stmt = $this->db->prepare(
803
<<< 'SQL'
804
    SELECT
805
        id, type, message, date_time 
806
    FROM 
807
        user_messages
808
    WHERE
809
        user_id = :user_id
810
    ORDER BY
811
        date_time DESC
812
SQL
813
        );
814
815
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
816
        $stmt->execute();
817
818
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
819
    }
820
821 View Code Duplication
    public function addUserMessage($userId, $type, $message)
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...
822
    {
823
        $this->addUser($userId);
824
        $stmt = $this->db->prepare(
825
<<< 'SQL'
826
    INSERT INTO user_messages 
827
        (user_id, type, message, date_time) 
828
    VALUES
829
        (:user_id, :type, :message, :date_time)
830
SQL
831
        );
832
833
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
834
        $stmt->bindValue(':type', $type, PDO::PARAM_STR);
835
        $stmt->bindValue(':message', $message, PDO::PARAM_STR);
836
        $stmt->bindValue(':date_time', $this->dateTime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
837
        $stmt->execute();
838
    }
839
840
    // TokenStorageInterface
841
842
    /**
843
     * @param string $userId
844
     *
845
     * @return array
846
     */
847
    public function getAccessTokenList($userId)
848
    {
849
        $vootToken = $this->getVootToken($userId);
850
        if (is_null($vootToken)) {
851
            return [];
852
        }
853
854
        return [
855
            AccessToken::fromJson($vootToken),
856
        ];
857
    }
858
859
    /**
860
     * @param string      $userId
861
     * @param AccessToken $accessToken
862
     */
863
    public function storeAccessToken($userId, AccessToken $accessToken)
864
    {
865
        $this->setVootToken($userId, $accessToken);
866
    }
867
868
    /**
869
     * @param string      $userId
870
     * @param AccessToken $accessToken
871
     */
872
    public function deleteAccessToken($userId, AccessToken $accessToken)
873
    {
874
        $this->deleteVootToken($userId);
875
    }
876
877
    public function init()
878
    {
879
        $queryList = [];
880
        $queryList[] =
881
<<< 'SQL'
882
    CREATE TABLE IF NOT EXISTS users (
883
        user_id VARCHAR(255) NOT NULL PRIMARY KEY UNIQUE,
884
        voot_token TEXT DEFAULT NULL,
885
        totp_secret VARCHAR(255) DEFAULT NULL,
886
        yubi_key_id VARCHAR(255) DEFAULT NULL,
887
        date_time DATETIME NOT NULL,
888
        is_disabled BOOLEAN DEFAULT 0 NOT NULL
889
    )
890
SQL;
891
892
        $queryList[] =
893
<<< 'SQL'
894
    CREATE TABLE IF NOT EXISTS certificates (
895
        common_name VARCHAR(255) UNIQUE NOT NULL,
896
        display_name VARCHAR(255) NOT NULL,
897
        valid_from DATETIME NOT NULL,
898
        valid_to DATETIME NOT NULL,
899
        is_disabled BOOLEAN DEFAULT 0,
900
        user_id VARCHAR(255) NOT NULL REFERENCES users(user_id) ON DELETE CASCADE
901
    )
902
SQL;
903
904
        $queryList[] =
905
<<< 'SQL'
906
    CREATE TABLE IF NOT EXISTS totp_log (
907
        totp_key VARCHAR(255) NOT NULL,
908
        date_time DATETIME NOT NULL,
909
        user_id VARCHAR(255) NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
910
        UNIQUE (user_id, totp_key)
911
    )
912
SQL;
913
914
        $queryList[] =
915
<<< 'SQL'
916
    CREATE TABLE IF NOT EXISTS connection_log (
917
        user_id VARCHAR(255) NOT NULL,
918
        common_name VARCHAR(255) NOT NULL,
919
        profile_id VARCHAR(255) NOT NULL,
920
        ip4 VARCHAR(255) NOT NULL,
921
        ip6 VARCHAR(255) NOT NULL,
922
        connected_at DATETIME NOT NULL,
923
        disconnected_at DATETIME DEFAULT NULL,
924
        bytes_transferred INTEGER DEFAULT NULL                
925
    )
926
SQL;
927
928
        $queryList[] =
929
<<< 'SQL'
930
    CREATE TABLE IF NOT EXISTS system_messages (
931
        id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
932
        type VARCHAR(255) NOT NULL DEFAULT "notification",
933
        message TINYTEXT NOT NULL,
934
        date_time DATETIME NOT NULL
935
    )
936
SQL;
937
938
        $queryList[] =
939
<<< 'SQL'
940
    CREATE TABLE IF NOT EXISTS user_messages (
941
        id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
942
        type VARCHAR(255) NOT NULL DEFAULT "notification",
943
        message TINYTEXT NOT NULL,
944
        date_time DATETIME NOT NULL,
945
        user_id VARCHAR(255) NOT NULL REFERENCES users(user_id) ON DELETE CASCADE
946
    )
947
SQL;
948
949
        foreach ($queryList as $query) {
950
            if ('sqlite' === $this->db->getAttribute(PDO::ATTR_DRIVER_NAME)) {
951
                $query = str_replace('AUTO_INCREMENT', 'AUTOINCREMENT', $query);
952
            }
953
            $this->db->query($query);
954
        }
955
    }
956
957 View Code Duplication
    private function addUser($userId)
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...
958
    {
959
        $stmt = $this->db->prepare(
960
<<< 'SQL'
961
    SELECT 
962
        COUNT(*)
963
    FROM 
964
        users
965
    WHERE user_id = :user_id
966
SQL
967
        );
968
969
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
970
        $stmt->execute();
971
972
        if (1 !== (int) $stmt->fetchColumn()) {
973
            // user does not exist yet
974
            $stmt = $this->db->prepare(
975
<<< 'SQL'
976
    INSERT INTO 
977
        users (
978
            user_id,
979
            date_time
980
        )
981
    VALUES (
982
        :user_id,
983
        :date_time
984
    )
985
SQL
986
            );
987
            $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
988
            $stmt->bindValue(':date_time', $this->dateTime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
989
            $stmt->execute();
990
        }
991
    }
992
}
993