Close the username completion and the actions that resolve an account - #27
Close the username completion and the actions that resolve an account#27JeroenDeDauw wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #27 +/- ##
============================================
+ Coverage 86.77% 86.98% +0.21%
- Complexity 594 618 +24
============================================
Files 67 69 +2
Lines 2072 2129 +57
============================================
+ Hits 1798 1852 +54
- Misses 274 277 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
786c19c to
867c304
Compare
867c304 to
4d0bfd8
Compare
Fixes #24 Follows-up to #23 Two paths named accounts to members past `UserListSpecialPageHandler` and `UserListApiHandler`: username completion, which bypasses `SpecialPage::run()`, and top-level API actions, which the API handler never looked at. **Username completion.** The core pages that complete a username — eight in 1.43, `Special:Contributions` and `Special:UserRights` among them — and the extension pages that do the same all declare the `UserNamePrefixSearch` service in their special-page list entry and ask it on behalf of the public, paging through the whole `user` table; `action=opensearch`, `list=prefixsearch`, `generator=prefixsearch` and `GET /rest.php/v1/search/title`, which the search box calls, all arrive there. The extension now rewrites, in `SpecialPage_initList`, every entry that declares the service, so the page is built with a wrapper that answers members with nothing and hands every other search on. Decorating the service from the `MediaWikiServices` hook is not an option: that hook never reaches extensions under ProAdmin's `loader.php` bootstrap (ProfessionalWiki/ProAdmin#1375). On the dev wiki, under that bootstrap, all four entry points now return nothing to a member and the names to an ordinary account. Since the answer now differs by reader, `$wgSearchSuggestCacheExpiry` is set to `0` on load; it is what marks `action=opensearch` and the REST title search publicly cacheable. **API actions.** `$wgMemberAccessBlockedApiModules`, closed to members as before, now refuses top-level actions as well and ships four: `feedcontributions`, `validatepassword`, `emailuser` and `userrights`, each of which names an account or confirms one before any right or token is checked (`feedcontributions` and `userrights` also resolve `user=#<id>`). A wiki that set the variable gets them too, since array settings merge. Members lose only the contributions feed: `sendemail` and `createaccount` are revoked already, a member has no password to validate, and no group to grant. Left open, on purpose: `Special:Contributions/<name>` and `Special:ListFiles/<name>` still tell a member that a name has no account. Each confirms one name at a time, and closing the pages would cost members every contribution listing and the list of files; a wiki that wants them closed adds them to `$wgMemberAccessBlockedSpecialPages`. Whom the roster is hidden from at all is #26. The `#<id>` existence answers that remain — in modules that return no name, and in `userrights` token validation, which runs before the hook and answers for a name as well — are #28. Considered, omitted: limiting `Special:Contributions` to the member's own account; naming the completing pages in the README. > <sub>AI-authored — Claude Code, `Opus 5 (max)` diff from a `Fable 5 (max)` spec for @JeroenDeDauw, redirected once when the first mechanism proved inert under the ProAdmin bootstrap, then adjusted after an independent review pass; diff not yet human-reviewed; both leaks reproduced on a dev wiki before the fix and seen closed after it under that bootstrap, regression tests written first and seen failing, mutations of the wrapper, the page-list rewrite, the wiring and the API handler each caught, every special page on the dev wiki built as member, ordinary account and anonymous visitor, PHPCS, PHPStan and the whole suite run locally, CI green.</sub> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4d0bfd8 to
edbd507
Compare
|
Might not do this one, certainly lower priority due to removing the emails from usernames (#29), which removes the main incentive for this PR |
|
Closing unmerged: #29 removed the identity behind every name these paths could return — username completion and the ID walks now yield
|
Fixes #24
Follows-up to #23
Two paths named accounts to members past
UserListSpecialPageHandlerandUserListApiHandler: usernamecompletion, which bypasses
SpecialPage::run(), and top-level API actions, which the API handler neverlooked at.
Username completion. The core pages that complete a username — eight in 1.43,
Special:Contributionsand
Special:UserRightsamong them — and the extension pages that do the same all declare theUserNamePrefixSearchservice in their special-page list entry and ask it on behalf of the public, pagingthrough the whole
usertable;action=opensearch,list=prefixsearch,generator=prefixsearchandGET /rest.php/v1/search/title, which the search box calls, all arrive there. The extension now rewrites,in
SpecialPage_initList, every entry that declares the service, so the page is built with a wrapper thatanswers members with nothing and hands every other search on. Decorating the service from the
MediaWikiServiceshook is not an option: that hook never reaches extensions under ProAdmin'sloader.phpbootstrap (https://github.com/ProfessionalWiki/ProAdmin/issues/1375). On the dev wiki, under that
bootstrap, all four entry points now return nothing to a member and the names to an ordinary account. Since the
answer now differs by reader,
$wgSearchSuggestCacheExpiryis set to0on load; it is what marksaction=opensearchand the REST title search publicly cacheable.API actions.
$wgMemberAccessBlockedApiModules, closed to members as before, now refuses top-levelactions as well and ships four:
feedcontributions,validatepassword,emailuseranduserrights,each of which names an account or confirms one before any right or token is checked (
feedcontributionsand
userrightsalso resolveuser=#<id>). A wiki that set the variable gets them too, since arraysettings merge. Members lose only the contributions feed:
sendemailandcreateaccountare revokedalready, a member has no password to validate, and no group to grant.
Left open, on purpose:
Special:Contributions/<name>andSpecial:ListFiles/<name>still tell a memberthat a name has no account. Each confirms one name at a time, and closing the pages would cost members every
contribution listing and the list of files; a wiki that wants them closed adds them to
$wgMemberAccessBlockedSpecialPages. Whom the roster is hidden from at all is#26. The
#<id>existence answers that remain —in modules that return no name, and in
userrightstoken validation, which runs before the hook andanswers for a name as well — are
#28.
Considered, omitted: limiting
Special:Contributionsto the member's own account; naming the completingpages in the README.