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 ( 015953...add58e )
by François
01:48
created

Storage::getUserCertificateInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 8

Duplication

Lines 16
Ratio 72.73 %

Importance

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