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 ( 6c4153...d181b6 )
by François
03:10
created

Storage::clientConnect()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 29
Code Lines 10

Duplication

Lines 29
Ratio 100 %

Importance

Changes 0
Metric Value
dl 29
loc 29
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 10
nc 1
nop 5
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 PDO;
22
use SURFnet\VPN\Common\RandomInterface;
23
24
class Storage
25
{
26
    /** @var PDO */
27
    private $db;
28
29
    /** @var \fkooman\VPN\Common\RandomInterface */
30
    private $random;
31
32
    public function __construct(PDO $db, RandomInterface $random)
33
    {
34
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
35
        $this->db = $db;
36
        // enable foreign keys
37
        $this->db->query('PRAGMA foreign_keys = ON');
38
39
        $this->random = $random;
0 ignored issues
show
Documentation Bug introduced by
It seems like $random of type object<SURFnet\VPN\Common\RandomInterface> is incompatible with the declared type object<fkooman\VPN\Common\RandomInterface> of property $random.

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

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

Loading history...
40
    }
41
42
    public function getUsers()
43
    {
44
        $stmt = $this->db->prepare(
45
            'SELECT external_user_id, is_disabled
46
             FROM users'
47
        );
48
        $stmt->execute();
49
50
        $userList = [];
51
        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $result) {
52
            $userList[] = [
53
                'user_id' => $result['external_user_id'],
54
                'is_disabled' => boolval($result['is_disabled']),
55
            ];
56
        }
57
58
        return $userList;
59
    }
60
61 View Code Duplication
    public function getUserCertificateStatus($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...
62
    {
63
        $stmt = $this->db->prepare(
64
            'SELECT 
65
                u.external_user_id AS external_user_id, 
66
                u.is_disabled AS user_is_disabled, 
67
                c.is_disabled AS certificate_is_disabled 
68
             FROM users u, certificates c 
69
             WHERE c.common_name = :common_name'
70
        );
71
72
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
73
        $stmt->execute();
74
75
        return $stmt->fetch(PDO::FETCH_ASSOC);
76
    }
77
78
    private function getUserId($externalUserId)
79
    {
80
        $stmt = $this->db->prepare(
81
            'SELECT user_id
82
             FROM users
83
             WHERE external_user_id = :external_user_id'
84
        );
85
        $stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR);
86
        $stmt->execute();
87
88
        if (false !== $result = $stmt->fetch(PDO::FETCH_ASSOC)) {
89
            return $result['user_id'];
90
        }
91
92
        // user does not exist yet, add it
93
        $stmt = $this->db->prepare(
94
            'INSERT INTO users (external_user_id, user_id) VALUES(:external_user_id, :user_id)'
95
        );
96
97
        $userId = $this->random->get(16);
98
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
99
        $stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR);
100
        $stmt->execute();
101
102
        return $userId;
103
    }
104
105
    public function setVootToken($externalUserId, $vootToken)
106
    {
107
        $userId = $this->getUserId($externalUserId);
108
        $stmt = $this->db->prepare(
109
            'INSERT INTO voot_tokens (user_id, voot_token) VALUES(:user_id, :voot_token)'
110
        );
111
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
112
        $stmt->bindValue(':voot_token', $vootToken, PDO::PARAM_STR);
113
114
        $stmt->execute();
115
116
        return 1 === $stmt->rowCount();
117
    }
118
119 View Code Duplication
    public function deleteVootToken($externalUserId)
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...
120
    {
121
        $userId = $this->getUserId($externalUserId);
122
        $stmt = $this->db->prepare(
123
            'DELETE FROM voot_tokens WHERE user_id = :user_id'
124
        );
125
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
126
127
        $stmt->execute();
128
129
        return 1 === $stmt->rowCount();
130
    }
131
132 View Code Duplication
    public function hasTotpSecret($externalUserId)
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...
133
    {
134
        $userId = $this->getUserId($externalUserId);
135
        $stmt = $this->db->prepare(
136
            'SELECT COUNT(*)
137
             FROM totp_secrets
138
             WHERE user_id = :user_id'
139
        );
140
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
141
        $stmt->execute();
142
143
        return 1 === intval($stmt->fetchColumn());
144
    }
145
146
    public function getTotpSecret($externalUserId)
147
    {
148
        $userId = $this->getUserId($externalUserId);
149
        $stmt = $this->db->prepare(
150
            'SELECT totp_secret
151
             FROM totp_secrets
152
             WHERE user_id = :user_id'
153
        );
154
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
155
        $stmt->execute();
156
157
        return $stmt->fetchColumn();
158
    }
159
160
    public function setTotpSecret($externalUserId, $totpSecret)
161
    {
162
        $userId = $this->getUserId($externalUserId);
163
        $stmt = $this->db->prepare(
164
            'INSERT INTO totp_secrets (user_id, totp_secret) VALUES(:user_id, :totp_secret)'
165
        );
166
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
167
        $stmt->bindValue(':totp_secret', $totpSecret, PDO::PARAM_STR);
168
169
        $stmt->execute();
170
171
        return 1 === $stmt->rowCount();
172
    }
173
174 View Code Duplication
    public function deleteTotpSecret($externalUserId)
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...
175
    {
176
        $userId = $this->getUserId($externalUserId);
177
        $stmt = $this->db->prepare(
178
            'DELETE FROM totp_secrets WHERE user_id = :user_id'
179
        );
180
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
181
182
        $stmt->execute();
183
184
        return 1 === $stmt->rowCount();
185
    }
186
187 View Code Duplication
    public function deleteUser($externalUserId)
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
        $stmt = $this->db->prepare(
190
            'DELETE FROM users WHERE external_user_id = :external_user_id'
191
        );
192
        $stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR);
193
194
        $stmt->execute();
195
196
        return 1 === $stmt->rowCount();
197
    }
198
199 View Code Duplication
    public function addCertificate($externalUserId, $commonName, $displayName, $validFrom, $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...
200
    {
201
        $userId = $this->getUserId($externalUserId);
202
        $stmt = $this->db->prepare(
203
            'INSERT INTO certificates (common_name, user_id, display_name, valid_from, valid_to) VALUES(:common_name, :user_id, :display_name, :valid_from, :valid_to)'
204
        );
205
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
206
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
207
        $stmt->bindValue(':display_name', $displayName, PDO::PARAM_STR);
208
        $stmt->bindValue(':valid_from', $validFrom, PDO::PARAM_INT);
209
        $stmt->bindValue(':valid_to', $validTo, PDO::PARAM_INT);
210
211
        $stmt->execute();
212
213
        return 1 === $stmt->rowCount();
214
    }
215
216
    public function getCertificates($externalUserId)
217
    {
218
        $userId = $this->getUserId($externalUserId);
219
        $stmt = $this->db->prepare(
220
            'SELECT common_name, display_name, valid_from, valid_to, is_disabled
221
             FROM certificates
222
             WHERE user_id = :user_id'
223
        );
224
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
225
        $stmt->execute();
226
227
        $certificateList = [];
228
        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $result) {
229
            $certificateList[] = [
230
                'common_name' => $result['common_name'],
231
                'display_name' => $result['display_name'],
232
                'valid_from' => intval($result['valid_from']),
233
                'valid_to' => intval($result['valid_to']),
234
                'is_disabled' => boolval($result['is_disabled']),
235
            ];
236
        }
237
238
        return $certificateList;
239
    }
240
241 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...
242
    {
243
        $stmt = $this->db->prepare(
244
            'UPDATE certificates SET is_disabled = 1 WHERE common_name = :common_name'
245
        );
246
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
247
248
        $stmt->execute();
249
250
        return 1 === $stmt->rowCount();
251
    }
252
253 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...
254
    {
255
        $stmt = $this->db->prepare(
256
            'UPDATE certificates SET is_disabled = 0 WHERE common_name = :common_name'
257
        );
258
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
259
260
        $stmt->execute();
261
262
        return 1 === $stmt->rowCount();
263
    }
264
265 View Code Duplication
    public function disableUser($externalUserId)
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
        $stmt = $this->db->prepare(
268
            'UPDATE users SET is_disabled = 1 WHERE external_user_id = :external_user_id'
269
        );
270
        $stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR);
271
272
        $stmt->execute();
273
274
        // XXX it seems on update the rowCount is always 1, even if nothing was
275
        // modified?
276
        return 1 === $stmt->rowCount();
277
    }
278
279 View Code Duplication
    public function enableUser($externalUserId)
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...
280
    {
281
        $stmt = $this->db->prepare(
282
            'UPDATE users SET is_disabled = 0 WHERE external_user_id = :external_user_id'
283
        );
284
        $stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR);
285
286
        $stmt->execute();
287
288
        // XXX it seems on update the rowCount is always 1, even if nothing was
289
        // modified?
290
        return 1 === $stmt->rowCount();
291
    }
292
293 View Code Duplication
    public function isDisabledUser($externalUserId)
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...
294
    {
295
        $stmt = $this->db->prepare(
296
            'SELECT COUNT(*)
297
             FROM users
298
             WHERE external_user_id = :external_user_id AND is_disabled = 1'
299
        );
300
        $stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR);
301
        $stmt->execute();
302
303
        return 1 === intval($stmt->fetchColumn());
304
    }
305
306 View Code Duplication
    public function clientConnect($profileId, $commonName, $ip4, $ip6, $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...
307
    {
308
        $stmt = $this->db->prepare(
309
            'INSERT INTO connection_log (
310
                profile_id,
311
                common_name,
312
                ip4,
313
                ip6,
314
                connected_at
315
             ) 
316
             VALUES(
317
                :profile_id, 
318
                :common_name,
319
                :ip4,
320
                :ip6,
321
                :connected_at
322
             )'
323
        );
324
325
        $stmt->bindValue(':profile_id', $profileId, PDO::PARAM_STR);
326
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
327
        $stmt->bindValue(':ip4', $ip4, PDO::PARAM_STR);
328
        $stmt->bindValue(':ip6', $ip6, PDO::PARAM_STR);
329
        $stmt->bindValue(':connected_at', $connectedAt, PDO::PARAM_INT);
330
331
        $stmt->execute();
332
333
        return 1 === $stmt->rowCount();
334
    }
335
336
    public function clientDisconnect($profileId, $commonName, $ip4, $ip6, $connectedAt, $disconnectedAt, $bytesTransferred)
337
    {
338
        $stmt = $this->db->prepare(
339
            'UPDATE connection_log
340
                SET 
341
                    disconnected_at = :disconnected_at, 
342
                    bytes_transferred = :bytes_transferred
343
                WHERE 
344
                    profile_id = :profile_id AND
345
                    common_name = :common_name AND
346
                    ip4 = :ip4 AND
347
                    ip6 = :ip6 AND
348
                    connected_at = :connected_at
349
            '
350
        );
351
352
        $stmt->bindValue(':profile_id', $profileId, PDO::PARAM_STR);
353
        $stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR);
354
        $stmt->bindValue(':ip4', $ip4, PDO::PARAM_STR);
355
        $stmt->bindValue(':ip6', $ip6, PDO::PARAM_STR);
356
        $stmt->bindValue(':connected_at', $connectedAt, PDO::PARAM_INT);
357
        $stmt->bindValue(':disconnected_at', $disconnectedAt, PDO::PARAM_INT);
358
        $stmt->bindValue(':bytes_transferred', $bytesTransferred, PDO::PARAM_INT);
359
360
        $stmt->execute();
361
362
        return 1 === $stmt->rowCount();
363
    }
364
365 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...
366
    {
367
        $stmt = $this->db->prepare(
368
            'SELECT profile_id, common_name, ip4, ip6, connected_at, disconnected_at
369
             FROM connection_log
370
             WHERE
371
                (ip4 = :ip_address OR ip6 = :ip_address)
372
                AND connected_at < :date_time_unix
373
                AND (disconnected_at > :date_time_unix OR disconnected_at IS NULL)'
374
        );
375
        $stmt->bindValue(':ip_address', $ipAddress, PDO::PARAM_STR);
376
        $stmt->bindValue(':date_time_unix', $dateTimeUnix, PDO::PARAM_STR);
377
        $stmt->execute();
378
379
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
380
    }
381
382
    public function recordTotpKey($externalUserId, $totpKey, $timeUnix)
383
    {
384
        $userId = $this->getUserId($externalUserId);
385
        $stmt = $this->db->prepare(
386
            'INSERT INTO totp_log (
387
                user_id,
388
                totp_key,
389
                time_unix
390
             ) 
391
             VALUES(
392
                :user_id, 
393
                :totp_key,
394
                :time_unix
395
             )'
396
        );
397
398
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_STR);
399
        $stmt->bindValue(':totp_key', $totpKey, PDO::PARAM_STR);
400
        $stmt->bindValue(':time_unix', $timeUnix, PDO::PARAM_INT);
401
402
        $stmt->execute();
403
404
        return 1 === $stmt->rowCount();
405
    }
406
407
    public function housekeeping($timeUnix)
408
    {
409
        // connection_log
410
        $stmt = $this->db->prepare(
411
            sprintf(
412
                'DELETE FROM connection_log
413
                    WHERE connected_at < :time_unix'
414
            )
415
        );
416
417
        $stmt->bindValue(':time_unix', $timeUnix, PDO::PARAM_INT);
418
        $stmt->execute();
419
420
        // otp_log
421
        $stmt = $this->db->prepare(
422
            sprintf(
423
                'DELETE FROM totp_log
424
                    WHERE time_unix < :time_unix'
425
            )
426
        );
427
428
        $stmt->bindValue(':time_unix', $timeUnix, PDO::PARAM_INT);
429
        $stmt->execute();
430
431
        return 1 === $stmt->rowCount();
432
    }
433
434
    public function motd()
435
    {
436
        $stmt = $this->db->prepare(
437
            'SELECT motd_message FROM motd'
438
        );
439
440
        $stmt->execute();
441
442
        return $stmt->fetchColumn();
443
    }
444
445 View Code Duplication
    public function setMotd($motdMessage)
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...
446
    {
447
        $this->deleteMotd();
448
449
        $stmt = $this->db->prepare(
450
            'INSERT INTO motd (motd_message) VALUES(:motd_message)'
451
        );
452
453
        $stmt->bindValue(':motd_message', $motdMessage, PDO::PARAM_STR);
454
        $stmt->execute();
455
456
        return 1 === $stmt->rowCount();
457
    }
458
459
    public function deleteMotd()
460
    {
461
        $stmt = $this->db->prepare(
462
            'DELETE FROM motd'
463
        );
464
465
        $stmt->execute();
466
467
        return 1 === $stmt->rowCount();
468
    }
469
470
    public function init()
471
    {
472
        $queryList = [
473
            'CREATE TABLE IF NOT EXISTS users (
474
                user_id VARCHAR(255) PRIMARY KEY,
475
                external_user_id VARCHAR(255) UNIQUE NOT NULL,
476
                is_disabled BOOLEAN DEFAULT 0
477
            )',
478
            'CREATE TABLE IF NOT EXISTS voot_tokens (
479
                voot_token VARCHAR(255) NOT NULL PRIMARY KEY,   
480
                user_id VARCHAR(255) UNIQUE NOT NULL REFERENCES users(user_id) ON DELETE CASCADE
481
            )',
482
            'CREATE TABLE IF NOT EXISTS totp_secrets (
483
                totp_secret VARCHAR(255) NOT NULL PRIMARY KEY,   
484
                user_id VARCHAR(255) UNIQUE NOT NULL REFERENCES users(user_id) ON DELETE CASCADE
485
            )',
486
            'CREATE TABLE IF NOT EXISTS certificates (
487
                common_name VARCHAR(255) NOT NULL PRIMARY KEY,
488
                user_id VARCHAR(255) NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
489
                display_name VARCHAR(255) NOT NULL,
490
                valid_from INTEGER NOT NULL,
491
                valid_to INTEGER NOT NULL,
492
                is_disabled BOOLEAN DEFAULT 0
493
            )',
494
            'CREATE TABLE IF NOT EXISTS connection_log (
495
                common_name VARCHAR(255) NOT NULL REFERENCES certificates(common_name),
496
                profile_id VARCHAR(255) NOT NULL,
497
                ip4 VARCHAR(255) NOT NULL,
498
                ip6 VARCHAR(255) NOT NULL,
499
                connected_at INTEGER NOT NULL,
500
                disconnected_at INTEGER DEFAULT NULL,
501
                bytes_transferred INTEGER DEFAULT NULL                
502
            )',
503
            'CREATE TABLE IF NOT EXISTS totp_log (
504
                user_id VARCHAR(255) NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
505
                totp_key VARCHAR(255) NOT NULL,
506
                time_unix INTEGER NOT NULL
507
            )',
508
            'CREATE TABLE IF NOT EXISTS motd (
509
                motd_message TEXT
510
            )',
511
        ];
512
513
        foreach ($queryList as $query) {
514
            $this->db->query($query);
515
        }
516
    }
517
}
518