/** * Invocation of hook SpecialPageBeforeExecute * * We use this hook to ensure that login/account creation pages * are redirected to HTTPS if they are not accessed via HTTPS and * $wgSecureLogin == true - but only when using the * mobile site. * * @param SpecialPage $special * @param string $subpage * @return bool */ public static function onSpecialPageBeforeExecute(SpecialPage $special, $subpage) { $mobileContext = MobileContext::singleton(); $isMobileView = $mobileContext->shouldDisplayMobileView(); $context = $special->getContext(); $out = $context->getOutput(); $secureLogin = $context->getConfig()->get('SecureLogin'); $request = $special->getContext()->getRequest(); $skin = $out->getSkin()->getSkinName(); $name = $special->getName(); // Ensure desktop version of Special:Preferences page gets mobile targeted modules // FIXME: Upstream to core (?) if ($skin === 'minerva') { if ($name === 'Preferences') { $out->addModules('skins.minerva.special.preferences.scripts'); } // Add default warning message to Special:UserLogin and Special:UserCreate // if no warning message set. if ($name === 'Userlogin' && !$request->getVal('warning', null) && !$context->getUser()->isLoggedIn()) { $request->setVal('warning', 'mobile-frontend-generic-login-new'); } } if ($isMobileView) { if ($name === 'Search') { $out->addModuleStyles('skins.minerva.special.search.styles'); } elseif ($name === 'Userlogin') { $out->addModuleStyles('skins.minerva.special.userlogin.styles'); $out->addModules('mobile.special.userlogin.scripts'); // make sure we're on https if we're supposed to be and currently aren't. // most of this is lifted from https redirect code in SpecialUserlogin::execute() // also, checking for 'https' in $wgServer is a little funky, but this is what // is done on the WMF cluster (see config in CommonSettings.php) if ($secureLogin && WebRequest::detectProtocol() != 'https') { // get the https url and redirect $query = $special->getContext()->getRequest()->getQueryValues(); if (isset($query['title'])) { unset($query['title']); } $url = $mobileContext->getMobileUrl($special->getFullTitle()->getFullURL($query), true); $special->getContext()->getOutput()->redirect($url); } } } return true; }
// Add a new log type $wgLogTypes[] = 'newusers'; $wgLogNames['newusers'] = 'newuserlogpage'; $wgLogHeaders['newusers'] = 'newuserlogpagetext'; $wgLogActionsHandlers['newusers/newusers'] = 'NewUsersLogFormatter'; $wgLogActionsHandlers['newusers/create'] = 'NewUsersLogFormatter'; $wgLogActionsHandlers['newusers/create2'] = 'NewUsersLogFormatter'; $wgLogActionsHandlers['newusers/byemail'] = 'NewUsersLogFormatter'; $wgLogActionsHandlers['newusers/autocreate'] = 'NewUsersLogFormatter'; } if ($wgPageLanguageUseDB) { $wgLogTypes[] = 'pagelang'; $wgLogActionsHandlers['pagelang/pagelang'] = 'PageLangLogFormatter'; } if ($wgCookieSecure === 'detect') { $wgCookieSecure = WebRequest::detectProtocol() === 'https'; } if ($wgProfileOnly) { $wgDebugLogGroups['profileoutput'] = $wgDebugLogFile; $wgDebugLogFile = ''; } // Backwards compatibility with old password limits if ($wgMinimalPasswordLength !== false) { $wgPasswordPolicy['policies']['default']['MinimalPasswordLength'] = $wgMinimalPasswordLength; } if ($wgMaximalPasswordLength !== false) { $wgPasswordPolicy['policies']['default']['MaximalPasswordLength'] = $wgMaximalPasswordLength; } // Backwards compatibility warning if (!$wgSessionsInObjectCache && !$wgSessionsInMemcached) { wfDeprecated('$wgSessionsInObjectCache = false', '1.27');
/** * Prepares a url to the Special:UserLogin with query parameters, * taking into account $wgSecureLogin * @param array $query * @return string */ public function getLoginUrl($query) { if ($this->isMobileMode) { // FIXME: Does mobile really need special casing here? $secureLogin = $this->getConfig()->get('SecureLogin'); if (WebRequest::detectProtocol() != 'https' && $secureLogin) { $loginUrl = SpecialPage::getTitleFor('Userlogin')->getFullURL($query); return $this->mobileContext->getMobileUrl($loginUrl, $secureLogin); } return SpecialPage::getTitleFor('Userlogin')->getLocalURL($query); } else { return SpecialPage::getTitleFor('Userlogin')->getFullURL($query); } }
/** * @private */ function mainLoginForm($msg, $msgtype = 'error') { global $wgEnableEmail, $wgEnableUserEmail; global $wgHiddenPrefs, $wgLoginLanguageSelector; global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration; global $wgSecureLogin, $wgSecureLoginDefaultHTTPS, $wgPasswordResetRoutes; $titleObj = $this->getTitle(); $user = $this->getUser(); $out = $this->getOutput(); if ($this->mType == 'signup') { // Block signup here if in readonly. Keeps user from // going through the process (filling out data, etc) // and being informed later. $permErrors = $titleObj->getUserPermissionsErrors('createaccount', $user, true); if (count($permErrors)) { throw new PermissionsError('createaccount', $permErrors); } elseif ($user->isBlockedFromCreateAccount()) { $this->userBlockedMessage($user->isBlockedFromCreateAccount()); return; } elseif (wfReadOnly()) { throw new ReadOnlyError(); } } // Pre-fill username (if not creating an account, bug 44775). if ($this->mUsername == '' && $this->mType != 'signup') { if ($user->isLoggedIn()) { $this->mUsername = $user->getName(); } else { $this->mUsername = $this->getRequest()->getCookie('UserName'); } } if ($this->mType == 'signup') { $out->addModules('mediawiki.special.userlogin.signup'); if ($this->mShowVForm) { $template = new UsercreateTemplateVForm(); $out->addModuleStyles(array('mediawiki.ui', 'mediawiki.special.createaccount.vform')); // XXX hack pending RL or JS parse() support for complex content messages // https://bugzilla.wikimedia.org/show_bug.cgi?id=25349 $out->addJsConfigVars('wgCreateacctImgcaptchaHelp', $this->msg('createacct-imgcaptcha-help')->parse()); $out->addModules('mediawiki.special.createaccount.vform.js'); // Must match number of benefits defined in messages $template->set('benefitCount', 3); } else { $template = new UsercreateTemplate(); } $q = 'action=submitlogin&type=signup'; $linkq = 'type=login'; $linkmsg = 'gotaccount'; } else { if ($this->mShowVForm) { $template = new UserloginTemplateVForm(); $out->addModuleStyles(array('mediawiki.ui', 'mediawiki.special.userlogin.vform')); } else { $template = new UserloginTemplate(); } $q = 'action=submitlogin&type=login'; $linkq = 'type=signup'; $linkmsg = 'nologin'; } if ($this->mReturnTo !== '') { $returnto = '&returnto=' . wfUrlencode($this->mReturnTo); if ($this->mReturnToQuery !== '') { $returnto .= '&returntoquery=' . wfUrlencode($this->mReturnToQuery); } $q .= $returnto; $linkq .= $returnto; } # Don't show a "create account" link if the user can't. if ($this->showCreateOrLoginLink($user)) { # Pass any language selection on to the mode switch link if ($wgLoginLanguageSelector && $this->mLanguage) { $linkq .= '&uselang=' . $this->mLanguage; } if (!$this->mShowVForm) { $link = Html::element('a', array('href' => $titleObj->getLocalURL($linkq)), $this->msg($linkmsg . 'link')->text()); # Calling either 'gotaccountlink' or 'nologinlink' $template->set('link', $this->msg($linkmsg)->rawParams($link)->parse()); } else { // Supply URL, login template creates the button. // (The template 'link' key, passed above, is obsolete in the VForm design.) $template->set('createOrLoginHref', $titleObj->getLocalURL($linkq)); } } else { $template->set('link', ''); } // Decide if we default stickHTTPS on if ($wgSecureLoginDefaultHTTPS && $this->mAction != 'submitlogin' && !$this->mLoginattempt) { $this->mStickHTTPS = true; } $resetLink = $this->mType == 'signup' ? null : is_array($wgPasswordResetRoutes) && in_array(true, array_values($wgPasswordResetRoutes)); $template->set('header', ''); $template->set('skin', $this->getSkin()); $template->set('name', $this->mUsername); $template->set('password', $this->mPassword); $template->set('retype', $this->mRetype); $template->set('createemailset', $this->mCreateaccountMail); $template->set('email', $this->mEmail); $template->set('realname', $this->mRealName); $template->set('domain', $this->mDomain); $template->set('reason', $this->mReason); $template->set('action', $titleObj->getLocalURL($q)); $template->set('message', $msg); $template->set('messagetype', $msgtype); $template->set('createemail', $wgEnableEmail && $user->isLoggedIn()); $template->set('userealname', !in_array('realname', $wgHiddenPrefs)); $template->set('useemail', $wgEnableEmail); $template->set('emailrequired', $wgEmailConfirmToEdit); $template->set('emailothers', $wgEnableUserEmail); $template->set('canreset', $wgAuth->allowPasswordChange()); $template->set('resetlink', $resetLink); $template->set('canremember', $wgCookieExpiration > 0); $template->set('usereason', $user->isLoggedIn()); $template->set('remember', $user->getOption('rememberpassword') || $this->mRemember); $template->set('cansecurelogin', $wgSecureLogin === true); $template->set('stickHTTPS', $this->mStickHTTPS); if ($this->mType == 'signup') { if (!self::getCreateaccountToken()) { self::setCreateaccountToken(); } $template->set('token', self::getCreateaccountToken()); } else { if (!self::getLoginToken()) { self::setLoginToken(); } $template->set('token', self::getLoginToken()); } # Prepare language selection links as needed if ($wgLoginLanguageSelector) { $template->set('languages', $this->makeLanguageSelector()); if ($this->mLanguage) { $template->set('uselang', $this->mLanguage); } } $template->set('secureLoginUrl', $this->mSecureLoginUrl); // Use loginend-https for HTTPS requests if it's not blank, loginend otherwise // Ditto for signupend. New forms use neither. $usingHTTPS = WebRequest::detectProtocol() == 'https'; $loginendHTTPS = $this->msg('loginend-https'); $signupendHTTPS = $this->msg('signupend-https'); if ($usingHTTPS && !$loginendHTTPS->isBlank()) { $template->set('loginend', $loginendHTTPS->parse()); } else { $template->set('loginend', $this->msg('loginend')->parse()); } if ($usingHTTPS && !$signupendHTTPS->isBlank()) { $template->set('signupend', $signupendHTTPS->parse()); } else { $template->set('signupend', $this->msg('signupend')->parse()); } // Give authentication and captcha plugins a chance to modify the form $wgAuth->modifyUITemplate($template, $this->mType); if ($this->mType == 'signup') { wfRunHooks('UserCreateForm', array(&$template)); } else { wfRunHooks('UserLoginForm', array(&$template)); } $out->disallowUserJs(); // just in case... $out->addTemplate($template); }
/** * Expand a potentially local URL to a fully-qualified URL. Assumes $wgServer * is correct. * * The meaning of the PROTO_* constants is as follows: * PROTO_HTTP: Output a URL starting with http:// * PROTO_HTTPS: Output a URL starting with https:// * PROTO_RELATIVE: Output a URL starting with // (protocol-relative URL) * PROTO_CURRENT: Output a URL starting with either http:// or https:// , depending on which protocol was used for the current incoming request * PROTO_CANONICAL: For URLs without a domain, like /w/index.php , use $wgCanonicalServer. For protocol-relative URLs, use the protocol of $wgCanonicalServer * PROTO_INTERNAL: Like PROTO_CANONICAL, but uses $wgInternalServer instead of $wgCanonicalServer * * @todo this won't work with current-path-relative URLs * like "subdir/foo.html", etc. * * @param $url String: either fully-qualified or a local path + query * @param $defaultProto Mixed: one of the PROTO_* constants. Determines the protocol to use if $url or $wgServer is protocol-relative * @return string Fully-qualified URL */ function wfExpandUrl($url, $defaultProto = PROTO_CURRENT) { global $wgServer, $wgCanonicalServer, $wgInternalServer; $serverUrl = $wgServer; if ($defaultProto === PROTO_CANONICAL) { $serverUrl = $wgCanonicalServer; } // Make $wgInternalServer fall back to $wgServer if not set if ($defaultProto === PROTO_INTERNAL && $wgInternalServer !== false) { $serverUrl = $wgInternalServer; } if ($defaultProto === PROTO_CURRENT) { $defaultProto = WebRequest::detectProtocol() . '://'; } // Analyze $serverUrl to obtain its protocol $bits = wfParseUrl($serverUrl); $serverHasProto = $bits && $bits['scheme'] != ''; if ($defaultProto === PROTO_CANONICAL || $defaultProto === PROTO_INTERNAL) { if ($serverHasProto) { $defaultProto = $bits['scheme'] . '://'; } else { // $wgCanonicalServer or $wgInternalServer doesn't have a protocol. This really isn't supposed to happen // Fall back to HTTP in this ridiculous case $defaultProto = PROTO_HTTP; } } $defaultProtoWithoutSlashes = substr($defaultProto, 0, -2); if (substr($url, 0, 2) == '//') { return $defaultProtoWithoutSlashes . $url; } elseif (substr($url, 0, 1) == '/') { // If $serverUrl is protocol-relative, prepend $defaultProtoWithoutSlashes, otherwise leave it alone return ($serverHasProto ? '' : $defaultProtoWithoutSlashes) . $serverUrl . $url; } else { return $url; } }
/** * @private */ function mainLoginForm($msg, $msgtype = 'error') { global $wgEnableEmail, $wgEnableUserEmail; global $wgHiddenPrefs, $wgLoginLanguageSelector; global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration; global $wgSecureLogin, $wgPasswordResetRoutes; $titleObj = $this->getTitle(); $user = $this->getUser(); if ($this->mType == 'signup') { // Block signup here if in readonly. Keeps user from // going through the process (filling out data, etc) // and being informed later. $permErrors = $titleObj->getUserPermissionsErrors('createaccount', $user, true); if (count($permErrors)) { throw new PermissionsError('createaccount', $permErrors); } elseif ($user->isBlockedFromCreateAccount()) { $this->userBlockedMessage($user->isBlockedFromCreateAccount()); return; } elseif (wfReadOnly()) { throw new ReadOnlyError(); } } if ($this->mUsername == '') { if ($user->isLoggedIn()) { $this->mUsername = $user->getName(); } else { $this->mUsername = $this->getRequest()->getCookie('UserName'); } } if ($this->mType == 'signup') { $template = new UsercreateTemplate(); $q = 'action=submitlogin&type=signup'; $linkq = 'type=login'; $linkmsg = 'gotaccount'; } else { $template = new UserloginTemplate(); $q = 'action=submitlogin&type=login'; $linkq = 'type=signup'; $linkmsg = 'nologin'; } if (!empty($this->mReturnTo)) { $returnto = '&returnto=' . wfUrlencode($this->mReturnTo); if (!empty($this->mReturnToQuery)) { $returnto .= '&returntoquery=' . wfUrlencode($this->mReturnToQuery); } $q .= $returnto; $linkq .= $returnto; } # Don't show a "create account" link if the user can't if ($this->showCreateOrLoginLink($user)) { # Pass any language selection on to the mode switch link if ($wgLoginLanguageSelector && $this->mLanguage) { $linkq .= '&uselang=' . $this->mLanguage; } $link = Html::element('a', array('href' => $titleObj->getLocalURL($linkq)), $this->msg($linkmsg . 'link')->text()); # Calling either 'gotaccountlink' or 'nologinlink' $template->set('link', $this->msg($linkmsg)->rawParams($link)->parse()); } else { $template->set('link', ''); } $resetLink = $this->mType == 'signup' ? null : is_array($wgPasswordResetRoutes) && in_array(true, array_values($wgPasswordResetRoutes)); $template->set('header', ''); $template->set('name', $this->mUsername); $template->set('password', $this->mPassword); $template->set('retype', $this->mRetype); $template->set('email', $this->mEmail); $template->set('realname', $this->mRealName); $template->set('domain', $this->mDomain); $template->set('reason', $this->mReason); $template->set('action', $titleObj->getLocalURL($q)); $template->set('message', $msg); $template->set('messagetype', $msgtype); $template->set('createemail', $wgEnableEmail && $user->isLoggedIn()); $template->set('userealname', !in_array('realname', $wgHiddenPrefs)); $template->set('useemail', $wgEnableEmail); $template->set('emailrequired', $wgEmailConfirmToEdit); $template->set('emailothers', $wgEnableUserEmail); $template->set('canreset', $wgAuth->allowPasswordChange()); $template->set('resetlink', $resetLink); $template->set('canremember', $wgCookieExpiration > 0); $template->set('usereason', $user->isLoggedIn()); $template->set('remember', $user->getOption('rememberpassword') || $this->mRemember); $template->set('cansecurelogin', $wgSecureLogin === true); $template->set('stickHTTPS', $this->mStickHTTPS); if ($this->mType == 'signup') { if (!self::getCreateaccountToken()) { self::setCreateaccountToken(); } $template->set('token', self::getCreateaccountToken()); } else { if (!self::getLoginToken()) { self::setLoginToken(); } $template->set('token', self::getLoginToken()); } # Prepare language selection links as needed if ($wgLoginLanguageSelector) { $template->set('languages', $this->makeLanguageSelector()); if ($this->mLanguage) { $template->set('uselang', $this->mLanguage); } } // Use loginend-https for HTTPS requests if it's not blank, loginend otherwise // Ditto for signupend $usingHTTPS = WebRequest::detectProtocol() == 'https'; $loginendHTTPS = $this->msg('loginend-https'); $signupendHTTPS = $this->msg('signupend-https'); if ($usingHTTPS && !$loginendHTTPS->isBlank()) { $template->set('loginend', $loginendHTTPS->parse()); } else { $template->set('loginend', $this->msg('loginend')->parse()); } if ($usingHTTPS && !$signupendHTTPS->isBlank()) { $template->set('signupend', $signupendHTTPS->parse()); } else { $template->set('signupend', $this->msg('signupend')->parse()); } // Give authentication and captcha plugins a chance to modify the form $wgAuth->modifyUITemplate($template, $this->mType); if ($this->mType == 'signup') { wfRunHooks('UserCreateForm', array(&$template)); } else { wfRunHooks('UserLoginForm', array(&$template)); } $out = $this->getOutput(); $out->disallowUserJs(); // just in case... $out->addTemplate($template); }
$deletedHashLevel = $wgHashedUploadDirectory ? 3 : 0; } $wgLocalFileRepo = array('class' => 'LocalRepo', 'name' => 'local', 'directory' => $wgUploadDirectory, 'scriptDirUrl' => $wgScriptPath, 'scriptExtension' => $wgScriptExtension, 'url' => $wgUploadBaseUrl ? $wgUploadBaseUrl . $wgUploadPath : $wgUploadPath, 'hashLevels' => $wgHashedUploadDirectory ? 2 : 0, 'thumbScriptUrl' => $wgThumbnailScriptPath, 'transformVia404' => !$wgGenerateThumbnailOnParse, 'deletedDir' => $wgDeletedDirectory, 'deletedHashLevels' => $deletedHashLevel); } /** * Initialise shared repo from backwards-compatible settings */ if ($wgUseSharedUploads) { if ($wgSharedUploadDBname) { $wgForeignFileRepos[] = array('class' => 'ForeignDBViaLBRepo', 'name' => 'shared', 'directory' => $wgSharedUploadDirectory, 'url' => $wgSharedUploadPath, 'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0, 'thumbScriptUrl' => $wgSharedThumbnailScriptPath, 'transformVia404' => !$wgGenerateThumbnailOnParse, 'dbType' => $wgDBtype, 'dbServer' => $wgDBserver, 'dbUser' => $wgDBuser, 'dbPassword' => $wgDBpassword, 'dbName' => $wgSharedUploadDBname, 'dbFlags' => ($wgDebugDumpSql ? DBO_DEBUG : 0) | DBO_DEFAULT, 'tablePrefix' => $wgSharedUploadDBprefix, 'hasSharedCache' => $wgCacheSharedUploads, 'descBaseUrl' => $wgRepositoryBaseUrl, 'fetchDescription' => $wgFetchCommonsDescriptions, 'wiki' => $wgSharedUploadDBname); } else { $wgForeignFileRepos[] = array('class' => 'FileRepo', 'name' => 'shared', 'directory' => $wgSharedUploadDirectory, 'url' => $wgSharedUploadPath, 'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0, 'thumbScriptUrl' => $wgSharedThumbnailScriptPath, 'transformVia404' => !$wgGenerateThumbnailOnParse, 'descBaseUrl' => $wgRepositoryBaseUrl, 'fetchDescription' => $wgFetchCommonsDescriptions); } } if ($wgUseInstantCommons) { $wgForeignFileRepos[] = array('class' => 'ForeignAPIRepo', 'name' => 'wikimediacommons', 'apibase' => WebRequest::detectProtocol() === 'https' ? 'https://commons.wikimedia.org/w/api.php' : 'http://commons.wikimedia.org/w/api.php', 'hashLevels' => 2, 'fetchDescription' => true, 'descriptionCacheExpiry' => 43200, 'apiThumbCacheExpiry' => 86400); } /* * Add on default file backend config for file repos. * FileBackendGroup will handle initializing the backends. */ if (!isset($wgLocalFileRepo['backend'])) { $wgLocalFileRepo['backend'] = $wgLocalFileRepo['name'] . '-backend'; } foreach ($wgForeignFileRepos as &$repo) { if (!isset($repo['directory']) && $repo['class'] === 'ForeignAPIRepo') { $repo['directory'] = $wgUploadDirectory; // b/c } if (!isset($repo['backend'])) { $repo['backend'] = $repo['name'] . '-backend';
// In case the MediaWiki default changed, T44594 # XFF log for vandal tracking $wgExtensionFunctions[] = function () { global $wmfUdp2logDest, $wgRequest; if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') { $uri = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; $xff = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : ''; $logger = LoggerFactory::getInstance('xff'); // TODO: it would be nice to log this as actual structured data // instead of this ad-hoc tab delimited format $logger->info(gmdate('r') . "\t" . "{$uri}\t" . "{$xff}, {$_SERVER['REMOTE_ADDR']}\t" . (isset($_REQUEST['wpSave']) && $_REQUEST['wpSave'] ? 'save' : '')); if ($wgRequest->getIP() === '127.0.0.1') { $logger = LoggerFactory::getInstance('localhost'); // TODO: it would be nice to log this as actual structured data // instead of this ad-hoc tab delimited format $logger->info(gmdate('r') . "\t" . wfHostname() . "\t{$xff}, {$_SERVER['REMOTE_ADDR']}\t" . WebRequest::detectProtocol()); } } }; // T26313, turn off minordefault on enwiki if ($wgDBname == 'enwiki') { $wgHiddenPrefs[] = 'minordefault'; } if ($wmgUseFooterContactLink) { $wgHooks['SkinTemplateOutputPageBeforeExec'][] = function ($sk, &$tpl) { $contactLink = Html::element('a', array('href' => $sk->msg('contact-url')->escaped()), $sk->msg('contact')->text()); $tpl->set('contact', $contactLink); $tpl->data['footerlinks']['places'][] = 'contact'; return true; }; }