Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
WebAuthn
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 14
506
0.00% covered (danger)
0.00%
0 / 1
 factory
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getWebAuthnKeys
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisplayName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 newKey
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getSecondaryAuthProvider
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isEnabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 verify
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 getManageForm
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
30
 getDescriptionMessage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisableWarningMessage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAddKeyMessage
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 isSpecial
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLoginSwitchButtonMessage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\OATHAuth\Module;
4
5use MediaWiki\Context\IContextSource;
6use MediaWiki\Context\RequestContext;
7use MediaWiki\Extension\OATHAuth\Auth\WebAuthnSecondaryAuthenticationProvider;
8use MediaWiki\Extension\OATHAuth\HTMLForm\OATHAuthOOUIHTMLForm;
9use MediaWiki\Extension\OATHAuth\HTMLForm\WebAuthnAddKeyForm;
10use MediaWiki\Extension\OATHAuth\HTMLForm\WebAuthnManageForm;
11use MediaWiki\Extension\OATHAuth\Key\WebAuthnKey;
12use MediaWiki\Extension\OATHAuth\OATHAuthModuleRegistry;
13use MediaWiki\Extension\OATHAuth\OATHUser;
14use MediaWiki\Extension\OATHAuth\OATHUserRepository;
15use MediaWiki\Extension\OATHAuth\Special\OATHManage;
16use MediaWiki\Message\Message;
17
18class WebAuthn implements IModule {
19    /**
20     * Custom action for the manage form
21     */
22    public const ACTION_ADD_KEY = 'addkey';
23
24    public const MODULE_ID = "webauthn";
25
26    public static function factory(): IModule {
27        return new static();
28    }
29
30    /**
31     * @return WebAuthnKey[]
32     */
33    public static function getWebAuthnKeys( OATHUser $user ): array {
34        // @phan-suppress-next-line PhanTypeMismatchReturn
35        return $user->getKeysForModule( self::MODULE_ID );
36    }
37
38    /** @inheritDoc */
39    public function getName(): string {
40        return self::MODULE_ID;
41    }
42
43    public function getDisplayName(): Message {
44        return wfMessage( 'oathauth-webauthn-module-label' );
45    }
46
47    public function newKey( array $data = [] ): WebAuthnKey {
48        if ( !$data ) {
49            return WebAuthnKey::newKey();
50        }
51        return WebAuthnKey::newFromData( $data );
52    }
53
54    public function getSecondaryAuthProvider(): WebAuthnSecondaryAuthenticationProvider {
55        return new WebAuthnSecondaryAuthenticationProvider();
56    }
57
58    /** @inheritDoc */
59    public function isEnabled( OATHUser $user ): bool {
60        return (bool)self::getWebAuthnKeys( $user );
61    }
62
63    /**
64     * Run the validation for each of the registered keys
65     */
66    public function verify( OATHUser $user, array $data ): bool {
67        $keys = self::getWebAuthnKeys( $user );
68        foreach ( $keys as $key ) {
69            // Pass if any of the keys matches
70            if ( $key->verify( $user, $data ) ) {
71                return true;
72            }
73        }
74        return false;
75    }
76
77    /**
78     * Returns the appropriate form for the given action.
79     * If the ability to add new credentials is disabled by configuration,
80     * the empty string will be returned for any action other than ACTION_DISABLE.
81     * The value null will be returned If no suitable form is found otherwise.
82     */
83    public function getManageForm(
84        string $action,
85        OATHUser $user,
86        OATHUserRepository $repo,
87        IContextSource $context,
88        OATHAuthModuleRegistry $registry
89    ): ?OATHAuthOOUIHTMLForm {
90        if ( $context->getConfig()->get( 'WebAuthnNewCredsDisabled' ) === false ) {
91            if ( $action === OATHManage::ACTION_ENABLE || $action === static::ACTION_ADD_KEY ) {
92                return new WebAuthnAddKeyForm( $user, $repo, $this, $context, $registry );
93            }
94            if ( $this->isEnabled( $user ) ) {
95                return new WebAuthnManageForm( $user, $repo, $this, $context, $registry );
96            }
97        }
98
99        return null;
100    }
101
102    /** @inheritDoc */
103    public function getDescriptionMessage(): Message {
104        return wfMessage( 'oathauth-webauthn-module-description' );
105    }
106
107    /** @inheritDoc */
108    public function getDisableWarningMessage(): ?Message {
109        return null;
110    }
111
112    /** @inheritDoc */
113    public function getAddKeyMessage(): ?Message {
114        return RequestContext::getMain()->getConfig()->get( 'WebAuthnNewCredsDisabled' ) ?
115            null :
116            wfMessage( 'oathauth-webauthn-add-security-key' );
117    }
118
119    /** @inheritDoc */
120    public function isSpecial(): bool {
121        return false;
122    }
123
124    /** @inheritDoc */
125    public function getLoginSwitchButtonMessage(): Message {
126        return wfMessage( 'oathauth-webauthn-auth-switch-module-label-passkey' );
127    }
128}