xref: /webtrees/app/Auth.php (revision 9867b2f0bfec6864e75b2501f3e96895ff42db48)
1a25f0a04SGreg Roach<?php
2a25f0a04SGreg Roach/**
3a25f0a04SGreg Roach * webtrees: online genealogy
48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team
5a25f0a04SGreg Roach * This program is free software: you can redistribute it and/or modify
6a25f0a04SGreg Roach * it under the terms of the GNU General Public License as published by
7a25f0a04SGreg Roach * the Free Software Foundation, either version 3 of the License, or
8a25f0a04SGreg Roach * (at your option) any later version.
9a25f0a04SGreg Roach * This program is distributed in the hope that it will be useful,
10a25f0a04SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
11a25f0a04SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12a25f0a04SGreg Roach * GNU General Public License for more details.
13a25f0a04SGreg Roach * You should have received a copy of the GNU General Public License
14a25f0a04SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
15a25f0a04SGreg Roach */
16e7f56f2aSGreg Roachdeclare(strict_types=1);
17e7f56f2aSGreg Roach
1876692c8bSGreg Roachnamespace Fisharebest\Webtrees;
19a25f0a04SGreg Roach
20e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\FamilyAccessDeniedException;
21e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\FamilyNotFoundException;
22e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\IndividualAccessDeniedException;
23e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\IndividualNotFoundException;
24e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\MediaAccessDeniedException;
25e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\MediaNotFoundException;
26e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\NoteAccessDeniedException;
27e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\NoteNotFoundException;
28e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\RecordAccessDeniedException;
29e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\RecordNotFoundException;
30e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\RepositoryAccessDeniedException;
31e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\RepositoryNotFoundException;
32e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\SourceAccessDeniedException;
33e539f5c6SGreg Roachuse Fisharebest\Webtrees\Exceptions\SourceNotFoundException;
34*9867b2f0SGreg Roachuse Fisharebest\Webtrees\Module\ModuleInterface;
3579529c87SGreg Roachuse stdClass;
36*9867b2f0SGreg Roachuse Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
3779529c87SGreg Roach
38a25f0a04SGreg Roach/**
3976692c8bSGreg Roach * Authentication.
40a25f0a04SGreg Roach */
41c1010edaSGreg Roachclass Auth
42c1010edaSGreg Roach{
434b9ff166SGreg Roach    // Privacy constants
4416d6367aSGreg Roach    public const PRIV_PRIVATE = 2; // Allows visitors to view the item
4516d6367aSGreg Roach    public const PRIV_USER    = 1; // Allows members to access the item
4616d6367aSGreg Roach    public const PRIV_NONE    = 0; // Allows managers to access the item
4716d6367aSGreg Roach    public const PRIV_HIDE    = -1; // Hide the item to all users
484b9ff166SGreg Roach
49a25f0a04SGreg Roach    /**
50a25f0a04SGreg Roach     * Are we currently logged in?
51a25f0a04SGreg Roach     *
52cbc1590aSGreg Roach     * @return bool
53a25f0a04SGreg Roach     */
548f53f488SRico Sonntag    public static function check(): bool
55c1010edaSGreg Roach    {
564b9ff166SGreg Roach        return self::id() !== null;
57a25f0a04SGreg Roach    }
58a25f0a04SGreg Roach
59a25f0a04SGreg Roach    /**
60a25f0a04SGreg Roach     * Is the specified/current user an administrator?
61a25f0a04SGreg Roach     *
62a25f0a04SGreg Roach     * @param User|null $user
63a25f0a04SGreg Roach     *
64cbc1590aSGreg Roach     * @return bool
65a25f0a04SGreg Roach     */
668f53f488SRico Sonntag    public static function isAdmin(User $user = null): bool
67c1010edaSGreg Roach    {
68cb923727SGreg Roach        $user = $user ?? self::user();
69a25f0a04SGreg Roach
70cb923727SGreg Roach        return $user->getPreference('canadmin') === '1';
71a25f0a04SGreg Roach    }
72a25f0a04SGreg Roach
73a25f0a04SGreg Roach    /**
744b9ff166SGreg Roach     * Is the specified/current user a manager of a tree?
75a25f0a04SGreg Roach     *
7684caa210SGreg Roach     * @param Tree      $tree
77a25f0a04SGreg Roach     * @param User|null $user
78a25f0a04SGreg Roach     *
79cbc1590aSGreg Roach     * @return bool
80a25f0a04SGreg Roach     */
818f53f488SRico Sonntag    public static function isManager(Tree $tree, User $user = null): bool
82c1010edaSGreg Roach    {
83cb923727SGreg Roach        $user = $user ?? self::user();
84a25f0a04SGreg Roach
85cb923727SGreg Roach        return self::isAdmin($user) || $tree->getUserPreference($user, 'canedit') === 'admin';
86a25f0a04SGreg Roach    }
87a25f0a04SGreg Roach
88a25f0a04SGreg Roach    /**
894b9ff166SGreg Roach     * Is the specified/current user a moderator of a tree?
90a25f0a04SGreg Roach     *
9184caa210SGreg Roach     * @param Tree      $tree
92a25f0a04SGreg Roach     * @param User|null $user
93a25f0a04SGreg Roach     *
94cbc1590aSGreg Roach     * @return bool
95a25f0a04SGreg Roach     */
968f53f488SRico Sonntag    public static function isModerator(Tree $tree, User $user = null): bool
97c1010edaSGreg Roach    {
98cb923727SGreg Roach        $user = $user ?? self::user();
99a25f0a04SGreg Roach
100cb923727SGreg Roach        return self::isManager($tree, $user) || $tree->getUserPreference($user, 'canedit') === 'accept';
101a25f0a04SGreg Roach    }
102a25f0a04SGreg Roach
103a25f0a04SGreg Roach    /**
1044b9ff166SGreg Roach     * Is the specified/current user an editor of a tree?
105a25f0a04SGreg Roach     *
10684caa210SGreg Roach     * @param Tree      $tree
107a25f0a04SGreg Roach     * @param User|null $user
108a25f0a04SGreg Roach     *
109cbc1590aSGreg Roach     * @return bool
110a25f0a04SGreg Roach     */
1118f53f488SRico Sonntag    public static function isEditor(Tree $tree, User $user = null): bool
112c1010edaSGreg Roach    {
113cb923727SGreg Roach        $user = $user ?? self::user();
114a25f0a04SGreg Roach
115cb923727SGreg Roach        return self::isModerator($tree, $user) || $tree->getUserPreference($user, 'canedit') === 'edit';
116a25f0a04SGreg Roach    }
117a25f0a04SGreg Roach
118a25f0a04SGreg Roach    /**
1194b9ff166SGreg Roach     * Is the specified/current user a member of a tree?
120a25f0a04SGreg Roach     *
12184caa210SGreg Roach     * @param Tree      $tree
122a25f0a04SGreg Roach     * @param User|null $user
123a25f0a04SGreg Roach     *
124cbc1590aSGreg Roach     * @return bool
125a25f0a04SGreg Roach     */
1268f53f488SRico Sonntag    public static function isMember(Tree $tree, User $user = null): bool
127c1010edaSGreg Roach    {
128cb923727SGreg Roach        $user = $user ?? self::user();
129a25f0a04SGreg Roach
130cb923727SGreg Roach        return self::isEditor($tree, $user) || $tree->getUserPreference($user, 'canedit') === 'access';
131a25f0a04SGreg Roach    }
132a25f0a04SGreg Roach
133a25f0a04SGreg Roach    /**
1344b9ff166SGreg Roach     * What is the specified/current user's access level within a tree?
1354b9ff166SGreg Roach     *
1364b9ff166SGreg Roach     * @param Tree      $tree
1374b9ff166SGreg Roach     * @param User|null $user
1384b9ff166SGreg Roach     *
139cbc1590aSGreg Roach     * @return int
1404b9ff166SGreg Roach     */
141c1010edaSGreg Roach    public static function accessLevel(Tree $tree, User $user = null)
142c1010edaSGreg Roach    {
143cb923727SGreg Roach        $user = $user ?? self::user();
1444b9ff166SGreg Roach
1454b9ff166SGreg Roach        if (self::isManager($tree, $user)) {
1464b9ff166SGreg Roach            return self::PRIV_NONE;
1474b9ff166SGreg Roach        }
148b2ce94c6SRico Sonntag
149b2ce94c6SRico Sonntag        if (self::isMember($tree, $user)) {
150b2ce94c6SRico Sonntag            return self::PRIV_USER;
151b2ce94c6SRico Sonntag        }
152b2ce94c6SRico Sonntag
153b2ce94c6SRico Sonntag        return self::PRIV_PRIVATE;
1544b9ff166SGreg Roach    }
1554b9ff166SGreg Roach
1564b9ff166SGreg Roach    /**
157a25f0a04SGreg Roach     * The ID of the authenticated user, from the current session.
158a25f0a04SGreg Roach     *
159c3ffc4cbSGreg Roach     * @return int|null
160a25f0a04SGreg Roach     */
161c1010edaSGreg Roach    public static function id()
162c1010edaSGreg Roach    {
16331bc7874SGreg Roach        return Session::get('wt_user');
164a25f0a04SGreg Roach    }
165a25f0a04SGreg Roach
166a25f0a04SGreg Roach    /**
167a25f0a04SGreg Roach     * The authenticated user, from the current session.
168a25f0a04SGreg Roach     *
169a25f0a04SGreg Roach     * @return User
170a25f0a04SGreg Roach     */
171c1010edaSGreg Roach    public static function user()
172c1010edaSGreg Roach    {
1738b67c11aSGreg Roach        return User::find(self::id()) ?? User::visitor();
174a25f0a04SGreg Roach    }
175a25f0a04SGreg Roach
176a25f0a04SGreg Roach    /**
177a25f0a04SGreg Roach     * Login directly as an explicit user - for masquerading.
178a25f0a04SGreg Roach     *
179a25f0a04SGreg Roach     * @param User $user
180cb923727SGreg Roach     *
181cb923727SGreg Roach     * @return void
182a25f0a04SGreg Roach     */
183c1010edaSGreg Roach    public static function login(User $user)
184c1010edaSGreg Roach    {
185e988f922SGreg Roach        Session::regenerate(false);
186895230eeSGreg Roach        Session::put('wt_user', $user->id());
187a25f0a04SGreg Roach    }
188a25f0a04SGreg Roach
189a25f0a04SGreg Roach    /**
190a25f0a04SGreg Roach     * End the session for the current user.
191cb923727SGreg Roach     *
192cb923727SGreg Roach     * @return void
193a25f0a04SGreg Roach     */
194c1010edaSGreg Roach    public static function logout()
195c1010edaSGreg Roach    {
19631bc7874SGreg Roach        Session::regenerate(true);
197a25f0a04SGreg Roach    }
198e539f5c6SGreg Roach
199e539f5c6SGreg Roach    /**
200*9867b2f0SGreg Roach     * @param ModuleInterface $module
201*9867b2f0SGreg Roach     * @param string          $component
202*9867b2f0SGreg Roach     * @param Tree            $tree
203*9867b2f0SGreg Roach     * @param User            $user
204*9867b2f0SGreg Roach     *
205*9867b2f0SGreg Roach     * @return void
206*9867b2f0SGreg Roach     */
207*9867b2f0SGreg Roach    public static function checkComponentAccess(ModuleInterface $module, string $component, Tree $tree, User $user)
208*9867b2f0SGreg Roach    {
209*9867b2f0SGreg Roach        if ($module->accessLevel($tree, $component) < Auth::accessLevel($tree, $user)) {
210*9867b2f0SGreg Roach            throw new AccessDeniedHttpException('');
211*9867b2f0SGreg Roach        }
212*9867b2f0SGreg Roach    }
213*9867b2f0SGreg Roach
214*9867b2f0SGreg Roach    /**
215e539f5c6SGreg Roach     * @param Family|null $family
216e539f5c6SGreg Roach     * @param bool|null   $edit
217e539f5c6SGreg Roach     *
218e539f5c6SGreg Roach     * @return void
219e539f5c6SGreg Roach     * @throws FamilyNotFoundException
220e539f5c6SGreg Roach     * @throws FamilyAccessDeniedException
221e539f5c6SGreg Roach     */
222e539f5c6SGreg Roach    public static function checkFamilyAccess(Family $family = null, $edit = false)
223e539f5c6SGreg Roach    {
224e539f5c6SGreg Roach        if ($family === null) {
225e539f5c6SGreg Roach            throw new FamilyNotFoundException();
226e539f5c6SGreg Roach        }
227e539f5c6SGreg Roach
228e539f5c6SGreg Roach        if (!$family->canShow() || $edit && (!$family->canEdit() || $family->isPendingDeletion())) {
229e539f5c6SGreg Roach            throw new FamilyAccessDeniedException();
230e539f5c6SGreg Roach        }
231e539f5c6SGreg Roach    }
232e539f5c6SGreg Roach
233e539f5c6SGreg Roach    /**
234e539f5c6SGreg Roach     * @param Individual|null $individual
235e539f5c6SGreg Roach     * @param bool|null       $edit
236e539f5c6SGreg Roach     *
237e539f5c6SGreg Roach     * @return void
238e539f5c6SGreg Roach     * @throws IndividualNotFoundException
239e539f5c6SGreg Roach     * @throws IndividualAccessDeniedException
240e539f5c6SGreg Roach     */
241e539f5c6SGreg Roach    public static function checkIndividualAccess(Individual $individual = null, $edit = false)
242e539f5c6SGreg Roach    {
243e539f5c6SGreg Roach        if ($individual === null) {
244e539f5c6SGreg Roach            throw new IndividualNotFoundException();
245e539f5c6SGreg Roach        }
246e539f5c6SGreg Roach
247e539f5c6SGreg Roach        if (!$individual->canShow() || $edit && (!$individual->canEdit() || $individual->isPendingDeletion())) {
248e539f5c6SGreg Roach            throw new IndividualAccessDeniedException();
249e539f5c6SGreg Roach        }
250e539f5c6SGreg Roach    }
251e539f5c6SGreg Roach
252e539f5c6SGreg Roach    /**
253e539f5c6SGreg Roach     * @param Media|null $media
254e539f5c6SGreg Roach     * @param bool|null  $edit
255e539f5c6SGreg Roach     *
256e539f5c6SGreg Roach     * @return void
257e539f5c6SGreg Roach     * @throws MediaNotFoundException
258e539f5c6SGreg Roach     * @throws MediaAccessDeniedException
259e539f5c6SGreg Roach     */
260e539f5c6SGreg Roach    public static function checkMediaAccess(Media $media = null, $edit = false)
261e539f5c6SGreg Roach    {
262e539f5c6SGreg Roach        if ($media === null) {
263e539f5c6SGreg Roach            throw new MediaNotFoundException();
264e539f5c6SGreg Roach        }
265e539f5c6SGreg Roach
266e539f5c6SGreg Roach        if (!$media->canShow() || $edit && (!$media->canEdit() || $media->isPendingDeletion())) {
267e539f5c6SGreg Roach            throw new MediaAccessDeniedException();
268e539f5c6SGreg Roach        }
269e539f5c6SGreg Roach    }
270e539f5c6SGreg Roach
271e539f5c6SGreg Roach    /**
272e539f5c6SGreg Roach     * @param Note|null $note
273e539f5c6SGreg Roach     * @param bool|null $edit
274e539f5c6SGreg Roach     *
275e539f5c6SGreg Roach     * @return void
276e539f5c6SGreg Roach     * @throws NoteNotFoundException
277e539f5c6SGreg Roach     * @throws NoteAccessDeniedException
278e539f5c6SGreg Roach     */
279e539f5c6SGreg Roach    public static function checkNoteAccess(Note $note = null, $edit = false)
280e539f5c6SGreg Roach    {
281e539f5c6SGreg Roach        if ($note === null) {
282e539f5c6SGreg Roach            throw new NoteNotFoundException();
283e539f5c6SGreg Roach        }
284e539f5c6SGreg Roach
285e539f5c6SGreg Roach        if (!$note->canShow() || $edit && (!$note->canEdit() || $note->isPendingDeletion())) {
286e539f5c6SGreg Roach            throw new NoteAccessDeniedException();
287e539f5c6SGreg Roach        }
288e539f5c6SGreg Roach    }
289e539f5c6SGreg Roach
290e539f5c6SGreg Roach    /**
291e539f5c6SGreg Roach     * @param GedcomRecord|null $record
292e539f5c6SGreg Roach     * @param bool|null         $edit
293e539f5c6SGreg Roach     *
294e539f5c6SGreg Roach     * @return void
295e539f5c6SGreg Roach     * @throws RecordNotFoundException
296e539f5c6SGreg Roach     * @throws RecordAccessDeniedException
297e539f5c6SGreg Roach     */
298e539f5c6SGreg Roach    public static function checkRecordAccess(GedcomRecord $record = null, $edit = false)
299e539f5c6SGreg Roach    {
300e539f5c6SGreg Roach        if ($record === null) {
301e539f5c6SGreg Roach            throw new RecordNotFoundException();
302e539f5c6SGreg Roach        }
303e539f5c6SGreg Roach
304e539f5c6SGreg Roach        if (!$record->canShow() || $edit && (!$record->canEdit() || $record->isPendingDeletion())) {
305e539f5c6SGreg Roach            throw new RecordAccessDeniedException();
306e539f5c6SGreg Roach        }
307e539f5c6SGreg Roach    }
308e539f5c6SGreg Roach
309e539f5c6SGreg Roach    /**
310e539f5c6SGreg Roach     * @param Repository|null $repository
311e539f5c6SGreg Roach     * @param bool|null       $edit
312e539f5c6SGreg Roach     *
313e539f5c6SGreg Roach     * @return void
314e539f5c6SGreg Roach     * @throws RepositoryNotFoundException
315e539f5c6SGreg Roach     * @throws RepositoryAccessDeniedException
316e539f5c6SGreg Roach     */
317e539f5c6SGreg Roach    public static function checkRepositoryAccess(Repository $repository = null, $edit = false)
318e539f5c6SGreg Roach    {
319e539f5c6SGreg Roach        if ($repository === null) {
320e539f5c6SGreg Roach            throw new RepositoryNotFoundException();
321e539f5c6SGreg Roach        }
322e539f5c6SGreg Roach
323e539f5c6SGreg Roach        if (!$repository->canShow() || $edit && (!$repository->canEdit() || $repository->isPendingDeletion())) {
324e539f5c6SGreg Roach            throw new RepositoryAccessDeniedException();
325e539f5c6SGreg Roach        }
326e539f5c6SGreg Roach    }
327e539f5c6SGreg Roach
328e539f5c6SGreg Roach    /**
329e539f5c6SGreg Roach     * @param Source|null $source
330e539f5c6SGreg Roach     * @param bool|null   $edit
331e539f5c6SGreg Roach     *
332e539f5c6SGreg Roach     * @return void
333e539f5c6SGreg Roach     * @throws SourceNotFoundException
334e539f5c6SGreg Roach     * @throws SourceAccessDeniedException
335e539f5c6SGreg Roach     */
336e539f5c6SGreg Roach    public static function checkSourceAccess(Source $source = null, $edit = false)
337e539f5c6SGreg Roach    {
338e539f5c6SGreg Roach        if ($source === null) {
339e539f5c6SGreg Roach            throw new SourceNotFoundException();
340e539f5c6SGreg Roach        }
341e539f5c6SGreg Roach
342e539f5c6SGreg Roach        if (!$source->canShow() || $edit && (!$source->canEdit() || $source->isPendingDeletion())) {
343e539f5c6SGreg Roach            throw new SourceAccessDeniedException();
344e539f5c6SGreg Roach        }
345e539f5c6SGreg Roach    }
346a25f0a04SGreg Roach}
347