diff --git a/extension.json b/extension.json index 0339746..3c0d43e 100644 --- a/extension.json +++ b/extension.json @@ -1,14 +1,14 @@ { "name": "Isekai OpenID Connect", "namemsg": "isekai-oidc-name", - "author": "hyperzlib", - "version": "1.1.0", + "author": "Hyperzlib", + "version": "1.1.2", "url": "https://www.isekai.cn", "descriptionmsg": "isekai-oidc-desc", "license-name": "MIT", "type": "other", "requires": { - + "MediaWiki": ">= 1.35.0" }, "MessagesDirs": { "IsekaiOIDC": [ @@ -28,7 +28,7 @@ "BeforePageDisplay": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onBeforePageDisplay", "UserLogoutComplete": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onLogout", "GetPreferences": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onGetPreferences", - "PersonalUrls": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onPersonalUrls", + "SkinTemplateNavigation::Universal": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onSkinTemplateUniversalNavigation", "ResourceLoaderGetConfigVars": "Isekai\\OIDC\\IsekaiOIDCAuthHooks::onResourceLoaderGetConfigVars" }, "ExtensionMessagesFiles": { diff --git a/includes/ApiOidcWebhook.php b/includes/ApiOidcWebhook.php index b0f0f83..c4aafe6 100644 --- a/includes/ApiOidcWebhook.php +++ b/includes/ApiOidcWebhook.php @@ -3,9 +3,8 @@ namespace Isekai\OIDC; use ApiBase; +use MediaWiki\MediaWikiServices; use Wikimedia\ParamValidator\ParamValidator; -use Isekai\OIDC\IsekaiOIDCAuth; -use User; class ApiOidcWebhook extends ApiBase { public function __construct( $main, $method ) { @@ -38,17 +37,19 @@ class ApiOidcWebhook extends ApiBase { private function keycloakCallback() { if (!$this->getRequest()->wasPosted()) { - return $this->addError('isekaioidc-api-post-body-invalid'); + $this->addError('isekaioidc-api-post-body-invalid'); + return; } $postBody = $this->getRequest()->getRawPostString(); $postData = json_decode($postBody); if (!$this->getRequest()->wasPosted() || !$postData) { - return $this->addError('isekaioidc-api-post-body-invalid'); + $this->addError('isekaioidc-api-post-body-invalid'); + return; } global $wgIsekaiOIDC; $realm = $wgIsekaiOIDC['realm']; - $apiMode = isset($wgIsekaiOIDC['apiMode']) ? $wgIsekaiOIDC['apiMode'] : 'oauth'; + $apiMode = $wgIsekaiOIDC['apiMode'] ?? 'oauth'; $eventType = $postData->type; $subject = $postData->userId; @@ -75,7 +76,7 @@ class ApiOidcWebhook extends ApiBase { 'phone' => $userInfo->phone_number, ]; - $user = User::newFromId($userId); + $user = MediaWikiServices::getInstance()->getUserFactory()->newFromId($userId); IsekaiOIDCAuth::updateUserInfo($user, $newProfile); } $this->getResult()->addValue(null, 'webhook', 1); @@ -85,11 +86,11 @@ class ApiOidcWebhook extends ApiBase { return [ 'provider' => [ ParamValidator::PARAM_DEFAULT => null, - ApiBase::PARAM_TYPE => 'text', + ParamValidator::PARAM_TYPE => 'text', ], 'key' => [ ParamValidator::PARAM_DEFAULT => null, - ApiBase::PARAM_TYPE => 'text', + ParamValidator::PARAM_TYPE => 'text', ] ]; } diff --git a/includes/IsekaiOIDCAuth.php b/includes/IsekaiOIDCAuth.php index a6407bf..6d82b99 100644 --- a/includes/IsekaiOIDCAuth.php +++ b/includes/IsekaiOIDCAuth.php @@ -15,10 +15,9 @@ use Title; use SpecialPage; use Sanitizer; use RequestContext; -use WebRequest; class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { - + private $subject; const LOG_TAG = 'Isekai OIDC'; @@ -72,7 +71,7 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { public function continuePrimaryAuthentication( array $reqs ) { global $wgIsekaiOIDC; $config = $wgIsekaiOIDC; - + $oidc =self::getOpenIDConnectClient(); if ($oidc->authenticate()) { $accessToken = $oidc->getAccessToken(); @@ -87,13 +86,8 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { if ( isset( $payload->remember_me ) && $payload->remember_me ) { $GLOBALS['wgIsekaiOIDCRemember'] = true; } - - if ( method_exists( MediaWikiServices::class, 'getAuthManager' ) ) { - // MediaWiki 1.35+ - $authManager = MediaWikiServices::getInstance()->getAuthManager(); - } else { - $authManager = AuthManager::singleton(); - } + + $authManager = MediaWikiServices::getInstance()->getAuthManager(); $request = RequestContext::getMain()->getRequest(); $session = $request->getSession(); $session->clear('AuthManager::AutoCreateBlacklist'); // 防止缓存检测 @@ -107,7 +101,7 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { //$authManager->setAuthenticationSessionData(self::BIO_SESSION_KEY, $bio); $authManager->setAuthenticationSessionData(self::ACCESS_TOKEN_SESSION_KEY, $accessToken); $authManager->setAuthenticationSessionData(self::REFRESH_TOKEN_SESSION_KEY, $refreshToken); - + list( $id, $username ) = $this->findUser( $this->subject ); if ( $id !== null ) { @@ -308,22 +302,17 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { */ public static function updateUserInfo($user, $data = null) { if (is_string($user)) { - $user = User::newFromName($user); + $user = MediaWikiServices::getInstance()->getUserFactory()->newFromName($user); } if ($data) { - $accessToken = isset($data['accessToken']) ? $data['accessToken'] : null; - $refreshToken = isset($data['refreshToken']) ? $data['refreshToken'] : null; - $newEmail = isset($data['email']) ? $data['email'] : null; - $newRealName = isset($data['realname']) ? $data['realname'] : null; - $newPhone = isset($data['phone']) ? $data['phone'] : null; + $accessToken = $data['accessToken'] ?? null; + $refreshToken = $data['refreshToken'] ?? null; + $newEmail = $data['email'] ?? null; + $newRealName = $data['realname'] ?? null; + $newPhone = $data['phone'] ?? null; } else { - if ( method_exists( MediaWikiServices::class, 'getAuthManager' ) ) { - // MediaWiki 1.35+ - $authManager = MediaWikiServices::getInstance()->getAuthManager(); - } else { - $authManager = AuthManager::singleton(); - } + $authManager = MediaWikiServices::getInstance()->getAuthManager(); $accessToken = $authManager->getAuthenticationSessionData(self::ACCESS_TOKEN_SESSION_KEY); $refreshToken = $authManager->getAuthenticationSessionData(self::REFRESH_TOKEN_SESSION_KEY); @@ -340,7 +329,8 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { wfDebugLog( self::LOG_TAG, 'update access token for: ' . $user->getId() . '.' . PHP_EOL ); - $dbw = wfGetDB( DB_MASTER ); + + $dbw = MediaWikiServices::getInstance()->getDBLoadBalancer()->getMaintenanceConnectionRef( DB_PRIMARY ); $dbw->upsert( self::OIDC_TABLE, [ @@ -382,19 +372,15 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { * @param int $id user id */ public function saveExtraAttributes( $id ) { - if ( method_exists( MediaWikiServices::class, 'getAuthManager' ) ) { - // MediaWiki 1.35+ - $authManager = MediaWikiServices::getInstance()->getAuthManager(); - } else { - $authManager = AuthManager::singleton(); - } + $authManager = MediaWikiServices::getInstance()->getAuthManager(); + if ( $this->subject === null ) { $this->subject = $authManager->getAuthenticationSessionData( self::OIDC_SUBJECT_SESSION_KEY ); $authManager->removeAuthenticationSessionData( self::OIDC_SUBJECT_SESSION_KEY ); } - $dbw = wfGetDB( DB_MASTER ); + $dbw = MediaWikiServices::getInstance()->getDBLoadBalancer()->getMaintenanceConnectionRef( DB_PRIMARY ); $dbw->upsert( self::OIDC_TABLE, [ @@ -412,7 +398,7 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { } public static function findUser( $subject ) { - $dbr = wfGetDB( DB_REPLICA ); + $dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getMaintenanceConnectionRef( DB_REPLICA ); $row = $dbr->selectRow( [ 'user', @@ -441,7 +427,7 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { } public static function findOidcDataByUserId( $userId ) { - $dbr = wfGetDB( DB_REPLICA ); + $dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getMaintenanceConnectionRef( DB_REPLICA ); $row = $dbr->selectRow( [ self::OIDC_TABLE @@ -503,7 +489,7 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { return null; } $username = $nt->getText(); - $dbr = wfGetDB( DB_REPLICA ); + $dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getMaintenanceConnectionRef( DB_REPLICA ); $row = $dbr->selectRow( [ 'user', @@ -531,7 +517,7 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { private static function getMigratedIdByEmail( $email ) { wfDebugLog( self::LOG_TAG, 'Matching user to email ' . $email . '.' . PHP_EOL ); - $dbr = wfGetDB( DB_REPLICA ); + $dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getMaintenanceConnectionRef( DB_REPLICA ); $row = $dbr->selectRow( [ 'user', @@ -565,19 +551,25 @@ class IsekaiOIDCAuth extends AbstractPrimaryAuthenticationProvider { $preferred_username = 'User'; } - if ( User::idFromName( $preferred_username ) === null ) { + if ( MediaWikiServices::getInstance() + ->getUserIdentityLookup() + ->getUserIdentityByName( $preferred_username ) ) { + return $preferred_username; } $count = 1; - while ( User::idFromName( $preferred_username . $count ) !== null ) { - $count++; + while ( MediaWikiServices::getInstance() + ->getUserIdentityLookup() + ->getUserIdentityByName( $preferred_username . $count ) ) { + + $count ++; } return $preferred_username . $count; } - protected static function punycodeEnc($str){ + protected static function punycodeEnc( $str ){ $punycode = new PunyCode(); - return $punycode->encode($str); + return $punycode->encode( $str ); } } diff --git a/includes/IsekaiOIDCAuthHooks.php b/includes/IsekaiOIDCAuthHooks.php index ff40fa2..0b490c2 100644 --- a/includes/IsekaiOIDCAuthHooks.php +++ b/includes/IsekaiOIDCAuthHooks.php @@ -1,13 +1,10 @@ getCookie(self::SYNLOGOUT_SESSIONKEY); $isLogoutPage = $title != null && $title->isSpecial('Userlogout'); if ($isLogoutPage || $needLogout) { // 需要重定向到用户退出页面 - $old_name = $request->getCookie('UserName'); - wfDebugLog('IsekaiOIDC', 'oldUser: ' . $old_name); - - $oldUser = User::newFromName($old_name); + $oldName = $request->getCookie('UserName'); + wfDebugLog('IsekaiOIDC', 'oldUser: ' . $oldName); + + $oldUser = MediaWikiServices::getInstance()->getUserFactory()->newFromName($oldName); if ( $oldUser === false ) { return; } @@ -132,7 +129,7 @@ class IsekaiOIDCAuthHooks { 'default' => Html::openElement('a', [ 'href' => $profileUrl, ]) . - '' . + 'avatar' . Html::closeElement('a'), 'section' => 'personal/info', ); @@ -141,25 +138,26 @@ class IsekaiOIDCAuthHooks { return true; } - /** - * @param array &$personal_urls - * @param Title $title - * @param \SkinTemplate $skin - */ - public static function onPersonalUrls(&$personal_urls, $title, $skin) { - if (isset($personal_urls['createaccount'])) { - unset($personal_urls['createaccount']); + /** + * @param \SkinTemplate $skinTemplate + * @param $links + * @return void + */ + public static function onSkinTemplateUniversalNavigation(\SkinTemplate $skinTemplate, &$links) { + if (isset($links['user-menu']['createaccount'])) { + unset($links['user-menu']['createaccount']); } - if (isset($personal_urls['login'])) { - $personal_urls['login']['text'] = wfMessage('nav-login-createaccount')->text(); + if (isset($links['user-menu']['login'])) { + $links['user-menu']['login']['text'] = wfMessage('nav-login-createaccount')->text(); } } - /** - * @param array &$personal_urls - * @param string $skin - * @param \Config $config - */ + /** + * @param $vars + * @param string $skin + * @param \Config $config + * @return bool + */ public static function onResourceLoaderGetConfigVars(&$vars, $skin, $config) { global $wgIsekaiOIDC; if (isset($wgIsekaiOIDC['avatarUrl'])) { diff --git a/includes/SpecialIsekaiOIDCCallback.php b/includes/SpecialIsekaiOIDCCallback.php index fc9979a..6d19f87 100644 --- a/includes/SpecialIsekaiOIDCCallback.php +++ b/includes/SpecialIsekaiOIDCCallback.php @@ -41,7 +41,7 @@ class SpecialIsekaiOIDCCallback extends LoginSignupSpecialPage { public function setHeaders() { // override the page title if we are doing a forced reauthentication parent::setHeaders(); - if ( $this->securityLevel && $this->getUser()->isLoggedIn() ) { + if ( $this->securityLevel && $this->getUser()->isRegistered() ) { $this->getOutput()->setPageTitle( $this->msg( 'login-security' ) ); } } @@ -50,17 +50,22 @@ class SpecialIsekaiOIDCCallback extends LoginSignupSpecialPage { return false; } - /** - * Run any hooks registered for logins, then HTTP redirect to - * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a - * nice message here, but that's really not as useful as just being sent to - * wherever you logged in from. It should be clear that the action was - * successful, given the lack of error messages plus the appearance of your - * name in the upper right. - * @param bool $direct True if the action was successful just now; false if that happened - * pre-redirection (so this handler was called already) - * @param StatusValue|null $extraMessages - */ + /** + * Run any hooks registered for logins, then HTTP redirect to + * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a + * nice message here, but that's really not as useful as just being sent to + * wherever you logged in from. It should be clear that the action was + * successful, given the lack of error messages plus the appearance of your + * name in the upper right. + * @param bool $direct True if the action was successful just now; false if that happened + * pre-redirection (so this handler was called already) + * @param \StatusValue|null $extraMessages + * @throws \ErrorPageError + * @throws \FatalError + * @throws \MWException + * @throws \PermissionsError + * @throws \ReadOnlyError + */ protected function successfulAction( $direct = false, $extraMessages = null ) { global $wgSecureLogin, $wgIsekaiOIDCRemember; @@ -110,7 +115,7 @@ class SpecialIsekaiOIDCCallback extends LoginSignupSpecialPage { } protected function clearToken() { - return $this->getRequest()->getSession()->resetToken( 'AuthManagerSpecialPage:IsekaiOIDCCallback' ); + $this->getRequest()->getSession()->resetToken( 'AuthManagerSpecialPage:IsekaiOIDCCallback' ); } protected function getTokenName() {