summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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--extensions/Variables/.gitignore7
-rw-r--r--extensions/Variables/.gitreview5
-rw-r--r--extensions/Variables/CODE_OF_CONDUCT.md1
-rw-r--r--extensions/Variables/COPYING16
-rw-r--r--extensions/Variables/Gruntfile.js29
-rw-r--r--extensions/Variables/README19
-rw-r--r--extensions/Variables/RELEASE-NOTES88
-rw-r--r--extensions/Variables/Variables.i18n.magic.php22
-rw-r--r--extensions/Variables/Variables.php375
-rw-r--r--extensions/Variables/Variables.settings.php29
-rw-r--r--extensions/Variables/gitinfo.json1
-rw-r--r--extensions/Variables/i18n/ast.json8
-rw-r--r--extensions/Variables/i18n/be-tarask.json9
-rw-r--r--extensions/Variables/i18n/de.json9
-rw-r--r--extensions/Variables/i18n/dsb.json8
-rw-r--r--extensions/Variables/i18n/el.json8
-rw-r--r--extensions/Variables/i18n/en.json8
-rw-r--r--extensions/Variables/i18n/es.json8
-rw-r--r--extensions/Variables/i18n/fa.json8
-rw-r--r--extensions/Variables/i18n/fr.json8
-rw-r--r--extensions/Variables/i18n/gl.json8
-rw-r--r--extensions/Variables/i18n/he.json8
-rw-r--r--extensions/Variables/i18n/hsb.json8
-rw-r--r--extensions/Variables/i18n/ia.json8
-rw-r--r--extensions/Variables/i18n/it.json8
-rw-r--r--extensions/Variables/i18n/ja.json8
-rw-r--r--extensions/Variables/i18n/ko.json8
-rw-r--r--extensions/Variables/i18n/ksh.json8
-rw-r--r--extensions/Variables/i18n/lb.json8
-rw-r--r--extensions/Variables/i18n/lij.json8
-rw-r--r--extensions/Variables/i18n/mk.json8
-rw-r--r--extensions/Variables/i18n/ms.json8
-rw-r--r--extensions/Variables/i18n/nl.json8
-rw-r--r--extensions/Variables/i18n/oc.json8
-rw-r--r--extensions/Variables/i18n/pl.json8
-rw-r--r--extensions/Variables/i18n/pms.json9
-rw-r--r--extensions/Variables/i18n/pt-br.json8
-rw-r--r--extensions/Variables/i18n/pt.json8
-rw-r--r--extensions/Variables/i18n/qqq.json10
-rw-r--r--extensions/Variables/i18n/roa-tara.json8
-rw-r--r--extensions/Variables/i18n/ru.json8
-rw-r--r--extensions/Variables/i18n/sv.json8
-rw-r--r--extensions/Variables/i18n/tl.json8
-rw-r--r--extensions/Variables/i18n/uk.json8
-rw-r--r--extensions/Variables/i18n/zh-hans.json8
-rw-r--r--extensions/Variables/i18n/zh-hant.json4
-rw-r--r--extensions/Variables/package.json12
-rw-r--r--extensions/Variables/tests/mwparsertests/Variables.txt49
-rw-r--r--extensions/Variables/version4
-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--skins/ArchLinux/ArchLinuxTemplate.php3
-rw-r--r--skins/ArchLinux/arch.css18
-rw-r--r--skins/ArchLinux/archnavbar.css2
-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
101 files changed, 1601 insertions, 166 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/extensions/Variables/.gitignore b/extensions/Variables/.gitignore
new file mode 100644
index 00000000..e62fc28b
--- /dev/null
+++ b/extensions/Variables/.gitignore
@@ -0,0 +1,7 @@
+node_modules/
+vendor/
+
+.svn
+*~
+*.kate-swp
+.*.swp
diff --git a/extensions/Variables/.gitreview b/extensions/Variables/.gitreview
new file mode 100644
index 00000000..70796b30
--- /dev/null
+++ b/extensions/Variables/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.wikimedia.org
+port=29418
+project=mediawiki/extensions/Variables.git
+track=1
diff --git a/extensions/Variables/CODE_OF_CONDUCT.md b/extensions/Variables/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..d8e5d087
--- /dev/null
+++ b/extensions/Variables/CODE_OF_CONDUCT.md
@@ -0,0 +1 @@
+The development of this software is covered by a [Code of Conduct](https://www.mediawiki.org/wiki/Code_of_Conduct).
diff --git a/extensions/Variables/COPYING b/extensions/Variables/COPYING
new file mode 100644
index 00000000..de01985a
--- /dev/null
+++ b/extensions/Variables/COPYING
@@ -0,0 +1,16 @@
+Copyright (c) 2006 - 2007 by Rob Adams
+Copyright (c) 2007 by Tom Hempel
+Copyright (c) 2008 by Xiloynaha
+Copyright (c) 2009 - 2012 by Daniel Werner < danweetz@web.de >
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/extensions/Variables/Gruntfile.js b/extensions/Variables/Gruntfile.js
new file mode 100644
index 00000000..2db815fa
--- /dev/null
+++ b/extensions/Variables/Gruntfile.js
@@ -0,0 +1,29 @@
+/*jshint node:true */
+module.exports = function ( grunt ) {
+ grunt.loadNpmTasks( 'grunt-jsonlint' );
+ grunt.loadNpmTasks( 'grunt-contrib-jshint' );
+ grunt.loadNpmTasks( 'grunt-banana-checker' );
+
+ grunt.initConfig( {
+ banana: {
+ all: 'i18n/'
+ },
+ jshint: {
+ all: [
+ '**/*.js',
+ '!node_modules/**',
+ '!vendor/**'
+ ]
+ },
+ jsonlint: {
+ all: [
+ '**/*.json',
+ '!node_modules/**',
+ '!vendor/**'
+ ]
+ }
+ } );
+
+ grunt.registerTask( 'test', [ 'jsonlint', 'banana', 'jshint' ] );
+ grunt.registerTask( 'default', 'test' );
+};
diff --git a/extensions/Variables/README b/extensions/Variables/README
new file mode 100644
index 00000000..9c5b7492
--- /dev/null
+++ b/extensions/Variables/README
@@ -0,0 +1,19 @@
+== About ==
+
+The 'Variables' extension for MediaWiki introduces parser functions for defining page-scoped
+variables within wiki pages.
+
+* Website: https://www.mediawiki.org/wiki/Extension:Variables
+* Authors: Rob Adams, Tom Hempel, Xiloynaha and Daniel Werner
+* License: Public domain
+
+
+== Installation ==
+
+Once you have downloaded the code, place the 'Variables' directory within your
+MediaWiki 'extensions' directory. Then add the following code to your
+[[Manual:LocalSettings.php|LocalSettings.php]] file:
+
+ # Variables
+ require_once( "$IP/extensions/Variables/Variables.php" );
+
diff --git a/extensions/Variables/RELEASE-NOTES b/extensions/Variables/RELEASE-NOTES
new file mode 100644
index 00000000..57ed6686
--- /dev/null
+++ b/extensions/Variables/RELEASE-NOTES
@@ -0,0 +1,88 @@
+ git era Changelog:
+ ==================
+
+ * (trunk) -- Version 2.0.1
+ - Using 'InternalParseBeforeSanitize' hook instead of 'InternalParseBeforeLinks' for MW 1.20
+ - Put into gerrit.wikimedia.org git repository.
+
+
+ svn era Changelog:
+ ==================
+
+ * (trunk) -- Version 2.0.1
+ - Localization added for various languages.
+
+ * November 16, 2010 -- Version 2.0 by Daniel Werner
+ Version 2.0 almost is a complete rewrite of the extension, just the idea remains the
+ same. It's the attempt to get rid of several bugs caused by the fact that MediaWiki
+ is using several Parser objects. Therefore in v2 each Parser has its own Variables
+ store, so nothing will get mixed up anymore. Full compatibility is given, except perhaps
+ in cases where bugs were used intentionally.
+
+ New features and bugfixes:
+ - Inclusion of special pages in the middle of the page won't reset all defined
+ variables anymore.
+ - Variables should now be compatible with all other extensions, except for those still
+ using Parser::parse() recursively in any way (which should never be done!).
+ - For MW 1.12 and later, '#var' default value no longer gets expanded when not needed.
+ - Experimental new function '#var_final' which allows to insert the variables final
+ (last) value after page processing is almost through.
+ - Global configuration variable '$egVariablesDisabledFunctions' added.
+
+ Internal changes:
+ - Parser class member $mExtVariables now contains an instance of ExtVariables where
+ only variables for that parser are getting stored. They won't be deleted by other
+ Parser actions anymore (e.g. special page inclusion doesn't reset variables anymore)
+ - ExtVariables class now has public functions which should be used by other extensions
+ for getting and setting variables information.
+ - Removed global '$wgExtVariables' variable.
+ - 'Variables_Settings.php' file for configuration settings added.
+
+ Others:
+ - Put under 'ISC License' (public domain before).
+ - In case you are using Extension:Loops, you should update it as well to remain compatibility.
+
+
+ * November 14, 2011 -- Version 1.3.1.1 (re-pack of 1.3.1 tagged version for svn)
+ - Although 1.4 is released already and 2.0 in the trunk, ensure one last version
+ compatible with MW < 1.12 still is available
+ - Some comments cleaned, 'RELEASE-NOTES' and 'README' files added.
+
+
+ * November 13, 2011 -- Version 1.4 by Daniel Werner
+ - Cleanup for use with more current MW versions:
+ + 'ParserFirstCallInit' hook in use and no more global extension functions.
+ + State of the Art internationalization files added.
+ - Dropped support for MW before 1.12
+ - 'ExtVariables::VARIABLES' constant with version info added.
+ - Put into mediawiki.org svn, 'RELEASE-NOTES' and 'README' files added.
+
+
+ Pre svn Changelog:
+ ==================
+
+ The following pre-svn changelog was composed by Daniel Werner in the hope it might
+ give an almost complete overview of all major releases of 'Variables' extension.
+ All changes can still be retrace at
+
+ https://www.mediawiki.org/w/index.php?title=Extension:VariablesExtension&action=history
+
+ * July 20, 2010 -- Version 1.3 by Daniel Werner
+ - Removed critical bug. Some kind of "Superglobal" variables. In some cases values
+ were passed from one page to another page during page imports and job queue jobs.
+
+ * March 28, 2009 -- Version 1.2 by Daniel Werner
+ - '#varexists' function introduced
+ - parameter for default value for '#var' function in case the variable doesn't exist
+ or its value is just an empty string.
+
+ * December 5, 2008 -- Version 1.1 by user 'Xiloynaha'
+ - '#vardefineecho' function introduced
+
+ * June 24, 2007 -- r3, Language file added by unknown contributor
+
+ * October 11, 2006 -- r2, Fixes for MediaWiki 1.8 compatibility by Tom Hempel
+ - '$wgExtensionCredits' and '$wgHooks' being used.
+
+ * October 11, 2006 -- r1, initial release by Rob Adams
+ - First version of 'Variables', introducing '#vardefine' and '#var'
diff --git a/extensions/Variables/Variables.i18n.magic.php b/extensions/Variables/Variables.i18n.magic.php
new file mode 100644
index 00000000..7d7292f0
--- /dev/null
+++ b/extensions/Variables/Variables.i18n.magic.php
@@ -0,0 +1,22 @@
+<?php
+#coding: utf-8
+
+/**
+ * Internationalization file for magic words of the 'Variables' extension.
+ *
+ * @since 1.4
+ *
+ * @file Variables.i18n.magic.php
+ * @ingroup Variables
+ * @author Daniel Werner < danweetz@web.de >
+ */
+
+$magicWords = array();
+
+$magicWords['en'] = array(
+ 'var' => array( 0, 'var' ),
+ 'var_final' => array( 0, 'var_final' ),
+ 'vardefine' => array( 0, 'vardefine' ),
+ 'vardefineecho' => array( 0, 'vardefineecho' ),
+ 'varexists' => array( 0, 'varexists' ),
+);
diff --git a/extensions/Variables/Variables.php b/extensions/Variables/Variables.php
new file mode 100644
index 00000000..84d6c90c
--- /dev/null
+++ b/extensions/Variables/Variables.php
@@ -0,0 +1,375 @@
+<?php
+
+/**
+ * 'Variables' introduces parser functions for defining page-scoped variables within
+ * wiki pages.
+ *
+ * Documentation: https://www.mediawiki.org/wiki/Extension:Variables
+ * Support: https://www.mediawiki.org/wiki/Extension_talk:Variables
+ * Source code: https://phabricator.wikimedia.org/diffusion/EVAR/
+ *
+ * @license: ISC License
+ * @author: Rob Adams
+ * @author: Tom Hempel
+ * @author: Xiloynaha
+ * @author: Daniel Werner < danweetz@web.de >
+ *
+ * @file Variables.php
+ * @ingroup Variables
+ */
+
+// Ensure that the script cannot be executed outside of MediaWiki.
+if ( !defined( 'MEDIAWIKI' ) ) {
+ die( 'This is an extension to MediaWiki and cannot be run standalone.' );
+}
+
+// Display extension properties on MediaWiki.
+$wgExtensionCredits['parserhook'][] = array(
+ 'path' => __FILE__,
+ 'name' => 'Variables',
+ 'descriptionmsg' => 'variables-desc',
+ 'version' => ExtVariables::VERSION,
+ 'author' => array(
+ 'Rob Adams',
+ 'Tom Hempel',
+ 'Xiloynaha',
+ '[https://www.mediawiki.org/wiki/User:Danwe Daniel Werner]',
+ '...'
+ ),
+ 'url' => 'https://www.mediawiki.org/wiki/Extension:Variables',
+ 'license-name' => 'ISC'
+);
+
+// language files:
+$wgMessagesDirs['Variables'] = __DIR__ . '/i18n';
+$wgExtensionMessagesFiles['VariablesMagic'] = ExtVariables::getDir() . '/Variables.i18n.magic.php';
+
+// hooks registration:
+$wgHooks['ParserFirstCallInit'][] = 'ExtVariables::init';
+$wgHooks['ParserClearState'][] = 'ExtVariables::onParserClearState';
+$wgHooks['InternalParseBeforeSanitize'][] = 'ExtVariables::onInternalParseBeforeSanitize';
+
+// parser tests registration:
+$wgParserTestFiles[] = ExtVariables::getDir() . '/tests/mwparsertests/Variables.txt';
+
+// Include the settings file:
+require_once ExtVariables::getDir() . '/Variables.settings.php';
+
+
+/**
+ * Extension class with basic extension information. This class serves as static
+ * class with the static parser functions but also als variables store instance
+ * as object assigned to a Parser object.
+ */
+class ExtVariables {
+
+ /**
+ * Version of the 'Variables' extension.
+ *
+ * @since 1.4
+ *
+ * @var string
+ */
+ const VERSION = '2.2.0';
+
+ /**
+ * Internal store for variable values
+ *
+ * @private
+ * @var array
+ */
+ public $mVariables = array();
+
+ /**
+ * Array with all names of variables requested by '#var_final'. Key of the values is the
+ * stripSateId of the strip-item placed where the final var should appear.
+ *
+ * @since 2.0
+ *
+ * @private
+ * @var array
+ */
+ public $mFinalizedVars = array();
+
+ /**
+ * Variables extensions own private StripState manager to manage '#final_var' placeholders
+ * and their replacement with the final var value or a defined default.
+ *
+ * @since 2.0
+ *
+ * @private
+ * @var StripState
+ */
+ public $mFinalizedVarsStripState;
+
+ /**
+ * Sets up parser functions
+ *
+ * @since 1.4
+ */
+ public static function init( Parser &$parser ) {
+
+ /*
+ * store for variables per parser object. This will solve several bugs related to
+ * 'ParserClearState' hook clearing all variables early in combination with certain
+ * other extensions. (since v2.0)
+ */
+ $parser->mExtVariables = new self();
+
+ // Parser::SFH_OBJECT_ARGS available since MW 1.12
+ self::initFunction( $parser, 'var', array( __CLASS__, 'pfObj_var' ), Parser::SFH_OBJECT_ARGS );
+ self::initFunction( $parser, 'var_final' );
+ self::initFunction( $parser, 'vardefine' );
+ self::initFunction( $parser, 'vardefineecho' );
+ self::initFunction( $parser, 'varexists' );
+
+ return true;
+ }
+ private static function initFunction( Parser &$parser, $name, $functionCallback = null, $flags = 0 ) {
+ if( $functionCallback === null ) {
+ // prefix parser functions with 'pf_'
+ $functionCallback = array( __CLASS__, 'pf_' . $name );
+ }
+ global $egVariablesDisabledFunctions;
+
+ // register function only if not disabled by configuration:
+ if( ! in_array( $name, $egVariablesDisabledFunctions ) ) {
+ $parser->setFunctionHook( $name, $functionCallback, $flags );
+ }
+ }
+
+ /**
+ * Returns the extensions base installation directory.
+ *
+ * @since 2.0
+ *
+ * @return string
+ */
+ public static function getDir() {
+ static $dir = null;
+
+ if( $dir === null ) {
+ $dir = dirname( __FILE__ );
+ }
+ return $dir;
+ }
+
+
+ ####################
+ # Parser Functions #
+ ####################
+
+ static function pf_varexists( Parser &$parser, $varName = '', $exists=true, $noexists=false ) {
+ if( self::get( $parser )->varExists( $varName ) ) {
+ return $exists;
+ } else {
+ return $noexists;
+ }
+ }
+
+ static function pf_vardefine( Parser &$parser, $varName = '', $value = '' ) {
+ self::get( $parser )->setVarValue( $varName, $value );
+ return '';
+ }
+
+ static function pf_vardefineecho( Parser &$parser, $varName = '', $value = '' ) {
+ self::get( $parser )->setVarValue( $varName, $value );
+ return $value;
+ }
+
+ static function pfObj_var( Parser &$parser, $frame, $args) {
+ $varName = trim( $frame->expand( $args[0] ) ); // first argument expanded already but lets do this anyway
+ $varVal = self::get( $parser )->getVarValue( $varName, null );
+
+ // default applies if var doesn't exist but also in case it is an empty string!
+ if( $varVal === null || $varVal === '' ) {
+ // only expand argument when needed:
+ $defaultVal = isset( $args[1] ) ? trim( $frame->expand( $args[1] ) ) : '';
+ return $defaultVal;
+ }
+ return $varVal;
+ }
+
+ static function pf_var_final( Parser &$parser, $varName, $defaultVal = '' ) {
+ return self::get( $parser )->requestFinalizedVar( $parser, $varName, $defaultVal );
+ }
+
+
+ ##############
+ # Used Hooks #
+ ##############
+
+ /**
+ * Used for '#var_final' parser function to insert the final variable values.
+ * @see http://www.mediawiki.org/wiki/Manual:Hooks/InternalParseBeforeSanitize
+ *
+ * @since 2.0.1
+ */
+ static function onInternalParseBeforeSanitize( Parser &$parser, &$text ) {
+ $varStore = self::get( $parser );
+
+ // only do this if '#var_final' was used
+ if( $varStore->mFinalizedVarsStripState === null ) {
+ return true;
+ }
+
+ /*
+ * all vars are final now, check whether requested vars can be inserted for '#final_var' or
+ * if the default has to be inserted. In any case, adjust the strip item value
+ */
+ foreach( $varStore->mFinalizedVars as $stripStateId => $varName ) {
+
+ $varVal = $varStore->getVarValue( $varName, '' );
+ if( $varVal !== '' ) {
+ // replace strip item value with final variables value or registered default:
+ $varStore->stripStatePair( $stripStateId, $varVal );
+ }
+ }
+
+ /**
+ * Unstrip all '#var_final' strip-markers with their final '#var' or default values.
+ * This HAS to be done here and can't be done through the normal unstrip process of MW.
+ * This because the default value as well as the variables value stil have to be rendered properly since they
+ * may contain links or even category links. On the other hand, they can't be parsed with Parser::recursiveTagParse()
+ * since this would parse wiki templates and functions which are intended as normal text, kind of similar to
+ * returning a parser functions value with 'noparse' => true.
+ * Also, there is no way to expand the '#var_final' default value here, just if needed, since the output could be an
+ * entirely different, e.g. if variables are used.
+ * This method also takes care of recursive '#var_final' calls (within the default value) quite well.
+ */
+ $text = $varStore->mFinalizedVarsStripState->unstripGeneral( $text );
+ return true;
+ }
+
+ /**
+ * This will clean up the variables store after parsing has finished. It will prevent strange things to happen
+ * for example during import of several pages or job queue is running for multiple pages. In these cases variables
+ * would become some kind of superglobals, being passed from one page to the other.
+ */
+ static function onParserClearState( Parser &$parser ) {
+ /**
+ * MessageCaches Parser clone will mess things up if we don't reset the entire object.
+ * Only resetting the array would unset it in the original object as well! This instead
+ * will break the entire reference to the object
+ */
+ $parser->mExtVariables = new self();
+ return true;
+ }
+
+
+ ##################
+ # Private Helper #
+ ##################
+
+ /**
+ * Takes care of setting a strip state pair
+ */
+ protected function stripStatePair( $marker, $value ) {
+ $this->mFinalizedVarsStripState->addGeneral( $marker, $value );
+ }
+
+
+ ####################################
+ # Public functions for interaction #
+ ####################################
+ #
+ # public non-parser functions, accessible for
+ # other extensions doing interactive stuff
+ # with 'Variables' (like Extension:Loops)
+ #
+
+ /**
+ * Convenience function to return the 'Variables' extensions variables store connected
+ * to a certain Parser object. Each parser has its own store which will be reset after
+ * a parsing process [Parser::parse()] has finished.
+ *
+ * @param Parser &$parser
+ *
+ * @return ExtVariables by reference so we still have the right object after 'ParserClearState'
+ */
+ public static function &get( Parser &$parser ) {
+ return $parser->mExtVariables;
+ }
+
+ /**
+ * Defines a variable, accessible by getVarValue() or '#var' parser function. Name and
+ * value will be trimmed and converted to string.
+ *
+ * @param string $varName
+ * @param string $value will be converted to string if no string is given
+ */
+ public function setVarValue( $varName, $value = '' ) {
+ $this->mVariables[ trim( $varName ) ] = trim( $value );
+ }
+
+ /**
+ * Returns a variables value or null if it doesn't exist.
+ *
+ * @param string $varName
+ * @param mixed $defaultVal
+ *
+ * @return string or mixed in case $defaultVal is being returned and not of type string
+ */
+ public function getVarValue( $varName, $defaultVal = null ) {
+ $varName = trim( $varName );
+ if ( $this->varExists( $varName ) ) {
+ return $this->mVariables[ $varName ];
+ } else {
+ return $defaultVal;
+ }
+ }
+
+ /**
+ * Checks whether a variable exists within the scope.
+ *
+ * @param string $varName
+ *
+ * @return boolean
+ */
+ public function varExists( $varName ) {
+ $varName = trim( $varName );
+ return array_key_exists( $varName, $this->mVariables );
+ }
+
+ /**
+ * Allows to unset a certain variable
+ *
+ * @param type $varName
+ */
+ public function unsetVar( $varName ) {
+ unset( $this->mVariables[ $varName ] );
+ }
+
+ /**
+ * Allows to register the usage of '#var_final'. Meaning a variable can be set as well
+ * as a default value. The return value, a strip-item then can be inserted into any
+ * wikitext processed by the same parser. Later that strip-item will be replaced with
+ * the final var text.
+ * Note: It's not possible to use the returned strip-item within other stripped text
+ * since 'Variables' unstripping will happen before the general unstripping!
+ *
+ * @param Parser $parser
+ * @param string $varName
+ * @param string $defaultVal
+ *
+ * @return string strip-item
+ */
+ function requestFinalizedVar( Parser &$parser, $varName, $defaultVal = '' ) {
+ if( $this->mFinalizedVarsStripState === null ) {
+ $this->mFinalizedVarsStripState = new StripState;
+ }
+ $id = count( $this->mFinalizedVars );
+ /*
+ * strip-item which will be unstripped in self::onInternalParseBeforeSanitize()
+ * In case the requested final variable has a value in the end, this strip-item
+ * value will be replaced with that value before unstripping.
+ */
+ $rnd = "{$parser->mUniqPrefix}-finalizedvar-{$id}-" . Parser::MARKER_SUFFIX;
+
+ $this->stripStatePair( $rnd, trim( $defaultVal ) );
+ $this->mFinalizedVars[ $rnd ] = trim( $varName );
+
+ return $rnd;
+ }
+
+}
diff --git a/extensions/Variables/Variables.settings.php b/extensions/Variables/Variables.settings.php
new file mode 100644
index 00000000..43b04cdf
--- /dev/null
+++ b/extensions/Variables/Variables.settings.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * File defining the settings for the 'Variables' extension.
+ * More info can be found at http://www.mediawiki.org/wiki/Extension:Variables#Configuration
+ *
+ * NOTICE:
+ * =======
+ * Changing one of these settings can be done by copying and placing
+ * it in LocalSettings.php, AFTER the inclusion of 'Variables'.
+ *
+ * @file Variables_Settings.php
+ * @ingroup Variables
+ * @since 2.0
+ *
+ * @author Daniel Werner
+ */
+
+/**
+ * Allows to define functions which should not be available within the wiki.
+ *
+ * @example
+ * # disable '#var_final' and '#vardefineecho' functions:
+ * $egVariablesDisabledFunctions = array( 'var_final', 'vardefineecho' );
+ *
+ * @since 2.0
+ * @var array
+ */
+$egVariablesDisabledFunctions = array();
diff --git a/extensions/Variables/gitinfo.json b/extensions/Variables/gitinfo.json
new file mode 100644
index 00000000..c972f07f
--- /dev/null
+++ b/extensions/Variables/gitinfo.json
@@ -0,0 +1 @@
+{"headSHA1": "c75b9d4669d15397ada8480d64cfe17dea798495\n", "head": "c75b9d4669d15397ada8480d64cfe17dea798495\n", "remoteURL": "https://gerrit.wikimedia.org/r/mediawiki/extensions/Variables", "branch": "c75b9d4669d15397ada8480d64cfe17dea798495\n", "headCommitDate": "1501149227"} \ No newline at end of file
diff --git a/extensions/Variables/i18n/ast.json b/extensions/Variables/i18n/ast.json
new file mode 100644
index 00000000..102fa51a
--- /dev/null
+++ b/extensions/Variables/i18n/ast.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu"
+ ]
+ },
+ "variables-desc": "Funciones analítiques que permiten trabayar con variables dinámiques nun contestu d'artículu"
+}
diff --git a/extensions/Variables/i18n/be-tarask.json b/extensions/Variables/i18n/be-tarask.json
new file mode 100644
index 00000000..2ed73e0b
--- /dev/null
+++ b/extensions/Variables/i18n/be-tarask.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jim-by",
+ "Wizardist"
+ ]
+ },
+ "variables-desc": "Функцыі парсэра для працы з дынамічнымі зьменнымі ў кантэксьце артыкулаў"
+}
diff --git a/extensions/Variables/i18n/de.json b/extensions/Variables/i18n/de.json
new file mode 100644
index 00000000..c234ec34
--- /dev/null
+++ b/extensions/Variables/i18n/de.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Daniel Werner",
+ "Kghbln"
+ ]
+ },
+ "variables-desc": "Ergänzt Parserfunktionen die dynamische Variablen ermöglichen"
+}
diff --git a/extensions/Variables/i18n/dsb.json b/extensions/Variables/i18n/dsb.json
new file mode 100644
index 00000000..51809668
--- /dev/null
+++ b/extensions/Variables/i18n/dsb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "variables-desc": "Parserowe funkcije, kótarež dowóluju źěłanje z dynamiskimi wariablami w nastawkach"
+}
diff --git a/extensions/Variables/i18n/el.json b/extensions/Variables/i18n/el.json
new file mode 100644
index 00000000..548f021d
--- /dev/null
+++ b/extensions/Variables/i18n/el.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Protnet"
+ ]
+ },
+ "variables-desc": "Συναρτήσεις συντακτικού αναλυτή που επιτρέπουν την εργασία με δυναμικές μεταβλητές σε πλαίσιο εύρους άρθρου"
+}
diff --git a/extensions/Variables/i18n/en.json b/extensions/Variables/i18n/en.json
new file mode 100644
index 00000000..b99b95f5
--- /dev/null
+++ b/extensions/Variables/i18n/en.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Daniel Werner"
+ ]
+ },
+ "variables-desc": "Parser functions allowing to work with dynamic variables in an article scoped context"
+}
diff --git a/extensions/Variables/i18n/es.json b/extensions/Variables/i18n/es.json
new file mode 100644
index 00000000..940100e4
--- /dev/null
+++ b/extensions/Variables/i18n/es.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armando-Martin"
+ ]
+ },
+ "variables-desc": "Funciones de analizador (parser) que permiten trabajar con variables dinámicas en el contexto de un artículo"
+}
diff --git a/extensions/Variables/i18n/fa.json b/extensions/Variables/i18n/fa.json
new file mode 100644
index 00000000..3f8949ed
--- /dev/null
+++ b/extensions/Variables/i18n/fa.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armin1392"
+ ]
+ },
+ "variables-desc": "عملیات تجزیه‌کننده برای کار کردن با متغیرهای پویا در یک مقاله بافت محدود شده، اجازه می‌دهد"
+}
diff --git a/extensions/Variables/i18n/fr.json b/extensions/Variables/i18n/fr.json
new file mode 100644
index 00000000..6cf721ab
--- /dev/null
+++ b/extensions/Variables/i18n/fr.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "DavidL"
+ ]
+ },
+ "variables-desc": "Fonctions de l'interpréteur permettant de travailler avec les variables dynamiques dans le contexte d'un article"
+}
diff --git a/extensions/Variables/i18n/gl.json b/extensions/Variables/i18n/gl.json
new file mode 100644
index 00000000..d75232cf
--- /dev/null
+++ b/extensions/Variables/i18n/gl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Toliño"
+ ]
+ },
+ "variables-desc": "Funcións analíticas destinadas aos artigos que permiten traballar con variables dinámicas"
+}
diff --git a/extensions/Variables/i18n/he.json b/extensions/Variables/i18n/he.json
new file mode 100644
index 00000000..d593d459
--- /dev/null
+++ b/extensions/Variables/i18n/he.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80"
+ ]
+ },
+ "variables-desc": "פונקציות מפענח שמאפשרות עבודה עם משתנים דינמיים בהקשר בתחום של ערך"
+}
diff --git a/extensions/Variables/i18n/hsb.json b/extensions/Variables/i18n/hsb.json
new file mode 100644
index 00000000..da4ed62c
--- /dev/null
+++ b/extensions/Variables/i18n/hsb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "variables-desc": "Parserowe funkcije, kotre dźěłanje z dynamiskimi wariablemi w nastawkach dowoleja"
+}
diff --git a/extensions/Variables/i18n/ia.json b/extensions/Variables/i18n/ia.json
new file mode 100644
index 00000000..0af21568
--- /dev/null
+++ b/extensions/Variables/i18n/ia.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "variables-desc": "Functiones del analysator syntactic que permitte laborar con variabiles dynamic in un \"article scoped context\""
+}
diff --git a/extensions/Variables/i18n/it.json b/extensions/Variables/i18n/it.json
new file mode 100644
index 00000000..f178cc94
--- /dev/null
+++ b/extensions/Variables/i18n/it.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16"
+ ]
+ },
+ "variables-desc": "Funzioni parser che permettono di lavorare con variabili dinamiche in una pagina con ambito di contesto"
+}
diff --git a/extensions/Variables/i18n/ja.json b/extensions/Variables/i18n/ja.json
new file mode 100644
index 00000000..94f7e865
--- /dev/null
+++ b/extensions/Variables/i18n/ja.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fryed-peach"
+ ]
+ },
+ "variables-desc": "記事をスコープとするコンテキストで動的変数を利用可能にするパーサー関数"
+}
diff --git a/extensions/Variables/i18n/ko.json b/extensions/Variables/i18n/ko.json
new file mode 100644
index 00000000..826facd5
--- /dev/null
+++ b/extensions/Variables/i18n/ko.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "아라"
+ ]
+ },
+ "variables-desc": "문서 범위 맥락에서 동적 변수와 함께 작동할 수 있도록 하는 파서 함수"
+}
diff --git a/extensions/Variables/i18n/ksh.json b/extensions/Variables/i18n/ksh.json
new file mode 100644
index 00000000..7eb61da1
--- /dev/null
+++ b/extensions/Variables/i18n/ksh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "variables-desc": "Paaser-Funxjuhne för dynaamesch Varijable em Zusammehang met Atikelle."
+}
diff --git a/extensions/Variables/i18n/lb.json b/extensions/Variables/i18n/lb.json
new file mode 100644
index 00000000..3c0e5dfc
--- /dev/null
+++ b/extensions/Variables/i18n/lb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby"
+ ]
+ },
+ "variables-desc": "Parserfonktiounen déi et erlabe fir mat dynamesche Variabelen am Kontext vun engem Artikel ze schaffen"
+}
diff --git a/extensions/Variables/i18n/lij.json b/extensions/Variables/i18n/lij.json
new file mode 100644
index 00000000..2c870016
--- /dev/null
+++ b/extensions/Variables/i18n/lij.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Giromin Cangiaxo"
+ ]
+ },
+ "variables-desc": "Fonçioin parser che permettan de travagiâ con de variabbile dinammiche into contesto de 'n articcolo."
+}
diff --git a/extensions/Variables/i18n/mk.json b/extensions/Variables/i18n/mk.json
new file mode 100644
index 00000000..9b7b5c5e
--- /dev/null
+++ b/extensions/Variables/i18n/mk.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06"
+ ]
+ },
+ "variables-desc": "Rасчленувачки функции што овозможуваат работа со динамични променливи во контекст со опфатност определена во страница"
+}
diff --git a/extensions/Variables/i18n/ms.json b/extensions/Variables/i18n/ms.json
new file mode 100644
index 00000000..8cf3cb8d
--- /dev/null
+++ b/extensions/Variables/i18n/ms.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia"
+ ]
+ },
+ "variables-desc": "Fungsi-fungsi penghurai yang membenarkan kerja dengan pembolehubah dinamk dalam konteks berskop rencana"
+}
diff --git a/extensions/Variables/i18n/nl.json b/extensions/Variables/i18n/nl.json
new file mode 100644
index 00000000..48c18209
--- /dev/null
+++ b/extensions/Variables/i18n/nl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Saruman"
+ ]
+ },
+ "variables-desc": "Parserfuncties die het mogelijk maken om met dynamische variabelen te werken in een paginacontext"
+}
diff --git a/extensions/Variables/i18n/oc.json b/extensions/Variables/i18n/oc.json
new file mode 100644
index 00000000..5f57be70
--- /dev/null
+++ b/extensions/Variables/i18n/oc.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cedric31"
+ ]
+ },
+ "variables-desc": "Foncions de l'interpretador que permeton de trabalhar amb las variablas dinamicas dins lo contèxte d'un article"
+}
diff --git a/extensions/Variables/i18n/pl.json b/extensions/Variables/i18n/pl.json
new file mode 100644
index 00000000..0493a77b
--- /dev/null
+++ b/extensions/Variables/i18n/pl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "BeginaFelicysym"
+ ]
+ },
+ "variables-desc": "Funkcje parsera umożliwiają pracę ze zmiennymi dynamicznymi w kontekście ograniczonym do artykułu"
+}
diff --git a/extensions/Variables/i18n/pms.json b/extensions/Variables/i18n/pms.json
new file mode 100644
index 00000000..9a77fa37
--- /dev/null
+++ b/extensions/Variables/i18n/pms.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Dragonòt"
+ ]
+ },
+ "variables-desc": "Funsion ëd l'analisator ch'a përmëtto ëd travajé con le variàbij dinàmiche ant ël contest ëd n'artìcol"
+}
diff --git a/extensions/Variables/i18n/pt-br.json b/extensions/Variables/i18n/pt-br.json
new file mode 100644
index 00000000..4e1abf2a
--- /dev/null
+++ b/extensions/Variables/i18n/pt-br.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cainamarques"
+ ]
+ },
+ "variables-desc": "Funções sintáticas que permitem trabalhar com variáveis dinâmicas no contexto de um artigo"
+}
diff --git a/extensions/Variables/i18n/pt.json b/extensions/Variables/i18n/pt.json
new file mode 100644
index 00000000..c907bfb6
--- /dev/null
+++ b/extensions/Variables/i18n/pt.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hamilton Abreu"
+ ]
+ },
+ "variables-desc": "Funções do analisador sintático que permitem trabalhar com variáveis dinâmicas num contexto limitado ao âmbito de uma página"
+}
diff --git a/extensions/Variables/i18n/qqq.json b/extensions/Variables/i18n/qqq.json
new file mode 100644
index 00000000..7976e780
--- /dev/null
+++ b/extensions/Variables/i18n/qqq.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha",
+ "Shirayuki",
+ "Umherirrender"
+ ]
+ },
+ "variables-desc": "{{desc|name=Variables|url=https://www.mediawiki.org/wiki/Extension:Variables}}"
+}
diff --git a/extensions/Variables/i18n/roa-tara.json b/extensions/Variables/i18n/roa-tara.json
new file mode 100644
index 00000000..9fc0cf60
--- /dev/null
+++ b/extensions/Variables/i18n/roa-tara.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "variables-desc": "Le funziune analizzatrice permettene de fatià cu le variabbile dinameche jndr'à 'na vôsce jndr'à 'nu condeste"
+}
diff --git a/extensions/Variables/i18n/ru.json b/extensions/Variables/i18n/ru.json
new file mode 100644
index 00000000..c9fc605b
--- /dev/null
+++ b/extensions/Variables/i18n/ru.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Putnik"
+ ]
+ },
+ "variables-desc": "Функции парсера, позволяющие работать с динамическими переменными в контексте области статьи"
+}
diff --git a/extensions/Variables/i18n/sv.json b/extensions/Variables/i18n/sv.json
new file mode 100644
index 00000000..0c87d22c
--- /dev/null
+++ b/extensions/Variables/i18n/sv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lokal Profil"
+ ]
+ },
+ "variables-desc": "Parserfunktioner som gör det möjligt att arbeta med dynamiska variabler en artikelkontext"
+}
diff --git a/extensions/Variables/i18n/tl.json b/extensions/Variables/i18n/tl.json
new file mode 100644
index 00000000..c2407aff
--- /dev/null
+++ b/extensions/Variables/i18n/tl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw"
+ ]
+ },
+ "variables-desc": "Mga tungkulin ng pambanghay na nagpapahintulot na gumawa sa piling ng dinamikong mga bagay na nagpapabagu-bago sa loob ng isang diwang nasasaklawan ng artikulo"
+}
diff --git a/extensions/Variables/i18n/uk.json b/extensions/Variables/i18n/uk.json
new file mode 100644
index 00000000..93b661a5
--- /dev/null
+++ b/extensions/Variables/i18n/uk.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Base"
+ ]
+ },
+ "variables-desc": "Функції парсера, що дозволяють працювати із динамічними змінними у контексті статей"
+}
diff --git a/extensions/Variables/i18n/zh-hans.json b/extensions/Variables/i18n/zh-hans.json
new file mode 100644
index 00000000..92d560bc
--- /dev/null
+++ b/extensions/Variables/i18n/zh-hans.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hzy980512"
+ ]
+ },
+ "variables-desc": "允许解析器函数在一个文章范围内使用动态变量"
+}
diff --git a/extensions/Variables/i18n/zh-hant.json b/extensions/Variables/i18n/zh-hant.json
new file mode 100644
index 00000000..d6733901
--- /dev/null
+++ b/extensions/Variables/i18n/zh-hant.json
@@ -0,0 +1,4 @@
+{
+ "@metadata": [],
+ "variables-desc": "允許解析器函數在一個文章範圍內使用動態變量"
+}
diff --git a/extensions/Variables/package.json b/extensions/Variables/package.json
new file mode 100644
index 00000000..e87548ca
--- /dev/null
+++ b/extensions/Variables/package.json
@@ -0,0 +1,12 @@
+{
+ "private": true,
+ "scripts": {
+ "test": "grunt test"
+ },
+ "devDependencies": {
+ "grunt": "1.0.1",
+ "grunt-banana-checker": "0.5.0",
+ "grunt-contrib-jshint": "1.1.0",
+ "grunt-jsonlint": "1.1.0"
+ }
+}
diff --git a/extensions/Variables/tests/mwparsertests/Variables.txt b/extensions/Variables/tests/mwparsertests/Variables.txt
new file mode 100644
index 00000000..d35578c4
--- /dev/null
+++ b/extensions/Variables/tests/mwparsertests/Variables.txt
@@ -0,0 +1,49 @@
+# @todo expand
+!! functionhooks
+var
+!! endfunctionhooks
+
+!! test
+#vardefine, #vardefineecho and #var
+!! input
+{{#vardefine: a | Test }}
+"{{#var: a }}"
+"{{#vardefineecho: a | Test 2 }}, {{#var: a }}"
+!!result
+<p>"Test"
+"Test 2, Test 2"
+</p>
+!! end
+
+!! test
+#varexists
+!! input
+{{#varexists: a }}{{#vardefine: a }}
+"{{#varexists: a }}"
+!!result
+<p>"1"
+</p>
+!! end
+
+!! test
+#var_final
+!! input
+"{{#var_final: a }}"
+{{#vardefine: a | something }}"{{#var: a }}"
+{{#vardefine: a | final }}"{{#var_final: a }}"
+!!result
+<p>"final"
+"something"
+"final"
+</p>
+!! end
+
+!! test
+Variables should not be reset on special page inclusion (old bug, solved in Variables 2.0)
+!! input
+{{#vardefine: a | 1 }}{{#vardefine: | {{Special:AllPages}} }}
+"{{#var: a }}"
+!!result
+<p>"1"
+</p>
+!! end
diff --git a/extensions/Variables/version b/extensions/Variables/version
new file mode 100644
index 00000000..a2d7d697
--- /dev/null
+++ b/extensions/Variables/version
@@ -0,0 +1,4 @@
+Variables: REL1_30
+2017-09-21T22:24:13
+
+c75b9d4
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/skins/ArchLinux/ArchLinuxTemplate.php b/skins/ArchLinux/ArchLinuxTemplate.php
index 3e10befc..26811599 100644
--- a/skins/ArchLinux/ArchLinuxTemplate.php
+++ b/skins/ArchLinux/ArchLinuxTemplate.php
@@ -52,7 +52,8 @@ class ArchLinuxTemplate extends BaseTemplate {
<li id="anb-home"><a href="https://www.parabola.nu/" title="Parabola news, packages, projects and more">Home</a></li>
<li id="anb-packages"><a href="https://www.parabola.nu/packages/" title="Package Database">Packages</a></li>
<li id="anb-wiki" class="anb-selected"><a href="https://wiki.parabola.nu/" title="Community documentation">Wiki</a></li>
- <li id="anb-bugs"><a href="https://labs.parabola.nu" title="Issue Tracker">Bugs</a></li>
+ <li id="anb-forum"><a href="https://labs.parabola.nu/projects/parabola-community-forum" title="Parabola Community Forum">Forum</a></li>
+ <li id="anb-bugs"><a href="https://labs.parabola.nu" title="Issue Tracker">Issues</a></li>
<li id="anb-projects"><a href="https://projects.parabola.nu/" title="Our Code">Projects</a></li>
<li id="anb-download"><a href="https://wiki.parabola.nu/Get_Parabola" title="Get Parabola">Download</a></li>
</ul>
diff --git a/skins/ArchLinux/arch.css b/skins/ArchLinux/arch.css
index c8abb749..7f628097 100644
--- a/skins/ArchLinux/arch.css
+++ b/skins/ArchLinux/arch.css
@@ -48,9 +48,11 @@ ul,
border-collapse: collapse;
padding: 2px;
}
+/*
#bodyContent td {
padding: 2px;
}
+*/
/* links (including page tabs and personal toolbar) */
#bodyContent > div.mw-content-ltr a,
@@ -176,3 +178,19 @@ div#footer {
#archnavbar ul li.anb-selected a {
color: white !important;
}
+
+/* downloads page */
+.isos-table th { padding: 8px 12px 8px 12px ; }
+.isos-table td:nth-child(1) { padding: 8px 12px 8px 12px ; }
+.isos-table td:nth-child(2) { padding: 8px 12px 8px 12px ; }
+.isos-table td:nth-child(3) { padding: 8px 12px 8px 12px ; }
+.isos-table td:nth-child(4) { padding: 8px 12px 8px 12px ; text-align: center ; }
+.isos-table td:nth-child(5) { padding: 8px 12px 8px 12px ; text-align: right ; }
+.isos-table td:nth-child(6) { padding: 8px 12px 8px 12px ; text-align: center ; }
+.isos-table td:nth-child(7) { padding: 8px 12px 8px 12px ; text-align: center ; }
+.isos-table td:nth-child(8) { padding: 8px 12px 8px 12px ; text-align: center ; }
+.isos-table td:nth-child(7) a:nth-child(2) { padding: 0em 1em 0em 1em !important ; }
+
+/* remove that annoying icon after external links
+ and that annoying space after internal links */
+a.external { padding-right: 0px !important ; background-image: none !important ; }
diff --git a/skins/ArchLinux/archnavbar.css b/skins/ArchLinux/archnavbar.css
index 574d8b2b..b3eb92fd 100644
--- a/skins/ArchLinux/archnavbar.css
+++ b/skins/ArchLinux/archnavbar.css
@@ -5,7 +5,7 @@
*/
/* container for the entire bar */
-#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #000 !important; border-bottom: 5px #787DAB solid !important; }
+#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #404060 !important; border-bottom: 5px #787DAB solid !important; }
#archnavbarlogo { float: left !important; margin: -5px 0 0 0 !important; padding: 0 !important; height: 50px !important; width: 324px !important; background: url('archlogo.png') no-repeat !important; }
/* move the heading/paragraph text offscreen */
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',