容器允许用户在同一站点上同时登录多个帐户,并为用户提供隔离网站数据以增强隐私和安全的功能。在 Firefox 中,我们一直在研究 容器 很长一段时间了。
我们从浏览器本身的平台工作开始,添加了一个基本的用户界面,然后继续进行 测试飞行员实验,我们在扩展程序中扩展了该功能。现在我们正在从测试飞行员毕业,并将 我们的扩展程序,Firefox 多帐户容器 移动到addons.mozilla.org.
此外,我们已经更新了 Firefox 平台,以便扩展程序可以管理容器。这意味着开发者可以访问必要的 API 来创建新的容器扩展程序。您可以在容器 API 之上构建新的扩展程序以满足您的需求和用例!这已经发生了, 在 addons.mozilla.org 上出现了许多新的扩展程序。
这篇文章介绍了 contextualIdentities
API,并以开发者为中心,逐步介绍了一个容器附加组件示例。
什么是容器?
容器通过允许用户在网站间的数据流中设置障碍来工作,方法是 隔离每个独立的浏览上下文中的 cookie、indexedDB、localStorage 和缓存。例如,与用户个人容器关联的浏览器存储与用户的“工作”容器分离。通过这种方式,用户可以根据所处的上下文采用不同的身份——我们称之为上下文身份。
Cookie 存储 是一个关键的 WebExtension API 概念,它表示浏览器中的存储隔离。在其他浏览器中,Cookie 存储用于区分私人窗口和普通窗口。在 Firefox 中,Cookie 存储现在还将区分容器。
容器是 Firefox 独有的。这些新的 API 使所有开发人员能够创建新的隐私、安全和选项卡管理体验,这些体验是目前其他浏览器中没有的。
设置您的清单
要使用 contextualIdentities
API,请将 “contextualIdentities”
和 “cookies”
权限添加到您的 manifest.json
中,以便您的扩展程序可以创建与 Cookie 存储关联的容器选项卡。
"permissions": [
"cookies",
"contextualIdentities"
]
管理容器选项卡
cookie 权限提供对 cookieStoreId
属性的访问,该属性是容器选项卡管理所需的。contexualIdentities
API 方法返回 cookieStoreId
,可用于诸如 tab.create
之类的 方法。
const containers = await browser.contextualIdentities.query({});
browser.tabs.create({
cookieStoreId: container[0].cookieStoreId,
url: "https://example.com"
});
此代码创建一个新的选项卡,它请求https://example.com使用与用户第一个容器关联的 cookieStoreId
。
我们还可以使用 cookieStoreId
来查找与之关联的所有打开的容器选项卡
browser.tabs.query({cookieStoreId});
监控更改
Firefox 和容器附加组件能够创建、更新和删除容器。扩展程序现在可以监控这些更改,在容器列表发生更改时提醒它们更新其布局或管理界面。
要监控更改,扩展程序可以使用 onCreated
、onUpdated
和 onRemoved
监听器,这些监听器会传递修改后的容器对象。
const rebuildEvent = () => {
this.rebuildMenu();
};
browser.contextualIdentities.onRemoved.addListener((container) => {
this.removeContainer(container.cookieStoreId);
rebuildEvent();
});
browser.contextualIdentities.onUpdated.addListener(rebuildEvent);
browser.contextualIdentities.onCreated.addListener(rebuildEvent);
this.rebuildMenu();
确保使用 onRemoved
监听器监控用户或其他扩展程序删除的容器。如果您扩展程序以编程方式创建容器选项卡,这一点尤其重要。例如,扩展程序可能配置为每周五下午 5 点打开一个“购物”选项卡,以便从当地酒吧订购啤酒。但是,如果用户先前删除了“购物”选项卡,那么如果扩展程序没有监控删除事件,则该扩展程序很可能会出现故障。这将是一个令人沮丧的结果。
使用颜色和图标保持一致的 UI
我们注意到上传到 addons.mozilla.org 的一些容器附加组件正在使用不同的图标,并且看起来与 Firefox 非常不同。为了让扩展程序开发人员的生活更轻松,并让用户体验更和谐,我们现在公开了颜色代码和图标 URL,您可以使用它们来保持您选择的颜色与我们的调色板一致。我们认为这是一个双赢的局面。
在 Firefox 和我们的容器扩展程序中,我们优化了我们的调色板。Firefox 设计师努力选择了在深色和浅色主题中都可见的颜色,以符合可访问性要求。当开发人员使用诸如“粉红色”和“蓝色”之类的 CSS 颜色关键字时,结果看起来与 Firefox 提供的本机颜色非常不同。
我们更新的 API 提供容器颜色的公共图标 URL 和十六进制颜色代码。请在您的扩展程序中使用 “colorCode”
属性,因为将来我们可能会更新颜色代码以匹配 Firefox 中的更改。
Firefox 和容器扩展程序之间的一致性对于防止错误和提供愉悦的用户体验至关重要。因此,与调色板一样,我们还在 iconUrl
属性中提供图标的 URL。我们鼓励您使用我们的资产来提供易于导航的用户界面,因为我们与容器一起构建。我们提前感谢您。
在扩展程序中,您可以像这样查询当前活动的容器
const containers = await browser.contextualIdentities.query({});
containers.forEach((container) => {
console.log(container);
/* Object {
name: "Personal",
icon: "fingerprint",
iconUrl: "resource://usercontext-content/fingerprint.svg",
color: "blue",
colorCode: "#37adff",
cookieStoreId: "firefox-container-1"
} */
});
构建容器附加组件示例
为了演示如何使用容器的 Web 扩展 API,我将带您逐步了解我制作的 容器扩展程序。此附加组件允许用户根据每个容器的偏好自动将 HTTP 流量重定向到 HTTPS。
用户可能决定为“银行”容器打开 HTTPS,如上所示。然后,当用户在“银行”选项卡中访问 http://example-bank.com 时,他们会看到他们的选项卡实际上最终会访问 HTTPS 页面,而不是:https://example-bank.com
在我编写的扩展程序中,我具有以下功能
createIcon(container) {
const icon = document.createElement("div");
icon.classList.add("icon");
const iconUrl = container.iconUrl || "img/blank-tab.svg";
icon.style.mask = `url(${iconUrl}) top left / contain`;
icon.style.background = container.colorCode || "#000";
return icon;
}
async createRow(container) {
const li = document.createElement("li");
li.appendChild(this.createIcon(container));
...
}
async rebuildMenu() {
const containers = await browser.contextualIdentities.query({});
...
containers.unshift({
cookieStoreId: "firefox-default",
name: "Default"
});
const rowPromises = [];
containers.forEach((container) => {
rowPromises.push(this.createRow(container));
});
...
}
在我的 rebuildMenu
函数中,我查询用户拥有的所有容器。然后,我为默认的 Firefox 选项卡添加一个项目。当代码使用容器对象调用 createIcon
时,可以使用 iconUrl
和 colorCode
属性来获取关联的图标。我将图标用作 CSS 中 div 的 SVG 遮罩,这会导致背景颜色用作图标颜色,就像它在原生 Firefox 菜单中一样。
使容器 API 可靠
容器是 Firefox Beta 版和正式版中默认禁用的平台功能。到目前为止,扩展程序开发人员必须通知用户在about:preferences中启用容器,以便使用容器 API。这种情况随着 Firefox Quantum 的发布而改变(现在在 开发者版 中)。在 Firefox Quantum 中,如果您是一位创建容器扩展程序的开发人员,那么您的扩展程序会启用容器。因此,现在,当用户安装您的扩展程序时,他们不需要执行其他步骤。如果他们尝试禁用容器,则需要先禁用您的扩展程序。
这为扩展程序开发人员提供了保证,即 容器 API 将在安装扩展程序时工作。过去,用户可以在任何时候禁用容器,并破坏所有依赖容器的扩展程序。现在,他们必须先禁用扩展程序本身,才能禁用容器选项卡。
我们还对现有的“query”、“get”、“update”和“remove”方法进行了更改,使其更“promise 友好”。我们现在不再使用 null 或 false 值来解析 promise,而是在出现错误时拒绝 promise。在无法找到容器或出现内部错误的情况下,我们会拒绝 API 的 promise,因此,将 API 调用包装在 try...catch
块中允许您的代码处理这些错误
async getContainer(cookieStoreId) {
let container;
try {
container = await browser.contextualIdentities.get(cookieStoreId);
} catch (e) {
/* Containers may be disabled, the API might have failed
or the container has been deleted. */
this.warnUser(e);
}
return container;
}
将容器添加到现有扩展程序
扩展程序通常为用户实现选项,这些选项并不适合所有浏览活动。特定的扩展程序可以提供隐私、安全或其他用户界面优势和增强功能。也许该扩展程序是一个简单的计时器,用于跟踪您在工作日中在社交媒体中观看猫咪 GIF 的频率。在完成“工作”容器后,您可能不再需要它。大多数扩展程序都需要用户发起交互,并且您的扩展程序“始终处于开启状态”可能没有必要或有益。
相反,将容器用作“上下文”的指示器会简化您扩展程序的用户体验。在打开特定容器时添加新功能的扩展程序更有可能被积极使用,因为它们会挂接到现有容器。例如,HTTPS Everywhere 的“始终使用 https”选项会破坏许多网站,但如果在您使用“银行”容器时默认实现,它始终是相关的,并且处于上下文中。
虽然扩展程序已经可以根据 URL 更改其行为,但我们认为容器的安全和隐私优势为用户创建了新的激励来配置设置。
新的容器扩展程序的想法
我们对容器扩展程序提供基于上下文的浏览增强功能的可能性感到兴奋。当用户想要使用“工作”选项卡时,扩展程序可以配置为阻止不适合工作的页面。当用户不想在家里被工作提醒时,扩展程序可以配置为自动删除用户的“工作”历史记录,但记住“个人”历史记录。
例如,扩展程序可以
- 将社交页面自动加载到“社交”选项卡中
- 在“工作”选项卡中关闭选项卡时删除 cookie
- 在“购物”选项卡中阻止按键记录脚本
- 为固定选项卡创建唯一的容器
- 加载网站的多个版本以进行 QA 测试,同时仍然提供嵌入在浏览器中的历史记录和开发工具(而不是无头浏览器测试)。
例如,我们已经看到创建了许多容器扩展程序
- Containers on the go - 为用户提供一个临时容器,该容器在选项卡的生命周期内有效。临时容器模拟私人选项卡,因为容器彼此隔离。一旦选项卡被丢弃,容器就会被删除,这将删除与之关联的 cookie 和其他存储。
- Cookie AutoDelete - 已被修改为在启用容器时逐渐增强,允许用户更改每个容器的 cookie 删除设置。
- Conex - panorama 扩展程序的容器实现
- 还有更多
容器 WebExtension API 允许开发者重写容器本身。开发者可以分叉 我们的扩展,并在此基础上构建改进。如果你正在寻找想法,我们有一份关于 开放增强请求 的长列表,扩展开发者可以使用提供的 API 在他们自己的扩展中解决这些请求。
正如你从所有这些更改和更新中看到的那样,我们确实 拥抱了容器在标签管理中的使用。
容器扩展的下一步
我们还需要对 API 进行一些改进。以下是队列中的一些内容:
- Web 请求支持
cookieStoreId
- 更整洁的从容器到容器的标签切换 API
- 用于
cookieStoreId
的窗口打开 API - 允许扩展作者使
contextualIdentities
API 可选,这将允许非容器扩展提示用户为他们的扩展启用容器增强功能。 - 扩展能够指定默认标签的
cookieStoreId
发布你的扩展
术语
在创建容器扩展时,我们建议使用“容器标签”来解释附加组件,而不是使用 API 名称 contextualIdentities
。
隐私最佳实践
如果你构建了一个使用容器的扩展,但它以损害用户隐私的方式使用容器,请公开此信息。让用户知道你的扩展不符合 为容器设计的隔离标准。例如,在容器之间移动标签会带来风险,可能会让用户接触到额外的跟踪器。
修复现有扩展的问题
为了使你的浏览器扩展在 Firefox 中正常工作,请记住在创建和查询标签时检查 cookieStoreId
。我们看到的一些扩展损坏报告是由于扩展复制标签网址并在稍后重新打开它们,而没有考虑标签所属的 cookieStoreId
。这是一个关于 GitHub 上报告的问题 的示例。
我要感谢无数为容器做出贡献的用户、测试者、编码人员和工作人员。
欢迎反馈:containers@mozilla.com 或访问 Discourse。
关于 Jonathan Kingston
Firefox 的前端安全工程师,致力于 HTTPS 采用、容器和内容安全。
12 条评论