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.
Completed
Push — master ( a9b118...da2aa4 )
by François
01:58
created

Storage::getAccessToken()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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