Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.11% covered (warning)
85.11%
40 / 47
88.24% covered (warning)
88.24%
15 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
OATHUser
85.11% covered (warning)
85.11%
40 / 47
88.24% covered (warning)
88.24%
15 / 17
19.07
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCentralId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIssuer
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 getAccount
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getKeys
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getKeysForModule
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getKeyById
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 removeKey
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 removeKeysForModule
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 addKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isTwoFactorAuthEnabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 disable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNonSpecialKeys
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 userHasNonSpecialEnabledKeys
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUserHandle
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setUserHandle
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * @license GPL-2.0-or-later
4 */
5
6namespace MediaWiki\Extension\OATHAuth;
7
8use MediaWiki\Extension\OATHAuth\Key\AuthKey;
9use MediaWiki\User\UserIdentity;
10
11/**
12 * Class representing a user from OATH's perspective
13 *
14 * @ingroup Extensions
15 */
16class OATHUser {
17    /** @var AuthKey[] */
18    private array $keys = [];
19
20    private ?string $userHandle = null;
21
22    /**
23     * Constructor. Can't be called directly. Use OATHUserRepository::findByUser instead.
24     */
25    public function __construct(
26        private readonly UserIdentity $user,
27        private readonly int $centralId,
28    ) {
29    }
30
31    public function getUser(): UserIdentity {
32        return $this->user;
33    }
34
35    /**
36     * @return int The central ID of this user
37     */
38    public function getCentralId(): int {
39        return $this->centralId;
40    }
41
42    public function getIssuer(): string {
43        global $wgSitename, $wgOATHAuthAccountPrefix;
44
45        if ( $wgOATHAuthAccountPrefix !== false ) {
46            return $wgOATHAuthAccountPrefix;
47        }
48        return $wgSitename;
49    }
50
51    public function getAccount(): string {
52        return $this->user->getName();
53    }
54
55    /**
56     * Get the key associated with this user.
57     *
58     * @return AuthKey[]
59     */
60    public function getKeys(): array {
61        return $this->keys;
62    }
63
64    /**
65     * @param string $moduleName As in IModule::getName().
66     * @return AuthKey[]
67     */
68    public function getKeysForModule( string $moduleName ): array {
69        return array_values(
70            array_filter(
71                $this->keys,
72                static fn ( AuthKey $key ) => $key->getModule() === $moduleName
73            )
74        );
75    }
76
77    public function getKeyById( int $id ): ?AuthKey {
78        $matchingKeys = array_values(
79            array_filter(
80                $this->keys,
81                static fn ( AuthKey $key ) => $key->getId() === $id
82            )
83        );
84        return $matchingKeys[0] ?? null;
85    }
86
87    public function removeKey( AuthKey $key ) {
88        $keyId = $key->getId();
89        $this->keys = array_values(
90            array_filter(
91                $this->keys,
92                static fn ( AuthKey $key ) => $key->getId() !== $keyId
93            )
94        );
95    }
96
97    /**
98     * @param string $moduleName As in IModule::getName()
99     */
100    public function removeKeysForModule( string $moduleName ): void {
101        $this->keys = array_values(
102            array_filter(
103                $this->keys,
104                static fn ( AuthKey $key ) => $key->getModule() !== $moduleName
105            )
106        );
107    }
108
109    /**
110     * Adds a single key to the key array
111     */
112    public function addKey( AuthKey $key ) {
113        $this->keys[] = $key;
114    }
115
116    /**
117     * @return bool Whether this user has two-factor authentication enabled or not
118     */
119    public function isTwoFactorAuthEnabled(): bool {
120        return count( $this->getKeys() ) >= 1;
121    }
122
123    /**
124     * Disables current (if any) auth method
125     */
126    public function disable() {
127        $this->keys = [];
128    }
129
130    /**
131     * Get all the user's keys, but exclude special keys
132     * @return AuthKey[]
133     */
134    public function getNonSpecialKeys(): array {
135        $moduleRegistry = OATHAuthServices::getInstance()->getModuleRegistry();
136        return array_values(
137            array_filter(
138                $this->keys,
139                static fn ( AuthKey $key ) => !$moduleRegistry->getModuleByKey( $key->getModule() )->isSpecial()
140            )
141        );
142    }
143
144    /**
145     * Returns a bool indicating whether a user has _any_ 2fa modules enabled
146     * which are not considered "special" modules, as defined via IModule::isSpecial()
147     */
148    public function userHasNonSpecialEnabledKeys(): bool {
149        return count( $this->getNonSpecialKeys() ) > 0;
150    }
151
152    /**
153     * Get the user's WebAuthn User Handle value. The User Handle appears in each of the user's
154     * WebAuthn keys, and is used to identify the user based on one of their WebAuthn keys.
155     * See also OATHUserRepository::findByUserHandle().
156     *
157     * For more information about User Handles, see
158     * https://developers.yubico.com/WebAuthn/WebAuthn_Developer_Guide/User_Handle.html
159     */
160    public function getUserHandle(): ?string {
161        return $this->userHandle;
162    }
163
164    /**
165     * Set the User Handle. This should only be used by OATHUserRepository.
166     * @internal
167     */
168    public function setUserHandle( ?string $userHandle ): void {
169        $this->userHandle = $userHandle;
170    }
171}