summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-08-02 16:31:15 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-08-02 16:31:15 -0400
commit7099c40bcc035e3b96ddd3e976d1cdbcfbf09398 (patch)
tree2fbc86f9c4cba01c0a266b7fefdd38b1ec3b5c01
parenta5f917bbc55e295896b8084f6657eb8b6abaf8a8 (diff)
parentb5e7f46db0fcb6f251206eaf36339ad3ad589f8b (diff)
Merge branch 'archwiki' into lukeshu/masterHEADproductionmaster
-rw-r--r--.gitmodules8
-rw-r--r--LocalSettings.archlinux.org.php304
l---------README.mediawiki1
-rw-r--r--RELEASE-NOTES-1.2628
-rw-r--r--docs/hooks.txt6
m---------extensions/AbuseFilter0
m---------extensions/CheckUser0
-rw-r--r--extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php5
-rw-r--r--extensions/SyntaxHighlight_GeSHi/tests/parserTests.txt9
-rw-r--r--includes/DefaultSettings.php16
-rw-r--r--includes/Defines.php6
-rw-r--r--includes/GlobalFunctions.php8
-rw-r--r--includes/Import.php18
-rw-r--r--includes/Linker.php11
-rw-r--r--includes/MediaWiki.php13
-rw-r--r--includes/OutputHandler.php4
-rw-r--r--includes/OutputPage.php28
-rw-r--r--includes/User.php3
-rw-r--r--includes/WebStart.php3
-rw-r--r--includes/actions/RawAction.php6
-rw-r--r--includes/api/ApiBase.php8
-rw-r--r--includes/api/ApiFormatJson.php4
-rw-r--r--includes/api/ApiFormatPhp.php2
-rw-r--r--includes/api/ApiMain.php35
-rw-r--r--includes/api/ApiMove.php5
-rw-r--r--includes/db/DatabasePostgres.php3
-rw-r--r--includes/diff/DairikiDiff.php6
-rw-r--r--includes/diff/DifferenceEngine.php31
-rw-r--r--includes/page/Article.php2
-rw-r--r--includes/parser/CoreTagHooks.php24
-rw-r--r--includes/parser/Parser.php28
-rw-r--r--includes/password/MWOldPassword.php4
-rw-r--r--includes/password/MWSaltedPassword.php4
-rw-r--r--includes/password/Pbkdf2Password.php9
-rw-r--r--includes/resourceloader/ResourceLoaderFileModule.php1
-rw-r--r--includes/resourceloader/ResourceLoaderImageModule.php6
-rw-r--r--includes/resourceloader/ResourceLoaderModule.php17
-rw-r--r--includes/resourceloader/ResourceLoaderWikiModule.php2
-rw-r--r--includes/specials/SpecialUserlogin.php15
-rw-r--r--includes/templates/Usercreate.php1
-rw-r--r--includes/upload/UploadBase.php2
-rw-r--r--resources/Resources.php2
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js2
-rw-r--r--tests/browser/README.mediawiki64
-rw-r--r--tests/parser/parserTests.txt13
-rw-r--r--tests/phpunit/includes/api/ApiMainTest.php27
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatJsonTest.php4
-rw-r--r--tests/phpunit/includes/upload/UploadBaseTest.php6
-rw-r--r--tests/qunit/data/testrunner.js2
49 files changed, 642 insertions, 164 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..d4d6a6c5
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,8 @@
+[submodule "extensions/CheckUser"]
+ path = extensions/CheckUser
+ url = https://gerrit.wikimedia.org/r/p/mediawiki/extensions/CheckUser.git
+ branch = REL1_26
+[submodule "extensions/AbuseFilter"]
+ path = extensions/AbuseFilter
+ url = https://github.com/wikimedia/mediawiki-extensions-AbuseFilter.git
+ branch = REL1_26
diff --git a/LocalSettings.archlinux.org.php b/LocalSettings.archlinux.org.php
new file mode 100644
index 00000000..db98bdb4
--- /dev/null
+++ b/LocalSettings.archlinux.org.php
@@ -0,0 +1,304 @@
+<?php
+# This file was automatically generated by the MediaWiki 1.19.0
+# installer. If you make manual changes, please keep track in case you
+# need to recreate them later.
+#
+# See includes/DefaultSettings.php for all configurable settings
+# and their default values, but don't forget to make changes in _this_
+# file, not there.
+#
+# Further documentation for configuration settings may be found at:
+# http://www.mediawiki.org/wiki/Manual:Configuration_settings
+
+# Protect against web entry
+if ( !defined( 'MEDIAWIKI' ) ) {
+ exit;
+}
+
+##
+## LocalSettings.php
+##
+
+#$wgDBname = "XXX";
+#$wgDBuser = "XXX";
+#$wgDBpassword = "XXX";
+#$wgSecretKey = "XXX";
+#$wgUpgradeKey = "XXX";
+#require_once( "$IP/extensions/FunnyQuestion/FunnyQuestion.php" );
+#$wgFunnyQuestionHash = "XXX";
+#$wgFunnyQuestions = array();
+
+
+##
+## General settings
+##
+
+$wgSitename = "ArchWiki";
+
+## The protocol and server name to use in fully-qualified URLs
+$wgServer = "https://wiki.archlinux.org";
+
+$wgLocaltimezone = 'UTC';
+
+# Site language code, should be one of the list in ./languages/Names.php
+$wgLanguageCode = "en";
+
+## The URL base path to the directory containing the wiki;
+## defaults for all runtime URL paths are based off of this.
+## For more information on customizing the URLs please see:
+## http://www.mediawiki.org/wiki/Manual:Short_URL
+$wgScriptPath = "";
+# $wgArticlePath = "$wgScript/$1";
+$wgUsePathInfo = true;
+$wgScriptExtension = ".php";
+
+## The relative URL path to the skins directory
+$wgStylePath = "$wgScriptPath/skins";
+
+## The relative URL path to the logo. Make sure you change this from the default,
+## or else you'll overwrite your logo when you upgrade!
+$wgLogo = "$wgStylePath/archlinux/archlogo.png";
+
+## For attaching licensing metadata to pages, and displaying an
+## appropriate copyright notice / icon. GNU Free Documentation
+## License and Creative Commons licenses are supported so far.
+$wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
+$wgRightsUrl = "http://www.gnu.org/copyleft/fdl.html";
+$wgRightsText = "GNU Free Documentation License 1.3 or later";
+$wgRightsIcon = "$wgScriptPath/resources/assets/licenses/gnu-fdl.png";
+
+# Query string length limit for ResourceLoader. You should only set this if
+# your web server has a query string length limit (then set it to that limit),
+# or if you have suhosin.get.max_value_length set in php.ini (then set it to
+# that value)
+# TODO: -1 is the default
+$wgResourceLoaderMaxQueryLength = -1;
+
+$wgGitRepositoryViewers['.+projects\.archlinux\.org/vhosts/wiki\.archlinux\.org\.git(.*)'] = 'https://projects.archlinux.org/vhosts/wiki.archlinux.org.git/commit/?id=%H';
+
+$wgJobRunRate = 0;
+
+# Enable subpages in the main namespace (FS#39668)
+$wgNamespacesWithSubpages[NS_MAIN] = true;
+
+# Enable support for userscripts and user-stylesheets (FS#46699)
+$wgAllowUserJs = true;
+$wgAllowUserCss = true;
+
+
+##
+## Database settings
+##
+
+$wgDBtype = "mysql";
+$wgDBserver = "localhost";
+
+# MySQL specific settings
+$wgDBprefix = "";
+
+# MySQL table options to use during installation or update
+$wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary";
+
+# Experimental charset support for MySQL 5.0.
+$wgDBmysql5 = false;
+
+
+##
+## Email settings
+##
+
+## UPO means: this is also a user preference option
+
+$wgEnableEmail = true;
+$wgEnableUserEmail = true; # UPO
+
+$wgEmergencyContact = "webmaster@archlinux.org";
+$wgPasswordSender = "webmaster@archlinux.org";
+
+$wgEnotifUserTalk = true; # UPO
+$wgEnotifWatchlist = true; # UPO
+$wgEmailAuthentication = true;
+
+# avoid bouncing of user-to-user emails (FS#26737)
+$wgUserEmailUseReplyTo = true;
+
+
+##
+## Cache and performance settings
+##
+
+## Shared memory settings
+$wgMainCacheType = CACHE_ACCEL;
+$wgMemCachedServers = array();
+
+## Set $wgCacheDirectory to a writable directory on the web server
+## to make your wiki go slightly faster. The directory should not
+## be publically accessible from the web.
+$wgCacheDirectory = "$IP/../cache/data";
+$wgShowIPinHeader = false;
+$wgEnableSidebarCache = true;
+$wgUseFileCache = true;
+$wgFileCacheDirectory = "$IP/../cache/html";
+$wgUseGzip = true;
+$wgUseETag = true;
+
+# CSS-based preferences supposedly cause about 20 times slower page loads
+# https://phabricator.wikimedia.org/rSVN63707
+$wgAllowUserCssPrefs = false;
+
+## Uncomment this to disable output compression
+# $wgDisableOutputCompression = true;
+
+
+##
+## Media settings
+##
+
+## To enable image uploads, make sure the 'images' directory
+## is writable, then set this to true:
+$wgEnableUploads = true;
+#$wgUseImageMagick = true;
+#$wgImageMagickConvertCommand = "/usr/bin/convert";
+
+# InstantCommons allows wiki to use images from http://commons.wikimedia.org
+$wgUseInstantCommons = false;
+
+## If you use ImageMagick (or any other shell command) on a
+## Linux server, this will need to be set to the name of an
+## available UTF-8 locale
+$wgShellLocale = "en_US.utf8";
+
+## If you want to use image uploads under safe mode,
+## create the directories images/archive, images/thumb and
+## images/temp, and make them all writable. Then uncomment
+## this, if it's not already uncommented:
+#$wgHashedUploadDirectory = false;
+
+
+##
+## Skin settings
+##
+
+## Default skin: you can change the default skin. Use the internal symbolic
+## names, ie 'standard', 'nostalgia', 'cologneblue', 'monobook', 'vector':
+//require_once "$IP/skins/ArchLinux/ArchLinux.php";
+wfLoadSkin( 'ArchLinux' );
+$wgDefaultSkin = 'archlinux';
+$wgDefaultUserOptions['skin'] = 'archlinux';
+$wgArchHome = 'https://www.archlinux.org/';
+$wgArchNavBar = array(
+ 'Home' => 'https://www.archlinux.org/',
+ 'Packages' => 'https://www.archlinux.org/packages/',
+ 'Forums' => 'https://bbs.archlinux.org/',
+ 'Wiki' => 'https://wiki.archlinux.org/',
+ 'Bugs' => 'https://bugs.archlinux.org/',
+ 'AUR' => 'https://aur.archlinux.org/',
+ 'Download' => 'https://www.archlinux.org/download/'
+ );
+$wgArchNavBarSelectedDefault = 'Wiki';
+$wgFooterIcons = array();
+
+
+##
+## Access control settings
+##
+
+# disable anonymous editing
+$wgEmailConfirmToEdit = true;
+$wgDisableAnonTalk = true;
+$wgGroupPermissions['*']['edit'] = false;
+
+# extra rights for admins
+$wgGroupPermissions['sysop']['deleterevision'] = true;
+
+# disable uploads by normal users
+$wgGroupPermissions['user']['upload'] = false;
+$wgGroupPermissions['user']['reupload'] = false;
+$wgGroupPermissions['user']['reupload-shared'] = false;
+$wgGroupPermissions['autoconfirmed']['upload'] = false;
+
+# maintainers' rights
+$wgGroupPermissions['maintainer']['autopatrol'] = true;
+$wgGroupPermissions['maintainer']['patrol'] = true;
+$wgGroupPermissions['maintainer']['noratelimit'] = true;
+$wgGroupPermissions['maintainer']['suppressredirect'] = true;
+$wgGroupPermissions['maintainer']['rollback'] = true;
+$wgGroupPermissions['maintainer']['browsearchive'] = true;
+$wgGroupPermissions['maintainer']['apihighlimits'] = true;
+$wgGroupPermissions['maintainer']['unwatchedpages'] = true;
+$wgGroupPermissions['maintainer']['deletedhistory'] = true;
+$wgGroupPermissions['maintainer']['deletedtext'] = true;
+
+# disable user account creation via API
+$wgAPIModules['createaccount'] = 'ApiDisabled';
+# remove 'writeapi' right from users
+$wgGroupPermissions['*']['writeapi'] = false;
+$wgGroupPermissions['user']['writeapi'] = false;
+# add 'writeapi' to autoconfirmed users, maintainers and admins
+$wgGroupPermissions['autoconfirmed']['writeapi'] = true;
+$wgGroupPermissions['maintainer']['writeapi'] = true;
+$wgGroupPermissions['sysop']['writeapi'] = true;
+# stricter conditions for 'autoconfirmed' promotion
+$wgAutoConfirmAge = 86400*3; // three days
+# require at least 20 normal edits before granting the 'writeapi' right
+$wgAutoConfirmCount = 20;
+
+# Enforce basic editing etiquette (FS#46190)
+# We set the defaults for "minordefault" (disabled) and "forceeditsummary"
+# (enabled) options and hide them from the user preferences dialog. Note that
+# hiding the user preferences with $wgHiddenPrefs results in everybody using
+# the defaults, regardless of the users' earlier preference.
+$wgDefaultUserOptions["minordefault"] = 0;
+$wgDefaultUserOptions["forceeditsummary"] = 1;
+$wgHiddenPrefs[] = "minordefault";
+$wgHiddenPrefs[] = "forceeditsummary";
+
+
+##
+## Additional extensions
+##
+
+require_once( "$IP/extensions/Nuke/Nuke.php" );
+
+# AbuseFilter extension
+require_once "$IP/extensions/AbuseFilter/AbuseFilter.php";
+$wgGroupPermissions['sysop']['abusefilter-modify'] = true;
+$wgGroupPermissions['*']['abusefilter-log-detail'] = true;
+$wgGroupPermissions['*']['abusefilter-view'] = true;
+$wgGroupPermissions['*']['abusefilter-log'] = true;
+$wgGroupPermissions['sysop']['abusefilter-private'] = true;
+$wgGroupPermissions['sysop']['abusefilter-modify-restricted'] = true;
+$wgGroupPermissions['sysop']['abusefilter-revert'] = true;
+
+# filter groups
+$wgAbuseFilterValidGroups = array( 'default', 'proofed' );
+$wgAbuseFilterEmergencyDisableThreshold = array(
+ 'default' => 0.5,
+ 'proofed' => 1.0,
+);
+$wgAbuseFilterEmergencyDisableCount = array(
+ 'default' => 10,
+ 'proofed' => 65535,
+);
+
+# CheckUser extension
+wfLoadExtension( 'CheckUser' );
+$wgGroupPermissions['sysop']['checkuser'] = true;
+$wgGroupPermissions['sysop']['checkuser-log'] = true;
+
+# ParserFunctions extension
+wfLoadExtension( 'ParserFunctions' );
+
+# Interwiki extension
+wfLoadExtension( 'Interwiki' );
+$wgGroupPermissions['sysop']['interwiki'] = true;
+
+##
+## Temporary settings for maintenance
+##
+
+# temporary disable registration; reverted 2016-6-26 bluewind
+#$wgGroupPermissions['*']['createaccount'] = false;
+
+# $wgShowSQLErrors = true;
+# $wgReadOnly = 'Database migration in progress. We`ll be back in a few minutes.';
diff --git a/README.mediawiki b/README.mediawiki
deleted file mode 120000
index 100b9382..00000000
--- a/README.mediawiki
+++ /dev/null
@@ -1 +0,0 @@
-README \ No newline at end of file
diff --git a/RELEASE-NOTES-1.26 b/RELEASE-NOTES-1.26
index e617f00b..fd2e5e69 100644
--- a/RELEASE-NOTES-1.26
+++ b/RELEASE-NOTES-1.26
@@ -1,6 +1,34 @@
Security reminder: If you have PHP's register_globals option set, you must
turn it off. MediaWiki will not work with it enabled.
+== MediaWiki 1.26.3 ==
+
+This is a maintenance release of the MediaWiki 1.26 branch.
+
+== Changes since 1.26.2 ==
+* (T116266) Fixed undefined property notices in DairikiDiff under HHVM.
+* (T123166) Fix fatal error when importing pages to titles which cannot be
+ created, such as invalid titles or titles the user is not allowed to edit.
+* (T122056) Old tokens are remaining valid within a new session
+* (T127114) Login throttle can be tricked using non-canonicalized usernames
+* (T123653) Cross-domain policy regexp is too narrow
+* (T123071) Incorrectly identifying http link in a's href attributes, due to
+ m modifier in regex
+* (T129506) MediaWiki:Gadget-popups.js isn't renderable
+* (T125283) Users occasionally logged in as different users after
+ SessionManager deployment
+* (T103239) Patrol allows click catching and patrolling of any page
+* (T122807) [tracking] Check php crypto primatives
+* (T98313) Graphs can leak tokens, leading to CSRF
+* (T130947) Diff generation should use PoolCounter
+* (T133507) Careless use of $wgExternalLinkTarget is insecure
+* (T132874) API action=move is not rate limited
+* (T110143) strip markers can be used to get around html attribute escaping in
+ (many?) parser tags
+* (T116030) Increase pbkdf2 parameter strengths
+* (T127420) Pbkdf2Password does not check if hash_pbkdf2() succeeded
+* (T126685) Globally throttle password attempts
+
== MediaWiki 1.26.2 ==
This is a maintenance release of the MediaWiki 1.26 branch.
diff --git a/docs/hooks.txt b/docs/hooks.txt
index 7671e6e3..4e134e5d 100644
--- a/docs/hooks.txt
+++ b/docs/hooks.txt
@@ -2449,6 +2449,12 @@ $context: (IContextSource) The RequestContext the skin is being created for.
&$skin: A variable reference you may set a Skin instance or string key on to
override the skin that will be used for the context.
+'RequestHasSameOriginSecurity': Called to determine if the request is somehow
+flagged to lack same-origin security. Return false to indicate the lack. Note
+if the "somehow" involves HTTP headers, you'll probably need to make sure
+the header is varied on.
+WebRequest $request: The request.
+
'ResetPasswordExpiration': Allow extensions to set a default password expiration
$user: The user having their password expiration reset
&$newExpire: The new expiration date
diff --git a/extensions/AbuseFilter b/extensions/AbuseFilter
new file mode 160000
+Subproject e4e82228a8af22fc423b282de36a970412e94a9
diff --git a/extensions/CheckUser b/extensions/CheckUser
new file mode 160000
+Subproject 710d30200318f1e8ec579bf0d07b07acbb105b5
diff --git a/extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php b/extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php
index 9eed2763..e2da350b 100644
--- a/extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php
+++ b/extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php
@@ -111,8 +111,11 @@ class SyntaxHighlight_GeSHi {
public static function parserHook( $text, $args = array(), $parser ) {
global $wgUseTidy;
+ // Replace strip markers (For e.g. {{#tag:syntaxhighlight|<nowiki>...}})
+ $out = $parser->mStripState->unstripNoWiki( $text );
+
// Don't trim leading spaces away, just the linefeeds
- $out = preg_replace( '/^\n+/', '', rtrim( $text ) );
+ $out = preg_replace( '/^\n+/', '', rtrim( $out ) );
// Convert deprecated attributes
if ( isset( $args['enclose'] ) ) {
diff --git a/extensions/SyntaxHighlight_GeSHi/tests/parserTests.txt b/extensions/SyntaxHighlight_GeSHi/tests/parserTests.txt
index c6aaa9a4..5d5038c9 100644
--- a/extensions/SyntaxHighlight_GeSHi/tests/parserTests.txt
+++ b/extensions/SyntaxHighlight_GeSHi/tests/parserTests.txt
@@ -154,3 +154,12 @@ Text <source lang="javascript" enclose="none">var a;</source>.
<p>Text <code class="mw-highlight" dir="ltr"><span class="kd">var</span> <span class="nx">a</span><span class="p">;</span></code>.
</p>
!! end
+
+!! test
+Enclose with nowiki
+!! input
+{{#tag:syntaxhighlight|<nowiki>foo</nowiki>|lang="text"|inline=none}}
+!! result
+<p><code class="mw-highlight" dir="ltr">foo</code>
+</p>
+!! end
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( '&gt;', '&lt;' ),
+ $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( '-{' => '-&#123;', '}-' => '&#125;-' ) );
- return array( Xml::escapeTagsOnly( $content ), 'markerType' => 'nowiki' );
+ $content = strtr( $content, array(
+ // lang converter
+ '-{' => '-&#123;',
+ '}-' => '&#125;-',
+ // html tags
+ '<' => '&lt;',
+ '>' => '&gt;'
+ // 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" );
diff --git a/resources/Resources.php b/resources/Resources.php
index 6a22af66..6626f05a 100644
--- a/resources/Resources.php
+++ b/resources/Resources.php
@@ -2031,6 +2031,8 @@ return array(
'dependencies' => array(
'oojs-ui',
'mediawiki.api',
+ 'mediawiki.ForeignApi',
+ 'mediawiki.Title',
),
'targets' => array( 'desktop', 'mobile' ),
),
diff --git a/resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js b/resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js
index f9b0d356..e0307b72 100644
--- a/resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js
+++ b/resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js
@@ -12,7 +12,7 @@
return;
}
$( function () {
- var $patrolLinks = $( '.patrollink a' );
+ var $patrolLinks = $( '.patrollink a.mw-patrollink' );
$patrolLinks.on( 'click', function ( e ) {
var $spinner, href, rcid, apiRequest;
diff --git a/tests/browser/README.mediawiki b/tests/browser/README.mediawiki
deleted file mode 100644
index 22657627..00000000
--- a/tests/browser/README.mediawiki
+++ /dev/null
@@ -1,64 +0,0 @@
-Purpose:
-
-The purpose of these tests is to validate that a newly installed (or updated, or hacked, or whatever) mediawiki instance presents to the user a set of expected features, regardless of what language the wiki is in, or where it is installed, or what extensions it might have.
-
-The tests are based on the basic definition of a wiki, a website where anyone
-
-* can read a page
-* can create a page
-* can edit a page
-* can link one page to another page
-
-Install:
-
-Ruby 1.9.3 or higher is required
-Firefox browser is required
-::
- cd /tests/browser
- gem update --system
- gem install bundler
- bundle install
-
-Run the tests:
-
-Edit the environment_variables file with appropriate values for your wiki
-$source environment_variables (example shown in bash shell)
-
-bundle exec cucumber features/
-
-Note that the acceptance tests will create three pages in your wiki entitled "Editing Test Page", "Link Source Test Page", and "Link Target Test Page". These pages may be deleted at any time. If you wish to re-run the tests at any time, these test pages will be re-created or reset to their original contents at the time that the tests run.
-
-For more information about running Selenium tests please see
-https://github.com/wikimedia/mediawiki-selenium
-
-Details:
-
-create_account.feature
-* Checks three different ways to arrive on page allowing the user to create an account
-
-create_and_follow_wiki_link.feature:
-* uses the mediawiki API to create a link target page
-* uses the mediawiki API to create a link source page
-* navigates a browser to the link source page
-* clicks the link in that page to the link target page
-* validates that the browser has in fact followed the link to the target page correctly
-
-edit_page.feature:
-* uses the mediawiki API to create an editable page on the wiki
-* navigates a browser to the page
-* clicks the Edit button to invoke the basic editor
-* edits the page with a particular string containing a static part and also a quasi-unique random part
-* saves the edited page
-* checks that the saved page contains the particular string with which the page was edited
-
-main_page.feature:
-* navigates a browser to the default landing page of the wiki
-* checks for the View History link on the landing page
-* checks for the full set of of sidebar links that should exist on every mediawiki wiki
-
-view_history.feature
-* similar to edit_page.feature but checks for an older version of the edited page
-
-Notes:
-
-Tested on beta labs hewiki, dewiki, enwiki, and on a local installation of mediawiki \ No newline at end of file
diff --git a/tests/parser/parserTests.txt b/tests/parser/parserTests.txt
index c8c63f39..67da1f0a 100644
--- a/tests/parser/parserTests.txt
+++ b/tests/parser/parserTests.txt
@@ -2263,6 +2263,15 @@ Entities inside <pre>
!! end
!! test
+<nowiki> inside of #tag:pre
+!! wikitext
+{{#tag:pre|Foo <nowiki>&rarr;bar</nowiki>}}
+!! html
+<pre>Foo &#8594;bar</pre>
+
+!! end
+
+!! test
<nowiki> and <pre> preference (first one wins)
!! wikitext
<pre>
@@ -12863,7 +12872,7 @@ Image with link parameter, wgExternalLinkTarget
!! config
wgExternalLinkTarget='foobar'
!! html
-<p><a href="http://example.com/" target="foobar" rel="nofollow"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+<p><a href="http://example.com/" target="foobar" rel="nofollow noreferrer noopener"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! end
@@ -12896,7 +12905,7 @@ Image with link parameter, wgExternalLinkTarget, unnamed parameter
!! config
wgExternalLinkTarget='foobar'
!! html
-<p><a href="http://example.com/" title="Title" target="foobar" rel="nofollow"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+<p><a href="http://example.com/" title="Title" target="foobar" rel="nofollow noreferrer noopener"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
</p>
!! end
diff --git a/tests/phpunit/includes/api/ApiMainTest.php b/tests/phpunit/includes/api/ApiMainTest.php
index 94b741dc..a2bc7aed 100644
--- a/tests/phpunit/includes/api/ApiMainTest.php
+++ b/tests/phpunit/includes/api/ApiMainTest.php
@@ -248,4 +248,31 @@ class ApiMainTest extends ApiTestCase {
);
}
+ /**
+ * @covers ApiMain::lacksSameOriginSecurity
+ */
+ public function testLacksSameOriginSecurity() {
+ // Basic test
+ $main = new ApiMain( new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) ) );
+ $this->assertFalse( $main->lacksSameOriginSecurity(), 'Basic test, should have security' );
+
+ // JSONp
+ $main = new ApiMain(
+ new FauxRequest( array( 'action' => 'query', 'format' => 'xml', 'callback' => 'foo' ) )
+ );
+ $this->assertTrue( $main->lacksSameOriginSecurity(), 'JSONp, should lack security' );
+
+ // Header
+ $request = new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) );
+ $request->setHeader( 'TrEaT-As-UnTrUsTeD', '' ); // With falsey value!
+ $main = new ApiMain( $request );
+ $this->assertTrue( $main->lacksSameOriginSecurity(), 'Header supplied, should lack security' );
+
+ // Hook
+ $this->mergeMwGlobalArrayValue( 'wgHooks', array(
+ 'RequestHasSameOriginSecurity' => array( function () { return false; } )
+ ) );
+ $main = new ApiMain( new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) ) );
+ $this->assertTrue( $main->lacksSameOriginSecurity(), 'Hook, should lack security' );
+ }
}
diff --git a/tests/phpunit/includes/api/format/ApiFormatJsonTest.php b/tests/phpunit/includes/api/format/ApiFormatJsonTest.php
index 3dfcaf0f..8d599b08 100644
--- a/tests/phpunit/includes/api/format/ApiFormatJsonTest.php
+++ b/tests/phpunit/includes/api/format/ApiFormatJsonTest.php
@@ -61,7 +61,7 @@ class ApiFormatJsonTest extends ApiFormatTestBase {
array( array( 1 ), '/**/myCallback([1])', array( 'callback' => 'myCallback' ) ),
// Cross-domain mangling
- array( array( '< Cross-Domain-Policy >' ), '["\u003C Cross-Domain-Policy \u003E"]' ),
+ array( array( '< Cross-Domain-Policy >' ), '["\u003C Cross-Domain-Policy >"]' ),
) ),
self::addFormatVersion( 2, array(
// Basic types
@@ -102,7 +102,7 @@ class ApiFormatJsonTest extends ApiFormatTestBase {
array( array( 1 ), '/**/myCallback([1])', array( 'callback' => 'myCallback' ) ),
// Cross-domain mangling
- array( array( '< Cross-Domain-Policy >' ), '["\u003C Cross-Domain-Policy \u003E"]' ),
+ array( array( '< Cross-Domain-Policy >' ), '["\u003C Cross-Domain-Policy >"]' ),
) )
);
}
diff --git a/tests/phpunit/includes/upload/UploadBaseTest.php b/tests/phpunit/includes/upload/UploadBaseTest.php
index 9441b77f..a3f8ae48 100644
--- a/tests/phpunit/includes/upload/UploadBaseTest.php
+++ b/tests/phpunit/includes/upload/UploadBaseTest.php
@@ -374,6 +374,12 @@ class UploadBaseTest extends MediaWikiTestCase {
false,
'SVG with external entity'
),
+ array(
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"> <g> <a xlink:href=\"javascript:alert('1&#10;https://google.com')\"> <rect width=\"300\" height=\"100\" style=\"fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,2)\" /> </a> </g> </svg>",
+ true,
+ true,
+ 'SVG with javascript <a> link with newline (T122653)'
+ ),
// Test good, but strange files that we want to allow
array(
diff --git a/tests/qunit/data/testrunner.js b/tests/qunit/data/testrunner.js
index 01f96252..53bff763 100644
--- a/tests/qunit/data/testrunner.js
+++ b/tests/qunit/data/testrunner.js
@@ -27,8 +27,6 @@
// and assuming failure.
QUnit.config.testTimeout = 30 * 1000;
- QUnit.config.requireExpects = true;
-
// Add a checkbox to QUnit header to toggle MediaWiki ResourceLoader debug mode.
QUnit.config.urlConfig.push( {
id: 'debug',