Passed
Push — master ( 63f369...ac5ee7 )
by Greg
05:52
created

Auth::checkSubmissionAccess()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 7
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 15
rs 9.6111
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2019 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
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 General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees;
21
22
use Fisharebest\Webtrees\Contracts\UserInterface;
23
use Fisharebest\Webtrees\Exceptions\FamilyAccessDeniedException;
24
use Fisharebest\Webtrees\Exceptions\FamilyNotFoundException;
25
use Fisharebest\Webtrees\Exceptions\HttpAccessDeniedException;
26
use Fisharebest\Webtrees\Exceptions\IndividualAccessDeniedException;
27
use Fisharebest\Webtrees\Exceptions\IndividualNotFoundException;
28
use Fisharebest\Webtrees\Exceptions\MediaAccessDeniedException;
29
use Fisharebest\Webtrees\Exceptions\MediaNotFoundException;
30
use Fisharebest\Webtrees\Exceptions\NoteAccessDeniedException;
31
use Fisharebest\Webtrees\Exceptions\NoteNotFoundException;
32
use Fisharebest\Webtrees\Exceptions\RecordAccessDeniedException;
33
use Fisharebest\Webtrees\Exceptions\RecordNotFoundException;
34
use Fisharebest\Webtrees\Exceptions\RepositoryAccessDeniedException;
35
use Fisharebest\Webtrees\Exceptions\RepositoryNotFoundException;
36
use Fisharebest\Webtrees\Exceptions\SourceAccessDeniedException;
37
use Fisharebest\Webtrees\Exceptions\SourceNotFoundException;
38
use Fisharebest\Webtrees\Module\ModuleInterface;
39
use Fisharebest\Webtrees\Services\UserService;
40
41
/**
42
 * Authentication.
43
 */
44
class Auth
45
{
46
    // Privacy constants
47
    public const PRIV_PRIVATE = 2; // Allows visitors to view the item
48
    public const PRIV_USER    = 1; // Allows members to access the item
49
    public const PRIV_NONE    = 0; // Allows managers to access the item
50
    public const PRIV_HIDE    = -1; // Hide the item to all users
51
52
    /**
53
     * Are we currently logged in?
54
     *
55
     * @return bool
56
     */
57
    public static function check(): bool
58
    {
59
        return self::id() !== null;
60
    }
61
62
    /**
63
     * Is the specified/current user an administrator?
64
     *
65
     * @param UserInterface|null $user
66
     *
67
     * @return bool
68
     */
69
    public static function isAdmin(UserInterface $user = null): bool
70
    {
71
        $user = $user ?? self::user();
72
73
        return $user->getPreference(User::PREF_IS_ADMINISTRATOR) === '1';
74
    }
75
76
    /**
77
     * Is the specified/current user a manager of a tree?
78
     *
79
     * @param Tree               $tree
80
     * @param UserInterface|null $user
81
     *
82
     * @return bool
83
     */
84
    public static function isManager(Tree $tree, UserInterface $user = null): bool
85
    {
86
        $user = $user ?? self::user();
87
88
        return self::isAdmin($user) || $tree->getUserPreference($user, User::PREF_TREE_ROLE) === User::ROLE_MANAGER;
89
    }
90
91
    /**
92
     * Is the specified/current user a moderator of a tree?
93
     *
94
     * @param Tree               $tree
95
     * @param UserInterface|null $user
96
     *
97
     * @return bool
98
     */
99
    public static function isModerator(Tree $tree, UserInterface $user = null): bool
100
    {
101
        $user = $user ?? self::user();
102
103
        return self::isManager($tree, $user) || $tree->getUserPreference($user, User::PREF_TREE_ROLE) === User::ROLE_MODERATOR;
104
    }
105
106
    /**
107
     * Is the specified/current user an editor of a tree?
108
     *
109
     * @param Tree               $tree
110
     * @param UserInterface|null $user
111
     *
112
     * @return bool
113
     */
114
    public static function isEditor(Tree $tree, UserInterface $user = null): bool
115
    {
116
        $user = $user ?? self::user();
117
118
        return self::isModerator($tree, $user) || $tree->getUserPreference($user, User::PREF_TREE_ROLE) === 'edit';
119
    }
120
121
    /**
122
     * Is the specified/current user a member of a tree?
123
     *
124
     * @param Tree               $tree
125
     * @param UserInterface|null $user
126
     *
127
     * @return bool
128
     */
129
    public static function isMember(Tree $tree, UserInterface $user = null): bool
130
    {
131
        $user = $user ?? self::user();
132
133
        return self::isEditor($tree, $user) || $tree->getUserPreference($user, User::PREF_TREE_ROLE) === 'access';
134
    }
135
136
    /**
137
     * What is the specified/current user's access level within a tree?
138
     *
139
     * @param Tree               $tree
140
     * @param UserInterface|null $user
141
     *
142
     * @return int
143
     */
144
    public static function accessLevel(Tree $tree, UserInterface $user = null): int
145
    {
146
        $user = $user ?? self::user();
147
148
        if (self::isManager($tree, $user)) {
149
            return self::PRIV_NONE;
150
        }
151
152
        if (self::isMember($tree, $user)) {
153
            return self::PRIV_USER;
154
        }
155
156
        return self::PRIV_PRIVATE;
157
    }
158
159
    /**
160
     * The ID of the authenticated user, from the current session.
161
     *
162
     * @return int|null
163
     */
164
    public static function id(): ?int
165
    {
166
        return Session::get('wt_user');
167
    }
168
169
    /**
170
     * The authenticated user, from the current session.
171
     *
172
     * @return UserInterface
173
     */
174
    public static function user(): UserInterface
175
    {
176
        return app(UserService::class)->find(self::id()) ?? new GuestUser();
177
    }
178
179
    /**
180
     * Login directly as an explicit user - for masquerading.
181
     *
182
     * @param UserInterface $user
183
     *
184
     * @return void
185
     */
186
    public static function login(UserInterface $user): void
187
    {
188
        Session::regenerate(false);
189
        Session::put('wt_user', $user->id());
190
    }
191
192
    /**
193
     * End the session for the current user.
194
     *
195
     * @return void
196
     */
197
    public static function logout(): void
198
    {
199
        Session::regenerate(true);
200
    }
201
202
    /**
203
     * @param ModuleInterface $module
204
     * @param string          $component
205
     * @param Tree            $tree
206
     * @param UserInterface   $user
207
     *
208
     * @return void
209
     */
210
    public static function checkComponentAccess(ModuleInterface $module, string $component, Tree $tree, UserInterface $user): void
211
    {
212
        if ($module->accessLevel($tree, $component) < self::accessLevel($tree, $user)) {
213
            throw new HttpAccessDeniedException();
214
        }
215
    }
216
217
    /**
218
     * @param Family|null $family
219
     * @param bool        $edit
220
     *
221
     * @return Family
222
     * @throws FamilyNotFoundException
223
     * @throws FamilyAccessDeniedException
224
     */
225
    public static function checkFamilyAccess(?Family $family, bool $edit = false): Family
226
    {
227
        if ($family === null) {
228
            throw new FamilyNotFoundException();
229
        }
230
231
        if ($edit && $family->canEdit()) {
232
            return $family;
233
        }
234
235
        if ($family->canShow()) {
236
            return $family;
237
        }
238
239
        throw new FamilyAccessDeniedException();
240
    }
241
242
    /**
243
     * @param Header|null $header
244
     * @param bool        $edit
245
     *
246
     * @return Header
247
     * @throws RecordNotFoundException
248
     * @throws RecordAccessDeniedException
249
     */
250
    public static function checkHeaderAccess(?Header $header, bool $edit = false): Header
251
    {
252
        if ($header === null) {
253
            throw new RecordNotFoundException();
254
        }
255
256
        if ($edit && $header->canEdit()) {
257
            return $header;
258
        }
259
260
        if ($header->canShow()) {
261
            return $header;
262
        }
263
264
        throw new RecordAccessDeniedException();
265
    }
266
267
    /**
268
     * @param Individual|null $individual
269
     * @param bool            $edit
270
     * @param bool            $chart      For some charts, we can show private records
271
     *
272
     * @return Individual
273
     * @throws IndividualNotFoundException
274
     * @throws IndividualAccessDeniedException
275
     */
276
    public static function checkIndividualAccess(?Individual $individual, bool $edit = false, $chart = false): Individual
277
    {
278
        if ($individual === null) {
279
            throw new IndividualNotFoundException();
280
        }
281
282
        if ($edit && $individual->canEdit()) {
283
            return $individual;
284
        }
285
286
        if ($chart && $individual->tree()->getPreference('SHOW_PRIVATE_RELATIONSHIPS') === '1') {
287
            return $individual;
288
        }
289
290
        if ($individual->canShow()) {
291
            return $individual;
292
        }
293
294
        throw new IndividualAccessDeniedException();
295
    }
296
297
    /**
298
     * @param Media|null $media
299
     * @param bool       $edit
300
     *
301
     * @return Media
302
     * @throws MediaNotFoundException
303
     * @throws MediaAccessDeniedException
304
     */
305
    public static function checkMediaAccess(?Media $media, bool $edit = false): Media
306
    {
307
        if ($media === null) {
308
            throw new MediaNotFoundException();
309
        }
310
311
        if ($edit && $media->canEdit()) {
312
            return $media;
313
        }
314
315
        if ($media->canShow()) {
316
            return $media;
317
        }
318
319
        throw new MediaAccessDeniedException();
320
    }
321
322
    /**
323
     * @param Note|null $note
324
     * @param bool      $edit
325
     *
326
     * @return Note
327
     * @throws NoteNotFoundException
328
     * @throws NoteAccessDeniedException
329
     */
330
    public static function checkNoteAccess(?Note $note, bool $edit = false): Note
331
    {
332
        if ($note === null) {
333
            throw new NoteNotFoundException();
334
        }
335
336
        if ($edit && $note->canEdit()) {
337
            return $note;
338
        }
339
340
        if ($note->canShow()) {
341
            return $note;
342
        }
343
344
        throw new NoteAccessDeniedException();
345
    }
346
347
    /**
348
     * @param GedcomRecord|null $record
349
     * @param bool              $edit
350
     *
351
     * @return GedcomRecord
352
     * @throws RecordNotFoundException
353
     * @throws RecordAccessDeniedException
354
     */
355
    public static function checkRecordAccess(?GedcomRecord $record, bool $edit = false): GedcomRecord
356
    {
357
        if ($record === null) {
358
            throw new RecordNotFoundException();
359
        }
360
361
        if ($edit && $record->canEdit()) {
362
            return $record;
363
        }
364
365
        if ($record->canShow()) {
366
            return $record;
367
        }
368
369
        throw new RecordAccessDeniedException();
370
    }
371
372
    /**
373
     * @param Repository|null $repository
374
     * @param bool            $edit
375
     *
376
     * @return Repository
377
     * @throws RepositoryNotFoundException
378
     * @throws RepositoryAccessDeniedException
379
     */
380
    public static function checkRepositoryAccess(?Repository $repository, bool $edit = false): Repository
381
    {
382
        if ($repository === null) {
383
            throw new RepositoryNotFoundException();
384
        }
385
386
        if ($edit && $repository->canEdit()) {
387
            return $repository;
388
        }
389
390
        if ($repository->canShow()) {
391
            return $repository;
392
        }
393
394
        throw new RepositoryAccessDeniedException();
395
    }
396
397
    /**
398
     * @param Source|null $source
399
     * @param bool        $edit
400
     *
401
     * @return Source
402
     * @throws SourceNotFoundException
403
     * @throws SourceAccessDeniedException
404
     */
405
    public static function checkSourceAccess(?Source $source, bool $edit = false): Source
406
    {
407
        if ($source === null) {
408
            throw new SourceNotFoundException();
409
        }
410
411
        if ($edit && $source->canEdit()) {
412
            return $source;
413
        }
414
415
        if ($source->canShow()) {
416
            return $source;
417
        }
418
419
        throw new SourceAccessDeniedException();
420
    }
421
    
422
    /*
423
     * @param Submitter|null $submitter
424
     * @param bool           $edit
425
     *
426
     * @return Submitter
427
     * @throws RecordNotFoundException
428
     * @throws RecordAccessDeniedException
429
     */
430
    public static function checkSubmitterAccess(?Submitter $submitter, bool $edit = false): Submitter
431
    {
432
        if ($submitter === null) {
433
            throw new RecordNotFoundException();
434
        }
435
436
        if ($edit && $submitter->canEdit()) {
437
            return $submitter;
438
        }
439
440
        if ($submitter->canShow()) {
441
            return $submitter;
442
        }
443
444
        throw new RecordAccessDeniedException();
445
    }
446
447
    /*
448
     * @param Submission|null $submission
449
     * @param bool            $edit
450
     *
451
     * @return Submission
452
     * @throws RecordNotFoundException
453
     * @throws RecordAccessDeniedException
454
     */
455
    public static function checkSubmissionAccess(?Submission $submission, bool $edit = false): Submission
456
    {
457
        if ($submission === null) {
458
            throw new RecordNotFoundException();
459
        }
460
461
        if ($edit && $submission->canEdit()) {
462
            return $submission;
463
        }
464
465
        if ($submission->canShow()) {
466
            return $submission;
467
        }
468
469
        throw new RecordAccessDeniedException();
470
    }
471
}
472