Page MenuHomePhabricator

Audit consumers of PermissionManager that end up calling Title::isBigDeletion
Closed, ResolvedPublic3 Estimated Story Points


As part of T288242, we want to move the logic for detecting big deletions away from Title. The main idea is to move it to a new command object that handles page deletion (DeletePage), but then PermissionManager wouldn't be able to check for big deletions (because it'd need to depend on DeletePage, which is a no-no).

The scope of this task is to create a list of public methods in PermissionManager that can lead to Title::isBigDeletion being called, and then checking the callers of those methods and determine whether they need to know about big deletions at all.

Event Timeline

Daimona set the point value for this task to 3.Aug 11 2021, 9:02 AM

Callers analysis

Title::isBigDeletion can be called by PermissionManager when all of the following conditions are met (plus others not dependent on the code):

  • checkActionPermissions is called
  • $action is 'delete'
  • $rigor is not QUICK

checkActionPermissions is private, called by getPermissionErrorsInternal (also private). $action and $rigor are passed through, so we're now looking for calls to getPermissionErrorsInternal with $action delete and $rigor QUICK.

There are three methods calling getPermissionErrorsInternal:

  • checkActionPermissions. This is for checking multiple rights, but since every call specifies an action literally and none of them are 'delete', we can ignore it.
  • getPermissionErrors
  • userCan

The last two are public and pass $action and $rigor through. So we need to audit those.


No usages as a string literal found out of tests. See codesearch for all calls.

Calls with literal 'delete'
  • SpecialMovepage::doSubmit (twice): this should go through the new DeletePage regardless, so it should be fine if we move the check in there
  • Ext:DynamicPageList, DPL::deleteArticleByRule: ditto
  • Ext:Nuke, SpecialNuke::doDelete: ditto
  • Ext:Translate, SpecialPageTranslationDeletePage::doBasicChecks: this one is a tad more complicated, because actual deletion happens via the job queue and is performed by a system user (not the one whose permissions are checked when using PermissionManager). I'd like to better understand the use case here. If it's just "basic checks", perhaps it doesn't need to know about big deletion. Also, since it's deleting a single page and "native" deletion can also use the jobqueue, deletion might happen outside of the job.
Calls with variable action

As for UserAuthority::internalCan: this is a private method used by definitelyCan, authorizeRead, and authorizeWrite. The permission is passed through, so we'd need to check usages of those methods.



Several methods with this name exist, and there are a lot of calls :-( I've filtered them according to the following rules:

  • Exclude calls like [dnv]->userCan\(: all of them are calling RevisionRecord::userCan
    • Of these, every occurrence not followed by a space after the opening parentheses isn't relevant, except for ExtRightFunctions::ifpageright, which is the same as the ifpageallowed case above.
    • Of those with a space, I've searched for the ones followed by a single or double quote and then a literal "d" (as everything else is passing some permission that we don't care about).
    • The ones followed by a space but not a quote were analyzed separately, excluding not just quotes but "R" and "F", used respectively for RevisionRecord constants (indicating RevisionRecord::userCan) and File constants (indicating File::userCan)
  • itle->userCan\( (calling Title::userCan, removed in 1.36) was checked separately
  • The remaining e->userCan\( are all for File::userCan and were ignored

Results for Title::userCan

Results for [^dven]->userCan\( ['"]d

  • BlueSpiceBookshelf, ApiBookshelfManage::task_deleteBook: calls WikiPage::doDeleteArticleReal immediately, so it can be addressed by switching to DeletePage and letting that handle the permission checks. It will need a hack to determine whether the user lacks permissions based on the status messages, but that's what you get if you want to replace standard messages with verbatim copies of them.
  • BlueSpiceSocial, Entity::getActions: I haven't checked deeply what it's used for, but it doesn't seem to delete anything (it's a list of actions that the user can do on a given page), so there shouldn't be any problem (and the maintainers will have a chance to fix that once we deprecate the old behaviour).
  • BlueSpiceContextMenu, Delete::shouldList: used for showing links, so no problem I would say

Results for [^dven]->userCan\( [^'"RF]


I don't see any showstopper or anything that prevents us from moving the logic from Title to DeletePage and make it not be page-wise but deletion-wise, as long as the following things are done/kept in mind:

  • The old behaviour should be deprecated: soft deprecation and a mention in the release notes. Hard deprecation is impossible as callers have no way to specify whether they want that code to be executed or not.
  • Add a notice to Tech/News once the old code is removed, in particular for the change to ApiQueryInfo behaviour
  • It'd be nice if we could migrate the methods listed above that also delete pages to the new DeletePage service
    • I'd like to better understand the code in Translate and see if it can be migrated, too
  • Obviously, make sure that deletion-related code in core (DeleteAction, FileDeleteForm, ApiDelete, WikiPage) will still perform the bigdeletion check.
Daimona claimed this task.
Daimona moved this task from Ready 🎬 to Done 🏁 on the Community-Tech (CommTech-Sprint-7) board.

Calling this resolved, I'll copy the conclusions to the parent task.