WebExtensions/UserScripts: Difference between revisions

Jump to navigation Jump to search
Updates and cleanup of the "APIs provided in the extension pages" section based on last brainstorming with Shane
(Fixed typo in the "Milestone 3: Improvements" section)
(Updates and cleanup of the "APIs provided in the extension pages" section based on last brainstorming with Shane)
Line 82: Line 82:
'''Status''': not implemented yet (TODO: link to bugzilla issue))
'''Status''': not implemented yet (TODO: link to bugzilla issue))


   browser.userScripts.registerAPI({contentAPI: {file: '...'}, parentAPI: {...}});
   browser.userScripts.setAPIScript({url: 'apiContentScript.js'});
   browser.userScripts.register(userScriptOptions);
   browser.userScripts.register(userScriptOptions);


These APIs are accessible only in the extension pages (any extension page besides the content script and the content script iframes):
These APIs are accessible only in the extension pages (any extension page besides the content script and the content script iframes):


- '''browser.userScripts.registerAPI''': used to register the custom APIs that the extension wants to make available to its registered userScripts, the contentAPI parameter specifies the script which register the custom API methods to inject in the userScripts sandbox (and it will be running in the content process as a regulat content script), while the parentAPI parameter is an optional parameter which can be provided when some of the custom API methods have to run some code in a regular extension page (the one that registered the custom API to the userScripts API)  
- '''browser.userScripts.setAPIScript''': used to specify an extension Content Script which will be executed (in the content process as a regular content script) to provide the custom APIs to inject into the registered userScripts sandboxes (if executed multiple times, it will replace the API script executed on the next page loads).


- '''browser.userScripts.register''': used to register a userScript, and optionally specify an object which will provide the API methods implementation that have to be executed in a regular extension page (e.g. to have access to the full WebExtensions APIs, like the tabs API etc.).
- '''browser.userScripts.register''': used to register a userScript and its options (the ones shared with contentScripts.register plus some additional one specific to the userScripts, e.g. scriptMetadata is an opaque object for the WebExtensions API which may contains any metadata that the extension wants to associate to the userScript, as an example Greasemonkey may want to have the userScript name and the array of the granted APIs)


==== example background.js ====
==== example background.js ====
    
    
   // Map<name: string -> {source: string, apiOptions: object, metadata: object, script: RegisteredUserScript}>
   // browser.userScripts.setAPIScript: specify an extension content script to execute automatically
  const userScrips: new Map();
   // when one or more userScripts matches a webpage, see the next section for more details about
   // RegisteredContentScript
   // how this content script can define which APIs should be available to the userScripts.
  let apiContentScript;
   browser.userScripts.setAPIScript({url: "apiContentScript.js"});
  // This would be a custom function implemented by the extension,
 
  // which would parse the user script source and extract its
  // browser.userScripts.register: register a userScript (and its options).
  // metadata (e.g. name, grants etc.)
  let userScript = await browser.userScripts.register({
  // and the apiOptions (url pattern to match, when it should run ext.)
    source,   // [string] Used by the API to know which source to execute in the userScript sandbox
  function parseUserScript(source) {
    // userScripts specific options.
    ... // parse source header for userScript name and options
    scriptMetadata, // [object] A serializable object for use by the extension, opaque to Firefox.
    return {metadata, apiOptions};
    sandboxOptions // [object] additional sandbox options we specifically choose to expose, in followups (needs research/sec-reviews/etc)
   }
    // Options shared with contentScripts.register.
  const parentAPI = {
    matches: [...],
    async GM_something([param1], userScript) {
    excludeMatches: [...],
      // May check userScript.metadata to affect the result.
    includeGlobs: [...],
      const result = // ...
    excludeGlobs: [...],
      const result = await somethingAsync(args);
    runAt: "...",
      return result;
    matchAboutBlank: true/false
    }
    allFrames: true/false,
  };
  });
  async fuction registerUserScript(userScriptSource) {
    if (!apiContentScript) {
      // Register the custom userScripts API methods:
      // - contentAPI is going to run as a regular content scripts injected automatically where on webpages
      //  that matches one of the registered userScripts
      // - parentAPI is an optional parameter which can be used to specify a set of userScripts API methods
      //  that have to be executed in a regular extension page (vs. being executed in the
      //   contentScript context as the apiContentScript)
      apiScript = await browser.userScripts.registerAPI({
        contentAPI: {file: "apiContentScript.js"}
        parentAPI: parentAPI
      });
    }
    // parse the script source and return the userScript
    // name (used as the key in the map) and its options
    // (e.g. matches url pattern, include/exclude pattern, runAt
    // etc.)
    const {metadata, apiOptions} = parseUserScript(userScriptSource);
    userScripts.set(metadata.name, {source: userScriptSource, apiOptions, metadata});
    const userScript = await browser.userScripts.register({
      ...apiOptions, // Used by the API to know which urls to match etc.
      code: source, // Used by the API to know which source to execute in the userScript sandbox
      metadata: metadata, // A serializable metadata object which is received by the userScripts API method
                          // implementation (provided by the extension from the registered content script).
    });
  }


=== APIs provided in the regular content scripts ===
=== APIs provided in the regular content scripts ===
41

edits

Navigation menu