diff options
author | Luke Shumaker <lukeshu@sbcglobal.net> | 2016-08-02 16:31:15 -0400 |
---|---|---|
committer | Luke Shumaker <lukeshu@sbcglobal.net> | 2016-08-02 16:31:15 -0400 |
commit | 7099c40bcc035e3b96ddd3e976d1cdbcfbf09398 (patch) | |
tree | 2fbc86f9c4cba01c0a266b7fefdd38b1ec3b5c01 /includes | |
parent | a5f917bbc55e295896b8084f6657eb8b6abaf8a8 (diff) | |
parent | b5e7f46db0fcb6f251206eaf36339ad3ad589f8b (diff) |
Merge branch 'archwiki' into lukeshu/masterHEADproductionmaster
Diffstat (limited to 'includes')
32 files changed, 234 insertions, 91 deletions
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 61fec6e1..7498a021 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -75,7 +75,7 @@ $wgConfigRegistry = array( * MediaWiki version number * @since 1.2 */ -$wgVersion = '1.26.2'; +$wgVersion = '1.26.3'; /** * Name of the site. It must be changed in LocalSettings.php @@ -4188,7 +4188,13 @@ $wgDebugTidy = false; $wgRawHtml = false; /** - * Set a default target for external links, e.g. _blank to pop up a new window + * Set a default target for external links, e.g. _blank to pop up a new window. + * + * This will also set the "noreferrer" and "noopener" link rel to prevent the + * attack described at https://mathiasbynens.github.io/rel-noopener/ . + * Some older browsers may not support these link attributes, hence + * setting $wgExternalLinkTarget to _blank may represent a security risk + * to some of your users. */ $wgExternalLinkTarget = false; @@ -4438,9 +4444,9 @@ $wgPasswordConfig = array( ), 'pbkdf2' => array( 'class' => 'Pbkdf2Password', - 'algo' => 'sha256', - 'cost' => '10000', - 'length' => '128', + 'algo' => 'sha512', + 'cost' => '30000', + 'length' => '64', ), ); diff --git a/includes/Defines.php b/includes/Defines.php index d55bbcf8..2f3d64fe 100644 --- a/includes/Defines.php +++ b/includes/Defines.php @@ -304,3 +304,9 @@ define( 'CONTENT_FORMAT_JSON', 'application/json' ); // for future use with the api, and for use by extensions define( 'CONTENT_FORMAT_XML', 'application/xml' ); /**@}*/ + +/**@{ + * Max string length for shell invocations; based on binfmts.h + */ +define( 'SHELL_MAX_ARG_STRLEN', '100000'); +/**@}*/ diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 64aa87ec..c4d5b5bc 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -2812,6 +2812,14 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(), } wfDebug( "wfShellExec: $cmd\n" ); + // Don't try to execute commands that exceed Linux's MAX_ARG_STRLEN. + // Other platforms may be more accomodating, but we don't want to be + // accomodating, because very long commands probably include user + // input. See T129506. + if ( strlen( $cmd ) > SHELL_MAX_ARG_STRLEN ) { + throw new Exception( __METHOD__ . '(): total length of $cmd must not exceed SHELL_MAX_ARG_STRLEN' ); + } + $desc = array( 0 => array( 'file', 'php://stdin', 'r' ), 1 => array( 'pipe', 'w' ), diff --git a/includes/Import.php b/includes/Import.php index 6a0bfd09..db4a6b2d 100644 --- a/includes/Import.php +++ b/includes/Import.php @@ -728,13 +728,14 @@ class WikiImporter { $title = $this->processTitle( $pageInfo['title'], isset( $pageInfo['ns'] ) ? $pageInfo['ns'] : null ); - if ( !$title ) { + // $title is either an array of two titles or false. + if ( is_array( $title ) ) { + $this->pageCallback( $title ); + list( $pageInfo['_title'], $foreignTitle ) = $title; + } else { $badTitle = true; $skip = true; } - - $this->pageCallback( $title ); - list( $pageInfo['_title'], $foreignTitle ) = $title; } if ( $title ) { @@ -750,10 +751,17 @@ class WikiImporter { } } - $this->pageOutCallback( $pageInfo['_title'], $foreignTitle, + // @note $pageInfo is only set if a valid $title is processed above with + // no error. If we have a valid $title, then pageCallback is called + // above, $pageInfo['title'] is set and we do pageOutCallback here. + // If $pageInfo['_title'] is not set, then $foreignTitle is also not + // set since they both come from $title above. + if ( array_key_exists( '_title', $pageInfo ) ) { + $this->pageOutCallback( $pageInfo['_title'], $foreignTitle, $pageInfo['revisionCount'], $pageInfo['successfulRevisionCount'], $pageInfo ); + } } /** diff --git a/includes/Linker.php b/includes/Linker.php index 9b5ff27b..f0fa4a5a 100644 --- a/includes/Linker.php +++ b/includes/Linker.php @@ -1073,7 +1073,16 @@ class Linker { if ( !$title ) { $title = $wgTitle; } - $attribs['rel'] = Parser::getExternalLinkRel( $url, $title ); + $newRel = Parser::getExternalLinkRel( $url, $title ); + if ( !isset( $attribs['rel'] ) || $attribs['rel'] === '' ) { + $attribs['rel'] = $newRel; + } elseif( $newRel !== '' ) { + // Merge the rel attributes. + $newRels = explode( ' ', $newRel ); + $oldRels = explode( ' ', $attribs['rel'] ); + $combined = array_unique( array_merge( $newRels, $oldRels ) ); + $attribs['rel'] = implode( ' ', $combined ); + } $link = ''; $success = Hooks::run( 'LinkerMakeExternalLink', array( &$url, &$text, &$link, &$attribs, $linktype ) ); diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php index 2da2f6ce..a902f367 100644 --- a/includes/MediaWiki.php +++ b/includes/MediaWiki.php @@ -806,9 +806,18 @@ class MediaWiki { $errno = $errstr = null; $info = wfParseUrl( $this->config->get( 'Server' ) ); MediaWiki\suppressWarnings(); + $host = $info['host']; + $port = 80; + if ( isset( $info['scheme'] ) && $info['scheme'] == 'https' ) { + $host = "tls://" . $host; + $port = 443; + } + if ( isset( $info['port'] ) ) { + $port = $info['port']; + } $sock = fsockopen( - $info['host'], - isset( $info['port'] ) ? $info['port'] : 80, + $host, + $port, $errno, $errstr, // If it takes more than 100ms to connect to ourselves there diff --git a/includes/OutputHandler.php b/includes/OutputHandler.php index c6209eeb..dd99361e 100644 --- a/includes/OutputHandler.php +++ b/includes/OutputHandler.php @@ -154,8 +154,8 @@ function wfGzipHandler( $s ) { */ function wfMangleFlashPolicy( $s ) { # Avoid weird excessive memory usage in PCRE on big articles - if ( preg_match( '/\<\s*cross-domain-policy\s*\>/i', $s ) ) { - return preg_replace( '/\<\s*cross-domain-policy\s*\>/i', '<NOT-cross-domain-policy>', $s ); + if ( preg_match( '/\<\s*cross-domain-policy(?=\s|\>)/i', $s ) ) { + return preg_replace( '/\<(\s*)(cross-domain-policy(?=\s|\>))/i', '<$1NOT-$2', $s ); } else { return $s; } diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 69ed8def..324cab34 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -610,20 +610,6 @@ class OutputPage extends ContextSource { * @return array Array of module names */ public function getModuleStyles( $filter = false, $position = null ) { - // T97420 - $resourceLoader = $this->getResourceLoader(); - - foreach ( $this->mModuleStyles as $val ) { - $module = $resourceLoader->getModule( $val ); - - if ( $module instanceof ResourceLoaderModule && $module->isPositionDefault() ) { - $warning = __METHOD__ . ': style module should define its position explicitly: ' . - $val . ' ' . get_class( $module ); - wfDebugLog( 'resourceloader', $warning ); - wfLogWarning( $warning ); - } - } - return $this->getModules( $filter, $position, 'mModuleStyles' ); } @@ -2044,6 +2030,11 @@ class OutputPage extends ContextSource { * @return string */ public function getVaryHeader() { + // If we vary on cookies, let's make sure it's always included here too. + if ( $this->getCacheVaryCookies() ) { + $this->addVaryHeader( 'Cookie' ); + } + return 'Vary: ' . join( ', ', array_keys( $this->mVaryHeader ) ); } @@ -3074,10 +3065,6 @@ class OutputPage extends ContextSource { ResourceLoaderModule::TYPE_SCRIPTS ); - $links[] = $this->makeResourceLoaderLink( $this->getModuleStyles( true, 'bottom' ), - ResourceLoaderModule::TYPE_STYLES - ); - // Modules requests - let the client calculate dependencies and batch requests as it likes // Only load modules that have marked themselves for loading at the bottom $modules = $this->getModules( true, 'bottom' ); @@ -3140,9 +3127,6 @@ class OutputPage extends ContextSource { * @return string */ function getBottomScripts() { - // In case the skin wants to add bottom CSS - $this->getSkin()->setupSkinUserCss( $this ); - return $this->getScriptsForBottomQueue(); } @@ -3665,7 +3649,7 @@ class OutputPage extends ContextSource { $otherTags = array(); // Tags to append after the normal <link> tags $resourceLoader = $this->getResourceLoader(); - $moduleStyles = $this->getModuleStyles( true, 'top' ); + $moduleStyles = $this->getModuleStyles(); // Per-site custom styles $moduleStyles[] = 'site'; diff --git a/includes/User.php b/includes/User.php index 199dd1dc..f6df7e03 100644 --- a/includes/User.php +++ b/includes/User.php @@ -3630,11 +3630,14 @@ class User implements IDBAccessObject { $this->clearInstanceCache( 'defaults' ); $this->getRequest()->setSessionData( 'wsUserID', 0 ); + $this->getRequest()->setSessionData( 'wsEditToken', null ); $this->clearCookie( 'UserID' ); $this->clearCookie( 'Token' ); $this->clearCookie( 'forceHTTPS', false, array( 'prefix' => '' ) ); + wfResetSessionID(); + // Remember when user logged out, to prevent seeing cached pages $this->setCookie( 'LoggedOut', time(), time() + 86400 ); } diff --git a/includes/WebStart.php b/includes/WebStart.php index f5a4f93b..e75e97fd 100644 --- a/includes/WebStart.php +++ b/includes/WebStart.php @@ -40,6 +40,9 @@ if ( function_exists( 'get_magic_quotes_gpc' ) && get_magic_quotes_gpc() ) { . 'for help on how to disable magic quotes.' ); } +if ( ini_get( 'mbstring.func_overload' ) ) { + die( 'MediaWiki does not support installations where mbstring.func_overload is non-zero.' ); +} # bug 15461: Make IE8 turn off content sniffing. Everybody else should ignore this # We're adding it here so that it's *always* set, even for alternate entry diff --git a/includes/actions/RawAction.php b/includes/actions/RawAction.php index b71b0e9e..6b99258f 100644 --- a/includes/actions/RawAction.php +++ b/includes/actions/RawAction.php @@ -90,6 +90,12 @@ class RawAction extends FormlessAction { } } + // Set standard Vary headers so cache varies on cookies and such (T125283) + $response->header( $this->getOutput()->getVaryHeader() ); + if ( $config->get( 'UseXVO' ) ) { + $response->header( $this->getOutput()->getXVO() ); + } + $response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' ); // Output may contain user-specific data; // vary generated content for open sessions on private wikis diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php index d53797bc..4f40499c 100644 --- a/includes/api/ApiBase.php +++ b/includes/api/ApiBase.php @@ -421,7 +421,13 @@ abstract class ApiBase extends ContextSource { * @return bool */ public function lacksSameOriginSecurity() { - return $this->getMain()->getRequest()->getVal( 'callback' ) !== null; + // Main module has this method overridden + // Safety - avoid infinite loop: + if ( $this->isMain() ) { + ApiBase::dieDebug( __METHOD__, 'base method was called on main module.' ); + } + + return $this->getMain()->lacksSameOriginSecurity(); } /** diff --git a/includes/api/ApiFormatJson.php b/includes/api/ApiFormatJson.php index be1b12c3..baba5b2d 100644 --- a/includes/api/ApiFormatJson.php +++ b/includes/api/ApiFormatJson.php @@ -102,9 +102,9 @@ class ApiFormatJson extends ApiFormatBase { // Bug 66776: wfMangleFlashPolicy() is needed to avoid a nasty bug in // Flash, but what it does isn't friendly for the API, so we need to // work around it. - if ( preg_match( '/\<\s*cross-domain-policy\s*\>/i', $json ) ) { + if ( preg_match( '/\<\s*cross-domain-policy(?=\s|\>)/i', $json ) ) { $json = preg_replace( - '/\<(\s*cross-domain-policy\s*)\>/i', '\\u003C$1\\u003E', $json + '/\<(\s*cross-domain-policy(?=\s|\>))/i', '\\u003C$1', $json ); } diff --git a/includes/api/ApiFormatPhp.php b/includes/api/ApiFormatPhp.php index 6420a5b5..643379c7 100644 --- a/includes/api/ApiFormatPhp.php +++ b/includes/api/ApiFormatPhp.php @@ -65,7 +65,7 @@ class ApiFormatPhp extends ApiFormatBase { // just be broken in a useful manner. if ( $this->getConfig()->get( 'MangleFlashPolicy' ) && in_array( 'wfOutputHandler', ob_list_handlers(), true ) && - preg_match( '/\<\s*cross-domain-policy\s*\>/i', $text ) + preg_match( '/\<\s*cross-domain-policy(?=\s|\>)/i', $text ) ) { $this->dieUsage( 'This response cannot be represented using format=php. ' . diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index d943c86b..1f0aebb6 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -145,6 +145,9 @@ class ApiMain extends ApiBase { private $mCacheControl = array(); private $mParamsUsed = array(); + /** @var bool|null Cached return value from self::lacksSameOriginSecurity() */ + private $lacksSameOriginSecurity = null; + /** * Constructs an instance of ApiMain that utilizes the module and format specified by $request. * @@ -243,6 +246,36 @@ class ApiMain extends ApiBase { } /** + * Get the security flag for the current request + * @return bool + */ + public function lacksSameOriginSecurity() { + if ( $this->lacksSameOriginSecurity !== null ) { + return $this->lacksSameOriginSecurity; + } + + $request = $this->getRequest(); + + // JSONP mode + if ( $request->getVal( 'callback' ) !== null ) { + $this->lacksSameOriginSecurity = true; + return true; + } + + // Header to be used from XMLHTTPRequest when the request might + // otherwise be used for XSS. + if ( $request->getHeader( 'Treat-as-Untrusted' ) !== false ) { + $this->lacksSameOriginSecurity = true; + return true; + } + + // Allow extensions to override. + $this->lacksSameOriginSecurity = !Hooks::run( 'RequestHasSameOriginSecurity', array( $request ) ); + return $this->lacksSameOriginSecurity; + } + + + /** * Get the ApiErrorFormatter object associated with current request * @return ApiErrorFormatter */ @@ -717,6 +750,8 @@ class ApiMain extends ApiBase { $response = $this->getRequest()->response(); $out = $this->getOutput(); + $out->addVaryHeader( 'Treat-as-Untrusted' ); + $config = $this->getConfig(); if ( $config->get( 'VaryOnXFP' ) ) { diff --git a/includes/api/ApiMove.php b/includes/api/ApiMove.php index aca43784..dc50594c 100644 --- a/includes/api/ApiMove.php +++ b/includes/api/ApiMove.php @@ -72,6 +72,11 @@ class ApiMove extends ApiBase { } } + // Rate limit + if ( $user->pingLimiter( 'move' ) ) { + $this->dieUsageMsg( 'actionthrottledtext' ); + } + // Move the page $toTitleExists = $toTitle->exists(); $status = $this->movePage( $fromTitle, $toTitle, $params['reason'], !$params['noredirect'] ); diff --git a/includes/db/DatabasePostgres.php b/includes/db/DatabasePostgres.php index 56a5b2cf..d5143689 100644 --- a/includes/db/DatabasePostgres.php +++ b/includes/db/DatabasePostgres.php @@ -486,6 +486,9 @@ class DatabasePostgres extends DatabaseBase { if ( function_exists( 'mb_convert_encoding' ) ) { $sql = mb_convert_encoding( $sql, 'UTF-8' ); } + while ( $res = pg_get_result( $this->mConn ) ) { + pg_free_result( $res ); + } $this->mTransactionState->check(); if ( pg_send_query( $this->mConn, $sql ) === false ) { throw new DBUnexpectedError( $this, "Unable to post new query to PostgreSQL\n" ); diff --git a/includes/diff/DairikiDiff.php b/includes/diff/DairikiDiff.php index d327433f..7bdc6543 100644 --- a/includes/diff/DairikiDiff.php +++ b/includes/diff/DairikiDiff.php @@ -296,9 +296,9 @@ class DiffEngine { $this->xchanged = $this->ychanged = array(); $this->xv = $this->yv = array(); $this->xind = $this->yind = array(); - unset( $this->seq ); - unset( $this->in_seq ); - unset( $this->lcs ); + $this->seq = array(); + $this->in_seq = array(); + $this->lcs = 0; // Skip leading common lines. for ( $skip = 0; $skip < $n_from && $skip < $n_to; $skip++ ) { diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php index c138eec2..fa1cd79d 100644 --- a/includes/diff/DifferenceEngine.php +++ b/includes/diff/DifferenceEngine.php @@ -511,7 +511,7 @@ class DifferenceEngine extends ContextSource { $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown( $this->mNewPage, $this->msg( 'markaspatrolleddiff' )->escaped(), - array(), + array( 'class' => 'mw-patrollink' ), array( 'action' => 'markpatrolled', 'rcid' => $rcid, @@ -823,6 +823,35 @@ class DifferenceEngine extends ContextSource { * @return bool|string */ public function generateTextDiffBody( $otext, $ntext ) { + $self = $this; + $diff = function() use ( $self, $otext, $ntext ) { + return $self->textDiff( $otext, $ntext ); + }; + + $error = function( $status ) { + throw new FatalError( $status->getWikiText() ); + }; + + // Use PoolCounter if the diff looks like it can be expensive + if ( strlen( $otext ) + strlen( $ntext ) > 20000 ) { + $work = new PoolCounterWorkViaCallback( 'diff', + md5( $otext ) . md5( $ntext ), + array( 'doWork' => $diff, 'error' => $error ) + ); + return $work->execute(); + } + + return $diff(); + } + + /** + * Generates diff, to be wrapped internally in a logging/instrumentation + * + * @param string $otext Old text, must be already segmented + * @param string $ntext New text, must be already segmented + * @return bool|string + */ + public function textDiff( $otext, $ntext ) { global $wgExternalDiffEngine, $wgContLang; $otext = str_replace( "\r\n", "\n", $otext ); diff --git a/includes/page/Article.php b/includes/page/Article.php index 56b9520a..97412dc7 100644 --- a/includes/page/Article.php +++ b/includes/page/Article.php @@ -1168,7 +1168,7 @@ class Article implements Page { $link = Linker::linkKnown( $this->getTitle(), wfMessage( 'markaspatrolledtext' )->escaped(), - array(), + array( 'class' => 'mw-patrollink' ), array( 'action' => 'markpatrolled', 'rcid' => $rcid, diff --git a/includes/parser/CoreTagHooks.php b/includes/parser/CoreTagHooks.php index 9755ea93..3f4f54a3 100644 --- a/includes/parser/CoreTagHooks.php +++ b/includes/parser/CoreTagHooks.php @@ -56,9 +56,14 @@ class CoreTagHooks { $content = StringUtils::delimiterReplace( '<nowiki>', '</nowiki>', '$1', $text, 'i' ); $attribs = Sanitizer::validateTagAttributes( $attribs, 'pre' ); - return Xml::openElement( 'pre', $attribs ) . - Xml::escapeTagsOnly( $content ) . - '</pre>'; + // We need to let both '"' and '&' through, + // for strip markers and entities respectively. + $content = str_replace( + array( '>', '<' ), + array( '>', '<' ), + $content + ); + return Html::rawElement( 'pre', $attribs, $content ); } /** @@ -98,8 +103,17 @@ class CoreTagHooks { * @return array */ public static function nowiki( $content, $attributes, $parser ) { - $content = strtr( $content, array( '-{' => '-{', '}-' => '}-' ) ); - return array( Xml::escapeTagsOnly( $content ), 'markerType' => 'nowiki' ); + $content = strtr( $content, array( + // lang converter + '-{' => '-{', + '}-' => '}-', + // html tags + '<' => '<', + '>' => '>' + // Note: Both '"' and '&' are not converted. + // This allows strip markers and entities through. + ) ); + return array( $content, 'markerType' => 'nowiki' ); } /** diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index c07a08ac..12953167 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -129,9 +129,14 @@ class Parser { * * Must not consist of all title characters, or else it will change * the behavior of <nowiki> in a link. + * + * Must have a character that needs escaping in attributes, otherwise + * someone could put a strip marker in an attribute, to get around + * escaping quote marks, and break out of the attribute. Thus we add + * `'". */ - const MARKER_SUFFIX = "-QINU\x7f"; - const MARKER_PREFIX = "\x7fUNIQ-"; + const MARKER_SUFFIX = "-QINU`\"'\x7f"; + const MARKER_PREFIX = "\x7f'\"`UNIQ-"; # Markers used for wrapping the table of contents const TOC_START = '<mw:toc>'; @@ -1862,11 +1867,22 @@ class Parser { */ public function getExternalLinkAttribs( $url = false ) { $attribs = array(); - $attribs['rel'] = self::getExternalLinkRel( $url, $this->mTitle ); - - if ( $this->mOptions->getExternalLinkTarget() ) { - $attribs['target'] = $this->mOptions->getExternalLinkTarget(); + $rel = self::getExternalLinkRel( $url, $this->mTitle ); + + $target = $this->mOptions->getExternalLinkTarget(); + if ( $target ) { + $attribs['target'] = $target; + if ( !in_array( $target, array( '_self', '_parent', '_top' ) ) ) { + // T133507. New windows can navigate parent cross-origin. + // Including noreferrer due to lacking browser + // support of noopener. Eventually noreferrer should be removed. + if ( $rel !== '' ) { + $rel .= ' '; + } + $rel .= 'noreferrer noopener'; + } } + $attribs['rel'] = $rel; return $attribs; } diff --git a/includes/password/MWOldPassword.php b/includes/password/MWOldPassword.php index afa5cacc..43c13553 100644 --- a/includes/password/MWOldPassword.php +++ b/includes/password/MWOldPassword.php @@ -44,5 +44,9 @@ class MWOldPassword extends ParameterizedPassword { $this->args = array(); $this->hash = md5( $plaintext ); } + + if ( !is_string( $this->hash ) || strlen( $this->hash ) < 32 ) { + throw new PasswordError( 'Error when hashing password.' ); + } } } diff --git a/includes/password/MWSaltedPassword.php b/includes/password/MWSaltedPassword.php index 6c6895a2..40d2b6a1 100644 --- a/includes/password/MWSaltedPassword.php +++ b/includes/password/MWSaltedPassword.php @@ -42,5 +42,9 @@ class MWSaltedPassword extends ParameterizedPassword { } $this->hash = md5( $this->args[0] . '-' . md5( $plaintext ) ); + + if ( !is_string( $this->hash ) || strlen( $this->hash ) < 32 ) { + throw new PasswordError( 'Error when hashing password.' ); + } } } diff --git a/includes/password/Pbkdf2Password.php b/includes/password/Pbkdf2Password.php index 080e3b0d..808fd8a6 100644 --- a/includes/password/Pbkdf2Password.php +++ b/includes/password/Pbkdf2Password.php @@ -55,8 +55,15 @@ class Pbkdf2Password extends ParameterizedPassword { (int)$this->params['length'], true ); + if ( !is_string( $hash ) ) { + throw new PasswordError( 'Error when hashing password.' ); + } } else { - $hashLen = strlen( hash( $this->params['algo'], '', true ) ); + $hashLenHash = hash( $this->params['algo'], '', true ); + if ( !is_string( $hashLenHash ) ) { + throw new PasswordError( 'Error when hashing password.' ); + } + $hashLen = strlen( $hashLenHash ); $blockCount = ceil( $this->params['length'] / $hashLen ); $hash = ''; diff --git a/includes/resourceloader/ResourceLoaderFileModule.php b/includes/resourceloader/ResourceLoaderFileModule.php index 7fbc1cb4..8060f6e1 100644 --- a/includes/resourceloader/ResourceLoaderFileModule.php +++ b/includes/resourceloader/ResourceLoaderFileModule.php @@ -279,7 +279,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { break; // Single strings case 'position': - $this->isPositionDefined = true; case 'group': case 'skipFunction': $this->{$member} = (string)$option; diff --git a/includes/resourceloader/ResourceLoaderImageModule.php b/includes/resourceloader/ResourceLoaderImageModule.php index 8de87f2e..e2da28bb 100644 --- a/includes/resourceloader/ResourceLoaderImageModule.php +++ b/includes/resourceloader/ResourceLoaderImageModule.php @@ -184,7 +184,6 @@ class ResourceLoaderImageModule extends ResourceLoaderModule { break; case 'position': - $this->isPositionDefined = true; case 'prefix': case 'selectorWithoutVariant': case 'selectorWithVariant': @@ -456,9 +455,4 @@ class ResourceLoaderImageModule extends ResourceLoaderModule { $this->loadFromDefinition(); return $this->position; } - - public function isPositionDefault() { - $this->loadFromDefinition(); - return parent::isPositionDefault(); - } } diff --git a/includes/resourceloader/ResourceLoaderModule.php b/includes/resourceloader/ResourceLoaderModule.php index 1d3ffb55..9b6702aa 100644 --- a/includes/resourceloader/ResourceLoaderModule.php +++ b/includes/resourceloader/ResourceLoaderModule.php @@ -67,10 +67,6 @@ abstract class ResourceLoaderModule { // In-object cache for module content protected $contents = array(); - // Whether the position returned by getPosition() is defined in the module configuration - // and not a default value - protected $isPositionDefined = false; - /** * @var Config */ @@ -292,19 +288,6 @@ abstract class ResourceLoaderModule { } /** - * Whether the position returned by getPosition() is a default value or comes from the module - * definition. This method is meant to be short-lived, and is only useful until classes added - * via addModuleStyles with a default value define an explicit position. See getModuleStyles() - * in OutputPage for the related migration warning. - * - * @return bool - * @since 1.26 - */ - public function isPositionDefault() { - return !$this->isPositionDefined; - } - - /** * Whether this module's JS expects to work without the client-side ResourceLoader module. * Returning true from this function will prevent mw.loader.state() call from being * appended to the bottom of the script. diff --git a/includes/resourceloader/ResourceLoaderWikiModule.php b/includes/resourceloader/ResourceLoaderWikiModule.php index 0023de27..693bcee4 100644 --- a/includes/resourceloader/ResourceLoaderWikiModule.php +++ b/includes/resourceloader/ResourceLoaderWikiModule.php @@ -72,8 +72,6 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule { foreach ( $options as $member => $option ) { switch ( $member ) { case 'position': - $this->isPositionDefined = true; - // Don't break since we need the member set as well case 'styles': case 'scripts': case 'group': diff --git a/includes/specials/SpecialUserlogin.php b/includes/specials/SpecialUserlogin.php index 21f1194f..2d6737bd 100644 --- a/includes/specials/SpecialUserlogin.php +++ b/includes/specials/SpecialUserlogin.php @@ -628,7 +628,7 @@ class LoginForm extends SpecialPage { "allowed account creation w/o throttle\n" ); } else { if ( ( $wgAccountCreationThrottle && $currentUser->isPingLimitable() ) ) { - $key = wfMemcKey( 'acctcreate', 'ip', $ip ); + $key = wfGlobalCacheKey( 'acctcreate', 'ip', $ip ); $value = $wgMemc->get( $key ); if ( !$value ) { $wgMemc->set( $key, 0, 86400 ); @@ -862,11 +862,12 @@ class LoginForm extends SpecialPage { */ public static function incLoginThrottle( $username ) { global $wgPasswordAttemptThrottle, $wgMemc, $wgRequest; - $username = trim( $username ); // sanity + $canUsername = User::getCanonicalName( $username, 'usable' ); + $username = $canUsername !== false ? $canUsername : $username; $throttleCount = 0; if ( is_array( $wgPasswordAttemptThrottle ) ) { - $throttleKey = wfMemcKey( 'password-throttle', $wgRequest->getIP(), md5( $username ) ); + $throttleKey = wfGlobalCacheKey( 'password-throttle', $wgRequest->getIP(), md5( $username ) ); $count = $wgPasswordAttemptThrottle['count']; $period = $wgPasswordAttemptThrottle['seconds']; @@ -890,9 +891,10 @@ class LoginForm extends SpecialPage { */ public static function clearLoginThrottle( $username ) { global $wgMemc, $wgRequest; - $username = trim( $username ); // sanity + $canUsername = User::getCanonicalName( $username, 'usable' ); + $username = $canUsername !== false ? $canUsername : $username; - $throttleKey = wfMemcKey( 'password-throttle', $wgRequest->getIP(), md5( $username ) ); + $throttleKey = wfGlobalCacheKey( 'password-throttle', $wgRequest->getIP(), md5( $username ) ); $wgMemc->delete( $throttleKey ); } @@ -1608,7 +1610,8 @@ class LoginForm extends SpecialPage { if ( $wgSecureLogin && !$this->mStickHTTPS ) { $wgCookieSecure = false; } - + // Always make sure edit token is regenerated. (T114419) + $this->getRequest()->setSessionData( 'wsEditToken', null ); wfResetSessionID(); } diff --git a/includes/templates/Usercreate.php b/includes/templates/Usercreate.php index a39690a7..84695e1f 100644 --- a/includes/templates/Usercreate.php +++ b/includes/templates/Usercreate.php @@ -164,6 +164,7 @@ class UsercreateTemplate extends BaseTemplate { ); ?> </label> + <p><b>Note:</b> We are currently experiencing delivery issues to Yahoo. Please do not use a Yahoo email account to sign up.</p> <?php echo Html::input( 'wpEmail', $this->data['email'], 'email', array( 'class' => 'mw-ui-input loginText', diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php index e9e1f658..02192904 100644 --- a/includes/upload/UploadBase.php +++ b/includes/upload/UploadBase.php @@ -1399,7 +1399,7 @@ abstract class UploadBase { && strpos( $value, '#' ) !== 0 ) { if ( !( $strippedElement === 'a' - && preg_match( '!^https?://!im', $value ) ) + && preg_match( '!^https?://!i', $value ) ) ) { wfDebug( __METHOD__ . ": Found href attribute <$strippedElement " . "'$attrib'='$value' in uploaded file.\n" ); |