We had a bumper release of WebExtensions API updates in Firefox 153. To start, there is a permissions change that affects how your extensions access local files. We then have two contributions from the community members: userScripts.execute() and the new publicSuffix API. We’re covering those contributions in more depth, including the people behind them, in a separate post. And there is more, read on…
File access now requires a dedicated permission
Extensions that need to read file:// URLs used to get that access as part of the “Access your data for all websites” host permission. Starting in Firefox 153, file access is a separate, explicit permission, “Access local files on your computer”, shown in the extension’s permissions settings. It’s off by default for every extension, including ones already installed.
This change has a few concrete effects on code:
- Before: an extension with <all_urls> or a matching host permission could read file:// pages without any additional grant, and extension.isAllowedFileSchemeAccess() always returned false regardless of the permission setting.
- After: the extension must have the new file-access permission granted, and extension.isAllowedFileSchemeAccess() correctly reflects whether the user has granted it.
async function checkFileSchemeAccess() {
const isAllowed = await browser.extension.isAllowedFileSchemeAccess();
if (!isAllowed) {
await browser.notifications.create("file-scheme-access-needed", {
type: "basic",
iconUrl: browser.runtime.getURL("icons/icon-48.png"),
title: "Local file access required",
message:
'This extension needs "Allow access to file URLs" enabled to work ' +
"with local files. Go to about:addons → select this extension → " +
"turn on that setting, then reload the page.",
});
return false;
}
return true;
}
devtools.inspectedWindow.eval() calls targeting file:// URLs are affected the same way; they now require this permission to succeed.
If your extension depends on file:// access, expect existing users to see that access stops after upgrading (until they enable the permission), and consider adding a prompt or fallback path, for example by specifying an embedded options page (options_ui) and calling browser.runtime.openOptionsPage() to open about:addons and including instructions to toggle the setting in the “Permissions and data” tab.
userScripts.execute() and publicSuffix: covered in our next post
Firefox 153 adds two community-contributed APIs:
- userScripts.execute(), which provides for one-off injection of one or more user script sources into a tab or frame, in a defined order, as a complement to the persistent, URL-pattern-based userScripts.register().
- publicSuffix, which enables synchronous lookups against the browser’s built-in Public Suffix List using publicSuffix.isKnownSuffix(), publicSuffix.getKnownSuffix(), and publicSuffix.getDomain(). This API means that extensions no longer need to bundle or maintain a suffix list to determine a hostname’s registrable domain (eTLD+1).
Both APIs were built by contributors motivated by real needs in their extensions. We take an in-depth look at these contributions, their developers, impact, and history in a forthcoming post.
documentId support across more APIs
Firefox 153 introduces documentId, a stable identifier for a document instance, including a new runtime.getDocumentId() method, several webNavigation events and methods, webRequest events, scripting injection targets, and the extension messaging APIs.
Many WebExtension APIs use tabId and frameId to identify where to perform an operation. However, because frameId identifies the frame rather than its content, the loaded document can change and the extension’s subsequent operation ends up targeting the new (intended) document. documentId addresses this problem by providing a unique ID for the document. Now, if an extension uses the ID and the frame’s document has changed, the operation fails rather than silently targeting the wrong document.
See Work with documentId for the full list of supported events and methods, along with guidance on using it.
Content scripts can read and modify adopted stylesheets
Content scripts can now access document.adoptedStyleSheets and ShadowRoot.adoptedStyleSheets directly.
const sheet = new CSSStyleSheet();
sheet.replaceSync("* { background: pink; }");
document.adoptedStyleSheets = [sheet];
This enables extensions to inspect or modify constructed stylesheets from a content script, without using .wrappedJSObject, a workaround that risks interference from the web page.
Theme manifest key: gradients in additional backgrounds
The theme manifest key’s images.additional_backgrounds property now accepts CSS gradients alongside image URLs. A new properties.additional_backgrounds_size property controls the size of each additional background item.
Contextual identities (containers)
If your extension supports contextual identities, you now have access to two new methods: contextualIdentities.getSupportedColors() and contextualIdentities.getSupportedIcons(). These methods return the supported colors and icons, so your extension doesn’t need to hardcode either list.
Also, the colors have been updated to align with the new UI theme: “turquoise” is now “cyan”, “toolbar” is now “gray”, and “violet” has been added. The old names still work for backward compatibility, but your extension should switch to using getSupportedColors() rather than hardcoding either the old or new names.
Add a build-for-amo script
While this isn’t about new APIs, I wanted to mention a change that’s part of our work to make source code review faster and more reliable. When you submit an extension version, AMO now attempts to build your extensions from the submitted source code and compares the result to the package you uploaded. When the two match, reviewers don’t have to verify the build manually. This means submission can move through its review faster.
For now, this applies only if you submit source code that includes a package.json file to build your extension. If your extension has no build step, or you use a different build system, nothing changes. The AMO builder keeps its zero-config approach.
So, if your extension’s source code uses a package.json file, add an npm script named build-for-amo that runs the commands needed to build your extension for Firefox:
{
"scripts": {
"fx-build": "some commands to build your add-on for Firefox",
"build-for-amo": "npm run fx-build"
}
}
If you’ve a Firefox-specific build command, just point build-for-amo at it. When present, the builder invokes this script instead of guessing how to build your extension. And while you are at it, make sure all your dev dependencies are listed in the package.json file.
For more information, including documentation and Bugzilla links, see the Changes for add-on developers section of the Firefox 153 for developers release notes on MDN.
As always, file extension-related issues on Bugzilla under the WebExtensions product, cross-browser API proposals are discussed in the W3C WebExtensions Community Group, and questions are welcome on the Add-ons Discourse.
No comments yet
Post a comment