You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
7.1 KiB
PHP

<?php
namespace Isekai\OIDC;
use MediaWiki\MediaWikiServices;
use MediaWiki\Html\Html;
use MediaWiki\Output\OutputPage;
use MediaWiki\Context\RequestContext;
use MediaWiki\Title\Title;
use MediaWiki\User\User;
class IsekaiOIDCAuthHooks {
const SYNLOGIN_SESSIONKEY = 'IsekaiOIDCSyncLogin';
const SYNLOGOUT_SESSIONKEY = 'IsekaiOIDCSyncLogout';
public static function onRegistration() {
$passwordProviders = [
'MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider',
'MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider'
];
$providers = $GLOBALS['wgAuthManagerAutoConfig'];
if ( isset( $providers['primaryauth'] ) ) {
$primaries = $providers['primaryauth'];
foreach ( $primaries as $key => $provider ) {
if ( in_array( $provider['class'], $passwordProviders ) ) {
unset( $GLOBALS['wgAuthManagerAutoConfig']['primaryauth'][$key] );
}
}
}
}
/**
* Implements LoadExtensionSchemaUpdates hook.
*
* @param \DatabaseUpdater $updater
*/
public static function loadExtensionSchemaUpdates( $updater ) {
$dir = dirname(__DIR__) . '/sql/';
$type = $updater->getDB()->getType();
$updater->addExtensionTable( 'isekai_oidc',
$dir . $type . '/AddTable.sql' );
}
/**
* Implements PageBeforeDisplay hook.
* @param OutputPage $out
*/
public static function onBeforePageDisplay($out) {
$services = MediaWikiServices::getInstance();
$wgIsekaiOIDC = $services->getMainConfig()->get('IsekaiOIDC');
if (isset($wgIsekaiOIDC['syncLogout']) && $wgIsekaiOIDC['syncLogout']) {
$title = $out->getTitle();
$request = RequestContext::getMain()->getRequest();
$needLogout = $request->getCookie(self::SYNLOGOUT_SESSIONKEY);
$isLogoutPage = $title != null && $title->isSpecial('Userlogout');
if ($isLogoutPage || $needLogout) { // 需要重定向到用户退出页面
$oldName = $request->getCookie('UserName');
wfDebugLog('IsekaiOIDC', 'oldUser: ' . $oldName);
$oldUser = MediaWikiServices::getInstance()->getUserFactory()->newFromName($oldName);
if ( $oldUser === false ) {
return;
}
list($subject, $accessToken, $refreshToken) = IsekaiOIDCAuth::findOidcDataByUserId($oldUser->getId());
if ($subject != null) {
$redirectUri = '';
if ($isLogoutPage) {
$returnto = $request->getVal('returnto');
$returntoquery = $request->getVal('returntoquery');
if ($returnto) {
$returnto = Title::newFromText($returnto);
} else {
$returnto = Title::newMainPage();
}
if (!$returnto) {
$returnto = Title::newMainPage();
}
$redirectUri = Title::newMainPage()->getFullURL($returntoquery);
} else if ($title != null) {
$redirectUri = $title->getFullURL();
} else {
$redirectUri = Title::newMainPage()->getFullURL();
}
$url = $wgIsekaiOIDC['endpoint'] . 'protocol/openid-connect/logout?' .
http_build_query([ 'redirect_uri' => $redirectUri ]);
wfDebugLog('IsekaiOIDC', 'logout url: ' . $url);
$response = $request->response();
$response->clearCookie(self::SYNLOGOUT_SESSIONKEY);
$response->header('Location: ' . $url);
}
}
}
}
public static function onLogout($user, &$injected_html) {
$request = RequestContext::getMain()->getRequest();
$request->response()->setCookie(self::SYNLOGOUT_SESSIONKEY, 1);
}
public static function onGetPreferences(User $user, &$preferences) {
$services = MediaWikiServices::getInstance();
$wgIsekaiOIDC = $services->getMainConfig()->get('IsekaiOIDC');
$profileUrl = $wgIsekaiOIDC['endpoint'] . 'account/';
$referrer = $wgIsekaiOIDC['clientID'];
$referrerUri = Title::newFromText('Special:Preferences')->getCanonicalURL();
$profileUrl .= '?' . http_build_query([
'referrer' => $referrer,
'referrer_uri' => $referrerUri
]);
$preferences['global-profile'] = array(
'type' => 'info',
'raw' => true,
'label-message' => 'prefs-global-profile',
'help-message' => 'prefs-help-golbal-profile',
'default' => strval(new \OOUI\ButtonWidget([
'id' => 'global-profile-link',
'href' => $profileUrl,
'label' => wfMessage('btn-idp-profile-settings')->text(),
])),
'section' => 'personal/info',
);
if (isset($wgIsekaiOIDC['avatarUrl'])) {
list($subject, $accessToken, $refreshToken) = IsekaiOIDCAuth::findOidcDataByUserId($user->getId());
$avatarLink = str_replace(['{openid}', '{username}'], [urlencode($subject), urlencode($user->getName())], $wgIsekaiOIDC['avatarUrl']);
$preferences['editavatar'] = array(
'type' => 'info',
'raw' => true,
'label-message' => 'prefs-editavatar',
'default' => Html::openElement('a', [
'href' => $profileUrl,
]) .
'<img src="' . $avatarLink . '" alt="avatar" width="64" height="64">' .
Html::closeElement('a'),
'section' => 'personal/info',
);
}
return true;
}
/**
* @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($links['user-menu']['login'])) {
$links['user-menu']['login']['text'] = wfMessage('nav-login-createaccount')->text();
}
}
/**
* @param $vars
* @param string $skin
* @param \Config $config
* @return bool
*/
public static function onResourceLoaderGetConfigVars(&$vars, $skin, $config) {
$services = MediaWikiServices::getInstance();
$wgIsekaiOIDC = $services->getMainConfig()->get('IsekaiOIDC');
if (isset($wgIsekaiOIDC['avatarUrl'])) {
$vars['wgAvatarTemplate'] = '/api.php?action=query&prop=oidcavatar&username={username}&redirect=1&format=json';
}
return true;
}
/**
* Get avatar url for users
* @param array &$avatars
* @param \User[] $users
* @param int $size
*/
public static function onGetUsersAvatar(&$avatars, array $users, $size = 128) {
if (!is_array($avatars)) {
$avatars = [];
}
$services = MediaWikiServices::getInstance();
$config = $services->getMainConfig();
$wgIsekaiOIDC = $config->get('IsekaiOIDC');
if (isset($wgIsekaiOIDC['avatarUrl'])) {
$userIds = array_map(function($user) {
return $user->getId();
}, $users);
$subjects = IsekaiOIDCAuth::findOidcSubjectsByUserIds($userIds);
foreach ($users as $user) {
$subject = null;
if (isset($subjects[$user->getId()])) {
$subject = $subjects[$user->getId()];
}
$avatarFinded = false;
if ($subject) {
$avatarUrl = str_replace(['{openid}', '{username}'], [urlencode($subject), urlencode($user->getName())], $wgIsekaiOIDC['avatarUrl']);
$avatarFinded = true;
} else {
if (isset($wgIsekaiOIDC['defaultAvatarUrl'])) {
$avatarUrl = $wgIsekaiOIDC['defaultAvatarUrl'];
$avatarFinded = true;
}
}
if ($avatarFinded) {
if ($size <= 64) {
$avatarUrl = "$avatarUrl?size=md";
} else if ($size <= 128) {
$avatarUrl = "$avatarUrl?size=lg";
} else if ($size <= 256) {
$avatarUrl = "$avatarUrl?size=xl";
} else {
$avatarUrl = "$avatarUrl?size=xxl";
}
$avatars[$user->getId()] = $avatarUrl;
}
}
}
return true;
}
}