Commit graph

30 commits

Author SHA1 Message Date
Reedy
c13fee87d4 Collapse some nested if statements
Change-Id: I9a97325d738d09370d29d35d5254bc0dadc57ff4
2019-04-04 19:02:22 +00:00
Timo Tijhof
8f69ff9a13 resourceloader: Improve test cases for ClientHtml
Change-Id: Ia10f212267d881ff4dec3eca3119f4bd9090c7de
2019-03-29 01:46:55 +00:00
Timo Tijhof
c6f3440832 resourceloader: Remove addModuleScripts, and deprecate getModuleScripts.
The addModuleScripts() methods were deprecated in 1.31 and 1.32,
these are now removed.

The getModuleScripts() are now deprecated as well, always returning
an empty array. To be removed in 1.34.

Depends on commits for bundled/wmf-deployed extensions that
remove the last few remaining callers to the deprecated functions
in: 3D, Collection, Flow, GlobalUserPage, and Wikibase.

Bug: T188689
Depends-On: If9f0bc6aef85117587fa1929f34f8861c8d80314
Depends-On: Ia8d41b97fbf6822f5f8f7ac889408acce1ac9a3a
Depends-On: I503b919739ea474ff33726815b0da55e2f7e2724
Depends-On: I236ef637fd03b810a46eb361e25067a037e9d183
Depends-On: I62e17779753b977a452cc0c9694947941e999cc3
Change-Id: I5a19b8f164ccf666485d2971202194b747f882df
2019-03-05 16:54:08 +00:00
Timo Tijhof
f22b3b81f9 resourceloader: Add internal RLPAGEMODULES constant
Expose this constant for internal use by Navigation Timing,
so that it can compute mwLoadEnd based on when these modules
finish loading.

The way mwLoadEnd is currently computed is by building a list
of all registered module names, and narrowing it down to the
ones in 'loading' state at the time that ext.navigationTiming.js
executes. The problem with doing that, is that it is includes
various lazy-loaded modules that aren't critical to the page and
aren't meant to be tracked by that metric. For example:

* Preloading of modules from various extensions (including VE,
  and Popups).
* Background chains for EventLogging schemas from mw.loader.using,
  including the one started by Navigation Timing itself.
  On my local install, the list of filtered down modules always
  includes 'schema.SaveTiming', '...rumSpeedIndex', etc.

Exporting the list passed to the initial load() call as constant
will enable Navigation Timing to instead only await only those
modules (and their dependneices).

Bug: T204426
Change-Id: Ida134b4dfee218db16c2d1f88d4f26e8d761e154
2018-09-18 01:10:01 +01:00
Umherirrender
130ec2523d Fix PhanTypeMismatchDeclaredParam
Auto fix MediaWiki.Commenting.FunctionComment.DefaultNullTypeParam sniff

Change-Id: I865323fd0295aabd06f3e3c75e0e5043fb31069e
2018-07-07 00:34:30 +00:00
Timo Tijhof
941e3c66ba resourceloader: Un-deprecate ClientHtml::setModuleStyles()
This follows 80e5b160e0, which introduced ClientHtml::setModuleScripts()
and setModuleStyles() with @deprecated marks. There was a vague intention
to remove both at some point.

The commit did not deprecate the related methods in OutputPage and ParserOutput.

The plan that eventually formed at T188689 was to keep methods relating to
"setModuleStyles" for the time being, and focus first on the removal of the
methods relating to "setModuleScripts". The latter since been properly
marked as deprecated and removal is scheduled for 1.33.

There is no current plan to deprecate/remove addModuleStyles
from OutputPage and ParserOutput. As such, the internal helper method
that makes those possible, probably shouldn't me marked as deprecated.

Bug: T188689
Change-Id: Ia36c057b73fe834bcbb2e3e8993d1a793a12ab72
2018-06-14 23:15:59 +01:00
Timo Tijhof
03db2f5b3c Enable merging of WrappedStringList between 'bottomscripts' and 'reportime'
* Fix ResourceLoaderClientHtml to return what it was documented to
  return, a WrappedStringList. It accidentally used the wrong join()
  method, causing it to create a plain string too early.

* Update method documentations from ClientHtml::getBodyHtml to
  BaseTemplate::getTrail for 'bottomscripts', and from
  ResourceLoader::makeInlineScript for 'reporttime'.

* Update BaseTemplate::getTrail to join by new line instead of native string
  concatenation.

This by itself would suffice for the most common case, but in order
to also account for the possibility of extensions using hooks for
'SkinAfterBottomScripts' that concatenate, update bottomScripts()
to pass a plain string to the hook and merge it later.

Change-Id: If0d227cb9db67229a27d489c082db790ea8e3840
2018-05-24 14:23:17 +01:00
Timo Tijhof
2db395abfc resourceloader: Move style deprecation warnings to <body>
Follows-up If35a106c7. These log messages are not criticial and
should not be in the <head> competing with stylesheets and article
content. Move them to the end of <body> instead, nearby other
low-priority script tags.

The getBodyHtml() method from ClientHtml was empty, but has been
non-empty in the past. It's fine to repopulate.

Also, while ClientHtml::getBodyHtml was empty, there are additional
RLQ scripts created by OutputPage that do exist even without this.
Namely, there is a <script> for wgPageParseReport, and one for
wgBackendResponseTime etc.

Change-Id: Ibda7091bdcd5ed207395b20196cdc33df926a24c
2018-05-22 22:14:22 +00:00
Timo Tijhof
ee8a5e488e resourceloader: Apply safemode to startup module registry
This effectively applies safemode to the mw.loader client,
without the client itself needing specific knowledge of safemode.

Test Plan:
* Unchanged: When viewing a page in safemode, the 'user' and
  'site' modules are still not queued by OutputPage.
* New: mw.loader.getState('site'), previously would yield
  'registered', but will now yield null.
* New: mw.loader.load('site'), previously loaded the module,
  it now logs a dependency warning for unknown module, like for
  any other unknown module.
* New: mw.loader.using('site'), previously resolved, it is now
  rejected.

Bug: T185303
Change-Id: I672e3891c8e1b3c2d13655fa134d0f1d031b8247
2018-05-19 22:14:33 +02:00
jenkins-bot
28d17d2b10 Merge "resourceloader: Allow style-only modules to have deprecation warnings" 2018-05-19 08:47:21 +00:00
Timo Tijhof
0980f94e13 resourceloader: Refactor CSP $nonce passing
Follows-up 70941efd35 which broke various public
signatures of the ClientHtml class that I'd prefer to handle
differently.

This commit mainly restores support for all previously public
signatures, and either removes the need for a parameter, or moves
it to the end of the original signature (as optional param).

* ClientHtml::getHeadHtml: Remove the positional/required parameter
  that was added. Restoring the method to being a stateless computer
  that requires no parameters. Pass the option via construct instead.

* ClientHtml::makeLoad:
  - Make $nonce optional.
  - Restore $extraQuery as optional.

* ResourceLoader::makeInlineScript: Document $nonce as optional
  (matching the implementation).

Change-Id: Iaf33f2a060048e6606fba8d875b6d2953b21ef45
2018-05-17 22:28:23 -07:00
Bartosz Dziewoński
febb1aefe0 resourceloader: Allow style-only modules to have deprecation warnings
The deprecation warning for the module 'mediawiki.ui' (used
e.g. on Special:UserLogin) is now actually shown.

Change-Id: If35a106c77622dbf7e8b5628fbea28f9e7ffd76d
2018-05-17 10:12:12 +00:00
Brian Wolff
70941efd35 Initial support for Content Security Policy, disabled by default
The primary goal here is a defense in depth measure to
stop an attacker who found a bug in the parser allowing
them to insert malicious attributes.

This wouldn't stop someone who could insert a full
script tag (since at current it can't distinguish between
malicious and legit user js). It also would not prevent
DOM-based or reflected XSS for anons, as the nonce value
is guessable for anons when receiving a response cached
by varnish. However, the limited protection of just stopping
stored XSS where the attacker only has control of attributes,
is still a big win in my opinion. (But it wouldn't prevent
someone who has that type of xss from abusing things like
data-ooui attribute).

This will likely break many gadgets. Its expected that any
sort of rollout on Wikimedia will be done very slowly, with
lots of testing and the report-only option to begin with.

This is behind feature flags that are off by default, so
merging this patch should not cause any change in default
behaviour.

This may break some extensions (The most obvious one
is charinsert (See fe648d41005), but will probably need
some testing in report-only mode to see if anything else breaks)

This uses the unsafe-eval option of CSP, in order to
support RL's local storage thingy. For better security,
we may want to remove some of the sillier uses of eval
(e.g. jquery.ui.datepicker.js).

For more info, see spec: https://www.w3.org/TR/CSP2/
Additionally see:
https://www.mediawiki.org/wiki/Requests_for_comment/Content-Security-Policy

Bug: T135963
Change-Id: I80f6f469ba4c0b608385483457df96ccb7429ae5
2018-05-13 21:01:11 -07:00
Brad Jorsch
3f1142045f Generalize ResourceLoader 'excludepage' functionality
There has long been a hack for previewing edits to user JS/CSS, where
OutputPage would pass an 'excludepage' parameter to
ResourceLoaderUserModule to tell it not to load one particular page and
would instead embed that page statically. That's nice, but there are
other places where we could use the same thing.

This patch generalizes it:
* DerivativeResourceLoaderContext may now contain a callback for mapping
  titles to replacement Content objects.
* ResourceLoaderWikiModule::getContent() uses the overrides, and
  requests embedding when they're used. All subclasses in Gerrit should
  pick it up automatically.
* OutputPage gains methods for callers to add to the override mapping,
  which it passes on to RL. It loses a bunch of the special casing it
  had for the 'user' and 'user.styles' modules.
* EditPage sets the overrides on OutputPage when doing the preview, as
  does ApiParse for prop=headhtml. TemplateSandbox does too in I83fa0856.
* OutputPage::userCanPreview() gets less specific to editing user CSS
  and JS, since RL now handles the embedding based on the actual
  modules' dependencies and EditPage only requests it on preview.

ApiParse also gets a new hook to support TemplateSandbox's API
integration (used in I83fa0856).

Bug: T112474
Change-Id: Ib9d2ce42931c1de8372e231314a1f672d7e2ac0e
2018-04-25 00:37:08 +00:00
Timo Tijhof
5ab0dd0888 resourceloader: Support loading group=user modules with addModules()
When a module has group=user specified, it means that its module contents
can vary by user. These kinds of requests have two special needs:
1) They need an additional "user" parameter in their load.php request,
   so that the response knows which user-context to use.
2) They need to have their 'version' hash pre-computed based on which assets
   will be loaded for this user. The general 'version' hash associated with
   this module name in the main registry (modules=startup) will be "wrong"
   as that is computed based on logged-out status.

We do this by omitting the module name from the `mw.load.load(Array modules)`
call in the HTML, and instead output a request for the full url.

This currently works fine for most cases, such as the 'user' module loaded
by MediaWiki core. The branch in getData() dealing with legacy 'only=scripts'
behaviour also covers this case.

But the case of an extension registering a group=user module and loading it the
general way (e.g. not with legacy only=scripts behaviour), would currently end
up in the Array-queue and dynamically loaded by the client-side without knowing
the correct version hash. Fortunately, no code exists that I know of that meets
these three critera (extension registered, group=user, non-legacy). However,
for the GlobalCssJs extension to migrate from legacy to non-legacy, they will
need to start doing this. This commit makes sure that that will work.

The makeLoad() method in ClientHtml has code ensuring the full-url form (with
pre-computed 'version' hash) is used for any modules with group=user. Before
this patch, we didn't get to call makeLoad() because getData() was assuming
that we only need makeLoad() when either the module should be embedded (group=private),
or when it is a style/scripts-only module. It didn't consider group=user.

Bug: T188689
Change-Id: Iaab15e5f5c12e7e28b8c81beab90948cd07cd352
2018-04-06 02:30:30 +00:00
Timo Tijhof
cfdc440d40 resourceloader: Replace ClientHtml 'target' param with 'options' array
In preparation for passing down 'safemode' from OutputPage.

Only used in one place in Wikimedia Git: OutputPage::getRlClient().

Bug: T185303
Change-Id: If01eca96986ff8d7dcdaab6910bf183ba7c7311f
2018-03-27 18:17:43 -07:00
Timo Tijhof
3bf06ad80c resourceloader: Remove redundant state assignment for styles in ClientHtml
The same variable index was set to the same value from two places,
one unconditionally, and two times within a conditional block after
the first one.

The second ones are a completely redundant remnant from a refactor
sometime last year.

Change-Id: Ia234d4aca398b1b365d457a439d9e449229f28fb
2018-03-20 23:44:41 +00:00
Reedy
9f8a886867 Update WrappedString use statements
Bug: T182273
Change-Id: Ia9515863491fa9c8684698fa33612eec5eb6d937
2018-01-21 04:39:17 +00:00
Timo Tijhof
0b1a7d4c59 resourceloader: Support isKnownEmpty for general modules
It was already supported for only=scripts and only=styles, but
not yet for general modules loaded as 'combined'.

This is especially useful for general modules that are private/embedded,
as this allows us to skip the loader.implement() boilerplate.

Bug: T176159
Change-Id: I83e9f74dad75867c10ebd0a94b87c31e4adbb57f
2017-09-18 18:37:13 +01:00
Brad Jorsch
f6466732bb resourceloader: Add ResourceLoaderModule::shouldEmbedModule and use it
Rather than only the 'private' group triggering embedding, allow modules
to explicitly specify if they should be embedded.

The default is still to only embed when the group is 'private', and the
'private' group is still special in that ResourceLoader::respond() will
still refuse to serve it from load.php.

Change-Id: Ib9a043c566822e278baecc15e87f9c5cebc2eb98
2017-07-21 17:57:34 +00:00
Timo Tijhof
98b148d247 resourceloader: Minor documentation and coding style improvements
Based on current non-voting codesniffer warnings.

Change-Id: I34cbc31eda3eaa519a71fe2c04122859f2f15914
2017-06-30 17:31:56 -07:00
Timo Tijhof
ed28e106e3 resourceloader: Restrict addModuleStyles() to type=styles modules
If a type=general module is enqueued, don't try to load it as a
stylesheet.

* Per a464d1d41d, state tracking is already disabled for
  these loads (as otherwise we wrongly claim state=ready, when in
  fact only the styles and not the scripts were loaded).

* The warning was added in a464d1d41d.

* Default install (tested in Vagrant), Wikimedia Beta cluster, and
  Wikimedia production have seen zero violations of this warning
  in the past 7 days.

Raise severity to ERROR and add the 'continue' statement so that
these are now not loaded at all.

Bug: T92459
Change-Id: I211d56ac2df479ebf5b98667c613ecf81489539b
2017-06-28 19:18:06 -07:00
Timo Tijhof
976943c991 resourceloader: Bump severity of style queue violation to Warning
Previously it was only in debug logs (which are enabled in Jenkins,
MediaWiki-Vagrant, Beta, and for mwdebug hosts in wmf-production).

Turning it into a warning() will log it for regular requests as well
which is the last step before we can consider hard enforcement.

Bug: T92459
Change-Id: I87c7794c5cfe35521bf76cc42f94907001e9d24b
2017-05-01 17:39:08 -07:00
James D. Forrester
9635dda73a includes: Replace implicit Bugzilla bug numbers with Phab ones
It's unreasonable to expect newbies to know that "bug 12345" means "Task T14345"
except where it doesn't, so let's just standardise on the real numbers.

Change-Id: I6f59febaf8fc96e80f8cfc11f4356283f461142a
2017-02-21 18:13:24 +00:00
Timo Tijhof
44f3f068df resourceloader: Consistent stylesheet order for debug and non-debug
Previously, style modules were only in a predictable order for production mode.
In debug mode, the order was determined by order in which modules were added
to queue at run time. This made it sometimes hard to debug, especially when
dealing with gadgets that apply in a different order among each other.

Change-Id: I4bff0c91d127e4ad8015cd8c1775220fe460cbc3
2017-02-17 15:21:59 -08:00
Leszek Manicki
95b9d82a3a Fix parameter type docs
Changes:
 - uses int instead of number as param and return value type,
 - uses stdClass instead of stdObject
 - fixes ResourceLoaderClientHtml constructor's $target param type:
   it is string|null, not an array (previously misspelled as "aray")
 - changes the type of references to XML parser in XMP lib to resource
   instead of not existing XMLParser

Change-Id: I98c363ebc6658d1f4dcabad97a9a92f3fcd7ea8c
2016-12-14 17:01:47 +01:00
Timo Tijhof
bc374082fa resourceloader: Remove top/bottom queue distinction
* The styles queue has always been top-only
  (except for a few months in 2015).
* The top queue loads asynchronous since mid-2015. (T107399)
  And LocalStorage eval, previously the last remaining non-async part
  of module loading, is also async as of October 2016. (T142129)

* This change merges the bottom 'mw.loader.load()' queue with the top queue.
  It also moves any other snippets potentially in the bottom queue still:
  - embed: I couldn't find any private modules with position=bottom
     (doesn't make sense due to their blocking nature). If any do exist,
     (third-party extensions?), they'll now be embedded in the <head>.
  - scripts: Any legacy 'only=scripts' requests will now initiate
     from the <head>.

Bug: T109837
Change-Id: I6c21e3e47c23df33a04c42ce94bd4c1964599c7f
2016-11-16 19:29:16 +00:00
Timo Tijhof
cf99077b0b resourceloader: Use makeVersionQuery for 'version' query parameter
makeVersionQuery and getCombinedVersion return the same string in
most cases, but there are exceptions, and it could diverge further
in the future. Use the semantically correct method.

Before 6fa1e56 it didn't matter how 'version' was computed as long
as it's deterministic and sufficiently unique. Now that we validate
the hashes it's important all methods use the same logic.

Rename method to makeVersionQuery since it's no longer used just
for comparison against the expected value.

Change-Id: I19f5818e27c8a0920d3d1374b40aeb0b6ba0b614
2016-09-07 14:44:00 -07:00
Timo Tijhof
4ed96c1dde OutputPage: Apply target and origin filter to exempt modules
Follows-up 80e5b160e, which moved filter logic to getRlClient()
so that ResourceLoaderClientHtml doesn't have to deal with this.

While that worked fine for most modules (including 'site'),
it no longer applied the filter for exempt/hardcoded modules
(such as 'site.styles' and 'startup').

Bug: T143066
Change-Id: Iec924003873bc47484a0dc2f1a215f87aa4afdfb
2016-08-16 15:56:02 -07:00
Timo Tijhof
80e5b160e0 resourceloader: Move queue formatting out of OutputPage
HTML formatting of the queue was distributed over several OutputPage methods.
Each method demanding a snippet of HTML by calling makeResourceLoaderLink()
with a limited amount of information. As such, makeResourceLoaderLink() was
unable to provide the client with the proper state information.

Centralising it also allows it to better reduce duplication in HTML output
and maintain a more accurate state.

Problems fixed by centralising:

1. The 'user' module is special (due to per-user 'version' and 'user' params).
   It is manually requested via script-src. To avoid a separate (and wrong)
   request from something that requires it, we set state=loading directly.
   However, because the module is in the bottom, the old HTML formatter could
   only put state=loading in the bottom also. This sometimes caused a wrong
   request to be fired for modules=user if something in the top queue
   triggered a requirement for it.

2. Since a464d1d4 (T87871) we track states of page-style modules, with purpose
   of allowing dependencies on style modules without risking duplicate loading
   on pages where the styles are loaded already. This didn't work, because the
   state information about page-style modules is output near the stylesheet,
   which is after the script tag with mw.loader.load(). That runs first, and
   mw.loader would still make a duplicate request before it learns the state.

Changes:

* Document reasons for style/script tag order in getHeadHtml (per 09537e83).

* Pass $type from getModuleStyles() to getAllowedModules(). This wasn't needed
  before since a duplicate check in makeResourceLoaderLink() verified the
  origin a second time.

* Declare explicit position 'top' on 'user.options' and 'user.tokens' module.
  Previously, OutputPage hardcoded them in the top. The new formatter doesn't.

* Remove getHeadScripts().
* Remove getInlineHeadScripts().
* Remove getExternalHeadScripts().
* Remove buildCssLinks().
* Remove getScriptsForBottomQueue().

* Change where Skin::setupSkinUserCss() is called. This methods lets the skin
  add modules to the queue. Previously it was called from buildCssLinks(),
  via headElement(), via prepareQuickTemplate(), via OutputPage::output().
  It's now in OutputPage::output() directly (slightly earlier). This is needed
  because prepareQuickTemplate() calls bottomScripts() before headElement().
  And bottomScript() would lazy-initialise the queue and lock it before
  setupSkinUserCss() is called from headElement().
  This makes execution order more predictable instead of being dependent on
  the arbitrary order of data extraction in prepareQuickTemplate (which varies
  from one skin to another).

* Compute isUserModulePreview() and isKnownEmpty() for the 'user' module early
  on so. This avoids wrongful loading and fixes problem 1.

Effective changes in output:

* mw.loader.state() is now before mw.loader.load(). This fixes problem 2.
* mw.loader.state() now sets 'user.options' and 'user.tokens' to "loading".
* mw.loader.state() now sets 'user' (as "loading" or "ready"). Fixes problem 1.

* The <script async src> tag for 'startup' changed position (slightly).
  Previously it was after all inline scripts and stylesheets. It's still after
  all inline scripts and after most stylesheets, but before any user styles.
  Since the queue is now formatted outside OutputPage, it can't inject the
  meta-ResourceLoaderDynamicStyles tag and user-stylesheet hack in the middle
  of existing output. This shouldn't have any noticable impact.

Bug: T87871
Change-Id: I605b8cd1e1fc009b4662a0edbc54d09dd65ee1df
2016-08-08 12:23:09 -07:00