Why:
- For account creations and account autocreations, the user_name
property is deliberately unset, to avoid displaying the IP address of
an unregistered user. Instead, `accountname` is set with the newly
created account name
- For logging that someone has seen a protected variable value, we need
to record the username that was seen
What:
- Use `accountname` as a fallback in case `user_name` is not set, when
logging protected variable access
- Update tests to cover this case.
Bug: T376885
Change-Id: I688a3529fac0ad8455977a0cfdb950f0105f550d
Changes to the use statements done automatically via script
Addition of missing use statement done manually
Change-Id: If80031678a474157e4cc78a3d3621dab53aded67
Like CheckUser, AbuseFilter should also log when specific protected
logs are viewed.
- Add support for debouncing logs to reduce log spam
- Log when AbuseFilterViewExamine with protected variables available
is accessed
- Log when SpecialAbuseLog with protected variables available is
accessed
- Log when QueryAbuseLog with protected variables available is accessed
Bug: T365743
Change-Id: If31a71ea5c7e2dd7c5d26ad37dc474787a7d5b1a
CVE-2024-PENDING
Why:
* The 'abusefiltercheckmatch' API allows callers to match
arbitary filter conditions against existing AbuseFilter logs
* The API does not check if the performer has the ability to
see the log details for the given filter, so can allow a user
to bypass hidden and protected visibility settings.
What:
* Call AbuseFilterPermissionManager::canSeeLogDetailsForFilter
before attempting to match a filter against a given AbuseFilter
log.
* Add a test to verify that this security fix works.
Bug: T372998
Change-Id: I4a2467dc4e0d1f8401d5428a89c7f6d6ebcdfa70
Users need to enable a preference before gaining access to the IPs
from `user_unnamed_ip`, a protected variable.
- Add a preference that the user can check to toggle their access
- Check for the preference and the view right for logs that reveal
protected variables on:
+ AbuseFilterViewExamine
+ SpecialAbuseLog
+ QueryAbuseLog
Bug: T371798
Change-Id: I5363380d999118982b216585ea73ee4274a6eac1
Make the `reason` parameter default to the empty string, so that we
don't end up passing null to ManualLogEntry::setComment.
Bug: T373010
Change-Id: Ifca828401628368bdddae14df2bbeb7391b2c02d
- Rename `$hidden` to `$privacyLevel` in Flags::__construct for
consistency with other places.
- Rename `shouldProtectFilter` and simplify its return value to always
be an array, since that's how it's currently used. Rename a variable
that is assigned the return value of this method.
- Add a missing message key to a list of dynamic message keys.
- Rename a property from 'hidden' to 'privacy' in FilterStoreTest for
consistency. Add a test for removing the protected flag.
- Update old comment referencing `filterHidden`; the method was removed
in I40b8c8452d9df.
- Use ISQLPlatform::bitAnd() instead of manual SQL in
AbuseFilterHistoryPager.
- Update mysterious reference to "formatRow" in SpecialAbuseLog.
- Update other references to the very same method in two other places,
this time credited as "SpecialAbuseLog".
- Add type hints to a few methods; this not only helps with type safety,
but it also allows PHPUnit to automatically use the proper type in
mocks.
Change-Id: Ib0167d993b761271c1e5311808435a616b6576fe
Some features restrict access when filters are private. These features
should treat protected filters similarly.
If the user doesn't have view rights for protected filters:
- Disallow viewing of logs generated by protected filters
- Disallow querying of matches against protected filters
Bug: T363906
Change-Id: Id84bd4ca7c8e0419fccc3ad83afff35067c9bf70
Changes to the use statements done automatically via script
Addition of missing use statement done manually
Change-Id: I48fcc02c61d423c9c5111ae545634fdc5c5cc710
Some exposed variables (eg. `user_ip`) used in filters are sensitive
and need to only be available to restricted groups of users.
Back-end changes:
- Add `AbuseFilterProtectedVariables` which defines what variables are
protected by the new right `abusefilter-access-protected-vars`
- Add the concept of a `protected` variable, the use of which will
denote the entire filter as protected via a flag on `af_hidden`
New UX features:
- Display changes to the protected status of filters on history and diff
pages
- Check for protected variables and the right to see them in filter
validation and don't allow a filter to be saved if it uses a variable
that the user doesn't have access to
- Check for the right to view protected variables before allowing access
and edits to existing filters that use them
Bug: T364465
Bug: T363906
Change-Id: I828bbb4015e87040f69a8e10c7888273c4f24dd3
Protected variables will cause the filter using them to become
protected as well. `af_hidden` can be used to track this flag,
as it is a TINYINT and can be converted into a bitmask with no
schema changes.
This is not a backwards-compatible change, as now all checks must
check the `hidden` flag specifically or otherwise will be cast to
true if any flag is set.
To support this change:
- "hidden" is considered a flag set in the `af_hidden`. This is a
change in concept with no need for updates to the column values,
as there is currently only one flag in the bitmask.
- `Flag`s store the bitmask as well as the state of single flags
and can return either.
- Any checks against the `af_hidden` value no longer check a
boolean value and instead now check the `hidden` flag value.
Bug: T363906
Change-Id: I358205cb1119cf1e4004892c37e36e0c0a864f37
After temporary accounts are enabled, filters that rely on an ip
in the `user_name` will fail (eg. `ip_in_range` and `ip_in_ranges`).
To keep these filters working:
- Expose the IP through another variable, `user_unnamed_ip`, that can be
used instead of `user_name`.
- The variable is scoped to only reveal the IPs of temporary accounts
and un-logged in users.
- Wikis that don't have temporary accounts enabled will be able to see
this variable but it won't provide information that `user_name`
wasn't already providing
- Introduce the concept of transforming variable values before writing
to the blob store and after retrieval, as IPs need to be deleted from
the logs eventually and can't be stored as-is in the amend-only blob
store
Bug: T357772
Change-Id: I8c11e06ccb9e78b9a991e033fe43f5dded8f7bb2
This requires 1.42 for some new names
Changes to the use statements done automatically via script
Addition of missing use statements and changes to docs done manually
Change-Id: Ic1e2c9a0c891382744e4792bba1effece48e53f3
TestUser requires a DB connection, so avoid using it in database-less
tests. Add to the Database group tests that are making DB writes (e.g.,
for log entries).
Change-Id: I211cb60296e5c2446128fcdf2caaadc728a8c272
This patch migrates abuse_filter and abuse_filter_history tables
to new actor schema.
MigrateActorsAF was copy-pasted from core's
maintenance/includes/MigrateActors.php before removal (ba3155214).
Bug: T188180
Change-Id: Ic755526d5f989c4a66b1d37527cda235f61cb437
Follows-up Iaa1b4683c5c856.
* Match $IP pattern verbatim from most other WMF extensions.
* Improve descriptions a bit, and move/merge any meaningful
information from file docblock into class docblock. The file blocks
are visually ignored and identical in each file, and often out of
date or duplicated when given text separately from the class block.
See also similar changes in core:
https://gerrit.wikimedia.org/r/q/message:ingroup+owner:Krinkle
* Use `@internal` instead of `@private` as per Stable interface
policy.
Change-Id: I8bed9a625af003446c7e25f6b794931164767b5a
In action=abusefilterunblockautopromote, leave UserIdentity
instantiation to the parent. Note that this changes the "code"
in the response from "baduser_user" to "baduser".
Change-Id: I97d2bf3fa3c5486e461823f840cad2763e1bcfea
This was most definitely my intention when I introduced the concept of
"generic vars", so it's a bit surprising to discover, 3.5 years later,
that the timestamp isn't computed there.
Also make the timestamp always be a string for consistency, since that's
the type documented on mw.org. I've manually checked all filters on
Wikimedia wikis using the timestamp variable, and added explicit int
casts where needed (although I think they'd still work due to implicit
casts).
Change-Id: Ib6e15225dd95c2eead7e48c200d203d6918e0c18
This is a breaking change for the API: 'hidden' is now either true or
false, depending on afl_deleted. 'implicit' is no longer a possible
value, the caller should compute it instead if necessary.
Then simplify the remaining usage of isHidden, using a temporary private
method.
Bug: T291718
Change-Id: I97b5195d306c35ddca3f071d9ff4d896f9fd5c8d
This replaces the previous pattern of callers having to use
RevisionLookup if the result was 'implicit'. Also, in some cases where
we were just hiding things if the visibility was !== true, properly
handle the implicit case by using the new method. Make the new method
return string constants rather than bool|string.
The new method also fixes some potential info leaks which happened when
the row was hidden, the user could view suppressed AbuseLog entries, but
the associated revision was also deleted and the user couldn't see it
(this shouldn't be relevant for WMF wikis since AF deletion is
oversight-level).
Also add a bunch of tests for the various cases to ensure we don't
regress again.
Bug: T261532
Change-Id: I929f865acf5d207b739cb3af043f70cb59243ee0
ParserStatus is now more lightweight, and doesn't know about "result"
and "from cache". Instead, it has an isValid() method which is merely a
shorthand for checking whether getException() is null.
Introduce a child class, RuleCheckerStatus, which knows about result and
cache and can be (un)serialized.
This removes the ambiguity of the $result field, and helps the
transition to a new RuleChecker class.
Change-Id: I0dac7ab4febbfdabe72596631db630411d967ab5
The old parser now has the correct name "Evaluator", so the
ParserFactory name was outdated. Additionally, the plan is to create a
new RuleChecker class, acting as a facade for the different
parsing-related stages (lexer, parser, evaluator, etc.), which is what
most if not all callers should use. The RuleCheckerFactory still returns
a FilterEvaluator for now.
Also, "Parser" is a specific term defining *how* things happen
internally, whereas "RuleChecker" describes *what* callers should expect
from the new class.
Change-Id: I25b47a162d933c1e385175aae715ca38872b1442
Create a dedicated "Exception" sub-namespace and remove the "AFP"
prefix, a leftover from the pre-namespace era.
Change-Id: I7e5fded9316d8b7d1628bc1a6ba8b1879ac901e1