diff --git a/OATHAuth.alias.php b/OATHAuth.alias.php
index fc20b548..6947347e 100644
--- a/OATHAuth.alias.php
+++ b/OATHAuth.alias.php
@@ -12,7 +12,8 @@ $specialPageAliases = [];
$specialPageAliases['en'] = [
'DisableOATHForUser' => [ 'DisableOATHForUser' ],
'OATHManage' => [ 'Manage_Two-factor_authentication', 'OATH_Manage', 'OATHManage',
- 'OATH', 'Two-factor_authentication', 'OATHAuth' ]
+ 'OATH', 'Two-factor_authentication', 'OATHAuth' ],
+ 'VerifyOATHForUser' => [ 'VerifyOATHForUser' ],
];
/** Arabic (العربية) */
diff --git a/extension.json b/extension.json
index e792e4c4..a07b5035 100644
--- a/extension.json
+++ b/extension.json
@@ -90,12 +90,14 @@
},
"SpecialPages": {
"DisableOATHForUser": "\\MediaWiki\\Extension\\OATHAuth\\Special\\DisableOATHForUser",
+ "VerifyOATHForUser": "\\MediaWiki\\Extension\\OATHAuth\\Special\\VerifyOATHForUser",
"OATHManage": "\\MediaWiki\\Extension\\OATHAuth\\Special\\OATHManage"
},
"AvailableRights": [
"oathauth-enable",
"oathauth-api-all",
"oathauth-disable-for-user",
+ "oathauth-verify-user",
"oathauth-view-log"
],
"GroupPermissions": {
@@ -108,6 +110,7 @@
},
"sysop": {
"oathauth-disable-for-user": true,
+ "oathauth-verify-user": true,
"oathauth-view-log": true
}
},
diff --git a/i18n/en.json b/i18n/en.json
index 748f8408..0081b319 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -28,13 +28,17 @@
"oathauth-step4": "Step 4: Verification",
"oathauth-entertoken": "Enter a code from your authentication device to verify:",
"oathauth-disable-for-user": "Disable two-factor authentication for a user",
+ "oathauth-verify-for-user": "Verify if a user has two-factor authentication enabled",
"right-oathauth-disable-for-user": "Disable two-factor authentication for a user",
"action-oathauth-disable-for-user": "disable two-factor authentication for a user",
+ "right-oathauth-verify-user": "Verify whether a user has two-factor authentication enabled",
+ "action-oathauth-verify-user": "verify whether a user has two-factor authentication enabled",
"right-oathauth-view-log": "Access to log of two-factor authentication changes",
"action-oathauth-view-log": "access to log of two-factor authentication changes",
"oathauth-disable-intro": "With great power, comes great responsibility",
"oathauth-enteruser": "Username:",
- "oathauth-enterreason": "Reason for disabling:",
+ "oathauth-enterdisablereason": "Reason for disabling:",
+ "oathauth-enterverifyreason": "Reason for checking:",
"oathauth-user-not-does-not-have-oath-enabled": "User doesn't have two-factor authentication enabled, so nothing to disable",
"right-oathauth-enable": "Enable two-factor authentication",
"action-oathauth-enable": "enable two-factor authentication",
@@ -52,6 +56,7 @@
"oath-log-name": "Two-factor authentication log",
"oath-log-header": "These events track changes to users' two-factor authentication status.",
"logentry-oath-disable-other": "$1 {{GENDER:$2|disabled}} the two-factor authentication of $3",
+ "logentry-oath-verify": "$1 {{GENDER:$2|checked}} if $3 had two-factor authentication enabled",
"oauthauth-ui-no-module": "None enabled",
"oathauth-module-invalid": "The OATHAuth module that the user has registered is invalid.",
"oathauth-module-totp-label": "TOTP (one-time token)",
@@ -75,5 +80,7 @@
"oathauth-switch-method-warning-header": "Confirm switching to a different authentication method",
"oathauth-switch-method-warning": "By switching to $2 two-factor authentication method, current method ($1) will be disabled, and all the data associated with the current authentication method will be deleted",
"oathauth-totp-disable-warning": "You will no longer be able to use the authentication device registered with this account. All scratch-tokens associated with this account will be invalidated.",
- "oathauth-invalidrequest": "Invalid request"
+ "oathauth-invalidrequest": "Invalid request",
+ "oathauth-verify-enabled": "{{GENDER:$1|$1}} has two-factor authentication enabled.",
+ "oathauth-verify-disabled": "{{GENDER:$1|$1}} does not have two-factor authentication enabled."
}
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 1fa6cc87..d0fb0d41 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -40,13 +40,17 @@
"oathauth-step4": "Label for step 4 information on Special:OATH",
"oathauth-entertoken": "Label on input field on Special:OATH asking user to enter token",
"oathauth-disable-for-user": "Title of the special page to disable other users' two-factor authentication (OATH)",
+ "oathauth-verify-for-user": "Title of the special page to verify other users' two-factor authentication (OATH) status",
"right-oathauth-disable-for-user": "{{doc-right|oathauth-disable-for-user}}",
"action-oathauth-disable-for-user": "{{doc-action|oathauth-disable-for-user}}",
+ "right-oathauth-verify-user": "{{doc-right|oathauth-verify-user}}",
+ "action-oathauth-verify-user": "{{doc-action|oathauth-verify-user}}",
"right-oathauth-view-log": "{{doc-right|oathauth-view-log}}",
"action-oathauth-view-log": "{{doc-action|oathauth-view-log}}",
"oathauth-disable-intro": "Intro message for special to disable other users' two-factor authentication (OATH)",
- "oathauth-enteruser": "Label for user field in special page to disable",
- "oathauth-enterreason": "Label for field for reason in special page to disable",
+ "oathauth-enteruser": "Label for user field in special page to verify or disable two-factor authentication",
+ "oathauth-enterdisablereason": "Label for field for reason in special page to disable two-factor authentication",
+ "oathauth-enterverifyreason": "Label for field for reason in special page to verify two-factor authentication",
"oathauth-user-not-does-not-have-oath-enabled": "Error message when user does not have two-factor authentication (OATH) enabled",
"right-oathauth-enable": "{{doc-right|oathauth-enable}}",
"action-oathauth-enable": "{{doc-action|oathauth-enable}}",
@@ -64,6 +68,7 @@
"oath-log-name": "The Special:Log log name that appears in the drop-down on the Special:Log page",
"oath-log-header": "The Special:Log description that appears on the Special:Log page when you filter logs on this specific log name",
"logentry-oath-disable-other": "The template of the log entry message\n\n* $1
is the person disabling the two-factor authentication.\n* $2
is the user whose 2FA is being disabled.\n* $3
is the user whose 2FA is being disabled (again).",
+ "logentry-oath-verify": "The template of the log entry message\n\n* $1
is the person verifying the two-factor authentication.\n* $2
is the user whose 2FA is being verified.\n* $3
is the user whose 2FA is being verified (again).",
"oauthauth-ui-no-module": "User preference value when no 2FA module is enabled",
"oathauth-module-invalid": "Error message when the OATHAuth module registered by user is invalid",
"oathauth-module-totp-label": "User preference value when the TOTP module is enabled",
@@ -87,5 +92,7 @@
"oathauth-switch-method-warning-header": "Page title for warning page when switching to an alternative 2FA method",
"oathauth-switch-method-warning": "Generic message warning the user of token/data loss when switching to an alternative method.\n$1 - Current method name, $2 - Name of the method that is being switched to",
"oathauth-totp-disable-warning": "TOTP specific warning message when disabling/switching to alternative 2FA method",
- "oathauth-invalidrequest": "Generic error message that is displayed when request cannot be processed due to an unpredicted reason"
+ "oathauth-invalidrequest": "Generic error message that is displayed when request cannot be processed due to an unpredicted reason",
+ "oathauth-verify-enabled": "Notice that a user has 2FA enabled, shown on success at [[Special:VerifyOATHForUser]].\n$1 - Name of user",
+ "oathauth-verify-disabled": "Notice that a user does not have 2FA enabled, shown on success at [[Special:VerifyOATHForUser]].\n$1 - Name of user"
}
diff --git a/src/Special/DisableOATHForUser.php b/src/Special/DisableOATHForUser.php
index 520769a7..a34a30cc 100644
--- a/src/Special/DisableOATHForUser.php
+++ b/src/Special/DisableOATHForUser.php
@@ -97,7 +97,7 @@ class DisableOATHForUser extends FormSpecialPage {
'reason' => [
'type' => 'text',
'default' => '',
- 'label-message' => 'oathauth-enterreason',
+ 'label-message' => 'oathauth-enterdisablereason',
'name' => 'reason',
'required' => true,
],
diff --git a/src/Special/VerifyOATHForUser.php b/src/Special/VerifyOATHForUser.php
new file mode 100644
index 00000000..a93690e8
--- /dev/null
+++ b/src/Special/VerifyOATHForUser.php
@@ -0,0 +1,160 @@
+userRepo = MediaWikiServices::getInstance()->getService( 'OATHUserRepository' );
+ }
+
+ public function doesWrites() {
+ return true;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLoginSecurityLevel() {
+ return $this->getName();
+ }
+
+ /**
+ * @param HTMLForm $form
+ */
+ public function alterForm( HTMLForm $form ) {
+ $form->setMessagePrefix( 'oathauth' );
+ $form->getOutput()->setPageTitle( $this->msg( 'oathauth-verify-for-user' ) );
+ }
+
+ /**
+ * @return string
+ */
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
+ /**
+ * @return bool
+ */
+ public function requiresUnblock() {
+ return true;
+ }
+
+ /**
+ * @param string $par
+ */
+ public function execute( $par ) {
+ $this->getOutput()->disallowUserJs();
+ parent::execute( $par );
+ }
+
+ /**
+ * @return array[]
+ */
+ protected function getFormFields() {
+ return [
+ 'user' => [
+ 'type' => 'user',
+ 'default' => '',
+ 'label-message' => 'oathauth-enteruser',
+ 'name' => 'user',
+ 'required' => true,
+ ],
+ 'reason' => [
+ 'type' => 'text',
+ 'default' => '',
+ 'label-message' => 'oathauth-enterverifyreason',
+ 'name' => 'reason',
+ 'required' => true,
+ ],
+ ];
+ }
+
+ /**
+ * @param array $formData
+ * @return array|true
+ * @throws ConfigException
+ * @throws MWException
+ */
+ public function onSubmit( array $formData ) {
+ $this->targetUser = $formData['user'];
+ $user = User::newFromName( $this->targetUser );
+ if ( !$user || $user->getId() === 0 ) {
+ return [ 'oathauth-user-not-found' ];
+ }
+ $oathUser = $this->userRepo->findByUser( $user );
+
+ if ( !( $oathUser->getModule() instanceof IModule ) ||
+ !$oathUser->getModule()->isEnabled( $oathUser ) ) {
+ $result = self::OATHAUTH_NOT_ENABLED;
+ } else {
+ $result = self::OATHAUTH_IS_ENABLED;
+ }
+
+ $this->enabledStatus = $result;
+
+ $logEntry = new ManualLogEntry( 'oath', 'verify' );
+ $logEntry->setPerformer( $this->getUser() );
+ $logEntry->setTarget( $user->getUserPage() );
+ $logEntry->setComment( $formData['reason'] );
+ $logEntry->insert();
+
+ LoggerFactory::getInstance( 'authentication' )->info(
+ 'OATHAuth status checked for {usertarget} by {user} from {clientip}', [
+ 'user' => $this->getUser()->getName(),
+ 'usertarget' => $this->targetUser,
+ 'clientip' => $this->getRequest()->getIP(),
+ ]
+ );
+
+ return true;
+ }
+
+ /**
+ * @throws MWException
+ */
+ public function onSuccess() {
+ switch ( $this->enabledStatus ) {
+ case self::OATHAUTH_IS_ENABLED:
+ $msg = 'oathauth-verify-enabled';
+ break;
+ case self::OATHAUTH_NOT_ENABLED:
+ $msg = 'oathauth-verify-disabled';
+ break;
+ default:
+ throw new MWException(
+ 'Verification was successful but status is unknown'
+ );
+ }
+
+ $out = $this->getOutput();
+ $out->addBacklinkSubtitle( $this->getPageTitle() );
+ $out->addWikiMsg( $msg, $this->targetUser );
+ }
+
+}