Requests for comment/CentralNotice backend improvements

Some thoughts on the next steps for the CentralNotice edit UI and text storage system.

How CentralNotice works

 * Banner/Campaign metadata is stored in custom tables in Meta's database (i.e. metawiki, https://meta.wikimedia.org/)
 * Banner text for delivery is stored in the MediaWiki namespace on Meta.
 * CentralNotice has its own edit page for editing banner text (Special:CentralNoticeBanners/edit), which bypasses normal authentication and simply requires centralnotice-admin rights. Banner pages can also be edited via the normal UI — no hooks are set to modify this behaviour.
 * The banner content is HTML preprocessed like wikitext.
 * Banners typically contain complex layout and very extensive &lt;style> and &lt;script> tags.
 * Banners typically use to fetch translated text from short MediaWiki namespace pages.
 * Some fundraising banners have embedded forms allowing the user to enter the amount they would like to donate. Users click a button in the banner which takes them directly to a page which asks for their credit card details.
 * Staged translations written by unprivileged users can be stored in the CNBanner namespace on Meta, to be copied into the MediaWiki namespace by a centralnotice-admin

Message caching
The caching system for the MediaWiki namespace (MessageCache) is designed to handle small numbers of UI customisations with fast access time. The primary way this is done is by storing the entire contents of the MediaWiki namespace into a single memcached key, and loading this when messages are requested. With a list of all customisations loaded into memory, the common, performance-critical case of a missing local customisation can be handled efficiently.

After CentralNotice started using the MediaWiki namespace for broader purposes than the ~1000 UI messages it was designed for, localisation on Meta soon stopped working entirely. Thus a number of heuristic improvements were introduced to MessageCache, mostly aimed at avoiding the caching of bulk CentralNotice text by omitting large texts from the cache.

This attempt by MessageCache to evict CentralNotice and restore reasonable performance is partly derailed by CentralNotice's use of, whereby a large number (~70,000) messages were introduced to Meta which were less than the threshold size of 1024 bytes. (Commons also suffers from misuse of .)

Brion has said that the reason the message cache was used was to improve the performance of CentralNotice. However, the primary message cache entry on Meta currently takes 60ms to load, which is an unacceptable slowdown imposed on almost every request to the Meta, including CentralNotice banner loads. Loading the text from the database, uncached, would be much faster. Meta's current primary message cache size is 378KB compressed (dangerously close to the entry limit of 1MB) and 3135KB uncompressed.

Security
CentralNotice is probably the most tempting target for compromise of privileged web-based accounts. It can trivially be used to direct substantial donation revenue to external untrusted websites — one just needs to change the form's action URL during an annual campaign. With slightly more effort, it can be used to hijack any web-based account active on any WMF website. It could be used to collect user passwords by fabricating a logout event. Unlike most XSS vulnerabilities, no action is needed on the part of the victim apart from using the site in a normal way.

Currently, there are 65 administrators on Meta and 38 members of the "staff" global group.

Despite these existing risks, we have a need for more openness:


 * Translators need to be able to make or propose edits (see m:Help:CentralNotice/Translations).
 * Developers need to be able to propose edits to JavaScript, CSS and layout.
 * The local site notice feature is terrible for a lot of reasons that are fixed in CentralNotice, the only reason it is still used is that site notices are editable locally by local sysops. So ideally, local sysops would be given access to CentralNotice. See Requests for comment/Dismissable notices.

Proposal
A very rough proposal, to be refined:


 * Don't require published banner text to be in MediaWiki namespace. When loading banners, use the revision cache instead of the message cache.
 * Use hooks for fine-grained access control in the namespace from which the banners are loaded.
 * Use a standard Translate workflow (no publishing in a third namespace) but only load message groups which reached a certain workflow state. (Might need some Translate extension development.)
 * Extend the administrative UI to local wikis. Allow local admins to create and publish banners which are seen on their own wiki.
 * Introduce a parser function that works like except that it uses any namespace as its text source.
 * Expose CSS and JS pages as RL modules, perhaps by subclassing ResourceLoaderWikiModule, and allow banners to depend on these modules.
 * Add syntax highlighting and Ace code editing to these pages
 * Remove all &lt;script> and &lt;style> tags from banner HTML.
 * Introduce a security filter which prevents scripting outside of the special JS pages. (Links and form actions pointing to pages outside WMF control should also be prevented.)
 * Introduce a new permissions level which is required to edit the JS pages.
 * Migrate more JS code to the existing Mixin system.
 * Instead of replacing the whole edit interface with Special:CentralNoticeBanners/edit, use ContentHandler to treat banners like pages, like what is done for Wikidata.