Per-window private browsing and the Add-on SDK

Update to the update!

We’ve now figured out that we only need to repack add-ons that actually use the private-browsing module.

  • If you don’t use private-browsing, you don’t need to do anything.
  • If you use the private-browsing module in an add-on that’s hosted on AMO, then it will be marked incompatible with Firefox 20, and will need to be repacked with SDK 1.14 when SDK 1.14 is released. We will repack it with SDK 1.14 if we can, and you will need to repack it yourself if you can’t. We will email you to let you know whether you need to do anything within a couple of days of releasing 1.14.
  • if you use the private-browsing module in an add-on that’s not hosted on AMO: then you will need to repack it with SDK 1.14, or it will start leaking your users’ private data from Firefox 20 onwards.

Update: since the original version of this post, we’ve decided to make repacking with SDK 1.14 mandatory. Add-ons which are not repacked with SDK 1.14 will be marked as incompatible with Firefox 20.

We’re running a project to automatically repack as many AMO-hosted SDK add-ons as we can. AMO-hosted SDK add-ons that we can’t repack, and SDK add-ons not hosted on AMO, will need to be repacked by their authors once SDK 1.14 is release on March 26.

We’ll have another blog post outlining the repacking plan soon.


 

Firefox 20 introduces major changes to the “private browsing” feature, which will affect add-ons developed using the SDK. This blog post explains what the change is, how the SDK is handling it, and what add-on developers will need to do as a result. In summary:

  • if your add-on uses the private-browsing API, you must repack it when SDK 1.14 is released on March 26th if you want your add-on to work properly on Firefox 20.
  • whether or not your add-on uses the private-browsing API, you must update it if you want your add-on to be able to see private windows on Firefox 20.

What’s per-window private browsing?

Up to and including Firefox 19, private browsing has been a global property for the entire browser. When the user enters private browsing, the existing browsing session is suspended and a new blank window opens. This window is private, as are any other windows opened until the user chooses to exit private browsing, at which point all private windows are closed and the user is returned to the original non-private session.

Firefox 20 introduces per-window private browsing. This means that private browsing status is a property of an individual window. The user enters private browsing by opening a new private window. When they do this, any existing non-private windows are kept open, so the user will typically have both private and non-private windows open at the same time.

How does the SDK handle this change?

Under the old, global, private browsing model, add-ons can handle private browsing as a simple binary condition: while private browsing is active, don’t store any user data. The SDK’s private-browsing API supports this by offering an isActive property to check whether the browser is in private browsing mode, alongside start and stop events to be notified when private browsing starts and stops.

Here’s an add-on that stores the titles of tabs the user loads, unless the browser is in private browsing mode:

var simpleStorage = require("simple-storage");

if (!simpleStorage.storage.titles)
  simpleStorage.storage.titles = [];

require("tabs").on("ready", function(tab) {
  if (!require("private-browsing").isActive) {
    console.log("storing...");
    simpleStorage.storage.titles.push(tab.title);
  }
  else {
    console.log("not storing, private data");
  }
});

The first SDK release to target Firefox 20 is SDK 1.14. This release updates the API to support per-window private browsing, and makes another important change: by default, SDK 1.14-based add-ons won’t see any private windows.

Repacking your add-on

Hiding private windows by default means that add-ons developers don’t need to update their code in order to respect per-window private browsing: all they need to do is repack their add-ons using SDK 1.14. The old API will log deprecation warnings, but will behave as if the user never enters private browsing:

  • isActive will always be false, and start and stop will never be triggered.
  • the add-on will never see private windows, or objects such as tabs that are associated with private windows
  • page-mods will not be matched for private windows

You must repack your add-on though! If you don’t, it may not function correctly, and will leak user private data, because private windows will not be hidden. We’re working on a plan to help add-on developers repack add-ons with 1.14.

Updating your code

If you want to see private windows, you’ll need to set the following key in your “package.json”
file:

"permissions": {"private-browsing": true}

Once you do that, you’ll see private windows, so if you store user data, you’ll need to use the new API to respect private browsing.

SDK 1.14 replaces the existing API with a new function isPrivate() that takes an object – a window, tab, or worker – as a parameter, and returns true if the object is a private window or is associated with a private window. So to update the add-on above, we could do something like this:

var simpleStorage = require("simple-storage");

if (!simpleStorage.storage.titles)
  simpleStorage.storage.titles = [];

require("tabs").on("ready", function(tab) {
  if (!require("private-browsing").isPrivate(tab)) {
    console.log("storing...");
    simpleStorage.storage.titles.push(tab.title);
  }
  else {
    console.log("not storing, private data");
    // do something else...
  }
});

Working with Firefox 19

SDK 1.14 bridges the gap between the old global private browsing, in Firefox 19, and the new per-window private browsing, in Firefox 20.

Since SDK 1.14 needs to support both versions, the new private-browsing API is designed to work with global private browsing. When running on Firefox 19, isPrivate() will return true if and only if the user has global private browsing enabled.

Summary

If you have an add-on built with an earlier version of the SDK, this section summarises your options when SDK 1.14 comes out.

If you do nothing

  • on Firefox 19 your add-on will continue to work fine: it will get results for isActive, start, and stop that track global private browsing, and you will be able to use them to avoid storing user private data.
  • on Firefox 20 your add-on might not work at all. If it does, it will see private windows, but the old private-browsing API will not ever tell you that they are private, so you may leak user private data.

If you repack with SDK 1.14

If you just repack your add-on but leave the code unchanged:

  • on Firefox 19 your add-on will continue to work as before: it will get results for isActive, start, and stop that track global private browsing, and you will be able to use them to avoid storing user private data.
  • on Firefox 20 any of the old private-browsing functions (isActive, start, and stop) will log deprecation warnings. Your add-on won’t see any private windows or objects, such as tabs, that are associated with them (it will behave as if these windows just don’t exist). isActive will always be false, and start and stop will never fire.

If you update your add-on

If you update your add-on, by setting the “private-browsing” flag, and updating your code to use the new isPrivate() API:

  • on Firefox 19 your add-on will work fine: isPrivate() will map on to global private browsing by returning true if and only if the user is in global private browsing mode.
  • on Firefox 20 you’ll see private windows, and isPrivate() will tell you whether it’s OK to store user data associated with windows, tabs, and workers.