From MediaWiki.org
Jump to navigation Jump to search

work in progress, related to older experiment Extension:EmbedSandbox

Mandelbrot set generator sample - click through for live sample and source

Designed to sandbox scripts from the local wiki by inserting them into an iframe hosted from a separate domain. Scripts from the wiki can thus run without being able to access the hosting wiki's JavaScript contexts, making them (in theory) as secure as linking to a third-party site, but with the benefits of on-wiki storage and editing to protect against web bitrot.

Basic protocol[edit]

  • Host opens <iframe> with the sandbox page's URL
  • Sandbox initializes self, jQuery
    • todo: remove the jQuery dependency
  • Host sees 'load' event on iframe
  • Host posts message to sandbox: {action: 'load', code: '...js source...', args: ['...string...', ...]}
    • todo: add HTML scaffold and CSS style options, and multiple scripts for library support
  • Sandbox makes the 'args' parameter available as 'sandbox.args' in script's local context
  • Sandbox executes the JavaScript code in its local context
  • todo: provide for reporting of errors back to a debug helper console

postMessage details[edit]

Send JSON-serialized strings of object maps, prefixed with 'mediawiki.embedscript:'

Host verifies the sandbox's messages by the origin window and the prefix. Sandbox verifies the host's messages by the origin window and the prefix.


Security is enforced by the browser's same-origin controls. As such, protection against malicious code can only be ensured by using a sandbox page hosted on a separate domain.

Remember that the code will have full capability to do anything the browser allows in an iframe, including loading foreign scripts or sending all data passed into it to an evil web site!

HTTPS is used for loading the sandbox page; this helps protect against MitM attacks. Only code that's actually in your module should get used, and the sandbox server will never see your code or data. (The script can still pass data on to other sites, if it wants to though!)

Using the HTML5 'sandbox="allow-scripts"' attribute may help too, but need to confirm that this doesn't interfere with postMessage.

Wiki-side usage[edit]

<embedscript arg1="arg1" ...>...JS code...</embedscript>
<embedscript src="ScriptPageName" />

Script pages are fetched from the 'JSApplet' namespace by default, which uses a custom #content handler. The inline JS mode will probably be removed in favor of ContentHandler and 'JSApplet' namespace.

Optional parameters:

  • width - defaults to 640
  • height - defaults to 480
  • src - to load script source from a wiki page instead of contents -- defaults to JSApplet: namespace
  • fallback - fallback content if JS unavailable (NYI)

Width and height default to 640x480

  • todo: trigger cache invalidations, or load dynamically

Content handler[edit]

Modules by default will go in 'JSApplet:' namespace. Right now this is a custom ContentHandler that does very little and just passes through JavaScript -- it will change soon to a structured format (using JSON serialization), which allows for putting more metadata into a single object:

  • Have a 'jsfiddle'-like interface for rapid editing/testing
    • show a small-size "mobile view" by default (?) to encourage people to make their tools size-responsive
  • Let HTML scaffold and CSS be expressed naturally in their own textareas instead of as strings
  • Add documentation subsections?
  • Add "flat" fallback content directly in the editor in its own area

The content handler also means the entire bundle can be versioned/diffed together.

File access[edit]

It should be possible to pass an on-wiki file into the sandbox, such as an SVG image or a raster image.... need to ponder best way.


Currently the extension can load a single wiki page via the 'src' parameter, replacing the provided text. These are pulled from the 'JSApplet:' namespace by default.

It could be useful to make code libraries available; eg to combine several scripts together so we can include, say, jQuery or the Raphael.js graphics library for some uses but skip them when they're not needed.

When loading multiple items on a single page, it may also be useful to load source dynamically, so common files only need to be loaded once.

Consider related Gadget issues.


Some features such as WebWorkers for background processing require additional scripts in the sandbox's contexts, so probably won't be possible.

The /Mandelbrot set example could benefit from one or two worker threads, but instead makes do by using setTimeout() to break processing into chunks without blocking the UI thread for too long.


See also[edit]

  • Extension:Gadgets and user scripts
    • Traditional gadgets must be trusted because they inject JS directly into the page, gadgets must be limited to sysops and user scripts are opt-in. There may be some overlap with functionality; also there may be interesting possibilities with the sandboxed JS model in a "headless" mode that allows for extending the UI in certain limited, and safe, ways.
  • Extension:Widgets
    • The Widgets extension is definitely one to look at and learn from; it injects HTML directly into your page so the widgets must be trusted, but has some potential overlap in usage and functionality.
  • Phab:T131436
    • New experimental work at 2016 Hackathon