Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 8 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ address hashed.
A member's name gives nothing away, so what is left to keep is that they exist at all. The action
API query modules whose purpose is enumerating accounts are closed to the reader group, and three
logs are closed to anyone who cannot manage members: the new user log, where every member's account
creation is recorded, the block log, where every deactivation is, and the rename log, which holds
what members were called before the update that gave them opaque names. Restricting a log type also
keeps it out of recent changes. The special pages that list or resolve accounts are closed to the
reader group as well, and transcluding `Special:ListUsers` renders it empty for everyone, since what
a transclusion renders is not kept to the reader who asked for it. `Special:Redirect` is closed
whole, so members lose its other lookups too, and `Special:FilePath`, which redirects through it.
creation is recorded, the block log, where every deactivation is, and the rename log, which names
both sides of a rename performed by hand. Restricting a log type also keeps it out of recent
changes. The special pages that list or resolve accounts are closed to the reader group as well, and
transcluding `Special:ListUsers` renders it empty for everyone, since what a transclusion renders is
not kept to the reader who asked for it. `Special:Redirect` is closed whole, so members lose its
other lookups too, and `Special:FilePath`, which redirects through it.

Page histories and recent changes still name whoever acted, which on a members-only wiki means the
staff who edit: members cannot appear there, since they cannot change anything.
Expand Down Expand Up @@ -196,10 +196,8 @@ Whatever the login routes are set to, loading the extension:
information or preferences, which closes `Special:ChangeEmail` to them;
* sets `$wgBlockDisablesLogin`, so blocking a member keeps them out of a private wiki;
* restricts the `newusers`, `block` and `renameuser` logs to the `memberaccess-manage` right, unless
the wiki already restricted them, so that who joined, who was deactivated, and what members were
called before the update renamed them stay out of view;
* reserves the username `MemberAccess`, which the update that renames members records its renames as,
so that no real account can be there for it to take over;
the wiki already restricted them, so that who joined, who was deactivated, and what an account
renamed by hand was called before stay out of view;
* refuses members a password, whatever the routes: setting one and having a temporary one mailed
stay refused;
* closes the account-listing API modules to the reader group;
Expand Down Expand Up @@ -272,13 +270,6 @@ upgrade, since one may add a column to a table the wiki already has. Until it ha
reads those tables fails with a database error; a wiki missing them altogether also says so, with a
warning on the `MemberAccess` log channel.

The same command gives an opaque name to every member the extension did not name, which is what
earlier versions left them under. It is recorded in the rename log, which is why that log is
restricted, and on the `MemberAccess` log channel by user id alone. It does not move a `User:` or
`User talk:` page titled after the old name, so a wiki that has any moves them by hand, without
leaving a redirect. Core's rename code names both the old and the new name at debug level, so run it
without `$wgDebugLogFile` pointing at a file you keep. Running it again has nothing left to rename.

## Management API

Groups, allowlist entries and the roster are managed over REST, under `/rest.php/member-access/v0/`.
Expand Down
1 change: 0 additions & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"memberaccess-special-page-denied": "This special page is not available to members.",
"memberaccess-block-reason": "Membership ended",
"memberaccess-unblock-reason": "Membership resumed",
"memberaccess-opaque-name-reason": "Email addresses are no longer used as usernames",
"right-memberaccess-manage": "Manage the member allowlist and roster",
"action-memberaccess-manage": "manage the member allowlist and roster",
"group-reader": "Readers",
Expand Down
1 change: 0 additions & 1 deletion i18n/qqq.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"memberaccess-special-page-denied": "Error page shown when a member opens a special page that lists or resolves the wiki's accounts.",
"memberaccess-block-reason": "Reason recorded in the block log when a member is deactivated. Reactivation recognises the extension's own block by this text in the wiki's content language: after a rewording, blocks placed under the old wording are reported as foreign instead of lifted.",
"memberaccess-unblock-reason": "Reason recorded in the block log when a member is reactivated.",
"memberaccess-opaque-name-reason": "Reason recorded in the rename log when the update that gives members opaque usernames renames a member account.",
"right-memberaccess-manage": "{{doc-right|memberaccess-manage}}",
"action-memberaccess-manage": "{{doc-action|memberaccess-manage}}",
"group-reader": "{{doc-group|reader}}",
Expand Down
34 changes: 6 additions & 28 deletions src/EntryPoints/RegistrationHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ class RegistrationHandler {
private const SSO_EMAIL_PROCESSOR_SETTING = 'wgOpenIDConnect_EmailProcessor';
private const SSO_USERNAME_PROCESSOR_SETTING = 'wgOpenIDConnect_PreferredUsernameProcessor';

/**
* The account the update that gives members opaque names records its renames as.
* {@see \ProfessionalWiki\MemberAccess\Persistence\OpaqueNameUpdate}
*/
private const SYSTEM_USER = 'MemberAccess';

public static function onRegistration(): void {
self::applyWhatMembersNeed();
self::applyWhatTheLoginRoutesNeed();
Expand All @@ -46,27 +40,11 @@ public static function onRegistration(): void {
private static function applyWhatMembersNeed(): void {
self::moveReaderRevocationsToTheConfiguredGroup();
self::closeTheLogsThatRecordMembers();
self::reserveTheAccountTheRenamesAreRecordedAs();

// A deactivated member is blocked, and only this makes a block keep them out of a private wiki.
$GLOBALS['wgBlockDisablesLogin'] = true;
}

/**
* The update that gives members opaque names takes the name over if the wiki has an account of
* it, since it has to run whatever else the wiki called that account. Reserving the name is what
* keeps a real account from being there to take over.
*/
private static function reserveTheAccountTheRenamesAreRecordedAs(): void {
$reserved = self::globalArray( 'wgReservedUsernames' );

if ( !in_array( self::SYSTEM_USER, $reserved, true ) ) {
$reserved[] = self::SYSTEM_USER;
}

$GLOBALS['wgReservedUsernames'] = $reserved;
}

/**
* The revoked rights are declared in extension.json under the default group name, which is the
* one place they are listed. A wiki that renamed the group gets the same list under its name.
Expand All @@ -87,13 +65,13 @@ private static function moveReaderRevocationsToTheConfiguredGroup(): void {

/**
* Three core logs record members: the new user log, where every account creation is, the block
* log, where every deactivation is, and the rename log, which holds what members were called
* before the update that gave them opaque names. All are closed to everyone who cannot manage
* members, which also keeps them out of recent changes, since a restricted log type is never
* written there.
* log, where every deactivation is, and the rename log, where a rename performed by hand names
* the account on both sides of it. All are closed to everyone who cannot manage members, which
* also keeps them out of recent changes, since a restricted log type is never written there.
*
* A member's name says nothing about them, so what the first two give away is that somebody
* joined or was deactivated, and when. The rename log is the one that still names addresses.
* A member's name says nothing about them, so what they give away is that somebody joined, was
* deactivated or was renamed, and when. A member still under a name from before the extension
* minted them is the one whose rename would name an address.
*
* A wiki that restricted one of them further keeps its own setting.
*/
Expand Down
16 changes: 0 additions & 16 deletions src/EntryPoints/SchemaChangesHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use MediaWiki\Installer\DatabaseUpdater;
use MediaWiki\Installer\Hook\LoadExtensionSchemaUpdatesHook;
use ProfessionalWiki\MemberAccess\MemberAccessExtension;

/**
* Separate from the other hook handlers because LoadExtensionSchemaUpdates cannot have services injected.
Expand Down Expand Up @@ -39,21 +38,6 @@ public function onLoadExtensionSchemaUpdates( $updater ) {
'mae_invited',
$sqlDir . '/patch-memberaccess_entry-mae_invited.sql'
);

$updater->addExtensionUpdate( [ [ self::class, 'giveMembersOpaqueNames' ] ] );
}

/**
* Members were once named after their address, which is a name no wiki has to allow anymore.
* This runs on every update, and has nothing to do on a wiki whose members are already named
* after nobody.
*/
public static function giveMembersOpaqueNames( DatabaseUpdater $updater ): void {
$renamed = MemberAccessExtension::getInstance()->newOpaqueNameUpdate()->run();

if ( $renamed > 0 ) {
$updater->output( "...gave $renamed member accounts an opaque username.\n" );
}
}

}
11 changes: 0 additions & 11 deletions src/MemberAccessExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@
use ProfessionalWiki\MemberAccess\Persistence\MediaWikiMemberBlocker;
use ProfessionalWiki\MemberAccess\Persistence\MediaWikiMemberRemover;
use ProfessionalWiki\MemberAccess\Persistence\MediaWikiUsernameMinter;
use ProfessionalWiki\MemberAccess\Persistence\OpaqueNameUpdate;
use ProfessionalWiki\MemberAccess\Persistence\StashCodeRepository;
use ProfessionalWiki\MemberAccess\Persistence\StashCounterStore;
use Psr\Log\LoggerInterface;
Expand Down Expand Up @@ -358,16 +357,6 @@ private function newPasswordResetHandler(): PasswordResetHandler {
return new PasswordResetHandler( members: $this->newMemberRepository() );
}

public function newOpaqueNameUpdate(): OpaqueNameUpdate {
return new OpaqueNameUpdate(
connectionProvider: $this->getConnectionProvider(),
loadBalancers: MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
minter: $this->newUsernameMinter(),
logger: $this->newLogger(),
readerGroup: $this->getReaderGroup()
);
}

private function newUsernameMinter(): UsernameMinter {
if ( $this->usernameMinterOverride !== null ) {
return $this->usernameMinterOverride;
Expand Down
Loading
Loading