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 ( 8e5a2b...2c0050 )
by François
02:46
created

Storage::getYubiKeyId()   A

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