Why:
- From MediaWiki 1.36 to MediaWiki 1.44 (inclusive),
`PostgresUpdater.php` contains a typo in the instruction to rename
the `sites_group` index to `site_group`.
- This typo means that - on Postgres wikis - the MediaWiki update
script will not currently rename this index as intended, as the index
which the updater is told to rename (i.e., containing the typo)
doesn't exist.
- From MediaWiki 1.42 onwards, this typo indirectly causes `update.php`
on Postgres wikis to throw an error on its first run:
- From MW 1.42 onwards, the update script included an instruction to
drop multiple indexes on the `sites` table, including this index
that was previously intended to be renamed.
- However, as this typo meant that the `sites_group` index was never
renamed on Postgres wikis, the database is unable to find the
renamed index in order to drop it; and consequently throws an
error (reported on Phabricator as T374042).
- This only affects the first run of `update.php` due to the fact
that - when deciding whether to apply the patch containing _all_ of
the index-drops for the `sites` table - the `dropIndex` instruction
only checks for the existence of the `site_type` index (and, if the
`site_type` index doesn't exist, the patch as a whole isn't applied).
However, as - within `patch-sites-drop_indexes.sql` - the statement
to drop the `site_type` index is located _before_ the instruction to
drop the `site_group` index, the `site_type` index will have been
dropped on the first run of `update.php`.
- This also means that - on any future runs of `update.php` - the
indexes listed after (and including) `site_group` in that SQL file
will currently remain un-dropped.
What:
- Fix the typo in the PostgresUpdater index renaming instruction:
`'sites_group, '` -> `'sites_group'`
- Update PostgresUpdater to individually re-attempt to drop the indexes
listed after & including `site_group` in
`patch-sites-drop_indexes.sql`, to ensure that they're dropped on
Postgres wikis that have already (1) upgraded to MW 1.42+, & (2) ran
`update.php`.
(These could theoretically have all been combined within one extra
SQL patch, rather than one for each index; but I thought it might be
best for the updater to check for the existence of each of these
indexes individually before it attempts to drop each one.)
Follows-up 9907b56c9b, 616744db1d
Bug: T374042
Change-Id: Ie6ffa92153e64ca653f726a35a5a6b5d95d093f5
Reason for backport:
This can also be a Debian 13 support issue, some MW installations may
have had `$wgLocaltimezone` set to deprecated values[1] like `PRC`
by the installer or manually.
After they upgrade to Debian 13, the `tzdata` package no longer
provides these timezones, and the `tzdata-legacy` package is not to be
installed by default.
[1]: https://www.php.net/manual/en/timezones.others.php
Bug: T380423
Change-Id: Ie2001796442ee6ba973fdb4b7b1dc7312f802e8d
(cherry picked from commit 45dc435d897d7716ddc8215cb841b07f1c7a2f9c)
- Handle GPS tags with decimal rational number instead of array of dms
rationals
- Mod the decimal values
- Increase validation on GPS tag format
Bug: T386208
Change-Id: Ief823af317bbb01b4a05e34b1d189ce1deaa1f33
(cherry picked from commit 55ffc43a596c0547986322ffe679d37daa921be7)
Use coalesce operator to check if the array key exists
Change-Id: Icf24e208a487bafe3d1983536870aac19cfc4b5e
(cherry picked from commit f0ad539b4e613216639b04386f56d6bb1b656d14)
In a future patch (Ia690f10ccbf4f60f9febca98915155c2df58f0d4) we will
use native JsonCodec serialization of the TOCData object. But first
we will add forward-compatibility code to deserialize TOCData, so that
if we need to rollback the future release we won't break the parser
cache.
New serialization test cases added, as per
https://www.mediawiki.org/wiki/Manual:Parser_cache/Serialization_compatibility
Bug: T327439
Change-Id: I4652b2709afd33ff5e469e36960391e993bc7bae
(cherry picked from commit bf61f6bc0eaf5013167e4b80860b0a610559c661)
Something changed in WMF CI config that causes this warning to be
emitted, perhaps T397429#11035011.
Change-Id: Ib477c1812c48a96b252a4f687e09f1ca5c30c2f3
(cherry picked from commit 4b5fc06c5e34b0a9332c9228ac3c28fd0f750c6c)
WHAT:
- Return the GTID style from `MySQLPrimaryPos::parseGTID`, which already identifies the style during parse.
- Rely on `parseGTID`'s detection in `MySQLPrimaryPos::init`.
WHY:
- When GTID-based replication is enabled and MySQL is used for the database, MediaWiki misidentifies the engine as MariaDB.
- This causes position waits to fail with "No active GTIDs in $1 share a domain with those in $1".
- This is a regression caused by I232274feb12c0ce4826be2c46a35315b425f6673:
- Before that change, parseGTID returned the domain ID as an integer for MariaDB and as a string for MySQL.
- The `init` method used this fact (`is_int`) when determining the GTID style.
- After the change, parseGTID always returns the domain ID as a string.
- The check in `init` was incorrectly updated to expect a string for MariaDB, but did not account for MySQL's source ID also being a string.
Change-Id: I4951e7967a45bae10d26b06ee236a55279fa8fb9
(cherry picked from commit 54154c87c084543fd659f24ae6b4c276184259cc)
This regression was introduced in I6670a58fe1.
Bug: T399793
Co-Authored-By: Jonathan Lee <cookmeplox@weirdgloop.org>
Change-Id: I26b61e2a08b51aaca5d2740dcaf20b509be380eb
(cherry picked from commit fa05279424e0688a7b34f1186050dca1e2ec5f4b)
We were getting PREG_BACKTRACK_LIMIT_ERROR in production from certain
inputs to Parser::extractBody(). Use possessive matchers and a
once-only subpattern to ensure that we don't backtrack unnecessarily
once a <body> tag is found.
Bug: T399064
Follows-Up: I59abad3a58ccd6edc6517b13a56d8253ba0e0928
Change-Id: If6860ca268236cf428d574f6bb21c2070f5aa6a3
(cherry picked from commit 2c56237235a5603a1757982f02d3e542bdafaf06)
Add a check for regex failure in the extractBody method and throw
a RuntimeException with the error details if preg_replace returns null.
Bug: T388729
Change-Id: I59abad3a58ccd6edc6517b13a56d8253ba0e0928
(cherry picked from commit 3b297d37dd368d1d66f7afd78851bbb7a47cab0b)
Add missing namespace prefix to the constant
Change-Id: I3ba37863b1e4de9d64d1c09045c0e5b1da678425
(cherry picked from commit ec02426638f0732a345bd8376f55819ec777741a)
A non-existing field may return null, when trying to drop the default.
Avoid a fatal error in this situation.
There is no real issue yet, but good coding practice to check for null.
Change-Id: I1041f24361febb52fd7fb20c42348b712dd70fe9
* Fix test failures
* Cherry-pick message cache change I957b6fb2bc0d9d4b1aae6e
* Cherry-pick part of I638d6d6d23f9624ba1dff0f4fcc to change cache from
static to non-static.
Change-Id: I77a2facf9923d38269538e48c79365fa117af9af
Follows-Up: Id5462b942f5e916c2f1dc725739615d54a1070de
Follows-Up: I5471fe615d222b936c6668bf3089dd8b5931cc75
Follows-Up: I7bbd6ae36a11840ed6b4620b5d07fa5158ff139e
CVE-2025-6927
In BlockListPager, restore the bl_deleted=0 condition removed in the
previous commit. Add tests.
Bug: T397595
Change-Id: I5471fe615d222b936c6668bf3089dd8b5931cc75
CVE-2025-6927
ApiQueryBlock was relying only on the filter returned by
HideUserUtils::getExpression which only works for blocks targeting a
user account
Bug: T397595
Change-Id: I7bbd6ae36a11840ed6b4620b5d07fa5158ff139e
CVE-2025-6590
The HTMLUserTextField is accessible to logged-out users on private wikis
through Special:PasswordReset. Validation error messages returned by this
field included unescaped usernames parsed as wikitext. This allowed
logged-out attackers arbitrary access to the parser, enabling them to
reveal page contents through transclusion, e.g., "{{:Private page}}".
Escape the username parameter using wfEscapeWikiText() to prevent
wikitext interpretation in error messages.
Bug: T392746
Change-Id: Ifd8283e107e1655fa3f5694183c4f67954e5c4c5
CVE-2025-6926
This is a workaround for extensions with some sort of "autologin"
implemented via the login page to indicate that the login flow
didn't involve the user actually logging in, it merely copied
some central login state, and so isn't appropriate for the
reauthentication flag.
This isn't the best way to provide an interface to extensions
(if we keep it, a more explicit interface, such as a
SessionPropertiesAuthenticationRequest object that's part of
the initial request set and can be modified by providers,
and can also be used for the "remember me" flag, would be
nicer), and maybe the whole approach of letting extensions
suppress the reauthentication flag is not the best way of
handling the problem in the first place, but it's simple
which is important for a security patch.
Bug: T389010
Change-Id: Ifce73837b25b0caad2d3d3cba000cceb0184c29d
CVE-2025-6597
Auotcreation doesn't necessarily involve real-time user
identification, it can be based on some provider identifying the
user based on a session cookie or similar low-fidelity information.
Do not restart the reauthentication timer.
Bug: T389009
Change-Id: Icfb4d0ffe71a92421e8630a92ae302cc459aa9d6
CVE-2025-6591
This is the same issue as CVE-2025-32072 (T386175), except in the
API's feedcontributions module. Escape the "Contributions" and
"colon-separator" messages so administrators cannot inject HTML
into them, triggering a potential XSS in feed readers.
Bug: T392276
Change-Id: Ic590a0d0cfc0a4a1e61859ecc57a175a8f5ec098
When autoload of HookRunner class fails (due to wrong namespaced
interface), it cannot be used in the exception handler,
that results in error about not found class, hiding the real error.
Bug: T387408
Change-Id: I93daa8b05bab42a4008a3bc09f26c7e041030a22
(cherry picked from commit 2037f6e41fcfa4b5240912f7fe09bc28ea1f0ae9)
Why:
- The exception handler may be triggered during service container
initialization, e.g. if an autoloaded class triggers a deprecation
warning.
- This causes callLogExceptionHook() to try to setup the service
container once again, which then causes a cryptic "class not found"
error as the service container attempts to autoload whatever class
triggered the deprecation warning once again and fails.
What:
- Avoid attempting to initialize the service container in our exception
handler if it was not setup already, since it may be unsafe to do so.
Bug: T380456
Change-Id: Ib439f25d9e309b77eac00c59c32e39ffbf3aa2a4
(cherry picked from commit 0b1480e60ef7d649bf7d22de5a7c032d04ed0f7a)
A special page has access to the request context which includes the site
config, no need to inject that separately here.
Change-Id: If8f01466c64dbacf806b6fccfa0bc4736c259607
(cherry picked from commit 0110bba7c9a8bdaf1cd8579534300c76b29c038a)
Int and float fields that are optional cannot currently specify the min
attribute. An unfilled value fails the validation because in PHP 8 any
number is greater than the empty string.
(For comparing numbers with non-numeric strings, the number is first
converted to a string and then compared. In PHP 7, the string was
converted to a number instead.)
Bug: T397883
Bug: T397643
Change-Id: I37be84554708e17eee27a7e599815891787e95bf
(cherry picked from commit 8e7ae749c0870e8133d083ac4125280c11a12ea6)
Why:
- action=compare was used to circumvent Lockdown
What:
- use checkTitleUserPermissions() to enforce read permissions in
ApiComparePages.
Bug: T397521
Change-Id: Id275382743957004fa7fc56318fc104d8e2d267b
(cherry picked from commit c62e4d93a33e94c7fe6f716a4747b1dbd59b3f90)
Why:
- When comparing the newly generated HTML to the cached HTML, there
might be cases when the new ParserOutput doesn't contain HTML.
What:
- If hasText() returns false, don't compare HTML and use the "unknown"
value for the html_changed stats label.
Bug: T388406
Change-Id: Ibc3e79e79a6421d4780739104a949bac50a5b01f
(cherry picked from commit a275e02771bc2ed4243804d5294188f54e47f9fc)
Make SqlPlatform::tableNameWithAlias() include the unqualified table
name as an alias if doing so is not redundant. This assures that the
default alias from JoinGroupBase::addJoin(), equal to the unqualified
table name, will be usable in SQL (regardless of table prefixes).
Clean up use of identifier quotes for sqlite_master tables. The called
methods expect unqualified names and a passthrough exception already
exists for sqlite_* tables.
Use "block_target.bt_user" directly in ApiQueryBlocks and BlockPager,
instead of using addIdentifierQuotes(). The "block_target" alias is
automatically added to the SQL by the rdbms layer when it's not clearly
redundant, so it is always safe to use block_target.bt_user. Also, there
is no reason for aliases to include quote characters. They are supposed
to be simple alphanumerics like column names. This makes it easy for
tableNameWithAlias() to avoid redundant aliases by checking tableName().
Avoid unneeded quotes around pg_catalog.* table names in the Postgres
installer. The relevant documentation of methods like selectField() is
that the table names be unqualified (no quotes nor dots), though dots
are still supported internally for compatibility reasons and ease of
querying schemas like pg_catalog and information_schema.
Change-Id: Ic7d7826da31f49915141692cb3bd84ed1e872e96
This patch was applied to release branches for MW 1.42 in April 2024, and
since ported to MW 1.43 and then MW 1.44 as well. This one-of-a-kind hot
patch will finally discontinue once this lands in the master branch as
part of MW 1.45+ releases.
A small handful of phan fixes make this pass so it can land; the rest
(including fixes rather than suppressions of events here) will happen in
later patches.
Bug: T328921
Bug: T359868
Change-Id: Ica2c11a6243795437ec652923e42ef3bd74a5fd8
psr/log 3.0.0 adds this return type.
For this specific case the fix is very simple, fully
compatible with the older version of psr/log, and
something we’ll have to do sooner or later anyway.
Bug: T356451
Change-Id: I49562ac7f1a71e82cab79fe44296feea573e26d4
(cherry picked from commit 9244d4b2623b9d789e7dea28e65b5ca6f9651aaf)