Compare commits

..

239 commits

Author SHA1 Message Date
Danny Colin
aca51cc11c
Merge pull request #2755 from apostrophest/eslint-ecmascript-2021
Increase eslint ecmaVersion to 2021
2025-05-20 15:09:33 -04:00
Danny Colin
b684ce7016
Merge pull request #2764 from apostrophest/version-upgrade-8.3.0
Version upgrade 8.3.0
2025-05-06 15:24:43 -04:00
Stephen Thompson
115d411218 Version upgrade 8.3.0
## IMPORTANT NOTE

Version 8.2.0 of this add-on configured Ctrl + Comma as the default keyboard shortcut for sorting the tab strip by container. This keyboard shortcut was removed from 8.3.0 in patch #2758. If you use Ctrl + Comma in order to quickly sort tabs by container, then you will need to explicitly reconfigure the keyboard shortcut. https://support.mozilla.org/en-US/kb/manage-extension-shortcuts-firefox

## Features
- #2753 Avoid sorting tabs in Firefox tab groups
- #2758 Removed suggested keyboard shortcut for tab sorting
- #2722 Removed Mozilla VPN logo banner

## Bugs
- #2572 Fixed add/remove site assignments logic bug
- #2754 Fixed "open/reopen in container" bug that would reopen outside of a Firefox tab group
- #2760 Removed console log spam related to context menu cleanup

## Developer
- #2671 Updated contributor documentation with tips and corrected links
- #2723 Updated GitHub Actions build image
2025-05-06 12:04:57 -04:00
Danny Colin
aec2aa5fb0
Merge pull request #2722 from mozilla/basti/remove_vpn_banner
Remove the Mozilla-VPN Banner Ad
2025-04-30 22:00:04 -04:00
Sebastian Streich
69ee83bbf6 Remove the Mozilla-VPN Banner Ad 2025-04-30 21:57:36 -04:00
Danny Colin
9434147b48
Merge pull request #2758 from apostrophest/remove-sort-tabs-suggested-key
Remove suggested key for `sort_tabs`
2025-04-30 18:13:08 -04:00
Danny Colin
d82341ce4a
Merge pull request #2760 from Rob--W/logspam-contextMenus.remove
Avoid logspam: "Cannot find menu item with id ..."
2025-04-30 18:09:22 -04:00
Rob Wu
60a6666222 Avoid logspam: "Cannot find menu item with id ..."
The extension frequently tries to remove context menus that do not
exists, which results in errors like:

> Error: Cannot find menu item with id firefox-container-1

because starting from Firefox 136, the contextMenus.remove method
rejects if the menu item does not exist. To avoid logspam, catch it.

References:

- https://bugzilla.mozilla.org/show_bug.cgi?id=1688743
- https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/136#changes_for_add-on_developers
2025-04-30 00:51:11 +02:00
Stephen Thompson
f1a24ed6fb Address code review comments for #2758
- Use `commands.reset` insead of `commands.update`
- Do not swallow errors
2025-04-29 16:36:19 -04:00
Danny Colin
0372abdc33
Merge pull request #2754 from apostrophest/issue-2747-reopen-in-container-tab-groups
Fix #2747: open/reopen container tabs in tab groups when appropriate
2025-04-28 11:04:18 -04:00
Danny Colin
366a50c8b6
Merge pull request #2753 from apostrophest/issue-2746-sort-ungrouped-tabs-only
Fix #2746: sort only ungrouped tabs
2025-04-28 11:03:46 -04:00
Stephen Thompson
e96b275e02 Remove suggested key for sort_tabs
A number of users have accidentally pressed Ctrl + Comma and sorted their tabs by container. For some of those users, they did not know what had happened.

#2492 added Ctrl + Comma as a default shortcut key for sorting tabs by container. This change was released with addon v8.2.0 in Sept 2024.

It is useful to make the sort-tabs-by-container operation accessible by keyboard shortcut, but I think Ctrl + Comma is too close to the main Ctrl + Period shortcut for this addon. I think it's reasonable to make the default sort_tabs keyboard shortcut more complex, but in this patch, I'm recommending that we:

1. do not set a shortcut by default for any future users. Users can still configure a shortcut via Firefox's Manage Extension Shortcuts UI.
2. for existing users upgrading from 8.2.0 who configured their own, non-default keyboard shortcut for sort_tabs, keep their shortcut in place. These users demonstrated a strong interest in using the sort_tabs feature and I do not want to interfere.
3. for existing users upgrading from 8.2.0 who have the default keyboard shortcut configured, clear the shortcut. Users who did not use the sort_tabs keyboard shortcut will no longer be at risk of accidentally using it. Users who did use the default sort_tabs keyboard shortcut will be harmed, but those users can use the Manage Extension Shortcuts UI to manually configure Ctrl + Comma (or another key combination).

I am not aware of any simple ways to ensure that existing users using Ctrl + Comma can continue to do so without interruption. Ideally, I think #2492 should not have set a suggested key -- the other keyboard shortcuts are "non-destructive" and easy to understand. However, since that already happened, I think the best harm reduction approach at this point is to inconvenience existing users of Ctrl + Comma.
2025-04-25 13:08:44 -04:00
Stephen Thompson
65243e2c06 eslint ecmaVersion to 2021
CONTRIBUTING.md specifies the minimum supported Firefox version as 91.1.0.

Based on the caniuse.com data for ECMAScript features listed at https://gist.github.com/Julien-Marcou/156b19aea4704e1d2f48adafc6e2acbf, I determined the following minimum Firefox versions that support each ECMAScript version:

- ECMAScript 2018 (current setting) = Firefox 78
- ECMAScript 2019 = Firefox 64
- ECMAScript 2020 = Firefox 80
- ECMAScript 2021 = Firefox 79
- ECMAScript 2022 = Firefox 92
- ECMAScript 2023 = Firefox 104
- ECMAScript 2024 = Firefox 119+ (not exactly sure)

This project is using v7 of eslint which depends on v7 of espree for JavaScript parsing. espree v7 has a maximum ECMAScript support version of ECMAScript 2021.

Based on these findings, increasing the configured `parser.ecmaVersion` from `2018` to `2021` will allow using all JavaScript syntax supported in Firefox 91.1.0+ without raising eslint errors.
2025-04-23 15:09:26 -04:00
Stephen Thompson
ab3e1ce4d8 Address code review from @Rob--W 2025-04-23 14:31:13 -04:00
Stephen Thompson
5194fcad0e Address code review from @Rob--W 2025-04-23 14:23:07 -04:00
Stephen Thompson
b6a1bff9e8 Fix #2747: open/reopen container tabs in tab groups when appropriate
Firefox 137 introduced tab groups. Tab group web extension support is rolling out in Firefox 138 and later. Creating a new tab after the last tab in a tab group can inadvertently create the new tab outside of the tab group.

When a user opens a new tab that should be in a container, this patch will make sure that the new tab resides in the same tab group as the original tab.
2025-04-21 23:45:11 -04:00
Stephen Thompson
5ae2047b2c Fix #2746: sort only ungrouped tabs
Firefox 137 introduced tab groups. Tab group web extension support is rolling out in Firefox 138 and later. Tab movements, like the movements done when sorting tabs by container, can inadvertently add or remove tabs from tab groups.

In order to keep users' tab groups intact, this patch only sorts tabs outside of tab groups. Due to the lack of the tabGroups web extensions API as of Firefox 138, this patch cannot move tab groups, so all ungrouped tabs move to the end of the tab strip. That means after sorting, all tab groups will move to the beginning of the tab strip.
2025-04-21 23:44:13 -04:00
Danny Colin
a60f5bb1be
Merge pull request #2723 from mozilla/basti/update_ci
Update CI actions/upload-artifact to v4
2025-02-25 11:17:38 -05:00
Sebastian Streich
c8c4e0f0c5
Update CI actions/upload-artifact to v4 2025-02-25 13:56:52 +01:00
Andrea Marchesini
037a804725
Merge pull request #2572 from Cimbali/main
Small fixes
2024-09-26 15:13:51 +02:00
Cimbali
6fcb828e1d Fix error in function name 2024-09-26 13:10:25 +01:00
Cimbali
aa9bb41305 Do not resolve promise twice 2024-09-26 13:10:25 +01:00
luke crouch
546ee7a098
Merge pull request #2671 from kelimuttu/community-docs
Community documentation update
2024-09-25 06:12:58 -05:00
kelimuttu
d8cff7ca41 tidy up links 2024-09-25 14:37:53 +07:00
kelimuttu
e6e7d5178e remove discourse and redirect to GH discussions board 2024-09-25 14:32:18 +07:00
kelimuttu
7767bb0c58 update the contributor guidelines 2024-09-25 14:30:48 +07:00
Rafee Rahman
580fb5234b
Merge pull request #2663 from mozilla/version-upgrade
Version upgrade
2024-09-10 11:04:30 -04:00
Rafee
8edcb1587d Version upgrade 2024-09-10 10:57:47 -04:00
Rafee Rahman
97891f61b0
Merge pull request #2659 from dannycolin/bz#1823729
Fix bz#1823729 - Listen only for status on tab updated
2024-08-29 09:22:53 -04:00
Danny Colin
51ead29d2b Fix bz#1823729 - Listen only for status on tab updated 2024-08-28 13:52:55 -04:00
luke crouch
a53eb64c03
Merge pull request #2654 from mozilla/feat-#303
#303: Reset cookies in site manager
2024-08-28 11:26:57 -05:00
Rafee
c644a60e46 feat #303: ask for browsing data permission dynamically 2024-08-27 17:06:07 -04:00
Rafee
2cd38299e2 feat #303: confirmation page for clearing container storage, added destructive colors 2024-08-27 15:34:06 -04:00
luke crouch
077c7e08c8
Merge pull request #2649 from mozilla/2263-always-open-in-container-bug
Remember choice for default containers in the "Always open in" confirm page
2024-08-27 13:47:53 -05:00
Rafee
6bde0a78d7 fix #2603: remember choice when choosing 'previous' (deny) container option 2024-08-23 12:57:50 -04:00
Rafee
3debe8a36f feat #303: change individual cookie removal to browsingData api 2024-08-20 15:04:25 -04:00
Rafee
606e08d2b7 feat #303: Container storage deletion and confirmation popup 2024-08-20 13:47:36 -04:00
Danny Colin
f9f5daf8f4
Merge pull request #2616 from dannycolin/bug1958
Fix #1958 - Propagate container list reordering in Firefox menus
2024-08-14 10:31:54 -04:00
Rafee
ffbb740445 feat #303: reset cookies in site manager 2024-08-01 18:13:58 -04:00
Rafee
cd343ab8c3 fix #2603: remember choice to always open in default containers 2024-07-23 11:42:01 -04:00
Danny Colin
1537e9f6f2
Merge pull request #2634 from mozilla/missingTranslation
Missing translation for a contextmenu item
2024-04-22 15:35:47 -04:00
Andrea Marchesini
f94c00b68a
Missing translation for a contextmenu item 2024-04-17 14:59:56 +02:00
Danny Colin
0acc48af48
Merge pull request #2628 from emilio/icon-macos-fix
Explicitly specify width and height in SVG icon.
2024-03-04 10:33:04 -05:00
Emilio Cobos Álvarez
cb96bf385b
Explicitly specify width and height in SVG icon.
To work around https://bugzil.la/1883166.
2024-03-02 02:39:13 +01:00
Danny Colin
6fd2b70032
Merge pull request #2622 from emilio/release-changes-back-to-main
Release changes back to main
2024-02-23 18:49:22 -05:00
maxxcrawford
f5aec9cb5a
Add latest strings 2024-02-23 20:41:34 +01:00
maxxcrawford
9469ed424e
Bump version number to 8.1.3 2024-02-23 20:41:10 +01:00
Danny Colin
7305b54635 Fix #1958 - Propagate container list reordering in Firefox menus
Since Fx 123, we have a new API (contextualIdentities.move) that let
us reorder the container list everywhere in Firefox. This patch
looks if the API is supported by the client and propagate the change
if it's the case.
2024-02-13 13:56:45 -05:00
Danny Colin
018b458ef6
Merge pull request #2599 from abhillman/abhillman/shebang-bash-with-env
Use `/usr/bin/env` to find bash
2023-11-28 19:51:22 -05:00
Danny Colin
6573123af5
Merge pull request #2587 from dannycolin/issue2553-shortcut-preventdefault
Revert monitoring modifier in popup shortcuts
2023-11-20 09:40:09 -05:00
Aryeh Hillman
4a9bc37a46 Use /usr/bin/env to find bash
This enables `npm test` to successfully call scripts in `bin/` with
the `bash` binary specified by `PROFILE`.

---

Additional information:

In addition to potentially preferring an alternative version of bash
than the one in `/bin/bash`, some distributions forego storing bash in
`bin/` at all, such as `NixOS`:

```bash
$ cat /etc/os-release | rg '^NAME=' -r ''
NixOS
$ which bash
/run/current-system/sw/bin/bash
```
2023-11-17 15:55:12 -08:00
Danny Colin
59e951e5d2
Merge pull request #2578 from dannycolin/bug1852393-icon-in-toolbar-by-default
Add MAC icon in toolbar on install
2023-10-16 14:32:34 -04:00
Danny Colin
4d4851d058
Merge pull request #2577 from dannycolin/fxa-rebrand
Rebrand Firefox Account
2023-10-16 14:25:57 -04:00
Danny Colin
dd574bbe99
Merge pull request #2558 from leodag/fix-pr-template
fix: correct pull request template placement
2023-10-14 18:38:00 -04:00
Leonardo Dagnino
6374a28932 fix: correct pull request template placement 2023-10-14 19:05:45 -03:00
Danny Colin
6a9afcf266 Revert monitoring modifier in popup shortcuts 2023-10-13 14:45:32 -04:00
Danny Colin
bea1cdcf87
Merge pull request #2584 from emilio/icons
Use color-scheme-aware icons.
2023-10-10 22:13:40 -04:00
Emilio Cobos Álvarez
3779f86088
Make icons react to color-scheme properly.
Note that due to https://bugzilla.mozilla.org/show_bug.cgi?id=1779457 /
https://github.com/w3c/csswg-drafts/issues/7213, prefers-color-scheme
works fine even if the user has an explicitly light theme or so.

This fixes #2583 entirely.
2023-10-09 00:57:23 +02:00
Emilio Cobos Álvarez
bb24647ff3
Make usercontext.svg use color-scheme-aware colors.
Fixes the individual icons in #2583.
2023-10-09 00:45:37 +02:00
Danny Colin
60466258b8 Rebrand Firefox Account
* Change Firefox Account to account
* Add brand=mozilla to accounts.firefox.com URLs
2023-10-02 13:13:17 -04:00
Danny Colin
dd4020069c Add MAC icon in toolbar on install 2023-09-23 19:31:01 -04:00
luke crouch
60b40a2d9f
Merge pull request #2562 from mozilla/fix-issue-template
Fix issue template
2023-08-11 09:57:42 -05:00
Danny Colin
1142c73812
Fix issue template
There's an escape character that breaks our issue template and prevents it to be parsed by Github. This patch removes it.
2023-08-10 14:05:34 -04:00
Danny Colin
f20688c453
Merge pull request #2543 from dannycolin/i18n-remove-hardcoded-strings
Fix missing i18n strings in the UI
2023-06-27 21:33:52 -04:00
Danny Colin
f85d75188a Fix missing i18n strings in the UI
This patch fix all the missing i18n strings in the UI. It also
standardize the main title to "Firefox Multi-Account Containers"
everywhere we use it in the addon.
2023-06-19 19:41:10 -04:00
Danny Colin
dae7d92595
Merge pull request #2501 from dannycolin/popup-shortcuts
Rework shortcut listener logic for the addon popup
2023-06-17 16:00:37 -04:00
Danny Colin
ef10307898 Rework shortcut listener logic for the addon popup
- Add Slash shortcut to focus search input
- Use event.code instead of event.keyCode
- Cancel [0-9] shortcuts when modified is pressed
- Cancel [0-9] shortcuts when search input is focused
2023-06-17 15:58:04 -04:00
Danny Colin
b29ba2094e
Merge pull request #2492 from dannycolin/bug-2457-sort-shortcut
Fix 2457 - add shortcut for sorting tabs by container
2023-06-08 11:55:27 -04:00
Andrea Marchesini
f7e9deebda
Merge pull request #2505 from mozilla/dependabot/npm_and_yarn/cacheable-request-10.2.7
Bump cacheable-request from 10.2.3 to 10.2.7
2023-03-11 05:05:23 -05:00
Danny Colin
473495ec0c
Merge pull request #2509 from drien/main
Add `file:` protocol to non-permissible protocol list
2023-02-23 18:03:55 -05:00
Adrien Delessert
38cdf0a98c
Merge branch 'mozilla:main' into main 2023-02-23 17:55:44 -05:00
Maxx Crawford
69bfac12de
Merge pull request #2511 from mozilla/revert-2506-npx-test-fix-fix
Fix Build and Test Github CI Scripts
2023-02-22 11:26:39 -06:00
Maxx Crawford
2dfd1ee4bb
Update build script to use npx instead of npm bin bash scripting 2023-02-22 11:23:45 -06:00
Danny Colin
37e0caec25
Merge pull request #2506 from mozilla/npx-test-fix
Fix failing test install by replacing $(npm bin) with npx
2023-02-20 11:39:50 -05:00
Adrien Delessert
2894de1127
Add file: protocol to non-permissible list 2023-02-16 12:39:44 -05:00
Maxx Crawford
e71cd19883
Fix failing test install by replacing (npm bin) with npx 2023-02-13 13:14:54 -06:00
dependabot[bot]
caa52cebf4
Bump cacheable-request from 10.2.3 to 10.2.7
Bumps [cacheable-request](https://github.com/jaredwray/cacheable-request) from 10.2.3 to 10.2.7.
- [Release notes](https://github.com/jaredwray/cacheable-request/releases)
- [Commits](https://github.com/jaredwray/cacheable-request/commits)

---
updated-dependencies:
- dependency-name: cacheable-request
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-11 00:28:54 +00:00
Danny Colin
0bcac2a741
Merge pull request #2499 from mozilla/dependabot/npm_and_yarn/fast-json-patch-and-addons-linter-and-web-ext-3.1.1
Bump fast-json-patch, addons-linter and web-ext
2023-02-07 14:30:48 -05:00
dependabot[bot]
1445c9c3db
Bump fast-json-patch, addons-linter and web-ext
Bumps [fast-json-patch](https://github.com/Starcounter-Jack/JSON-Patch) to 3.1.1 and updates ancestor dependencies [fast-json-patch](https://github.com/Starcounter-Jack/JSON-Patch), [addons-linter](https://github.com/mozilla/addons-linter) and [web-ext](https://github.com/mozilla/web-ext). These dependencies need to be updated together.


Updates `fast-json-patch` from 2.2.1 to 3.1.1
- [Release notes](https://github.com/Starcounter-Jack/JSON-Patch/releases)
- [Commits](https://github.com/Starcounter-Jack/JSON-Patch/compare/v2.2.1...3.1.1)

Updates `addons-linter` from 5.24.0 to 5.28.0
- [Release notes](https://github.com/mozilla/addons-linter/releases)
- [Commits](https://github.com/mozilla/addons-linter/compare/5.24.0...5.28.0)

Updates `web-ext` from 7.4.0 to 7.5.0
- [Release notes](https://github.com/mozilla/web-ext/releases)
- [Commits](https://github.com/mozilla/web-ext/compare/7.4.0...7.5.0)

---
updated-dependencies:
- dependency-name: fast-json-patch
  dependency-type: indirect
- dependency-name: addons-linter
  dependency-type: direct:development
- dependency-name: web-ext
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 21:47:50 +00:00
Danny Colin
e2628a20ac
Merge pull request #2497 from mozilla/dependabot/npm_and_yarn/http-cache-semantics-4.1.1
Bump http-cache-semantics from 4.1.0 to 4.1.1
2023-02-06 16:46:01 -05:00
dependabot[bot]
a30499ecfd
Bump http-cache-semantics from 4.1.0 to 4.1.1
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-04 19:49:54 +00:00
Danny Colin
c948a9501d Fix 2457 - add shortcut for sorting tabs by container 2023-01-23 18:49:39 -05:00
Danny Colin
a91c6b09a9
Merge pull request #2427 from mozilla/add-helper-dev-scripts
Add remove/restore scripts for nested .git folder
2023-01-09 19:11:07 -05:00
Danny Colin
0b2347834c
Merge pull request #2485 from mozilla/dependabot/npm_and_yarn/json5-2.2.3
Bump json5 from 2.2.1 to 2.2.3
2023-01-09 19:08:53 -05:00
dependabot[bot]
d5e14aa628
Bump json5 from 2.2.1 to 2.2.3
Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-09 17:46:13 +00:00
Danny Colin
95f598c25c
Merge pull request #2476 from mozilla/dependabot/npm_and_yarn/got-and-addons-linter-12.5.3
Bump got and addons-linter
2022-12-14 12:02:51 -05:00
Danny Colin
16a6e21bc5
Merge pull request #2475 from mozilla/dependabot/npm_and_yarn/express-and-addons-linter--removed
Bump express and addons-linter
2022-12-14 12:02:13 -05:00
Danny Colin
781b1caeb5
Merge pull request #2473 from mozilla/dependabot/npm_and_yarn/decode-uri-component-0.2.2
Bump decode-uri-component from 0.2.0 to 0.2.2
2022-12-14 11:59:59 -05:00
dependabot[bot]
c9786f28da
Bump decode-uri-component from 0.2.0 to 0.2.2
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-14 16:57:32 +00:00
dependabot[bot]
2196098512
Bump got and addons-linter
Bumps [got](https://github.com/sindresorhus/got) to 12.5.3 and updates ancestor dependency [addons-linter](https://github.com/mozilla/addons-linter). These dependencies need to be updated together.


Updates `got` from 8.3.2 to 12.5.3
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v8.3.2...v12.5.3)

Updates `addons-linter` from 3.23.0 to 5.24.0
- [Release notes](https://github.com/mozilla/addons-linter/releases)
- [Commits](https://github.com/mozilla/addons-linter/compare/3.23.0...5.24.0)

---
updated-dependencies:
- dependency-name: got
  dependency-type: indirect
- dependency-name: addons-linter
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-14 16:57:23 +00:00
dependabot[bot]
31e1f4478d
Bump express and addons-linter
Removes [express](https://github.com/expressjs/express). It's no longer used after updating ancestor dependency [addons-linter](https://github.com/mozilla/addons-linter). These dependencies need to be updated together.


Removes `express`

Updates `addons-linter` from 3.23.0 to 5.24.0
- [Release notes](https://github.com/mozilla/addons-linter/releases)
- [Commits](https://github.com/mozilla/addons-linter/compare/3.23.0...5.24.0)

---
updated-dependencies:
- dependency-name: express
  dependency-type: indirect
- dependency-name: addons-linter
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-14 16:57:20 +00:00
Danny Colin
12fab97d62
Merge pull request #2461 from mozilla/dependabot/npm_and_yarn/minimatch-and-mocha-3.1.2
Bump minimatch and mocha
2022-12-14 11:56:42 -05:00
dependabot[bot]
e45883d6bc
Bump minimatch and mocha
Bumps [minimatch](https://github.com/isaacs/minimatch) to 3.1.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.


Updates `minimatch` from 3.0.4 to 3.1.2
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

Updates `mocha` from 6.2.3 to 10.1.0
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v6.2.3...v10.1.0)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
- dependency-name: mocha
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-29 17:07:03 +00:00
Danny Colin
6594a061d6
Merge pull request #2460 from mozilla/version-bump-package-json
version bump package json
2022-11-29 12:05:29 -05:00
Danny Colin
65a36ee5be
Merge pull request #2428 from dannycolin/radio-hover-css
Fix broken radio focus styling in light mode
2022-11-29 12:05:10 -05:00
Maxx Crawford
00fd9b7aab
Merge pull request #2432 from dannycolin/update-l10n
update l10n to get the missing strings in 8.1.0 build
2022-11-29 10:14:07 -06:00
Maxx Crawford
4d1acc1d8e
Generate package-lock.json locally with correct versions of node, npm 2022-11-29 10:09:32 -06:00
Danny Colin
2f99ec4613
Merge pull request #2450 from dannycolin/revert-2231
Backout #2231 from 8.1.0
2022-11-29 10:47:59 -05:00
Maxx Crawford
0070f9c942
Bump version number to 8.1.1 2022-11-29 09:44:07 -06:00
Maxx Crawford
00beddc4cd
Add package-lock.json to tracked files 2022-11-29 09:43:50 -06:00
Danny Colin
8e7d9f7574 Revert "Excluding containers from sync with RegExp"
This reverts commit bf31fa9196.
2022-11-18 23:40:58 -05:00
Danny Colin
06c897583b Revert "Fix empty sync exclude regexp behavior (#2383)"
This reverts commit e5fa98d69e.
2022-11-18 23:40:46 -05:00
Danny Colin
f41139402e update l10n 2022-10-26 13:55:06 -04:00
Danny Colin
c4b0823526 bump version to 8.1.1 2022-10-20 17:58:06 -04:00
Danny Colin
5ccf55cbd1 Fix broken radio focus styling in light mode 2022-10-20 14:57:18 -04:00
Maxx Crawford
7256456463
Add missing build script to package.json and ignore root build directory 2022-10-20 09:47:51 -05:00
Maxx Crawford
035450ae96
Add remove/restore scripts for nested .git folder
The /src/_locales/.github folder causes `web-ext run` to fail when running the npm dev script. This folder removal isn't tracked or surfaced during local dev work when working from the root directory.
2022-10-20 09:29:51 -05:00
Danny Colin
a7aaacd82c
Merge pull request #2422 from dannycolin/issue-2421
Fix #2421 - Truncate text to ensure the delete icon is visible
2022-10-13 11:07:23 -04:00
Danny Colin
638524ad67
Merge pull request #2424 from eemeli/bug-1794329
Account for moved aboutNetError.css in Firefox 107
2022-10-11 09:25:14 -04:00
Danny Colin
4e91a86072
Keep both files 2022-10-11 09:22:48 -04:00
Eemeli Aro
9597c1bdab Account for moved aboutNetError.css in Firefox 107 2022-10-10 10:18:06 +03:00
Danny Colin
441f6c6c34 Fix #2421 - Truncate text to ensure the delete icon is visible 2022-10-06 19:29:23 -04:00
Danny Colin
80970dbe02
Merge pull request #2410 from mozilla/bump-version-to-8.1.0
bump version to 8.1.0
2022-08-31 14:27:21 -04:00
luke crouch
e8baa00935 bump version to 8.1.0 2022-08-31 11:14:12 -05:00
luke crouch
d642f132fc
Merge pull request #2405 from dannycolin/update-deps
Update minimal version of web-ext
2022-08-10 15:52:57 -05:00
Danny Colin
233c2a5498 Update minimal version of web-ext
This removes all the critical and high vulnerabilities
2022-08-10 16:21:45 -04:00
luke crouch
54a2254763
Merge pull request #2403 from dannycolin/update-bug-template
Make Troubleshooting Information optional
2022-08-04 09:05:29 -05:00
Danny Colin
3d5785df4b Make Troubleshooting Information optional 2022-08-04 09:47:06 -04:00
luke crouch
4508c940ae
Merge pull request #2391 from dannycolin/issue-2168
Fix #2168 Use a different l10n string for sites opened in no container
2022-08-01 09:08:46 -05:00
Danny Colin
222d4e7d37 Fix #2168 Use a different l10n string for sites opened in no container 2022-07-27 19:48:39 -04:00
Danny Colin
b69b839fa4
Merge pull request #2390 from dannycolin/issue-1103
Add ability to filter the container list
2022-07-27 12:48:17 -04:00
Danny Colin
47062d2bea add ability to filter the container list 2022-07-21 17:30:16 -04:00
Danny Colin
12dd2ee05c
Merge pull request #2389 from polarn/fix-contrib-submodule-doc
fix git submodule command doc
2022-07-18 19:37:26 -04:00
Marcus Johansson
8dcb561468 fix git submodule command doc 2022-07-18 15:35:28 +02:00
stoically
2f32c915a9
Merge pull request #1141 from stoically/delete-identitystate
Remove identityState when deleting containers
2022-07-15 20:12:03 +02:00
Danny Colin
7dee05ec1f
Merge pull request #2384 from dannycolin/clean-documentation
Update documentation and templates
2022-07-08 18:21:05 -04:00
stoically
e5fa98d69e
Fix empty sync exclude regexp behavior (#2383) 2022-07-07 01:39:58 +02:00
Danny Colin
ee3ead965f Use local web-ext for the dev environment 2022-07-05 13:32:26 -04:00
Danny Colin
b66e0fa6a3
Update CONTRIBUTING.md
Co-authored-by: Maxx Crawford <maxx.crawford@gmail.com>
2022-07-05 12:26:27 -04:00
Danny Colin
78423a17af update contributing section 2022-06-24 17:16:30 -04:00
Danny Colin
6b02da4dc1 add pull request template 2022-06-24 16:55:03 -04:00
Danny Colin
ecaee4bcf9 Update documentation 2022-06-24 16:51:15 -04:00
Danny Colin
a399f8452b
Merge pull request #2231 from stoically/stoically/feat/sync-exclude-regexp
Excluding containers from sync with RegExp
2022-06-23 14:27:26 -04:00
stoically
76d5b36563 Remove identityState when deleting containers
Fixes #1140
2022-06-23 01:46:02 +02:00
stoically
bf31fa9196 Excluding containers from sync with RegExp 2022-06-23 00:28:54 +02:00
Danny Colin
66b90006bd
Merge pull request #2380 from dannycolin/issue-2377
Fix #2377 Tooltip renders off viewport when hovering over a container assigned to VPN.
2022-06-21 15:57:28 -04:00
Danny Colin
c64df9f260 Use browser builtin tooltip
If the containers list is too long, the tooltip is rendered outside the visible area. Using the builtin tooltip ensures that it is always rendered on top of all the items and so it prevents it to be hidden if the list overflow.
2022-06-21 11:29:06 -04:00
Danny Colin
af73c1a401
Merge pull request #2374 from dannycolin/add-bug-template
Fix rendering for Troubleshooting info section
2022-06-09 16:39:59 -04:00
Danny Colin
a55f7411f8
Fix rendering for Troubleshooting info section 2022-06-08 18:57:00 -04:00
luke crouch
27401a5678
Merge pull request #2367 from dannycolin/add-bug-template
Update issue menu
2022-05-20 12:36:43 -05:00
Danny Colin
73e690a559
Update issue menu
- Remove en-US in SUMO URLs so it redirects the user to right locales
- Make it clearer that Ask a question is about support questions
2022-05-19 19:47:09 -04:00
luke crouch
cdc014e3ee
Merge pull request #2366 from dannycolin/add-bug-template
Update the "new issue" template
2022-05-19 07:38:48 -05:00
Danny Colin
352131a8f9
Delete deprecated bug template 2022-05-18 19:50:54 -04:00
Danny Colin
da942a8def
Add a "new issue" menu
This menu offers different options to redirect the user to the right resources for their issue.
2022-05-18 19:50:10 -04:00
Danny Colin
ce63dc2f6b
Add a new bug template 2022-05-18 19:48:50 -04:00
Danny Colin
adeab46229
Merge pull request #1964 from dannycolin/issue-1948
fix #1948 Add option to select a light/dark theme
2022-05-11 17:08:57 -04:00
Andrea Marchesini
e47b26698f
Merge pull request #2355 from rodcul/hyphens-in-proxy
Also allow hyphens in proxy username/password
2022-05-11 15:08:51 -04:00
Danny Colin
aaef0fd4a6 Fix elements styling to follow the Proton Design System more closely
This includes fixes for the hover, active and focus states of all the
elements that didn't have one.
2022-05-10 20:51:34 -04:00
Rodney Cullen
931e0a4c13 Also allow hyphens in proxy username/password 2022-05-09 14:10:14 +01:00
Andrea Marchesini
873ba0ab09
Merge pull request #2346 from mozilla/order
Fix the tab sorting for custom container ordering - MAC-710
2022-05-02 16:15:20 +02:00
Andrea Marchesini
beb6a40231
Merge pull request #2347 from ranjan-purbey/main
Make "default container" entry keyboard navigable
2022-05-02 12:13:46 +02:00
Ranjan Purbey
a8f22944b9 Make "default container" entry kbd navigable
Allows selecting "default container" in "reopen this site in" identity picker
 using keyboard
2022-04-30 00:59:58 +05:30
Andrea Marchesini
d6c6ce6e67
Fix the tab sorting for custom container ordering - MAC-710 2022-04-29 01:29:54 +02:00
Andrea Marchesini
ba5c58ccbb
Merge pull request #2343 from flodolo/gh_test
Use GitHub Actions for testing
2022-04-27 17:26:16 +02:00
Francesco Lodolo [:flod]
fd1200fcfe
Use GitHub Actions for testing 2022-04-27 16:25:57 +02:00
Andrea Marchesini
847fba26a9
Merge pull request #2340 from mozilla/MAC709
Refresh the UI even when there are no proxy settings - MAC-709
2022-04-26 07:39:23 +02:00
Andrea Marchesini
d4e9502e94
Merge pull request #2333 from eladyn/proxy_proxyDNS_fix
enable proxyDNS only for supported proxies (SOCKS4/5)
2022-04-25 19:52:48 +02:00
Andrea Marchesini
5d7b970f1c
Refresh the UI even when there are no proxy settings - MAC-709 2022-04-25 09:10:41 +02:00
eladyn
0b869a139a
improve proxy type matching
Co-authored-by: nekno <nekno@users.noreply.github.com>
2022-04-21 14:09:38 +02:00
eladyn
0ef50dd2f0
enable proxyDNS only for supported proxies (SOCKS4/5) 2022-04-19 16:21:56 +02:00
Andrea Marchesini
26457f4c3f
Merge pull request #2296 from Caligatio/proxy-limit-fix
Remove maxlength from proxy settings
2022-04-06 18:15:34 +02:00
Andrea Marchesini
d4291c5e0d
Merge pull request #2325 from mozilla/version-bump
Bump version to 8.0.7
2022-04-06 18:14:48 +02:00
Lesley Norton
e6a2e34740 Bump version to 8.0.7 2022-04-06 10:58:43 -05:00
Andrea Marchesini
7af82ad54d
Merge pull request #2323 from strseb/basti/fixInitDelay
Handle any response as signal that the mvpn-bridge is present
2022-04-05 20:28:20 +02:00
Sebastian Streich
338bd1e6ac Handle any response as signal that the mvpn-bridge is present 2022-04-05 17:45:08 +02:00
Brian Turek
a9e3014652 Remove maxlength from proxy settings
The proxy settings input needs to be able to accept input in the of
form of type://username:password@hostname:port which can exceed 50
characters.
2022-02-21 22:07:43 +00:00
luke crouch
cdd8ebc66a
Merge pull request #2285 from mozilla/version-bump-8.0.6
Bump version number to 8.0.6
2022-02-10 15:52:53 -06:00
luke crouch
916151482c
Merge pull request #2283 from mozilla/fix-advanced-proxy-2278
return single ProxyInfo object when advanced proxy
2022-02-10 15:52:37 -06:00
Lesley Norton
e013fae815
Bump version number to 8.0.6 2022-02-09 19:32:19 -06:00
luke crouch
a3e978338a return single ProxyInfo object when advanced proxy 2022-02-09 14:47:59 -06:00
luke crouch
81258abfa8
Merge pull request #2243 from mozilla/update-readme-fx-req
Update required Firefox version number to 91.1.0
2022-02-09 14:22:21 -06:00
Lesley Norton
e4a7658a33
Merge pull request #2275 from mozilla/8.0.5
Bump extension version number to 8.0.5
2022-01-24 15:03:51 -06:00
Lesley Norton
8e68707706
Bump extension version number to 8.0.5 2022-01-24 14:55:25 -06:00
Lesley Norton
83b7f5819b
Merge pull request #2267 from mozilla/remove-delete-warning
Remove delete container warning
2022-01-19 08:52:36 -08:00
Lesley Norton
e8ca2065b1
Use localized "Enable" string 2022-01-19 10:45:47 -06:00
Lesley Norton
1fe887bab3
Merge pull request #2270 from mozilla/server-list-scrollbars
Remove unusable scrollbars on Mozilla VNP server list (Windows)
2022-01-18 16:22:00 -08:00
Lesley Norton
6ba77014bc Fix server list scroll bars 2022-01-17 10:39:50 -08:00
Lesley Norton
6a1723b415
Remove delete container warning 2022-01-17 11:11:09 -06:00
Andrea Marchesini
cb31410dd9
Merge pull request #2258 from mozilla/proxy-dns-2248
fix #2248: proxy DNS too
2022-01-01 21:47:31 +01:00
luke crouch
53e9d24d40 fix #2248: proxy DNS too 2022-01-01 11:01:41 -06:00
Lesley Norton
3df8750c6c
Update required Firefox version number to 91.1.0 2021-12-16 22:43:08 -06:00
Andrea Marchesini
3b00ade521 Reintroduce all the languages for the next release 2021-12-15 21:09:14 +01:00
Andrea Marchesini
19600a6f2d
Merge pull request #2242 from mozilla/bump-version
Bump version number to 8.0.4
2021-12-14 18:19:17 +00:00
Lesley Norton
f4df97f9b0
Bump version number to 8.0.4 2021-12-14 12:14:37 -06:00
Andrea Marchesini
4651126fc1
Merge pull request #2225 from mozilla/make-proxy/nativeMessaging-optional
Make proxy & nativeMessaging permissions optional
2021-12-14 18:09:05 +00:00
Andrea Marchesini
f544f41145 Fix travis builds 2021-12-14 19:06:17 +01:00
Lesley Norton
478a6dbdc5
Address review comment 2021-12-14 11:46:44 -06:00
Lesley Norton
e87be3df2a
Fix MAC-689
This prevents permission prompts from getting lost when multiple permission checkboxes are checked before their corresponding prompts are accepted or declined and one of the permissions requires a reboot when enabled (Jira ticket MAC-689)
2021-12-10 11:49:31 -06:00
Lesley Norton
cbcae353a3
Use 'inline-size' instead of 'width' 2021-12-08 18:07:08 -06:00
Lesley Norton
29d586353c
Fix onboarding panel buttons on Windows 2021-12-08 17:57:55 -06:00
Lesley Norton
c91409646a
Use localized string 2021-12-08 17:52:26 -06:00
Lesley Norton
2361fc7899 Fix Windows UI edge cases (Jira - 683) 2021-12-08 14:59:04 -08:00
Lesley Norton
dc7b5ca396
Add sumo link to options page 2021-12-08 15:58:30 -06:00
Lesley Norton
1f5245b0bc
Update options page when permissions change (Jira 682, 686, 680) 2021-12-08 15:57:18 -06:00
Lesley Norton
8e51ea0134
Add ability to enable permissions from Mozilla VPN + Proxy onboarding panel 2021-12-07 10:22:51 -06:00
Lesley Norton
567a284196
Update options page to latest UX 2021-12-07 10:22:51 -06:00
Lesley Norton
2fbb3e0087
Hide Mozilla VPN proxy flags when proxy permission is disabled 2021-12-07 10:22:50 -06:00
Lesley Norton
396411f8b3
Update panel
- Badge the Options icon when proxy and/or nativeMessaging permissions are disabled. Remove on click, don't show again.
- Use localized strings
- Refactors + cleanup
2021-12-07 10:22:50 -06:00
Lesley Norton
3c3b5ae705
Add Mozilla VPN & Proxy permissions block to options.html 2021-12-07 10:22:50 -06:00
Andrea Marchesini
07d7b0cad4
Make the linter happy again 2021-12-07 10:22:50 -06:00
Andrea Marchesini
ca861e2727
Permission handlers triggered on add and on remove 2021-12-07 10:22:50 -06:00
Andrea Marchesini
c146a0bd11
Move the permission observers in the background scripts 2021-12-07 10:22:49 -06:00
Lesley Norton
1b165aebb5
Handle proxy and nativeMessaging permission disabling + enabling 2021-12-07 10:22:49 -06:00
Lesley Norton
ed63f18cf1
Lint roll 2021-12-07 10:22:49 -06:00
Lesley Norton
5a2e631ed3
Gate MozillaVPN tout on enabled permissions in edit container panels 2021-12-07 10:22:49 -06:00
Lesley Norton
ef662cdc72
Show permission warning in advanced proxy panel 2021-12-07 10:22:49 -06:00
Lesley Norton
66359941bf
Start updates to to options.html 2021-12-07 10:22:49 -06:00
Lesley Norton
09d9b05a93
Make nativeMessaging and proxy permissions optional 2021-12-07 10:22:48 -06:00
Andrea Marchesini
e3772b28b9 Disable languages again for 8.0.3 2021-11-30 10:58:52 +01:00
Andrea Marchesini
9aeb80e6ab
Merge pull request #2223 from mozilla/proxy
Use an empty object for no-proxy requests
2021-11-30 07:04:10 +01:00
Andrea Marchesini
aae1fc0016
Merge pull request #2224 from mozilla/version8.0.3
Version bump: 8.0.3
2021-11-30 07:01:40 +01:00
Andrea Marchesini
64cf810c30 Version bump: 8.0.3 2021-11-29 23:29:11 +01:00
Andrea Marchesini
8bde28a4ac Use an empty object for no-proxy requests 2021-11-29 16:21:36 +01:00
luke crouch
ac98046a65
Merge pull request #2215 from Exagone313/confirm-page-autofocus-confirm
Automatically focus confirm button on confirm page
2021-11-28 08:47:15 -06:00
Elouan Martinet
cd8e1ea0f7 Automatically focus confirm button on confirm page (#2214)
This is a regression introduced in commit:
05dc48eac2

The autofocus attribute was removed unexpectedly in a localization
change.
2021-11-25 18:31:50 +01:00
Andrea Marchesini
80393ceb04 Include all the languages 2021-11-25 08:12:00 +01:00
Andrea Marchesini
31d48bf6dc Exclude extra languages for 8.0.2 2021-11-24 17:36:03 +01:00
luke crouch
e6b93e216b
Merge pull request #2204 from mozilla/update-v8.0.2
Update version number to 8.0.2
2021-11-16 09:15:02 -06:00
Lesley Norton
fbba53a8cb
Merge pull request #2191 from mozilla/use-correct-manifest-key
Remove nonexistent "applications" manifest key
2021-11-15 16:06:31 -06:00
Lesley Norton
9c2e5f8c7d
Add authors
Co-authored-by: Maxx Crawford <maxx.crawford@gmail.com>
2021-11-15 15:47:35 -06:00
Lesley Norton
8933edb93a
Update version number to 8.0.2 2021-11-15 11:13:31 -06:00
Lesley Norton
ea569184e1
Remove nonexistent "applications" manifest key 2021-11-02 10:15:56 -05:00
Andrea Marchesini
a3766ffcc3
Merge pull request #2189 from mozilla/custom-proxy-panel-bug
Fix bug when opening custom proxy panel
2021-11-02 06:38:53 +01:00
Lesley Norton
0343c8cc00
Fix bug when opening custom proxy panel 2021-11-01 19:39:52 -05:00
luke crouch
b50f3d3d9e
Merge pull request #2188 from mozilla/bump-min-version
Bump minimum version number per AMO guidelines
2021-11-01 15:53:36 -05:00
Lesley Norton
cffad0c8ad
Bump minimum version number per AMO guidelines 2021-11-01 15:41:57 -05:00
Lesley Norton
b8025f7666
Merge pull request #2187 from mozilla/bump-version
Update version number in package.json
2021-11-01 15:27:05 -05:00
Lesley Norton
78cbe72bbc
Update version number in package.json 2021-11-01 15:21:39 -05:00
Andrea Marchesini
06dbe62c82
Merge pull request #2182 from mozilla/fix-mac-658
Fix MAC-659 - Don't clear proxy input on "Enter"
2021-10-30 08:57:37 +02:00
Andrea Marchesini
d51e4cf165
Merge pull request #2184 from mozilla/add-final-string-v2
Add tooltip string
2021-10-30 08:56:08 +02:00
Lesley Norton
cb30ac0bbc
Implement final string correctly with browser.i18n 2021-10-28 14:31:21 -05:00
Lesley Norton
4c898f7d91
Fix MAC-658 - Don't clear proxy input on "Enter" 2021-10-28 13:46:04 -05:00
Andrea Marchesini
b9f69e2b99
Merge pull request #2176 from mozilla/fix-mac-661
Vertically center icons when container name is " ".
2021-10-28 16:21:32 +02:00
Andrea Marchesini
bfde6d73e9
Merge pull request #2179 from mozilla/fix-mac-658
Fix MAC-658
2021-10-28 16:21:13 +02:00
Andrea Marchesini
8c444713df
Merge pull request #2180 from mozilla/flodolo-patch-1
Run builds also as scheduled task
2021-10-28 11:51:03 +02:00
Lesley Norton
f723089308
Hide horizontal scrollbar 2021-10-27 14:23:41 -05:00
Lesley Norton
fca6e9d97e
Improve Mozilla VPN proxy location picking 2021-10-27 14:19:03 -05:00
Lesley Norton
7be7bb2b22
Use 'inline-size' instead of 'width' 2021-10-27 09:06:57 -05:00
Lesley Norton
d361ca9266
Vertically center icons when container name is " ". 2021-10-26 21:31:56 -05:00
50 changed files with 27217 additions and 1035 deletions

View file

@ -1,6 +1,6 @@
module.exports = {
"parserOptions": {
"ecmaVersion": 2018
"ecmaVersion": 2021
},
"env": {
"browser": true,
@ -19,6 +19,7 @@ module.exports = {
"OS": true,
"ADDON_UNINSTALL": true,
"ADDON_DISABLE": true,
"CONTAINER_ORDER_STORAGE_KEY": true,
"proxifiedContainers": true,
"MozillaVPN": true,
"MozillaVPN_Background": true

View file

@ -1,27 +0,0 @@
<!--
Feel free to ignore this Issue template if you just want to ask or suggest something. If you experience an Issue then please provide all asked information.
Also please make sure that:
- "Firefox will: Never remember history" in the Firefox Preferences/Options under "Privacy & Security > History" is NOT selected
- You are NOT using Firefox in a Private Window
- You can see a grayed out but ticked Checkbox with the description "Enable Container Tabs" in the Firefox Preferences/Options under "Tabs"
-->
- Multi-Account Containers Version:
- Operating System + Version:
- Firefox Version:
- Other installed Add-ons + Version + Enabled/Disabled-Status:
<!-- To be able to copy & paste the full list of your Add-ons navigate to "about:support" and scroll down to "Extensions" -->
### Actual behavior
### Expected behavior
### Steps to reproduce
1.
2.
3.
### Notes

53
.github/ISSUE_TEMPLATE/bug.yml vendored Normal file
View file

@ -0,0 +1,53 @@
name: Bug Report
description: Report a problem in Multi-Account Containers
labels: [bug]
body:
- type: checkboxes
id: before-bug-report
attributes:
label: Before submitting a bug report
options:
- label: "I updated to the latest version of Multi-Account Container and tested if I can reproduce the issue"
required: true
- label: "I searched for existing reports to see if it hasn't already been reported"
required: true
- type: textarea
id: step_to_reproduce
attributes:
label: "Step to reproduce"
description: "Provide a list of steps you did to trigger this bug"
placeholder: |
1. I opened ...
2. I clicked on ...
3. ...
validations:
required: true
- type: textarea
id: actual_behavior
attributes:
label: "Actual behavior"
description: "Provide a description of what is currently happening"
validations:
required: true
- type: textarea
id: expected_behavior
attributes:
label: "Expected behavior"
description: "Provide a description of what should happen"
validations:
required: true
- type: textarea
id: additional_informations
attributes:
label: "Additional informations"
description: "Provide any other information revelant to this issue"
validations:
required: false
- type: textarea
id: about_support
attributes:
label: "Provide a copy of Troubleshooting Information page (optional)"
description: "To get a copy of the Troubleshooting Information page, type *about:support* in the address bar and click on the *Copy text to clipboard* button."
render: "plain text"
validations:
required: false

17
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,17 @@
blank_issues_enabled: false
contact_links:
- name: "Explore our help articles"
url: "https://support.mozilla.org/kb/containers"
about: "Dig into the knowledge base, tips and tricks, troubleshooting, and so much more."
- name: "Ask a support question"
url: "https://support.mozilla.org/questions/new/desktop/form"
about: "Get support from our contributors or staff members."
- name: "Submit new ideas"
url: "https://connect.mozilla.org/t5/discussions/how-to-submit-a-great-idea-in-five-easy-steps/td-p/24"
about: "Have an idea for a new product feature? Share it with our community and staff members!"
- name: "Discussions"
url: "https://connect.mozilla.org/t5/discussions/bd-p/discussions"
about: "Give feedback and participate in meaningful conversations with the community and Mozilla employees"
- name: "Discover more awesome tools"
url: "https://www.mozilla.org/firefox/products/"
about: "Learn more about other products from Mozilla"

24
.github/pull_request_template.md vendored Normal file
View file

@ -0,0 +1,24 @@
**Before submitting your pull request**
- [ ] I agree to license my code under the [MPL 2.0 license](https://www.mozilla.org/en-US/MPL/2.0/).
- [ ] I rebased my work on top of the main branch.
- [ ] I ran `npm test` and all tests passed.
- [ ] I added test coverages if relevant.
# Description
*Please include a summary of the changes including relevant motivation and context.*
## Type of change
*Select all that apply.*
- [ ] Bug fix
- [ ] New feature
- [ ] Major change (fix or feature that would cause existing functionality to work differently than in the current version)
Tag issues related to this pull request:
*
*
*

View file

@ -9,16 +9,16 @@ on:
- main
- production
schedule:
- cron: '0 2 * * *' # Daily at 2AM UTC
- cron: '0 2 * * *' # Daily at 2AM UTC
jobs:
builds:
name: Builds
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Create the package
shell: bash
@ -26,7 +26,7 @@ jobs:
./bin/build-addon.sh nightly.xpi
- name: Uploading
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v4
with:
name: ${{matrix.config.name}} Build
path: src/web-ext-artifacts

28
.github/workflows/test.yaml vendored Normal file
View file

@ -0,0 +1,28 @@
name: Test
on:
push:
branches:
- main
- production
pull_request:
branches:
jobs:
test:
name: Run tests
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Set up node
uses: actions/setup-node@v3
with:
node-version: lts/*
- name: Install dependencies
run: npm install --legacy-peer-deps
- name: Run tests
run: npm run test

2
.gitignore vendored
View file

@ -1,5 +1,4 @@
.DS_Store
package-lock.json
node_modules
README.html
*.xpi
@ -9,6 +8,7 @@ README.html
addon.env
src/web-ext-artifacts/*
web-ext-artifacts
# JetBrains IDE files
.idea

View file

@ -1,7 +0,0 @@
language: node_js
node_js:
- "lts/*"
notifications:
irc:
- "ircs://irc.mozilla.org:6697/#testpilot-containers-bots"

View file

@ -1,35 +1,54 @@
# Contributing
Everyone is welcome to contribute to containers. Reach out to team members if you have questions:
## Requirements
- Matrix chat: [#containers:mozilla.org](https://matrix.to/#/#containers:mozilla.org)
- Email: containers@mozilla.com
* Firefox 91.1.0+
* Git 2.13+
* Node 7+
## Filing bugs
## Getting Started
If you find a bug with containers, please file a issue.
1. Follow the instructions on [How to fork a repository][fork]
2. Fetch the locales:
Check first if the bug might already exist: https://github.com/mozilla/multi-account-containers/issues
```
cd multi-account-containers
git submodule update --init
```
3. Install the project dependencies
```
npm install --legacy-peer-deps
```
4. Run `npm run dev`.
[Open an issue](https://github.com/mozilla/multi-account-containers/issues/new)
## Translations
1. Visit about:support
2. Click "Copy raw data to clipboard" and paste into the bug. Alternatively copy the following sections into the issue:
- Application Basics
- Nightly Features (if you are in nightly)
- Extensions
- Experimental Features
3. Include clear steps to reproduce the issue you have experienced.
4. Include screenshots if possible.
The translations are located in `src/_locales`. This directory is a git
repository like any other. Before editing files in this folder, you need to:
## Sending Pull Requests
1. `cd src/_locales/`
2. `git checkout -b message-updates-yyyymmdd`
3. `git push -u origin message-updates-yyyymmdd`
Patches should be submitted as pull requests. When submitting patches as PRs:
You can then [open a pull request][pr] on [the l10n repository][l10n].
- You agree to license your code under the project's open source license (MPL 2.0).
- Base your branch off the current master (see below for an example workflow).
- Add both your code and new tests if relevant.
- Run npm test to make sure all tests still pass.
- Please do not include merge commits in pull requests; include only commits with the new relevant code.
## Tips for contributing
See the main [README](./README.md) for information on prerequisites, installing, running and testing.
1. Choose [an issue][issues] that you would like to work on.
2. Fork the repository and follow the instructions for setting it up locally.
3. Run the add-on locally and try reproducing the issue.
4. Debug add-ons by clicking the “Settings” icon in about:addons, and then clicking “Debug Add-ons”
5. Click “Inspect” on the MAC add-on to open developer tools for the popup extension (see [this documentation][extension-doc] for more information)
6. Once you have a fix ready, commit your changes with the following commit message template: “Fix #<insert issue id #>: <short description>
7. Push your changes and open a pull request for review.
If you run into an issue, you can always ask the other community members in the [discussions board][discussions].
<!-- Please keep the list in alphabetical order -->
[discussions]: https://github.com/mozilla/multi-account-containers/discussions
[extension-doc]: https://extensionworkshop.com/documentation/develop/debugging/
[fork]: https://docs.github.com/en/get-started/quickstart/fork-a-repo
[issues]: https://github.com/mozilla/multi-account-containers/issues
[l10n]: https://github.com/mozilla-l10n/multi-account-containers-l10n/
[pr]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests
[web-ext]: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext

120
README.md
View file

@ -1,109 +1,33 @@
# Multi-Account Containers
The Firefox Multi-Account Containers extension lets you carve out a separate box for each of your online lives no more opening a different browser just to check your work email! [Learn More Here](https://blog.mozilla.org/firefox/introducing-firefox-multi-account-containers/)
[![Test](https://github.com/mozilla/multi-account-containers/actions/workflows/test.yaml/badge.svg)](https://github.com/mozilla/multi-account-containers/actions/workflows/test.yaml)
[Available on addons.mozilla.org](https://addons.mozilla.org/firefox/addon/multi-account-containers/)
The Firefox Multi-Account Containers extension lets you carve out a separate box for each of your online lives no more opening a different browser just to check your work email!
For more info, see:
Learn more about Multi-Account Containers in
[our end-user documentation][enduser].
* [Test Pilot Product Hypothesis Document](https://docs.google.com/document/d/1WQdHTVXROk7dYkSFluc6_hS44tqZjIrG9I-uPyzevE8/edit#)
* [Shield Product Hypothesis Document](https://docs.google.com/document/d/1vMD-fH_5hGDDqNvpRZk12_RhCN2WAe4_yaBamaNdtik/edit#)
## Contributing
Everyone is welcome to contribute to Multi-Account Containers. To learn how
to contribute a patch to Multi-Account Container, please
[read our contributing guide][contributing].
## Requirements
You can also chat with us on [our Matrix room][matrix] or ask in [our discussions board][discussions].
* node 7+ (for jpm)
* Firefox 57+
This repository is governed by Mozilla's code of conduct and etiquette
guidelines. For more details, [please read the Mozilla Community Participation Guidelines][cpg].
### License
## Development
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
### Running Locally
#### Via WebExtensions API (web-ext)
1. Fetch the locales updating the git-submodules: `git submodule init && git submodule update --remote --depth 1 src/_locales`
2. Install the [web-ext](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext) tool.
3. Run `web-ext run -s src/`. This launches Firefox and installs the extension automatically.
This tool provides some additional development features, such as [automatic reloading](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext#Automatic_extension_reloading).
#### Via about:debugging in Firefox
1. Fetch the locales updating the git-submodules: `git submodule init && git submodule update --remote --depth 1 src/_locales`
2. Open the `about:debugging` page in Firefox.
3. Click on `This Firefox`.
4. Click on [Load Temporary Add-on](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox).
5. Select `src/manifest.json`.
Here is a [video](https://www.youtube.com/watch?v=cer9EUKegG4) that demonstrates how to do this.
### Testing
* Install dependencies:
```
npm install
```
* Run all tests:
```
npm run test
```
* Only run the linter:
```
npm run lint
```
There is a timeout test that sometimes fails on certain machines, so make sure to run the tests on your clone before you make any changes to see if you have this problem.
#### Add/update messages for translation
The `src/_locales` directory is a git repository like any other, so to make changes to the messages:
1. Make whatever changes you need in `src/_locales/en` as you work.
2. `cd src/_locales/en`
3. `git branch message-updates-yyyymmdd`
4. `git push -u origin message-updates-yyyymmdd`
You can then open a pull request from the `message-updates-yyyymmdd` branch to
[the l10n repo](https://github.com/mozilla-l10n/multi-account-containers-l10n/) `main` branch.
### Distributing
#### Make the new version
1. Bump the version number in `package.json` and `manifest.json`
2. Commit the version number bump
3. Create a git tag for the version: `git tag <version>`
4. Push the tag up to GitHub: `git push --tags`
#### Publish to AMO
1. `./bin/build-addon.sh`
2. [Upload the `.zip` to AMO](https://addons.mozilla.org/developers/addon/multi-account-containers/versions/submit/)
#### Publish to GitHub
Finally, we also publish the release to GitHub for those followers.
1. Download the signed `.xpi` from [the addon versions page](https://addons.mozilla.org/developers/addon/multi-account-containers/versions)
2. [Make the new release on
GitHub](https://github.com/mozilla/multi-account-containers/releases/new)
* Use the version number for "Tag version" and "Release title"
* Release notes: copy the output of `git log --no-merges --pretty=format:"%h %s" <previous-version>..<new-version>`
* Attach binaries: select the signed `.xpi` file
### Links
Facebook & Twitter icons CC-Attrib https://fairheadcreative.com.
- [License](./LICENSE.txt)
- [Contributing](./CONTRIBUTING.md)
- [Code Of Conduct](./CODE_OF_CONDUCT.md)
<!-- Please keep the list in alphabetical order -->
[contributing]: CONTRIBUTING.md
[cpg]: https://www.mozilla.org/about/governance/policies/participation/
[enduser]: https://support.mozilla.org/en-US/kb/containers
[forum]: https://discourse.mozilla.org/c/containers/223
[discussions]: https://github.com/mozilla/multi-account-containers/discussions
[matrix]: https://matrix.to/#/#containers:mozilla.org

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/env bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
@ -32,4 +32,4 @@ rm -rf $TMPDIR/src/_locales/.github || die
print G "done."
print Y "Running the test..."
$(npm bin)/addons-linter $TMPDIR/src || die
npx addons-linter $TMPDIR/src || die

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/env bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
@ -11,7 +11,7 @@ git submodule init || die
git submodule update --remote --depth 1 src/_locales || die
print Y "Installing dependencies..."
npm install || die
npm install --legacy-peer-deps || die
print Y "Running tests..."
npm test
@ -23,4 +23,4 @@ if [[ $# -gt 0 ]]; then
EXTRA_PARAMS="--filename $1"
fi
$(npm bin)/web-ext build --overwrite-dest $EXTRA_PARAMS || die
npx web-ext build --overwrite-dest $EXTRA_PARAMS || die

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/env bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this

View file

@ -1,31 +0,0 @@
# Acceptance Criteria
## User Experience
- [ ] It should place a containers button on the users browser toolbar
- [ ] It should include all containers management UI inside a door hanger from this toolbar button
- [ ] It should provide a set of default container choices for users to pick from (work, home, travel etc.)
- [ ] Each container type should have a color, icon and name
- [ ] It should allow users to create new containers
- [ ] It should allow users to delete containers
- [ ] It should allow users to open container tabs
- [ ] each container tab should be clearly demarcated by color/icon etc.
- [ ] It should provide a control to show/hide all open tabs of one container type
- [ ] It should provide a control to sort tabs by container type
- [ ] It should provide a control to allow users to open containers in new tab or new window by default
## User Experience Non-Requirements (out of scope)
- [ ] It should not show any UI in browser settings
- [ ] It should not effect the awesome bar
- [ ] It should not effect the Firefox Library
- [ ] It should not make any changes to sync functionality
## Measurements
- [ ] It should measure container tab creations per session
- [ ] It should measure the type of container tab created
- [ ] It should measure container tab creations
- [ ] It should measure new container creations
- [ ] It should measure container deletes
- [ ] It should measure container sorts
- [ ] It should measure container hides
- [ ] It should report URIs accessed across multiple containers
- [ ] It should measure the % of tab-based vs windows-based containers

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

31
docs/release.md Normal file
View file

@ -0,0 +1,31 @@
# Release a new version
## Make the new version
1. Bump the version number in `package.json` and `manifest.json`
2. Commit the version number bump
3. Create a git tag for the version: `git tag <version>`
4. Push the tag up to GitHub: `git push --tags`
## Publish to AMO
1. Run `./bin/build-addon.sh`
2. [Upload the zip file to AMO][amo-upload]
## Publish to GitHub
Finally, we also publish the release to GitHub.
1. Download the signed `.xpi` from [the addon versions page][addon-page]
2. [Create a new release on GitHub][gh-release]
* For *Tag version* and *Release title*, use the version number
* For *Release notes*, copy the output of:
```
git log --no-merges \
--pretty=format:"%h %s" <previous-version>..<new-version>
```
* For the *Attach binaries*, select the signed `.xpi` file
[addon-page]: https://addons.mozilla.org/developers/addon/multi-account-containers/versions
[amo-upload]: https://addons.mozilla.org/developers/addon/multi-account-containers/versions/submit/
[gh-release]: https://github.com/mozilla/multi-account-containers/releases/new

25098
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,22 +2,22 @@
"name": "testpilot-containers",
"title": "Multi-Account Containers",
"description": "Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.",
"version": "7.4.0",
"author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston",
"version": "8.3.0",
"author": "Andrea Marchesini, Luke Crouch, Lesley Norton, Kendall Werts, Maxx Crawford, Jonathan Kingston",
"bugs": {
"url": "https://github.com/mozilla/multi-account-containers/issues"
},
"dependencies": {},
"devDependencies": {
"addons-linter": "^1.3.2",
"addons-linter": "^5.28.0",
"ajv": "^6.6.3",
"chai": "^4.2.0",
"eslint": "^6.6.0",
"eslint-plugin-no-unsanitized": "^2.0.0",
"eslint-plugin-promise": "^3.4.0",
"eslint": "^7.32.0",
"eslint-plugin-no-unsanitized": "^4.0.0",
"eslint-plugin-promise": "^5.2.0",
"htmllint-cli": "0.0.7",
"json": ">=10.0.0",
"mocha": "^6.2.2",
"mocha": "^10.1.0",
"npm-run-all": "^4.0.0",
"nyc": "^15.0.0",
"sinon": "^7.5.0",
@ -25,7 +25,7 @@
"stylelint": "^13.5.0",
"stylelint-config-standard": "^20.0.0",
"stylelint-order": "^4.0.0",
"web-ext": "^5.4.1",
"web-ext": "^7.5.0",
"webextensions-jsdom": "^1.2.1"
},
"homepage": "https://github.com/mozilla/multi-account-containers#readme",
@ -36,13 +36,16 @@
"url": "git+https://github.com/mozilla/multi-account-containers.git"
},
"scripts": {
"webext": "web-ext run -s src/",
"build": "web-ext build -s src/",
"dev": "npm run remove-locales-github && web-ext run -s src/",
"lint": "npm-run-all lint:*",
"lint:addon": "./bin/addons-linter.sh",
"lint:css": "stylelint src/css/*.css",
"lint:html": "htmllint *.html",
"lint:js": "eslint .",
"package": "rm -rf src/web-ext-artifacts && npm run build && mv src/web-ext-artifacts/firefox_multi-account_containers-*.zip addon.xpi",
"restore-locales-github": "cd src/_locales && git restore .github/",
"remove-locales-github": "rm -rf src/_locales/.github",
"test": "npm run lint && npm run coverage",
"test:once": "mocha test/**/*.test.js",
"test:watch": "npm run test:once -- --watch",

@ -1 +1 @@
Subproject commit f3da295d004b7d6314c5baa321d9a5418ec937d9
Subproject commit bdaa01291b7367a5e815470fd263ea36c862fe32

View file

@ -3,6 +3,7 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title data-i18n-message-id="confirmNavigationTitle"></title>
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="chrome://browser/skin/aboutNetError.css" type="text/css" media="all" />
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="chrome://global/skin/aboutNetError.css" type="text/css" media="all" />
<script type="text/javascript" src="./js/i18n.js"></script>
<link rel="stylesheet" href="/css/confirm-page.css" />
</head>
@ -23,8 +24,21 @@
</label>
<br />
<div class="button-container">
<button id="deny" class="button" data-message-id="openInContainer" data-message-arg="current-container-name"></button>
<button id="confirm" class="button primary" data-message-id="openInContainer" data-message-arg="container-name"></button>
<button id="deny"
class="button"
data-message-id="openInContainer"
data-message-arg="current-container-name">
</button>
<button id="deny-no-container"
class="button"
data-message-id="openInNoContainer">
</button>
<button id="confirm"
class="button primary"
autofocus
data-message-id="openInContainer"
data-message-arg="container-name">
</button>
</div>
</form>
</main>

View file

@ -1,29 +1,122 @@
body {
background: #fff;
color: #202023;
}
--grey10: #e7e7e7;
h3 {
margin-block-start: 2.5rem;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
background: #fff;
color: rgb(74, 74, 79);
font-size: 13px;
overflow: hidden;
}
h3:first-of-type {
margin-block-start: 1rem;
margin-block-start: 2.5rem;
}
p,
label {
color: rgb(74, 74, 79);
display: flex;
align-items: center;
font-size: 14px;
}
label > span {
padding-inline-end: 4px;
}
.settings-group {
margin-block-end: 16px;
}
form {
display: flex;
flex-direction: column;
padding-block-end: 1rem;
}
.settings-group p {
margin-inline-start: 24px;
margin-block: 4px 8px;
}
input[type="checkbox"] {
margin-inline: 0 8px;
margin-block: 1px auto;
inline-size: 16px;
block-size: 16px;
}
button {
margin-inline: 0 auto;
}
.keyboard-shortcut {
display: flex;
flex-direction: row;
justify-content: space-between;
max-inline-size: 70%;
align-items: center;
}
.bold {
font-weight: 600;
}
.moz-vpn-proxy-permissions {
margin-block: 0 2rem;
padding-block-end: 1rem;
border-block-end: 1px solid var(--grey10);
display: flex;
flex-direction: column;
}
h3.moz-vpn-proxy-permissions-title {
margin-block-start: 0;
position: relative;
display: flex;
align-items: center;
}
.warning-icon {
display: flex;
align-items: center;
}
.warning-icon.show-warning::before {
background-image: url("/img/warning.svg");
background-size: 24px;
background-repeat: no-repeat;
background-position: center;
content: "";
display: block;
block-size: 24px;
inline-size: 24px;
margin-inline-end: 0.5rem;
}
.moz-vpn-proxy-permissions-title::before,
.moz-vpn-proxy-permissions-title::after {
background-color: var(--grey10);
content: "";
height: 1px;
flex: 1 1 0%;
}
h3.moz-vpn-proxy-permissions-title::before {
margin-inline-end: 2rem;
margin-inline-start: -50%;
}
h3.moz-vpn-proxy-permissions-title::after {
margin-inline-start: 2rem;
margin-inline-end: -50%;
}
@media (prefers-color-scheme: dark) {
body {
background: #202023;
background: #23212a;
color: #fff;
}
p,
label {
p {
color: rgb(177, 177, 179);
}
}

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1,9 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg data-name="Flat (For Export)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<style>rect,path {fill: rgba(249, 249, 250, 0.8);}</style>
<rect x="1" y="1" width="6" height="6" rx="1"/>
<path d="M14.75 3H13V1.25A0.25 0.25 0 0 0 12.75 1h-1.5A0.25 0.25 0 0 0 11 1.25V3H9.25A0.25 0.25 0 0 0 9 3.25v1.5A0.25 0.25 0 0 0 9.25 5H11v1.75A0.25 0.25 0 0 0 11.25 7h1.5A0.25 0.25 0 0 0 13 6.75V5h1.75A0.25 0.25 0 0 0 15 4.75v-1.5A0.25 0.25 0 0 0 14.75 3z" fill-rule="evenodd"/>
<rect x="1" y="9" width="6" height="6" rx="1"/>
<rect x="9" y="9" width="6" height="6" rx="1"/>
</svg>

Before

Width:  |  Height:  |  Size: 801 B

View file

@ -1,7 +1,13 @@
<svg data-name="Flat (For Export)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<style>rect,path {fill: rgba(24, 25, 26, 01);}</style>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<style>
:root { color-scheme: light dark; }
rect, path { fill: rgb(24, 25, 26); }
@media (prefers-color-scheme: dark) {
rect, path { fill: rgba(249, 249, 250, 0.8); }
}
</style>
<rect x="1" y="1" width="6" height="6" rx="1"/>
<path d="M14.75 3H13V1.25A0.25 0.25 0 0 0 12.75 1h-1.5A0.25 0.25 0 0 0 11 1.25V3H9.25A0.25 0.25 0 0 0 9 3.25v1.5A0.25 0.25 0 0 0 9.25 5H11v1.75A0.25 0.25 0 0 0 11.25 7h1.5A0.25 0.25 0 0 0 13 6.75V5h1.75A0.25 0.25 0 0 0 15 4.75v-1.5A0.25 0.25 0 0 0 14.75 3z" fill-rule="evenodd"/>
<rect x="1" y="9" width="6" height="6" rx="1"/>
<rect x="9" y="9" width="6" height="6" rx="1"/>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 727 B

View file

@ -4,6 +4,7 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;">
<style>
:root { color-scheme: light dark; }
path, circle, g {
fill: menutext;
}

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

3
src/img/warning.svg Normal file
View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.6929 16.0119L13.7399 6.10586C13.5739 5.77358 13.3185 5.49411 13.0025 5.29878C12.6866 5.10346 12.3224 5 11.9509 5C11.5795 5 11.2153 5.10346 10.8993 5.29878C10.5834 5.49411 10.328 5.77358 10.1619 6.10586L5.20894 16.0159C5.0575 16.3206 4.98633 16.659 5.00217 16.999C5.01801 17.3389 5.12033 17.6692 5.29946 17.9586C5.47858 18.2479 5.72858 18.4868 6.0258 18.6526C6.32302 18.8183 6.65762 18.9055 6.99794 18.9059H16.9029C17.2439 18.906 17.5792 18.819 17.8771 18.6531C18.1749 18.4872 18.4255 18.2479 18.6048 17.9579C18.7842 17.668 18.8864 17.337 18.9018 16.9964C18.9172 16.6557 18.8453 16.3169 18.6929 16.0119V16.0119ZM10.9509 8.90586C10.9509 8.64065 11.0563 8.38629 11.2438 8.19876C11.4314 8.01122 11.6857 7.90586 11.9509 7.90586C12.2162 7.90586 12.4705 8.01122 12.658 8.19876C12.8456 8.38629 12.9509 8.64065 12.9509 8.90586V12.9059C12.9509 13.1711 12.8456 13.4254 12.658 13.613C12.4705 13.8005 12.2162 13.9059 11.9509 13.9059C11.6857 13.9059 11.4314 13.8005 11.2438 13.613C11.0563 13.4254 10.9509 13.1711 10.9509 12.9059V8.90586ZM11.9509 17.1559C11.7037 17.1559 11.462 17.0826 11.2565 16.9452C11.0509 16.8078 10.8907 16.6126 10.7961 16.3842C10.7015 16.1558 10.6767 15.9045 10.725 15.662C10.7732 15.4195 10.8922 15.1968 11.0671 15.022C11.2419 14.8472 11.4646 14.7281 11.7071 14.6799C11.9496 14.6317 12.2009 14.6564 12.4293 14.751C12.6577 14.8456 12.8529 15.0058 12.9903 15.2114C13.1276 15.417 13.2009 15.6586 13.2009 15.9059C13.2009 16.2374 13.0692 16.5553 12.8348 16.7897C12.6004 17.0242 12.2825 17.1559 11.9509 17.1559V17.1559Z" fill="#FF4F5E" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -61,8 +61,9 @@ window.assignManager = {
this.area.get([siteStoreKey]).then((storageResponse) => {
if (storageResponse && siteStoreKey in storageResponse) {
resolve(storageResponse[siteStoreKey]);
} else {
resolve(null);
}
resolve(null);
}).catch((e) => {
reject(e);
});
@ -102,6 +103,7 @@ window.assignManager = {
async deleteContainer(userContextId) {
const sitesByContainer = await this.getAssignedSites(userContextId);
this.area.remove(Object.keys(sitesByContainer));
identityState.storageArea.remove(backgroundLogic.cookieStoreId(userContextId));
},
async getAssignedSites(userContextId = null) {
@ -164,11 +166,17 @@ window.assignManager = {
_neverAsk(m) {
const pageUrl = m.pageUrl;
if (m.neverAsk === true) {
if (m.defaultContainer === true) {
this.storageArea.remove(pageUrl);
return;
}
// If we have existing data and for some reason it hasn't been
// deleted etc lets update it
this.storageArea.get(pageUrl).then((siteSettings) => {
if (siteSettings) {
siteSettings.neverAsk = true;
siteSettings.userContextId = backgroundLogic.getUserContextIdFromCookieStoreId(m.cookieStoreId);
this.storageArea.set(pageUrl, siteSettings);
}
}).catch((e) => {
@ -188,13 +196,18 @@ window.assignManager = {
// The following blocks potentially dangerous requests for privacy that come without a tabId
if(requestInfo.tabId === -1) {
return {type: "direct"};
return {};
}
const tab = await browser.tabs.get(requestInfo.tabId);
const result = await proxifiedContainers.retrieve(tab.cookieStoreId);
if (!result || !result.proxy) {
return {type: "direct"};
return {};
}
// proxyDNS only works for SOCKS proxies
if (["socks", "socks4"].includes(result.proxy.type)) {
result.proxy.proxyDNS = true;
}
if (!result.proxy.mozProxyEnabled) {
@ -313,7 +326,8 @@ window.assignManager = {
options.url,
tab.index + 1,
tab.active,
openTabId
openTabId,
tab.groupId
);
} else {
this.reloadPageInContainer(
@ -323,7 +337,8 @@ window.assignManager = {
tab.index + 1,
tab.active,
siteSettings.neverAsk,
openTabId
openTabId,
tab.groupId
);
}
this.calculateContextMenu(tab);
@ -382,6 +397,12 @@ window.assignManager = {
return currentContainerState && currentContainerState.isIsolated;
},
maybeAddProxyListeners() {
if (browser.proxy) {
browser.proxy.onRequest.addListener(this.handleProxifiedRequest, {urls: ["<all_urls>"]});
}
},
init() {
browser.contextMenus.onClicked.addListener((info, tab) => {
info.bookmarkId ?
@ -390,7 +411,7 @@ window.assignManager = {
});
// Before anything happens we decide if the request should be proxified
browser.proxy.onRequest.addListener(this.handleProxifiedRequest, {urls: ["<all_urls>"]});
this.maybeAddProxyListeners();
// Before a request is handled by the browser we decide if we should
// route through a different container
@ -462,9 +483,7 @@ window.assignManager = {
},
contextualIdentityRemoved(changeInfo) {
browser.contextMenus.remove(
changeInfo.contextualIdentity.cookieStoreId
);
this.removeMenuItem(changeInfo.contextualIdentity.cookieStoreId);
},
async _onClickedHandler(info, tab) {
@ -559,6 +578,16 @@ window.assignManager = {
return true;
},
async _resetCookiesForSite(hostname, cookieStoreId) {
const hostNameTruncated = hostname.replace(/^www\./, ""); // Remove "www." from the hostname
await browser.browsingData.removeCookies({
cookieStoreId: cookieStoreId,
hostnames: [hostNameTruncated] // This does not remove cookies from associated domains. To remove all cookies, we have a container storage removal option.
});
return true;
},
async _setOrRemoveAssignment(tabId, pageUrl, userContextId, remove) {
let actionName;
// https://github.com/mozilla/testpilot-containers/issues/626
@ -610,7 +639,7 @@ window.assignManager = {
},
async _maybeRemoveSiteIsolation(userContextId) {
const assignments = await this.storageArea.getByContainer(userContextId);
const assignments = await this.storageArea.getAssignedSites(userContextId);
const hasAssignments = assignments && Object.keys(assignments).length > 0;
if (hasAssignments) {
return;
@ -641,11 +670,11 @@ window.assignManager = {
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1215376#c16
// We also can't change for always private mode
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1352102
browser.contextMenus.remove(this.MENU_ASSIGN_ID);
browser.contextMenus.remove(this.MENU_REMOVE_ID);
browser.contextMenus.remove(this.MENU_SEPARATOR_ID);
browser.contextMenus.remove(this.MENU_HIDE_ID);
browser.contextMenus.remove(this.MENU_MOVE_ID);
this.removeMenuItem(this.MENU_ASSIGN_ID);
this.removeMenuItem(this.MENU_REMOVE_ID);
this.removeMenuItem(this.MENU_SEPARATOR_ID);
this.removeMenuItem(this.MENU_HIDE_ID);
this.removeMenuItem(this.MENU_MOVE_ID);
},
async calculateContextMenu(tab) {
@ -666,7 +695,7 @@ window.assignManager = {
}
browser.contextMenus.create({
id: menuId,
title: "Always Open in This Container",
title: browser.i18n.getMessage("alwaysOpenSiteInContainer"),
checked,
type: "checkbox",
contexts: ["all"],
@ -680,13 +709,13 @@ window.assignManager = {
browser.contextMenus.create({
id: this.MENU_HIDE_ID,
title: "Hide This Container",
title: browser.i18n.getMessage("hideThisContainer"),
contexts: ["all"],
});
browser.contextMenus.create({
id: this.MENU_MOVE_ID,
title: "Move Tabs to a New Window",
title: browser.i18n.getMessage("moveTabsToANewWindow"),
contexts: ["all"],
});
},
@ -698,7 +727,15 @@ window.assignManager = {
});
},
reloadPageInDefaultContainer(url, index, active, openerTabId) {
/**
* @param {string} url
* @param {number} index
* @param {boolean} active
* @param {number} [openerTabId]
* @param {number} [groupId]
* @returns {void}
*/
reloadPageInDefaultContainer(url, index, active, openerTabId, groupId) {
// To create a new tab in the default container, it is easiest just to omit the
// cookieStoreId entirely.
//
@ -717,16 +754,58 @@ window.assignManager = {
// does not automatically return to the original opener tab. To get this desired behaviour,
// we MUST specify the openerTabId when creating the new tab.
const cookieStoreId = "firefox-default";
browser.tabs.create({url, cookieStoreId, index, active, openerTabId});
this.createTabWrapper(url, cookieStoreId, index, active, openerTabId, groupId);
},
reloadPageInContainer(url, currentUserContextId, userContextId, index, active, neverAsk = false, openerTabId = null) {
/**
* Wraps around `browser.tabs.create` and `browser.tabs.group` to create a
* tab and ensure that it ends up in the requested tab group, if applicable.
*
* @param {string} url
* @param {string} cookieStoreId
* @param {number} index
* @param {boolean} active
* @param {number} openerTabId
* @param {number} [groupId] Tab group ID
* @returns {Promise<Tab>}
*/
async createTabWrapper(url, cookieStoreId, index, active, openerTabId, groupId) {
const newTab = await browser.tabs.create({
url,
cookieStoreId,
index,
active,
openerTabId,
});
if (groupId >= 0) {
// If the original tab was in a tab group, make sure that the reopened tab
// stays in the same tab group.
await browser.tabs.group({ groupId, tabIds: newTab.id });
}
return newTab;
},
/**
* @param {string} url
* @param {string} currentUserContextId
* @param {string} userContextId
* @param {number} index
* @param {boolean} active
* @param {boolean} [neverAsk=false]
* @param {number} [openerTabId=null]
* @param {number} [groupId]
* @returns {Promise<Tab>}
*/
reloadPageInContainer(url, currentUserContextId, userContextId, index, active, neverAsk = false, openerTabId = null, groupId = undefined) {
const cookieStoreId = backgroundLogic.cookieStoreId(userContextId);
const loadPage = browser.runtime.getURL("confirm-page.html");
// False represents assignment is not permitted
// If the user has explicitly checked "Never Ask Again" on the warning page we will send them straight there
if (neverAsk) {
return browser.tabs.create({url, cookieStoreId, index, active, openerTabId});
return this.createTabWrapper(url, cookieStoreId, index, active, openerTabId, groupId);
} else {
let confirmUrl = `${loadPage}?url=${this.encodeURLProperty(url)}&cookieStoreId=${cookieStoreId}`;
let currentCookieStoreId;
@ -734,13 +813,14 @@ window.assignManager = {
currentCookieStoreId = backgroundLogic.cookieStoreId(currentUserContextId);
confirmUrl += `&currentCookieStoreId=${currentCookieStoreId}`;
}
return browser.tabs.create({
url: confirmUrl,
cookieStoreId: currentCookieStoreId,
openerTabId,
return this.createTabWrapper(
confirmUrl,
currentCookieStoreId,
index,
active
}).then(() => {
active,
openerTabId,
groupId
).then(() => {
// We don't want to sync this URL ever nor clutter the users history
browser.history.deleteUrl({url: confirmUrl});
}).catch((e) => {
@ -752,7 +832,7 @@ window.assignManager = {
async initBookmarksMenu() {
browser.contextMenus.create({
id: this.OPEN_IN_CONTAINER,
title: "Open Bookmark in Container Tab",
title: browser.i18n.getMessage("openBookmarkInContainerTab"),
contexts: ["bookmark"],
});
@ -768,12 +848,19 @@ window.assignManager = {
},
async removeBookmarksMenu() {
browser.contextMenus.remove(this.OPEN_IN_CONTAINER);
this.removeMenuItem(this.OPEN_IN_CONTAINER);
const identities = await browser.contextualIdentities.query({});
for (const identity of identities) {
browser.contextMenus.remove(identity.cookieStoreId);
this.removeMenuItem(identity.cookieStoreId);
}
},
removeMenuItem(menuItemId) {
// Callers do not check whether the menu exists before attempting to remove
// it. contextMenus.remove rejects when the menu does not exist, so we need
// to catch and swallow the error to avoid logspam.
browser.contextMenus.remove(menuItemId).catch(() => {});
}
};
assignManager.init();

View file

@ -1,4 +1,9 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const DEFAULT_TAB = "about:newtab";
const backgroundLogic = {
NEW_TAB_PAGES: new Set([
"about:startpage",
@ -9,7 +14,13 @@ const backgroundLogic = {
NUMBER_OF_KEYBOARD_SHORTCUTS: 10,
unhideQueue: [],
init() {
browser.commands.onCommand.addListener(function (command) {
if (command === "sort_tabs") {
backgroundLogic.sortTabs();
return;
}
for (let i=0; i < backgroundLogic.NUMBER_OF_KEYBOARD_SHORTCUTS; i++) {
const key = "open_container_" + i;
const cookieStoreId = identityState.keyboardShortcut[key];
@ -19,6 +30,71 @@ const backgroundLogic = {
}
}
});
browser.permissions.onAdded.addListener(permissions => this.resetPermissions(permissions));
browser.permissions.onRemoved.addListener(permissions => this.resetPermissions(permissions));
// Update Translation in Manifest
browser.runtime.onInstalled.addListener((details) => {
this.updateTranslationInManifest();
this._undoDefault820SortTabsKeyboardShortcut(details);
});
browser.runtime.onStartup.addListener(this.updateTranslationInManifest);
},
/**
* One-time migration after updating from v8.2.0:
* Unset the default keyboard shortcut (Ctrl+Comma) for the `sort_tabs`
* command if it was set in v8.2.0 of this addon. If the user remapped
* a different shortcut manually, retain their shortcut. Users who used
* the default keyboard shortcut will need to manually set a shortcut.
* See https://support.mozilla.org/en-US/kb/manage-extension-shortcuts-firefox
*
* @param {{reason: runtime.OnInstalledReason, previousVersion?: string}} details
*/
async _undoDefault820SortTabsKeyboardShortcut(details) {
if (details.reason === "update" && details.previousVersion === "8.2.0") {
const commands = await browser.commands.getAll();
const sortTabsCommand = commands.find(command => command.name === "sort_tabs");
if (sortTabsCommand) {
const previouslySuggestedKeys = [
"Ctrl+Comma", // "default"
"MacCtrl+Comma", // "mac"
];
if (previouslySuggestedKeys.includes(sortTabsCommand.shortcut)) {
browser.commands.reset("sort_tabs");
}
}
}
},
updateTranslationInManifest() {
for (let index = 0; index < 10; index++) {
const ajustedIndex = index + 1; // We want to start from 1 instead of 0 in the UI.
browser.commands.update({
name: `open_container_${index}`,
description: browser.i18n.getMessage("containerShortcut", `${ajustedIndex}`)
});
}
},
resetPermissions(permissions) {
permissions.permissions.forEach(async permission => {
switch (permission) {
case "bookmarks":
assignManager.resetBookmarksMenuItem();
break;
case "nativeMessaging":
await MozillaVPN_Background.removeMozillaVpnProxies();
await browser.runtime.reload();
break;
case "proxy":
assignManager.maybeAddProxyListeners();
break;
}
});
},
async getExtensionInfo() {
@ -28,6 +104,19 @@ const backgroundLogic = {
return extensionInfo;
},
// Remove container data (cookies, localStorage and cache)
async deleteContainerDataOnly(userContextId) {
await browser.browsingData.removeCookies({
cookieStoreId: this.cookieStoreId(userContextId)
});
await browser.browsingData.removeLocalStorage({
cookieStoreId: this.cookieStoreId(userContextId)
});
return {done: true, userContextId};
},
getUserContextIdFromCookieStoreId(cookieStoreId) {
if (!cookieStoreId) {
return false;
@ -96,7 +185,8 @@ const backgroundLogic = {
// We can't open these we just have to throw them away
if (protocol === "about:"
|| protocol === "chrome:"
|| protocol === "moz-extension:") {
|| protocol === "moz-extension:"
|| protocol === "file:") {
return false;
}
return true;
@ -146,7 +236,7 @@ const backgroundLogic = {
if ("isIsolated" in containerState || remove) {
delete containerState.isIsolated;
} else {
containerState.isIsolated = "locked";
containerState.isIsolated = "locked";
}
return await identityState.storageArea.set(cookieStoreId, containerState);
} catch (error) {
@ -282,7 +372,13 @@ const backgroundLogic = {
let pos = 0;
// Let's collect UCIs/tabs for this window.
/** @type {Map<string, {order: string, tabs: Tab[]}>} */
const map = new Map;
const lastTab = tabs.at(-1);
/** @type {boolean} */
let lastTabIsInTabGroup = !!lastTab && lastTab.groupId >= 0;
for (const tab of tabs) {
if (pinnedTabs && !tab.pinned) {
// We don't have, or we already handled all the pinned tabs.
@ -295,26 +391,51 @@ const backgroundLogic = {
continue;
}
const userContextId = backgroundLogic.getUserContextIdFromCookieStoreId(tab.cookieStoreId);
if (!map.has(userContextId)) {
map.set(userContextId, []);
if (tab.groupId >= 0) {
// Skip over tabs in tab groups until it's possible to handle them better.
continue;
}
map.get(userContextId).push(tab);
if (!map.has(tab.cookieStoreId)) {
const userContextId = backgroundLogic.getUserContextIdFromCookieStoreId(tab.cookieStoreId);
map.set(tab.cookieStoreId, { order: userContextId, tabs: [] });
}
map.get(tab.cookieStoreId).tabs.push(tab);
}
const containerOrderStorage = await browser.storage.local.get([CONTAINER_ORDER_STORAGE_KEY]);
const containerOrder =
containerOrderStorage && containerOrderStorage[CONTAINER_ORDER_STORAGE_KEY];
if (containerOrder) {
map.forEach((obj, key) => {
obj.order = (key in containerOrder) ? containerOrder[key] : -1;
});
}
// Let's sort the map.
const sortMap = new Map([...map.entries()].sort((a, b) => a[0] > b[0]));
const sortMap = new Map([...map.entries()].sort((a, b) => a[1].order > b[1].order));
// Let's move tabs.
sortMap.forEach(tabs => {
for (const { tabs } of sortMap.values()) {
for (const tab of tabs) {
++pos;
browser.tabs.move(tab.id, {
windowId: windowObj.id,
index: pos
index: pinnedTabs ? pos : -1
});
// Pinned tabs are never grouped and always inserted in the front.
if (!pinnedTabs && lastTabIsInTabGroup && browser.tabs.ungroup) {
// If the last item in the tab strip is a grouped tab, moving a tab
// to its position will also add it to the tab group. Since this code
// is only sorting ungrouped tabs, this forcibly ungroups the first
// tab to be moved. All subsequent iterations will only be moving
// ungrouped tabs to the position of other ungrouped tabs.
lastTabIsInTabGroup = false;
browser.tabs.ungroup(tab.id);
}
}
});
}
},
async hideTabs(options) {

View file

@ -1,4 +1,4 @@
const MAJOR_VERSIONS = ["2.3.0", "2.4.0", "6.2.0", "8.0.0"];
const MAJOR_VERSIONS = ["2.3.0", "2.4.0", "6.2.0", "8.0.2"];
const badge = {
async init() {
const currentWindow = await browser.windows.getCurrent();

View file

@ -20,12 +20,12 @@ const messageHandler = {
case "resetSync":
response = sync.resetSync();
break;
case "resetBookmarksContext":
response = assignManager.resetBookmarksMenuItem();
break;
case "deleteContainer":
response = backgroundLogic.deleteContainer(m.message.userContextId);
break;
case "deleteContainerDataOnly":
response = backgroundLogic.deleteContainerDataOnly(m.message.userContextId);
break;
case "createOrUpdateContainer":
response = backgroundLogic.createOrUpdateContainer(m.message);
break;
@ -48,6 +48,9 @@ const messageHandler = {
// m.url is the assignment to be removed/added
response = assignManager._setOrRemoveAssignment(m.tabId, m.url, m.userContextId, m.value);
break;
case "resetCookiesForSite":
response = assignManager._resetCookiesForSite(m.pageUrl, m.cookieStoreId);
break;
case "sortTabs":
backgroundLogic.sortTabs();
break;
@ -88,17 +91,21 @@ const messageHandler = {
m.newUserContextId,
m.tabIndex,
m.active,
true
true,
null,
m.groupId
);
break;
case "assignAndReloadInContainer":
tab = await assignManager.reloadPageInContainer(
m.url,
m.url,
m.currentUserContextId,
m.newUserContextId,
m.tabIndex,
m.newUserContextId,
m.tabIndex,
m.active,
true
true,
null,
m.groupId
);
// m.tabId is used for where to place the in content message
// m.url is the assignment to be removed/added
@ -223,7 +230,9 @@ const messageHandler = {
// if it's a container tab wait for it to complete and
// unhide other tabs from this container
if (tab.cookieStoreId.startsWith("firefox-container")) {
browser.tabs.onUpdated.addListener(this.tabUpdateHandler);
browser.tabs.onUpdated.addListener(this.tabUpdateHandler, {
properties: ["status"]
});
}
}
}

View file

@ -66,11 +66,11 @@ const MozillaVPN_Background = {
// Handle responses from MozillaVPN client
async handleResponse(response) {
MozillaVPN_Background._installed = true;
if (response.error && response.error === "vpn-client-down") {
MozillaVPN_Background._connected = false;
return;
}
MozillaVPN_Background._installed = true;
if (response.servers) {
const servers = response.servers.countries;
browser.storage.local.set({ [MozillaVPN_Background.MOZILLA_VPN_SERVERS_KEY]: servers});
@ -100,6 +100,19 @@ const MozillaVPN_Background = {
get isolationKey() {
return this._isolationKey;
},
async removeMozillaVpnProxies() {
const proxies = await proxifiedContainers.retrieveAll();
if (!proxies) {
return;
}
for (const proxyObj of proxies) {
const { proxy } = proxyObj;
if (proxy.countryCode !== undefined) {
await proxifiedContainers.delete(proxyObj.cookieStoreId);
}
}
},
};
MozillaVPN_Background.init();

View file

@ -7,27 +7,47 @@ async function load() {
redirectUrlElement.textContent = redirectUrl;
appendFavicon(redirectUrl, redirectUrlElement);
// Option for staying on the previous container
document.getElementById("deny").addEventListener("click", (e) => {
e.preventDefault();
denySubmit(redirectUrl);
denySubmit(redirectUrl, currentCookieStoreId);
});
// Option for going to the default container (no container)
document.getElementById("deny-no-container").addEventListener("click", (e) => {
e.preventDefault();
denySubmit(redirectUrl, currentCookieStoreId);
});
const container = await browser.contextualIdentities.get(cookieStoreId);
const currentContainer = currentCookieStoreId ? await browser.contextualIdentities.get(currentCookieStoreId) : null;
const currentContainerName = currentContainer ? currentContainer.name : "";
const currentContainerName = currentContainer ? setDenyButton(currentContainer.name) : setDenyButton("");
document.querySelectorAll("[data-message-id]").forEach(el => {
const elementData = el.dataset;
const containerName = elementData.messageArg === "container-name" ? container.name : currentContainerName;
el.textContent = browser.i18n.getMessage(elementData.messageId, containerName);
});
// Option for going to newly selected container
document.getElementById("confirm").addEventListener("click", (e) => {
e.preventDefault();
confirmSubmit(redirectUrl, cookieStoreId);
});
}
function setDenyButton(currentContainerName) {
const buttonDeny = document.getElementById("deny");
const buttonDenyNoContainer = document.getElementById("deny-no-container");
if (currentContainerName) {
buttonDenyNoContainer.style.display = "none";
return currentContainerName;
}
buttonDeny.style.display = "none";
return;
}
function appendFavicon(pageUrl, redirectUrlElement) {
const origin = new URL(pageUrl).origin;
const favIconElement = Utils.createFavIconElement(`${origin}/favicon.ico`);
@ -42,24 +62,42 @@ function confirmSubmit(redirectUrl, cookieStoreId) {
browser.runtime.sendMessage({
method: "neverAsk",
neverAsk: true,
cookieStoreId: cookieStoreId,
pageUrl: redirectUrl
});
}
openInContainer(redirectUrl, cookieStoreId);
}
function getCurrentTab() {
return browser.tabs.query({
/**
* @returns {Promise<Tab>}
*/
async function getCurrentTab() {
const tabs = await browser.tabs.query({
active: true,
windowId: browser.windows.WINDOW_ID_CURRENT
});
return tabs[0];
}
async function denySubmit(redirectUrl) {
async function denySubmit(redirectUrl, currentCookieStoreId) {
const tab = await getCurrentTab();
const currentContainer = currentCookieStoreId ? await browser.contextualIdentities.get(currentCookieStoreId) : null;
const neverAsk = document.getElementById("never-ask").checked;
if (neverAsk) {
await browser.runtime.sendMessage({
method: "neverAsk",
neverAsk: true,
cookieStoreId: currentCookieStoreId,
pageUrl: redirectUrl,
defaultContainer: !currentContainer
});
}
await browser.runtime.sendMessage({
method: "exemptContainerAssignment",
tabId: tab[0].id,
tabId: tab.id,
pageUrl: redirectUrl
});
document.location.replace(redirectUrl);
@ -69,12 +107,15 @@ load();
async function openInContainer(redirectUrl, cookieStoreId) {
const tab = await getCurrentTab();
await browser.tabs.create({
index: tab[0].index + 1,
const reopenedTab = await browser.tabs.create({
index: tab.index + 1,
cookieStoreId,
url: redirectUrl
});
if (tab.length > 0) {
browser.tabs.remove(tab[0].id);
if (tab.groupId >= 0) {
// If the original tab was in a tab group, make sure that the reopened tab
// stays in the same tab group.
await browser.tabs.group({ groupId: tab.groupId, tabIds: reopenedTab.id });
}
await browser.tabs.remove(tab.id);
}

View file

@ -24,11 +24,12 @@ async function addMessage(message) {
divElement.innerText = message.text;
const imageElement = document.createElement("img");
const imagePath = browser.runtime.getURL("/img/container-site-d-24.png");
const imagePath = browser.runtime.getURL("/img/multiaccountcontainer-16.svg");
const response = await fetch(imagePath);
const blob = await response.blob();
const objectUrl = URL.createObjectURL(blob);
imageElement.src = objectUrl;
imageElement.width = imageElement.height = 24;
divElement.prepend(imageElement);
document.body.appendChild(divElement);

View file

@ -5,11 +5,17 @@ const MozillaVPN = {
const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" });
this.handleStatusIndicatorsInContainerLists(mozillaVpnInstalled);
const permissionsEnabled = await this.bothPermissionsEnabled();
if (!permissionsEnabled) {
return;
}
const proxies = await this.getProxies(identities);
if (Object.keys(proxies).length === 0) {
return;
}
const tooltipProxyWarning = browser.i18n.getMessage("tooltipWarning");
for (const el of document.querySelectorAll("[data-cookie-store-id]")) {
const cookieStoreId = el.dataset.cookieStoreId;
@ -29,6 +35,7 @@ const MozillaVPN = {
if (!mozillaVpnConnected && proxy.mozProxyEnabled) {
flag.classList.add("proxy-unavailable");
const menuItemName = el.querySelector(".menu-item-name");
menuItemName.setAttribute("title", tooltipProxyWarning);
if (menuItemName) {
el.querySelector(".menu-item-name").dataset.mozProxyWarning = "proxy-unavailable";
}
@ -58,14 +65,11 @@ const MozillaVPN = {
const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" });
const connectionStatusStringId = mozillaVpnConnected ? "moz-vpn-connected" : "moz-vpn-disconnected";
const connectionStatusLocalizedString = browser.i18n.getMessage(connectionStatusStringId);
const connectionStatusTooltip = document.querySelector(".vpn-status-container-list");
connectionStatusTooltip.setAttribute("title", connectionStatusLocalizedString);
statusIconEls.forEach(el => {
el.style.backgroundImage = mozillaVpnConnected ? connectedIndicatorSrc : disconnectedIndicatorSrc;
if (el.querySelector(".tooltip")) {
el.querySelector(".tooltip").textContent = connectionStatusLocalizedString;
} else {
el.textContent = connectionStatusLocalizedString;
}
});
},
@ -151,6 +155,10 @@ const MozillaVPN = {
};
},
async bothPermissionsEnabled() {
return await browser.permissions.contains({ permissions: ["proxy", "nativeMessaging"] });
},
async getProxyWarnings(proxyObj) {
if (!proxyObj) {
@ -240,7 +248,7 @@ const MozillaVPN = {
randomInteger = (randomInteger - server.weight);
}
return nextServer;
}
},
};
window.MozillaVPN = MozillaVPN;

View file

@ -1,17 +1,45 @@
const NUMBER_OF_KEYBOARD_SHORTCUTS = 10;
async function requestPermissions() {
const checkbox = document.querySelector("#bookmarksPermissions");
if (checkbox.checked) {
const granted = await browser.permissions.request({permissions: ["bookmarks"]});
if (!granted) {
checkbox.checked = false;
async function setUpCheckBoxes() {
document.querySelectorAll("[data-permission-id]").forEach(async(el) => {
const permissionId = el.dataset.permissionId;
const permissionEnabled = await browser.permissions.contains({ permissions: [permissionId] });
el.checked = !!permissionEnabled;
});
}
function disablePermissionsInputs() {
document.querySelectorAll("[data-permission-id").forEach(el => {
el.disabled = true;
});
}
function enablePermissionsInputs() {
document.querySelectorAll("[data-permission-id").forEach(el => {
el.disabled = false;
});
}
document.querySelectorAll("[data-permission-id").forEach(async(el) => {
const permissionId = el.dataset.permissionId;
el.addEventListener("change", async() => {
if (el.checked) {
disablePermissionsInputs();
const granted = await browser.permissions.request({ permissions: [permissionId] });
if (!granted) {
el.checked = false;
enablePermissionsInputs();
}
return;
}
} else {
await browser.permissions.remove({permissions: ["bookmarks"]});
}
browser.runtime.sendMessage({ method: "resetBookmarksContext" });
await browser.permissions.remove({ permissions: [permissionId] });
});
});
async function maybeShowPermissionsWarningIcon() {
const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled();
const permissionsWarningEl = document.querySelector(".warning-icon");
permissionsWarningEl.classList.toggle("show-warning", !bothMozillaVpnPermissionsEnabled);
}
async function enableDisableSync() {
@ -25,15 +53,20 @@ async function enableDisableReplaceTab() {
await browser.storage.local.set({replaceTabEnabled: !!checkbox.checked});
}
async function changeTheme(event) {
const theme = event.currentTarget;
await browser.storage.local.set({currentTheme: theme.value});
await browser.storage.local.set({currentThemeId: theme.selectedIndex});
}
async function setupOptions() {
const hasPermission = await browser.permissions.contains({permissions: ["bookmarks"]});
const { syncEnabled } = await browser.storage.local.get("syncEnabled");
const { replaceTabEnabled } = await browser.storage.local.get("replaceTabEnabled");
if (hasPermission) {
document.querySelector("#bookmarksPermissions").checked = true;
}
const { currentThemeId } = await browser.storage.local.get("currentThemeId");
document.querySelector("#syncCheck").checked = !!syncEnabled;
document.querySelector("#replaceTabCheck").checked = !!replaceTabEnabled;
document.querySelector("#changeTheme").selectedIndex = currentThemeId;
setupContainerShortcutSelects();
}
@ -78,13 +111,38 @@ function resetOnboarding() {
browser.storage.local.set({"onboarding-stage": 0});
}
async function resetPermissionsUi() {
await maybeShowPermissionsWarningIcon();
await setUpCheckBoxes();
enablePermissionsInputs();
}
browser.permissions.onAdded.addListener(resetPermissionsUi);
browser.permissions.onRemoved.addListener(resetPermissionsUi);
document.addEventListener("DOMContentLoaded", setupOptions);
document.querySelector("#bookmarksPermissions").addEventListener( "change", requestPermissions);
document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync);
document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab);
document.querySelector("button").addEventListener("click", resetOnboarding);
document.querySelector("#changeTheme").addEventListener( "change", changeTheme);
maybeShowPermissionsWarningIcon();
for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) {
document.querySelector("#open_container_"+i)
.addEventListener("change", storeShortcutChoice);
}
}
document.querySelectorAll("[data-btn-id]").forEach(btn => {
btn.addEventListener("click", () => {
switch (btn.dataset.btnId) {
case "reset-onboarding":
resetOnboarding();
break;
case "moz-vpn-learn-more":
browser.tabs.create({
url: MozillaVPN.attachUtmParameters("https://support.mozilla.org/kb/protect-your-container-tabs-mozilla-vpn", "options-learn-more")
});
break;
}
});
});
resetPermissionsUi();

View file

@ -32,6 +32,9 @@ async function init() {
list.appendChild(fragment);
MozillaVPN.handleContainerList(identities);
// Set the theme
Utils.applyTheme();
}
init();

View file

@ -10,7 +10,6 @@ const DEFAULT_ICON = "circle";
const NEW_CONTAINER_ID = "new";
const ONBOARDING_STORAGE_KEY = "onboarding-stage";
const CONTAINER_ORDER_STORAGE_KEY = "container-order";
const CONTAINER_DRAG_DATA_TYPE = "firefox-container";
// List of panels
@ -33,6 +32,7 @@ const P_CONTAINER_EDIT = "containerEdit";
const P_CONTAINER_DELETE = "containerDelete";
const P_CONTAINERS_ACHIEVEMENT = "containersAchievement";
const P_CONTAINER_ASSIGNMENTS = "containerAssignments";
const P_CLEAR_CONTAINER_STORAGE = "clearContainerStorage";
const P_MOZILLA_VPN_SERVER_LIST = "moz-vpn-server-list";
const P_ADVANCED_PROXY_SETTINGS = "advanced-proxy-settings-panel";
@ -66,6 +66,9 @@ const Logic = {
method: "MozillaVPN_attemptPort"
}),
// Set the theme
Utils.applyTheme();
// Remove browserAction "upgraded" badge when opening panel
this.clearBrowserActionBadge();
@ -120,6 +123,19 @@ const Logic = {
},
notify(i18nOpts) {
const notificationCards = document.querySelectorAll(".popup-notification-card");
const text = browser.i18n.getMessage(i18nOpts.messageId, i18nOpts.placeholders);
notificationCards.forEach(notificationCard => {
notificationCard.textContent = text;
notificationCard.classList.add("is-shown");
setTimeout(() => {
notificationCard.classList.remove("is-shown");
}, 2000);
});
},
async showAchievementOrContainersListPanel() {
// Do we need to show an achievement panel?
let showAchievements = false;
@ -209,6 +225,11 @@ const Logic = {
async saveContainerOrder(rows) {
const containerOrder = {};
rows.forEach((node, index) => {
if (typeof browser.contextualIdentities.move === "function") {
browser.contextualIdentities.move(
node.dataset.containerId, index);
}
return containerOrder[node.dataset.containerId] = index;
});
await browser.storage.local.set({
@ -394,7 +415,11 @@ const Logic = {
},
shortcutListener(e){
function openNewContainerTab(identity) {
function openTopContainers() {
const identities = Logic.identities();
const key = e.code.substring(5);
const identity = e.code === "Digit0" ? identities[9] : identities[key - 1];
try {
browser.tabs.create({
cookieStoreId: identity.cookieStoreId
@ -404,12 +429,34 @@ const Logic = {
window.close();
}
}
const identities = Logic.identities();
if ((e.keyCode >= 49 && e.keyCode <= 57) &&
Logic._currentPanel === "containersList") {
const identity = identities[e.keyCode - 49];
if (identity) {
openNewContainerTab(identity);
// We monitor if the search input is focused so we can disable opening
// containers by typing a digit between 0-9 while the popup is open.
const searchInput = document.getElementById("search-terms");
let isSearchInputFocused = false;
if (document.activeElement === searchInput) {
isSearchInputFocused = true;
}
if (Logic._currentPanel === "containersList" && !isSearchInputFocused) {
switch(e.code) {
case "Digit0":
case "Digit1":
case "Digit2":
case "Digit3":
case "Digit4":
case "Digit5":
case "Digit6":
case "Digit7":
case "Digit8":
case "Digit9":
openTopContainers();
break;
case "Slash":
document.getElementById("search-terms").focus();
e.preventDefault();
break;
}
}
},
@ -462,6 +509,23 @@ const Logic = {
default:
break;
}
},
filterContainerList() {
const pattern = /^\s+|\s+$/g;
const list = Array.from(document.querySelectorAll("#identities-list tr"));
const search = document.querySelector("#search-terms").value.replace(pattern, "").toLowerCase();
for (const i in list) {
const text = list[i].querySelector("td div span");
if (text.innerText.replace(pattern, "").toLowerCase().includes(search) ||
!search) {
list[i].style.display = "block";
} else {
list[i].style.display = "none";
}
}
}
};
@ -621,7 +685,7 @@ Logic.registerPanel(P_ONBOARDING_7, {
// Let's move to the containers list panel.
Utils.addEnterHandler(document.querySelector("#sign-in"), async () => {
browser.tabs.create({
url: "https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=multi-account-containers&utm_source=addon&utm_medium=panel&utm_campaign=container-sync",
url: "https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=multi-account-containers&utm_source=addon&utm_medium=panel&utm_campaign=container-sync&brand=mozilla",
});
await Logic.setOnboardingStage(7);
Logic.showPanel(P_ONBOARDING_8);
@ -643,14 +707,29 @@ Logic.registerPanel(P_ONBOARDING_8, {
// This method is called when the object is registered.
initialize() {
Utils.addEnterHandler(document.querySelector("#onboarding-done-btn"), async () => {
await Logic.setOnboardingStage(8);
Logic.showPanel(P_CONTAINERS_LIST);
document.querySelectorAll(".onboarding-done").forEach(el => {
Utils.addEnterHandler(el, async () => {
await Logic.setOnboardingStage(8);
Logic.showPanel(P_CONTAINERS_LIST);
});
});
},
// This method is called when the panel is shown.
prepare() {
async prepare() {
const mozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled();
if (!mozillaVpnPermissionsEnabled) {
const panel = document.querySelector(".onboarding-panel-8");
panel.classList.add("optional-permissions-disabled");
Utils.addEnterHandler(panel.querySelector("#onboarding-enable-permissions"), async () => {
const granted = await browser.permissions.request({ permissions: ["proxy", "nativeMessaging"] });
if (granted) {
await Logic.setOnboardingStage(8);
}
});
}
return Promise.resolve(null);
},
});
@ -662,24 +741,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
// This method is called when the object is registered.
async initialize() {
const mozillaVpnToutName = "moz-tout-main-panel";
await browser.runtime.sendMessage({ method: "MozillaVPN_queryStatus" });
Utils.addEnterHandler(document.querySelector("#moz-vpn-learn-more"), () => {
MozillaVPN.handleMozillaCtaClick("mac-main-panel-btn");
window.close();
});
Utils.addEnterHandler(document.querySelector(".dismiss-moz-vpn-tout"), async() => {
const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList");
if (typeof(mozillaVpnHiddenToutsList) === "undefined") {
await browser.storage.local.set({ "mozillaVpnHiddenToutsList": [] });
}
document.querySelector("#moz-vpn-tout").classList.add("disappear");
mozillaVpnHiddenToutsList.push({
name: mozillaVpnToutName
});
await browser.storage.local.set({ mozillaVpnHiddenToutsList });
});
Utils.addEnterHandler(document.querySelector("#manage-containers-link"), (e) => {
if (!e.target.classList.contains("disable-edit-containers")) {
Logic.showPanel(MANAGE_CONTAINERS_PICKER);
@ -694,9 +756,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
Utils.addEnterHandler(document.querySelector("#always-open-in"), () => {
Logic.showPanel(ALWAYS_OPEN_IN_PICKER);
});
Utils.addEnterHandler(document.querySelector("#info-icon"), () => {
browser.runtime.openOptionsPage();
});
Utils.addEnterHandler(document.querySelector("#sort-containers-link"), async () => {
try {
await browser.runtime.sendMessage({
@ -708,16 +767,32 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
}
});
const mozVpnTout = document.getElementById("moz-vpn-tout");
const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" });
if (mozillaVpnInstalled) {
return mozVpnTout.remove();
const mozillaVpnPermissionsWarningDotName = "moz-permissions-warning-dot";
let { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList");
if (typeof(mozillaVpnHiddenToutsList) === "undefined") {
await browser.storage.local.set({ "mozillaVpnHiddenToutsList": [] });
mozillaVpnHiddenToutsList = [];
}
const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList");
const mozillaVpnToutShouldBeHidden = mozillaVpnHiddenToutsList && mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnToutName);
if (mozillaVpnToutShouldBeHidden) {
return mozVpnTout.remove();
// Badge Options icon if both nativeMessaging and/or proxy permissions are disabled
const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled();
const warningDotShouldBeHidden = mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnPermissionsWarningDotName);
const optionsIcon = document.getElementById("info-icon");
if (optionsIcon && !bothMozillaVpnPermissionsEnabled && !warningDotShouldBeHidden) {
optionsIcon.classList.add("info-icon-alert");
}
Utils.addEnterHandler((document.querySelector("#info-icon")), async() => {
browser.runtime.openOptionsPage();
if (!mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnPermissionsWarningDotName)) {
optionsIcon.classList.remove("info-icon-alert");
mozillaVpnHiddenToutsList.push({
name: mozillaVpnPermissionsWarningDotName
});
}
await browser.storage.local.set({ mozillaVpnHiddenToutsList });
});
},
unregister() {
@ -749,7 +824,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
</div>
</div>
<span class="menu-text">${identity.name}</span>
<span class="tooltip proxy-unavailable">This container has been configured to use a Mozilla VPN proxy, but Mozilla VPN is not on. Turn Mozilla VPN on to use this proxy.</span>
</div>
<span class="menu-right-float">
<img alt="" class="always-open-in-flag flag-img" src="/img/flags/.png"/>
@ -767,8 +841,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
tr.appendChild(td);
const openInThisContainer = tr.querySelector(".menu-item-name");
// const mozProxyWarning = await MozillaVPN.getProxyWarnings(proxies[identity.cookieStoreId]);
// openInThisContainer.dataset.mozProxyWarning = mozProxyWarning;
Utils.addEnterHandler(openInThisContainer, (e) => {
e.preventDefault();
if (openInThisContainer.dataset.mozProxyWarning === "proxy-unavailable") {
@ -801,7 +873,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
Utils.addEnterHandler(showPanelButton, () => {
Logic.showPanel(P_CONTAINER_INFO, identity);
});
}
const list = document.querySelector("#identities-list");
@ -811,6 +882,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
document.addEventListener("keydown", Logic.keyboardNavListener);
document.addEventListener("keydown", Logic.shortcutListener);
document.addEventListener("input", Logic.filterContainerList);
MozillaVPN.handleContainerList(identities);
@ -887,6 +959,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
Utils.alwaysOpenInContainer(identity);
window.close();
});
// Show or not the has-tabs section.
for (let trHasTabs of document.getElementsByClassName("container-info-has-tabs")) { // eslint-disable-line prefer-const
trHasTabs.style.display = !identity.hasHiddenTabs && !identity.hasOpenTabs ? "none" : "";
@ -910,6 +983,13 @@ Logic.registerPanel(P_CONTAINER_INFO, {
Utils.addEnterHandler(manageContainer, async () => {
Logic.showPanel(P_CONTAINER_EDIT, identity);
});
const clearContainerStorageButton = document.getElementById("clear-container-storage-info");
Utils.addEnterHandler(clearContainerStorageButton, async () => {
const granted = await browser.permissions.request({ permissions: ["browsingData"] });
if (granted) {
Logic.showPanel(P_CLEAR_CONTAINER_STORAGE, identity);
}
});
return this.buildOpenTabTable(tabs);
},
@ -1200,7 +1280,8 @@ Logic.registerPanel(REOPEN_IN_CONTAINER_PICKER, {
false,
newUserContextId,
currentTab.index + 1,
currentTab.active
currentTab.active,
currentTab.groupId
);
window.close();
};
@ -1210,6 +1291,7 @@ Logic.registerPanel(REOPEN_IN_CONTAINER_PICKER, {
if (currentTab.cookieStoreId !== "firefox-default") {
const tr = document.createElement("tr");
tr.classList.add("menu-item", "hover-highlight", "keyboard-nav");
tr.setAttribute("tabindex", "0");
const td = document.createElement("td");
td.innerHTML = Utils.escaped`
@ -1229,7 +1311,8 @@ Logic.registerPanel(REOPEN_IN_CONTAINER_PICKER, {
false,
0,
currentTab.index + 1,
currentTab.active
currentTab.active,
currentTab.groupId
);
window.close();
});
@ -1370,11 +1453,14 @@ Logic.registerPanel(P_CONTAINER_ASSIGNMENTS, {
/* As we don't have the full or correct path the best we can assume is the path is HTTPS and then replace with a broken icon later if it doesn't load.
This is pending a better solution for favicons from web extensions */
const assumedUrl = `https://${site.hostname}/favicon.ico`;
const resetSiteCookiesInfo = browser.i18n.getMessage("clearSiteCookiesTooltipInfo");
const deleteSiteInfo = browser.i18n.getMessage("deleteSiteTooltipInfo");
trElement.innerHTML = Utils.escaped`
<td>
<div class="favicon"></div>
<span title="${site.hostname}" class="menu-text">${site.hostname}</span>
<img class="trash-button delete-assignment" src="/img/container-delete.svg" />
<span title="${site.hostname}" class="menu-text truncate-text">${site.hostname}</span>
<img title="${resetSiteCookiesInfo}" class="reset-button reset-assignment" src="/img/refresh-16.svg" />
<img title="${deleteSiteInfo}" class="trash-button delete-assignment" src="/img/container-delete.svg" />
</td>`;
trElement.getElementsByClassName("favicon")[0].appendChild(Utils.createFavIconElement(assumedUrl));
const deleteButton = trElement.querySelector(".trash-button");
@ -1386,6 +1472,20 @@ Logic.registerPanel(P_CONTAINER_ASSIGNMENTS, {
delete assignments[siteKey];
this.showAssignedContainers(assignments);
});
const resetButton = trElement.querySelector(".reset-button");
Utils.addEnterHandler(resetButton, async () => {
const cookieStoreId = Logic.currentCookieStoreId();
const granted = await browser.permissions.request({ permissions: ["browsingData"] });
if (!granted) {
return;
}
const result = await Utils.resetCookiesForSite(site.hostname, cookieStoreId);
if (result === true) {
Logic.notify({messageId: "cookiesClearedSuccess", placeholders: [site.hostname]});
} else {
Logic.notify({messageId: "cookiesCouldNotBeCleared", placeholders: [site.hostname]});
}
});
trElement.classList.add("menu-item", "hover-highlight", "keyboard-nav");
tableElement.appendChild(trElement);
});
@ -1440,18 +1540,25 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
async connectedCallback() {
const { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList");
const mozillaVpnCollapseEditContainerTout = mozillaVpnHiddenToutsList && mozillaVpnHiddenToutsList.find(tout => tout.name === this.toutName);
const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" });
this.hideShowButton.addEventListener("click", this);
if (mozillaVpnCollapseEditContainerTout) {
if (mozillaVpnCollapseEditContainerTout && !mozillaVpnInstalled) {
this.collapseUi();
}
// Add listeners
if (!this.classList.contains("has-attached-listeners")) {
this.primaryCta.addEventListener("click", () => {
MozillaVPN.handleMozillaCtaClick("mac-edit-container-panel-btn");
const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled();
this.primaryCta.addEventListener("click", async() => {
if (!bothMozillaVpnPermissionsEnabled && mozillaVpnInstalled) {
await browser.permissions.request({ permissions: ["proxy", "nativeMessaging"] });
} else {
MozillaVPN.handleMozillaCtaClick("mac-edit-container-panel-btn");
}
});
this.switch.addEventListener("click", async() => {
@ -1504,9 +1611,9 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
await proxifiedContainers.set(id.cookieStoreId, proxy);
this.switch.checked = true;
this.updateProxyDependentUi(proxy);
} else {
this.switch.checked = false;
this.updateProxyDependentUi({});
return;
}
});
@ -1520,24 +1627,35 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" });
const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" });
if (!mozillaVpnInstalled) {
this.subtitle.textContent = browser.i18n.getMessage("integrateContainers");
this.hideEls(this.switch, this.switchLabel, this.currentServerButton);
this.subtitle.textContent = browser.i18n.getMessage("protectThisContainer");
this.primaryCta.addEventListener("click", this);
const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled();
} else {
// Mozilla VPN installed...
if (mozillaVpnInstalled && !bothMozillaVpnPermissionsEnabled) {
this.subtitle.style.flex = "1 1 100%";
this.classList.remove("show-server-button");
this.subtitle.textContent = browser.i18n.getMessage("additionalPermissionNeeded");
this.hideEls(this.hideShowButton, this.switch, this.switchLabel, this.currentServerButton);
this.primaryCta.style.display = "block";
this.primaryCta.textContent = browser.i18n.getMessage("enable");
return;
}
if (mozillaVpnInstalled) {
// Hide cta and hide/show button
this.hideEls(this.primaryCta, this.hideShowButton);
// Update subtitle
this.subtitle.textContent = mozillaVpnConnected ? browser.i18n.getMessage("useCustomLocation") : browser.i18n.getMessage("mozillaVpnMustBeOn");
this.subtitle.style.flex = "1 1 80%";
this.currentServerButton.style.display = "flex";
}
if (!mozillaVpnConnected) {
if (mozillaVpnConnected) {
[this.switchLabel, this.switch].forEach(el => {
el.style.display = "inline-block";
});
} else {
this.hideEls(this.switch, this.switchLabel, this.currentServerButton);
this.switch.checked = false;
}
@ -1584,17 +1702,15 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
this.mozProxyEnabledInput.value = proxyInfo.mozProxyEnabled;
this.proxyAddressInput.value = `${proxyInfo.type}://${proxyInfo.host}:${proxyInfo.port}`;
if (typeof(proxyInfo.countryCode) === "undefined" && proxyInfo.type !== "direct") {
if (typeof(proxyInfo.countryCode) === "undefined" && proxyInfo.type) {
// Set custom proxy URL below 'Advanced proxy settings' button label
this.advancedProxyAddress.textContent = `${proxyInfo.type}://${proxyInfo.host}:${proxyInfo.port}`;
}
}
async updateProxyDependentUi(proxyInfo) {
const containerHasProxy = typeof(proxyInfo) !== "undefined";
const mozillaVpnProxyLocationAvailable = (proxy) => {
return typeof(proxy.countryCode) !== "undefined" && typeof(proxyInfo.cityName) !== "undefined";
return typeof(proxy) !== "undefined" && typeof(proxy.countryCode) !== "undefined" && typeof(proxy.cityName) !== "undefined";
};
const mozillaVpnProxyIsEnabled = (proxy) => {
@ -1607,7 +1723,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" });
if (
!containerHasProxy ||
!proxyInfo ||
!mozillaVpnProxyLocationAvailable(proxyInfo) ||
!mozillaVpnConnected
) {
@ -1622,23 +1738,20 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
}
// Populate inputs and server button with current or previously stored mozilla vpn proxy
if(containerHasProxy && mozillaVpnProxyLocationAvailable(proxyInfo)) {
if(proxyInfo && mozillaVpnProxyLocationAvailable(proxyInfo)) {
this.currentCountryFlag.style.backgroundImage = `url("./img/flags/${proxyInfo.countryCode.toUpperCase()}.png")`;
this.currentCountryFlag.style.backgroundImage = proxyInfo.countryCode + ".png";
this.currentCityName.textContent = proxyInfo.cityName;
this.countryCode = proxyInfo.countryCode;
}
return;
}
expandUi() {
this.classList.add("expanded");
this.style.maxHeight = 500 + "px";
}
collapseUi() {
this.classList.remove("expanded");
this.style.maxHeight = 56 + "px";
}
hideEls(...els) {
@ -1675,6 +1788,10 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
customElements.define("moz-vpn-container-ui", MozVpnContainerUi);
const mozillaVpnUi = document.querySelector("moz-vpn-container-ui");
mozillaVpnUi.updateMozVpnStatusDependentUi();
browser.permissions.onAdded.addListener(() => { mozillaVpnUi.updateMozVpnStatusDependentUi(); });
browser.permissions.onRemoved.addListener(() => { mozillaVpnUi.updateMozVpnStatusDependentUi(); });
const advancedProxySettingsButton = document.querySelector(".advanced-proxy-settings-btn");
Utils.addEnterHandler(advancedProxySettingsButton, () => {
Logic.showPanel(P_ADVANCED_PROXY_SETTINGS, this.getEditInProgressIdentity(), false, false);
@ -1837,60 +1954,65 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
return;
}
const proxyData = await proxifiedContainers.retrieve(identity.cookieStoreId);
if (proxyData) {
if (proxyData.proxy && proxyData.proxy.mozProxyEnabled && !mozillaVpnConnected) {
const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] });
if (proxyPermissionEnabled) {
const proxyData = await proxifiedContainers.retrieve(identity.cookieStoreId);
if (proxyData && proxyData.proxy.mozProxyEnabled && !mozillaVpnConnected) {
mozillaVpnUi.updateProxyDependentUi({});
return;
}
mozillaVpnUi.updateProxyDependentUi(proxyData.proxy);
return;
const proxy = proxyData ? proxyData.proxy : {};
mozillaVpnUi.updateProxyDependentUi(proxy);
}
mozillaVpnUi.updateProxyDependentUi({});
},
});
Logic.registerPanel(P_ADVANCED_PROXY_SETTINGS, {
panelSelector: "#advanced-proxy-settings-panel",
initialize(){
async initialize() {
this._proxyForm = document.querySelector(".advanced-proxy-panel-content");
const advancedProxyInput = this._proxyForm.querySelector("#edit-advanced-proxy-input");
const clearadvancedProxyInput = this._proxyForm.querySelector("#clear-advanced-proxy-input");
this._advancedProxyInput = this._proxyForm.querySelector("#edit-advanced-proxy-input");
const clearAdvancedProxyInput = this._proxyForm.querySelector("#clear-advanced-proxy-input");
this._submitadvancedProxy = this._proxyForm.querySelector("#submit-advanced-proxy");
advancedProxyInput.addEventListener("keydown", () => {
advancedProxyInput.dataset.editedStatus = "edited";
this._advancedProxyInput.addEventListener("keydown", (e) => {
if (e.key !== "Enter") {
this.hideInvalidEntryWarning();
}
});
this._submitadvancedProxy.addEventListener("click", (e) => {
e.preventDefault();
const parsedProxy = proxifiedContainers.parseProxy(advancedProxyInput.value);
if (advancedProxyInput.value.length > 0 && !parsedProxy) {
this._proxyForm.classList.add("invalid");
return;
}
const identity = Logic.currentIdentity();
proxifiedContainers.set(identity.cookieStoreId, parsedProxy);
Logic.showPanel(P_CONTAINER_EDIT, Logic.currentIdentity(), false, false);
this.submitProxyForm();
});
clearadvancedProxyInput.addEventListener("click", (e) => {
e.stopPropagation();
clearAdvancedProxyInput.addEventListener("click", (e) => {
e.preventDefault();
this._proxyForm.classList.remove("invalid");
advancedProxyInput.value = "";
});
advancedProxyInput.addEventListener("blur", () => {
if (advancedProxyInput.value.length === 0) {
const activeEl = document.activeElement;
if (activeEl === this._advancedProxyInput) {
return this.submitProxyForm();
}
if (activeEl !== clearAdvancedProxyInput) {
return;
}
if(!proxifiedContainers.parseProxy(advancedProxyInput.value)) {
this._proxyForm.classList.add("invalid");
this.hideInvalidEntryWarning();
this._advancedProxyInput.value = "";
this._advancedProxyInput.focus();
});
this._advancedProxyInput.addEventListener("blur", () => {
if (this._advancedProxyInput.value.length === 0) {
return;
}
if(!proxifiedContainers.parseProxy(this._advancedProxyInput.value)) {
this.showInvalidEntryWarning();
}
});
advancedProxyInput.addEventListener("focus", () => {
this._proxyForm.classList.remove("invalid");
this._advancedProxyInput.addEventListener("focus", () => {
this.hideInvalidEntryWarning();
});
const returnButton = document.getElementById("advanced-proxy-settings-return");
@ -1904,31 +2026,94 @@ Logic.registerPanel(P_ADVANCED_PROXY_SETTINGS, {
});
},
showInvalidEntryWarning() {
this._proxyForm.classList.add("invalid");
},
hideInvalidEntryWarning() {
this._proxyForm.classList.remove("invalid");
},
async submitProxyForm() {
const parsedProxy = proxifiedContainers.parseProxy(this._advancedProxyInput.value);
if (this._advancedProxyInput.value.length > 0 && !parsedProxy) {
this.showInvalidEntryWarning();
return;
}
const identity = Logic.currentIdentity();
proxifiedContainers.set(identity.cookieStoreId, parsedProxy);
Logic.showPanel(P_CONTAINER_EDIT, Logic.currentIdentity(), false, false);
},
async prepare() {
const identity = Logic.currentIdentity();
const advancedProxyInput = document.getElementById("edit-advanced-proxy-input");
// Clear the proxy field, reset form validity and edited classes
advancedProxyInput.value = "";
advancedProxyInput.dataset.editedStatus = "";
this._proxyForm.classList.remove("invalid");
const proxyPermissionEnabled = await browser.permissions.contains({ permissions: ["proxy"] });
if (!proxyPermissionEnabled) {
const edit_proxy_dom = function(proxy) {
if (proxy.type === "direct" || typeof proxy.type === "undefined" || MozillaVPN.proxyIsDisabled(proxy)) {
advancedProxyInput.value = "";
// Restrict tabbing inside advanced proxy panel to proxy permissions ui
const panel = document.getElementById("advanced-proxy-settings-panel");
const clickableEls = panel.querySelectorAll("button, a, input");
clickableEls.forEach(el => {
if (!el.dataset.tabGroup && el.id !== "advanced-proxy-settings-return") {
el.setAttribute("tabindex", "-1");
el.disabled = true;
}
});
// Show proxy permission overlay
const permissionsOverlay = document.getElementById("permissions-overlay");
permissionsOverlay.style.display = "flex";
// Add "enable" button handling
const enableProxyPermissionsButton = document.getElementById("enable-proxy-permissions");
enableProxyPermissionsButton.addEventListener("click", async() => {
const granted = await browser.permissions.request({ permissions: ["proxy"] });
if (granted) {
permissionsOverlay.style.display = "none";
// restore normal panel tabbing
clickableEls.forEach(el => {
el.tabindex = "0";
el.disabled = false;
});
}
});
}
// reset input
const resetProxyInput = () => {
if (!advancedProxyInput) {
return;
}
advancedProxyInput.value = `${proxy.type}://${proxy.host}:${proxy.port}`;
advancedProxyInput.value = "";
};
resetProxyInput();
this.hideInvalidEntryWarning();
const setProxyInputPlaceholder = (proxy) => {
this._advancedProxyInput.value = `${proxy.type}://${proxy.host}:${proxy.port}`;
};
const edit_proxy_dom = function(proxy) {
if (!proxy.type || MozillaVPN.proxyIsDisabled(proxy)) {
resetProxyInput();
return;
}
return setProxyInputPlaceholder(proxy);
};
const proxyData = await proxifiedContainers.retrieve(identity.cookieStoreId);
if (proxyData) {
edit_proxy_dom(proxyData.proxy);
} else {
advancedProxyInput.value = "";
resetProxyInput();
}
const containerColor = document.querySelector(".proxy-title-container-color");
containerColor.dataset.identityColor = identity.color;
return Promise.resolve(null);
@ -1943,17 +2128,6 @@ Logic.registerPanel(P_MOZILLA_VPN_SERVER_LIST, {
Utils.addEnterHandler(document.getElementById("moz-vpn-return"), async () => {
const identity = Logic.currentIdentity();
const { mozillaVpnServers } = await browser.storage.local.get("mozillaVpnServers");
const selectedServer = document.querySelector(".server-radio-btn:checked");
const proxy = MozillaVPN.getProxy(
selectedServer.dataset.countryCode,
selectedServer.dataset.cityName,
true,
mozillaVpnServers
);
await proxifiedContainers.set(identity.cookieStoreId, proxy);
Logic.showPanel(P_CONTAINER_EDIT, identity, false, false);
Logic.showPreviousPanel();
});
@ -1997,6 +2171,21 @@ Logic.registerPanel(P_MOZILLA_VPN_SERVER_LIST, {
radioBtn.dataset.cityName = city.name;
radioBtn.name = "server-city";
const cityListItem = cityTemplateClone.querySelector(".server-city-list-item");
Utils.addEnterHandler((cityListItem), async(e) => {
if (e.key === "Enter") {
radioBtn.checked = true;
}
const identity = Logic.currentIdentity();
const proxy = MozillaVPN.getProxy(
radioBtn.dataset.countryCode,
radioBtn.dataset.cityName,
true,
mozillaVpnServers
);
await proxifiedContainers.set(identity.cookieStoreId, proxy);
});
// Set city name
cityName.textContent = city.name;
cityList.appendChild(cityTemplateClone);
@ -2072,6 +2261,47 @@ Logic.registerPanel(P_MOZILLA_VPN_SERVER_LIST, {
}
});
// P_CLEAR_CONTAINER_STORAGE: Page for confirming container storage removal.
// ----------------------------------------------------------------------------
Logic.registerPanel(P_CLEAR_CONTAINER_STORAGE, {
panelSelector: "#clear-container-storage-panel",
// This method is called when the object is registered.
initialize() {
Utils.addEnterHandler(document.querySelector("#clear-container-storage-cancel-link"), () => {
const identity = Logic.currentIdentity();
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
});
Utils.addEnterHandler(document.querySelector("#close-clear-container-storage-panel"), () => {
const identity = Logic.currentIdentity();
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
});
Utils.addEnterHandler(document.querySelector("#clear-container-storage-ok-link"), async () => {
const identity = Logic.currentIdentity();
const userContextId = Utils.userContextId(identity.cookieStoreId);
const result = await browser.runtime.sendMessage({
method: "deleteContainerDataOnly",
message: { userContextId }
});
if (result.done === true) {
Logic.notify({messageId: "storageWasClearedConfirmation", placeholders: [identity.name]});
}
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
});
},
// This method is called when the panel is shown.
prepare() {
const identity = Logic.currentIdentity();
// Populating the panel: name, icon, and warning message
document.getElementById("container-clear-storage-title").textContent = identity.name;
return Promise.resolve(null);
},
});
// P_CONTAINER_DELETE: Delete a container.
// ----------------------------------------------------------------------------
@ -2121,15 +2351,6 @@ Logic.registerPanel(P_CONTAINER_DELETE, {
// Populating the panel: name, icon, and warning message
document.getElementById("container-delete-title").textContent = identity.name;
const totalNumberOfTabs = identity.numberOfHiddenTabs + identity.numberOfOpenTabs;
let warningMessage = "";
if (totalNumberOfTabs > 0) {
const grammaticalNumTabs = totalNumberOfTabs > 1 ? "tabs" : "tab";
warningMessage = `If you remove this container now, ${totalNumberOfTabs} container ${grammaticalNumTabs} will be closed.`;
}
document.getElementById("delete-container-tab-warning").textContent = warningMessage;
return Promise.resolve(null);
},
});

View file

@ -44,14 +44,14 @@ proxifiedContainers = {
// Parses a proxy description string of the format type://host[:port] or type://username:password@host[:port] (port is optional)
parseProxy(proxy_str, mozillaVpnData = null) {
const proxyRegexp = /(?<type>(https?)|(socks4?)):\/\/(\b(?<username>\w+):(?<password>\w+)@)?(?<host>((?:\d{1,3}\.){3}\d{1,3}\b)|(\b([\w.-]+)+))(:(?<port>\d+))?/;
const proxyRegexp = /(?<type>(https?)|(socks4?)):\/\/(\b(?<username>[\w-]+):(?<password>[\w-]+)@)?(?<host>((?:\d{1,3}\.){3}\d{1,3}\b)|(\b([\w.-]+)+))(:(?<port>\d+))?/;
const matches = proxyRegexp.exec(proxy_str);
if (!matches) {
return false;
}
if (mozillaVpnData && mozillaVpnData.mozProxyEnabled === undefined) {
matches.groups.type = "direct";
matches.groups.type = null;
}
if (!mozillaVpnData) {

View file

@ -2,6 +2,9 @@
const DEFAULT_FAVICON = "/img/blank-favicon.svg";
// eslint-disable-next-line
const CONTAINER_ORDER_STORAGE_KEY = "container-order";
// TODO use export here instead of globals
const Utils = {
@ -91,6 +94,9 @@ const Utils = {
return result.join("");
},
/**
* @returns {Promise<Tab|false>}
*/
async currentTab() {
const activeTabs = await browser.tabs.query({ active: true, windowId: browser.windows.WINDOW_ID_CURRENT });
if (activeTabs.length > 0) {
@ -135,14 +141,32 @@ const Utils = {
});
},
async reloadInContainer(url, currentUserContextId, newUserContextId, tabIndex, active) {
resetCookiesForSite(pageUrl, cookieStoreId) {
return browser.runtime.sendMessage({
method: "resetCookiesForSite",
pageUrl,
cookieStoreId,
});
},
/**
* @param {string} url
* @param {string} currentUserContextId
* @param {string} newUserContextId
* @param {number} tabIndex
* @param {boolean} active
* @param {number} [groupId]
* @returns {Promise<any>}
*/
async reloadInContainer(url, currentUserContextId, newUserContextId, tabIndex, active, groupId = undefined) {
return await browser.runtime.sendMessage({
method: "reloadInContainer",
url,
currentUserContextId,
newUserContextId,
tabIndex,
active
active,
groupId
});
},
@ -156,7 +180,8 @@ const Utils = {
currentUserContextId: false,
newUserContextId: assignedUserContextId,
tabIndex: currentTab.index +1,
active:currentTab.active
active: currentTab.active,
groupId: currentTab.groupId
});
}
await Utils.setOrRemoveAssignment(
@ -166,6 +191,26 @@ const Utils = {
false
);
},
/* Theme helper
*
* First, we look if there's a theme already set in the local storage. If
* there isn't one, we set the theme based on `prefers-color-scheme`.
* */
getTheme(currentTheme, window) {
if (typeof currentTheme !== "undefined" && currentTheme !== "auto") {
return currentTheme;
}
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
return "dark";
}
return "light";
},
async applyTheme() {
const { currentTheme } = await browser.storage.local.get("currentTheme");
const popup = document.getElementsByTagName("html")[0];
const theme = Utils.getTheme(currentTheme, window);
popup.setAttribute("data-theme", theme);
}
};
window.Utils = Utils;

View file

@ -1,18 +1,12 @@
{
"manifest_version": 2,
"name": "Firefox Multi-Account Containers",
"version": "8.0.0",
"version": "8.3.0",
"incognito": "not_allowed",
"description": "__MSG_extensionDescription__",
"icons": {
"48": "img/container-site-d-48.png",
"96": "img/container-site-d-96.png"
},
"applications": {
"gecko": {
"id": "@testpilot-containers",
"strict_min_version": "67.0"
}
"48": "img/multiaccountcontainer-16.svg",
"96": "img/multiaccountcontainer-16.svg"
},
"homepage_url": "https://github.com/mozilla/multi-account-containers#readme",
"permissions": [
@ -24,20 +18,22 @@
"history",
"idle",
"management",
"nativeMessaging",
"storage",
"unlimitedStorage",
"tabs",
"webRequestBlocking",
"webRequest",
"proxy"
"webRequest"
],
"optional_permissions": [
"bookmarks"
"bookmarks",
"browsingData",
"nativeMessaging",
"proxy"
],
"browser_specific_settings": {
"gecko": {
"id": "@testpilot-containers"
"id": "@testpilot-containers",
"strict_min_version": "91.1.0"
}
},
"commands": {
@ -46,77 +42,81 @@
"default": "Ctrl+Period",
"mac": "MacCtrl+Period"
},
"description": "Open containers panel"
"description": "__MSG_openContainerPanel__"
},
"sort_tabs": {
"description": "__MSG_sortTabsByContainer__"
},
"open_container_0": {
"suggested_key": {
"default": "Ctrl+Shift+1"
},
"description": "Container Shortcut 1"
"description": "__MSG_containerShortcut__"
},
"open_container_1": {
"suggested_key": {
"default": "Ctrl+Shift+2"
},
"description": "Container Shortcut 2"
"description": "__MSG_containerShortcut__"
},
"open_container_2": {
"suggested_key": {
"default": "Ctrl+Shift+3"
},
"description": "Container Shortcut 3"
"description": "__MSG_containerShortcut__"
},
"open_container_3": {
"suggested_key": {
"default": "Ctrl+Shift+4"
},
"description": "Container Shortcut 4"
"description": "__MSG_containerShortcut__"
},
"open_container_4": {
"suggested_key": {
"default": "Ctrl+Shift+5"
},
"description": "Container Shortcut 5"
"description": "__MSG_containerShortcut__"
},
"open_container_5": {
"suggested_key": {
"default": "Ctrl+Shift+6"
},
"description": "Container Shortcut 6"
"description": "__MSG_containerShortcut__"
},
"open_container_6": {
"suggested_key": {
"default": "Ctrl+Shift+7"
},
"description": "Container Shortcut 7"
"description": "__MSG_containerShortcut__"
},
"open_container_7": {
"suggested_key": {
"default": "Ctrl+Shift+8"
},
"description": "Container Shortcut 8"
"description": "__MSG_containerShortcut__"
},
"open_container_8": {
"suggested_key": {
"default": "Ctrl+Shift+9"
},
"description": "Container Shortcut 9"
"description": "__MSG_containerShortcut__"
},
"open_container_9": {
"suggested_key": {
"default": "Ctrl+Shift+0"
},
"description": "Container Shortcut 10"
"description": "__MSG_containerShortcut__"
}
},
"browser_action": {
"browser_style": true,
"default_icon": "img/multiaccountcontainer-16.svg",
"default_title": "Multi-Account Containers",
"default_title": "Firefox Multi-Account Containers",
"default_popup": "popup.html",
"default_area": "navbar",
"theme_icons": [
{
"light": "img/multiaccountcontainer-16-dark.svg",
"light": "img/multiaccountcontainer-16.svg",
"dark": "img/multiaccountcontainer-16.svg",
"size": 32
}
@ -125,7 +125,7 @@
"page_action": {
"browser_style": true,
"default_icon": "img/container-openin-16.svg",
"default_title": "Always open this in a Container",
"default_title": "__MSG_alwaysOpenSiteInContainer__",
"default_popup": "pageActionPopup.html",
"pinned": false,
"show_matches": ["*://*/*"]
@ -149,7 +149,7 @@
],
"default_locale": "en",
"web_accessible_resources": [
"/img/container-site-d-24.png"
"/img/multiaccountcontainer-16.svg"
],
"options_ui": {
"page": "options.html",

View file

@ -4,85 +4,137 @@
<head>
<meta charset="utf-8">
<script type="text/javascript" src="./js/i18n.js"></script>
<script type="text/javascript" src="./js/mozillaVpn.js"></script>
<script type="text/javascript" src="./js/proxified-containers.js"></script>
<link rel="stylesheet" href="css/options.css">
</head>
<body>
<form>
<h3 data-i18n-message-id="optionalPermissions"></h3>
<label >
<input type="checkbox" id="bookmarksPermissions">
<span data-i18n-message-id="enableBookMarkMenus"></span>
<div class="settings-group">
<label class="permission">
<input type="checkbox" data-permission-id="bookmarks" id="bookmarksPermissions">
<span class="bold" data-i18n-message-id="enableBookMarkMenus"></span>
</label>
<p><em data-i18n-message-id="enableBookMarkMenusDescription"></em></p>
</div>
<div id="moz-vpn-proxy-permissions" class="moz-vpn-proxy-permissions">
<h3 class="moz-vpn-proxy-permissions-title">
<span data-i18n-message-id="mozillaVpnAndProxyPermissionsTitle" class="warning-icon"></span>
</h3>
<div class="moz-vpn-proxy-permissions-content">
<div class="settings-group">
<label class="permission">
<input type="checkbox" data-permission-id="nativeMessaging">
<span class="bold" data-i18n-message-id="nativeMessagingPermissionTitle"></span>
</label>
<p><em data-i18n-message-id="nativeMessagingPermissionDescription"></em></p>
</div>
<div class="settings-group">
<label class="permission">
<input type="checkbox" data-permission-id="proxy">
<span class="bold" data-i18n-message-id="proxyPermissionTitle"></span>
</label>
<p><em data-i18n-message-id="proxyPermissionDescription"></em></p>
</div>
</div>
</div>
<h3 data-i18n-message-id="sync"></h3>
<div class="settings-group">
<label>
<input type="checkbox" id="syncCheck">
<span class="bold" data-i18n-message-id="enableSync"></span>
</label>
<p><em data-i18n-message-id="enableSyncDescription"></em></p>
</div>
</label>
<p><em data-i18n-message-id="enableBookMarkMenusDescription"></em></p>
<h3 data-i18n-message-id="firefoxAccountsSync"></h3>
<label>
<input type="checkbox" id="syncCheck">
<span data-i18n-message-id="enableSync"></span>
</label>
<p><em data-i18n-message-id="enableSyncDescription"></em></p>
<h3 data-i18n-message-id="tabBehavior"></h3>
<label>
<input type="checkbox" id="replaceTabCheck">
<span data-i18n-message-id="replaceTab"></span>
</label>
<p><em data-i18n-message-id="replaceTabDescription"></em></p>
<div class="settings-group">
<label>
<input type="checkbox" id="replaceTabCheck">
<span class="bold" data-i18n-message-id="replaceTab"></span>
</label>
<p><em data-i18n-message-id="replaceTabDescription"></em></p>
</div>
<!--
TODO
- Add data-i18n
-->
<h3 data-i18n-message-id="theme"></h3>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="chooseTheme"></span>
<select id="changeTheme" name="changeTheme">
<option value="auto" selected data-i18n-message-id="themeAuto">
</option>
<option value="light" data-i18n-message-id="themeLight">
</option>
<option value="dark" data-i18n-message-id="themeDark">
</option>
</select>
</label></p>
<h3 data-i18n-message-id="keyboardShortCuts"></h3>
<p><em data-i18n-message-id="editWhichContainer"></em></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="1"></span>
<select id="open_container_0">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="2"></span>
<select id="open_container_1">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="3"></span>
<select id="open_container_2">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="4"></span>
<select id="open_container_3">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="5"></span>
<select id="open_container_4">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="6"></span>
<select id="open_container_5">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="7"></span>
<select id="open_container_6">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="8"></span>
<select id="open_container_7">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="9"></span>
<select id="open_container_8">
</select>
</label></p>
<p><label>
<p><label class="keyboard-shortcut">
<span data-i18n-message-id="keyboardShortCut" data-i18n-placeholder="10"></span>
<select id="open_container_9">
</select>
</label></p>
<h3 data-i18n-message-id="onboarding"></h3>
<button data-i18n-message-id="resetOnboardingPanels"></button>
<button data-btn-id="reset-onboarding" data-i18n-message-id="resetOnboardingPanels"></button>
<p><em data-i18n-message-id="onboardingToggle"></em></p>
<h3>Mozilla VPN</h3>
<button data-btn-id="moz-vpn-learn-more" data-i18n-message-id="learnMore"></button>
</form>
<script src="js/options.js"></script>
</body>

View file

@ -1,7 +1,7 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Multi-Account Containers</title>
<title>Firefox Multi-Account Containers</title>
<script type="text/javascript" src="./js/i18n.js"></script>
<link rel="stylesheet" type="text/css" href="css/popup.css">

View file

@ -1,7 +1,7 @@
<html>
<html data-theme="auto">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Multi-Account Containers</title>
<title>Firefox Multi-Account Containers</title>
<script type="text/javascript" src="./js/i18n.js"></script>
<link rel="stylesheet" href="./css/popup.css">
</head>
@ -44,7 +44,7 @@
<div class="panel onboarding onboarding-panel-6 hide" id="onboarding-panel-6">
<img class="onboarding-img" alt="" src="/img/Sync.svg" />
<h3 class="onboarding-title" data-i18n-message-id="onboarding-6-header"></h3>
<p data-i18n-message-id="onboarding-6-description"></p>
<p data-i18n-message-id="onboarding-6-description-2"></p>
<div class="half-button-wrapper">
<a href="#" id="no-sync" class="half-onboarding-button grey-button keyboard-nav" tabindex="0" data-i18n-message-id="notNow"></a>
<a href="#" id="start-sync-button" class="half-onboarding-button keyboard-nav" tabindex="0" data-i18n-message-id="startSyncing"></a>
@ -53,8 +53,8 @@
<div class="panel onboarding onboarding-panel-7 hide" id="onboarding-panel-7">
<img class="onboarding-img" alt="" src="/img/Account.svg" />
<h3 class="onboarding-title" data-i18n-message-id="onboarding-7-header"></h3>
<p data-i18n-message-id="onboarding-7-description"></p>
<h3 class="onboarding-title" data-i18n-message-id="onboarding-7-header-2"></h3>
<p data-i18n-message-id="onboarding-7-description-2"></p>
<div class="half-button-wrapper">
<a href="#" id="no-sign-in" class="half-onboarding-button grey-button keyboard-nav" tabindex="0" data-i18n-message-id="notNow"></a>
<a href="#" id="sign-in" class="half-onboarding-button keyboard-nav" tabindex="0" data-i18n-message-id="signIn"></a>
@ -62,11 +62,22 @@
</div>
<div class="panel onboarding onboarding-panel-8 hide" id="onboarding-panel-8">
<img class="onboarding-img" alt="" src="/img/moz-vpn-onboarding.svg" />
<h3 class="onboarding-title" data-i18n-message-id="proxyNowAvailable"></h3>
<p data-i18n-message-id="onboarding-8-description"></p>
<div class="half-button-wrapper">
<a href="#" id="onboarding-done-btn" class="half-onboarding-button keyboard-nav" tabindex="0" data-i18n-message-id="done"></a>
<div class="moz-vpn-onboarding-content">
<img class="onboarding-img" alt="" src="/img/moz-vpn-onboarding.svg" />
<h3 class="onboarding-title" data-i18n-message-id="proxyNowAvailable"></h3>
<p data-i18n-message-id="onboarding-8-description"></p>
</div>
<div id="moz-vpn-fw-onboarding-done" class="half-button-wrapper">
<a id="moz-vpn-fw-onboarding-done" href="#" class="half-onboarding-button keyboard-nav onboarding-done" tabindex="0" data-i18n-message-id="done"></a>
</div>
<div class="moz-vpn-permissions">
<div class="moz-vpn-permissions-copy">
<span data-i18n-message-id="mozillaVpnRequiresAdditionalPermissions"></span>
</div>
<div class="half-button-wrapper">
<a href="#" id="permissions-not-now" class="half-onboarding-button grey-button keyboard-nav onboarding-done" tabindex="0" data-i18n-message-id="notNow"></a>
<a href="#" id="onboarding-enable-permissions" class="half-onboarding-button keyboard-nav" tabindex="0" data-i18n-message-id="enable"></a>
</div>
</div>
</div>
@ -96,9 +107,10 @@
</div>
<div class="panel menu-panel container-panel hide" id="container-panel">
<h3 class="title">Multi-Account Containers</h3>
<span class="popup-notification-card"></span>
<h3 class="title">Firefox Multi-Account Containers</h3>
<a href="#" class="info-icon" id="info-icon" tabindex="10">
<img data-i18n-attribute-message-id="info" data-i18n-attribute="alt" alt="" ="info" src="/img/info.svg" / >
<img data-i18n-attribute-message-id="info" data-i18n-attribute="alt" alt="" src="/img/info.svg" / >
</a>
<hr>
<table class="menu">
@ -143,11 +155,22 @@
<div class="sub-header" data-i18n-message-id="containers"></div>
<h4 class="moz-vpn-logotype vpn-status-container-list display-none">Mozilla VPN
<span class="moz-vpn-connection-status-indicator container-list-status-icon">
<span class="tooltip"></span>
</span>
</h4>
</div>
<div class="scrollable identities-list">
<div class="searchbar">
<label for="search-terms"
class="hide-label"
data-i18n-message-id="filterInputLabel">
</label>
<input type="text"
id="search-terms"
name="search-terms"
placeholder="Search container name"
data-i18n-attribute="placeholder"
data-i18n-attribute-message-id="filterInputPlaceholder">
</div>
<table class="menu" id="identities-list">
<tr class="menu-item hover-highlight">
<td>
@ -169,24 +192,14 @@
</tr>
</table>
</div>
<div id="moz-vpn-tout" class="moz-vpn-content expanded">
<div class="flx-row button-wrapper">
<h4 class="moz-vpn-logo">Mozilla VPN</h4>
<button class="controller dismiss-moz-vpn-tout" tab-index="0"></button>
</div>
<div class="collapsible-content flx-col controller-collapsible-content">
<div class="flx-row flx-space-between">
<span class="moz-vpn-subtitle" data-i18n-message-id="protectYourContainers"></span>
</div>
<button id="moz-vpn-learn-more" class="moz-vpn-cta primary-cta" data-i18n-message-id="learnMore"></button>
</div>
</div>
<v-padding-hack-footer></v-padding-hack-footer> <!--presents last container from getting covered up by the 'manage containers button' when list is long-->
<v-padding-hack-footer></v-padding-hack-footer> <!--prevents last container from getting covered up by the 'manage containers button' when list is long-->
<div class="bottom-btn keyboard-nav controller" id="manage-containers-link" tabindex="0" data-i18n-message-id="manageContainers"></div>
</div>
<div class="hide panel menu-panel container-info-panel" id="container-info-panel" tabindex="-1">
<span class="popup-notification-card"></span>
<h3 class="title" id="container-info-title" data-i18n-attribute-message-id="personal"></h3>
<button class="btn-return arrow-left controller keyboard-nav-back" id="close-container-info-panel" tabindex="0"></button>
<hr>
@ -223,6 +236,14 @@
</span>
</td>
</tr>
<tr class="menu-item hover-highlight keyboard-nav" id="clear-container-storage" tabindex="0">
<td>
<img class="menu-icon clear-storage-icon" alt="" src="img/container-delete.svg" />
<span class="menu-text" id="clear-container-storage-info" data-i18n-message-id="clearContainerStorage"></span>
<span class="menu-arrow">
</span>
</td>
</tr>
</table>
<hr>
<div class="sub-header-wrapper">
@ -240,13 +261,14 @@
</table>
</div>
<v-padding-hack-footer></v-padding-hack-footer>
<div class="bottom-btn keyboard-nav hover-highlight" id="manage-container-link" tabindex="0" data-i18n-message-id="manageThisContainer"></div>
<div class="bottom-btn keyboard-nav hover-highlight controller" id="manage-container-link" tabindex="0" data-i18n-message-id="manageThisContainer"></div>
</div>
<div class="panel menu-panel container-picker-panel hide" id="container-picker-panel">
<span class="popup-notification-card"></span>
<h3 class="title" id="picker-title">
Multi-Account Containers
Firefox Multi-Account Containers
</h3>
<button class="btn-return arrow-left controller keyboard-nav-back" id="close-container-picker-panel" tabindex="0"></button>
<hr>
@ -269,6 +291,7 @@
</div>
<div class="panel menu-panel edit-container-panel hide" id="edit-container-panel">
<span class="popup-notification-card"></span>
<h3 class="title" id="container-edit-title" data-i18n-message-id="default"></h3>
<button class="btn-return arrow-left controller" id="close-container-edit-panel"></button>
<hr>
@ -288,7 +311,7 @@
<legend class="form-header" data-i18n-message-id="icon"></legend>
</fieldset>
<fieldset class="proxies"> <!---- PROXIES -->
<input type="text" class="proxies" name="container-proxy" id="edit-container-panel-proxy" maxlength="50" placeholder="type://host:port" hidden/>
<input type="text" class="proxies" name="container-proxy" id="edit-container-panel-proxy" placeholder="type://host:port" hidden/>
<input type="text" class="proxies" name="moz-proxy-enabled" id="moz-proxy-enabled" maxlength="5" hidden/>
<input type="text" class="proxies" name="country-code" id="country-code-input" maxlength="5" hidden/>
<input type="text" class="proxies" name="city-name" id="city-name-input" maxlength="5" hidden/>
@ -324,17 +347,18 @@
<span class="slider round"></span>
</label>
</div>
<button id="get-mozilla-vpn" class="moz-vpn-cta primary-cta" data-i18n-message-id="learnMore"></button>
<button id="get-mozilla-vpn" class="moz-vpn-cta primary-cta" data-i18n-message-id="getMozillaVpn"></button>
<button id="moz-vpn-current-server" class="controller">
<span class="current-country-flag"></span>
<span class="current-city-name"></span>
</button>
</div>
</moz-vpn-container-ui>
<button id="advanced-proxy-settings-btn" class="proxy-section advanced-proxy-settings-btn controller">
<button id="advanced-proxy-settings-btn" class="proxy-section advanced-proxy-settings-btn">
<span class="advanced-proxy-settings-btn-label" data-i18n-message-id="advancedProxySettings"></span>
<span id="advanced-proxy-address"></span>
</button>
<hr>
<button class="delete-container delete-btn alert-text" id="delete-container-button" data-i18n-message-id="deleteThisContainer"></button>
<!-- TODO get UX / CONTENT on how to message about unavailable proxies -->
@ -358,6 +382,7 @@
</div>
<div class="panel menu-panel edit-container-assignments hide" id="edit-container-assignments">
<span class="popup-notification-card"></span>
<h3 class="title" id="edit-assignments-title" data-i18n-message-id="default"></h3>
<button class="btn-return arrow-left controller" id="close-container-assignment-panel"></button>
<hr>
@ -383,12 +408,27 @@
<hr>
<div class="panel-content delete-container-confirm">
<h4 class="delete-container-confirm-title" data-i18n-message-id="removeThisContainer"></h4>
<p class="delete-warning" id="delete-container-tab-warning"></p>
<p class="delete-warning" data-i18n-message-id="removeThisContainerConfirmation"></p>
</div>
<div class="panel-footer">
<a href="#" class="button expanded secondary footer-button cancel-button" data-i18n-message-id="cancel" id="delete-container-cancel-link"></a>
<a href="#" class="button expanded primary footer-button" data-i18n-message-id="ok" id="delete-container-ok-link"></a>
<a href="#" class="button expanded confirmation-destructive-ok-btn footer-button alert-text" data-i18n-message-id="ok" id="delete-container-ok-link"></a>
</div>
</div>
<div class="hide panel clear-container-storage-panel" id="clear-container-storage-panel">
<h3 class="title" id="container-clear-storage-title" data-i18n-message-id="default">
</h3>
<button class="btn-return arrow-left controller" id="close-clear-container-storage-panel"></button>
<hr>
<div class="panel-content clear-container-storage-confirm">
<h4 class="clear-container-storage-confirm-title" data-i18n-message-id="clearContainerStoragePanelTitle"></h4>
<p class="clear-container-storage-warning" data-i18n-message-id="clearContainerStorageConfirmation"></p>
</div>
<div class="panel-footer">
<a href="#" class="button expanded secondary footer-button cancel-button" data-i18n-message-id="cancel" id="clear-container-storage-cancel-link"></a>
<a href="#" class="button expanded confirmation-destructive-ok-btn footer-button alert-text" data-i18n-message-id="ok" id="clear-container-storage-ok-link"></a>
</div>
</div>
@ -408,7 +448,7 @@
</template>
<template id="server-city-list-items">
<li>
<label class="server-city-list-item">
<label class="server-city-list-item" tabindex="0">
<input class="server-radio-btn" type="radio" data-country-code="" data-city-name="" checked=""/>
<div class="server-radio-control"></div>
<span class="server-city-name"></span>
@ -430,13 +470,17 @@
<form class="advanced-proxy-panel-content">
<label class="advanced-proxy-input-label" for="container-proxy" data-i18n-message-id="advancedProxySettings"></label>
<div class="advanced-proxy-input-wrapper">
<input id="edit-advanced-proxy-input" class="proxy-host primary-input" name="container-proxy" type="text" maxlength="50" placeholder="type://host:port" />
<input id="edit-advanced-proxy-input" class="proxy-host primary-input" name="container-proxy" type="text" placeholder="type://host:port" />
<button id="clear-advanced-proxy-input" class="controller" data-i18n-attribute="value" data-i18n-attribute-message-id="clearproxylabel"></button>
<span class="proxy-validity" data-i18n-message-id="invalidProxyAlert"></span>
</div>
<button id="submit-advanced-proxy" class="primary-cta apply-to-container" data-i18n-message-id="applyToContainer"></button>
<a id="advanced-proxy-settings-learn-more" href="" class="blue-link" data-i18n-message-id="learnMore"></a>
</form>
<div id="permissions-overlay" class="permissions-overlay" data-tab-group="proxy-disabled">
<p data-tab-group="proxy-disabled" data-i18n-message-id="additionalPermissionNeeded"></p>
<button id="enable-proxy-permissions" class="primary-cta" data-tab-group="proxy-disabled" data-i18n-message-id="enable"></button>
</div>
</div>
<script src="js/utils.js"></script>
<script src="js/popup.js"></script>

View file

@ -32,6 +32,10 @@ const buildDom = async ({background = {}, popup = {}}) => {
window.crypto = {
getRandomValues: arr => crypto.randomBytes(arr.length),
};
// By default, the mock contextMenus.remove() returns undefined;
// Let it return a Promise instead, so that .then() calls chained to
// it (in src/js/background/assignManager.js) do not fail.
window.browser.contextMenus.remove.resolves();
}
}
};

27
test/issues/1140.test.js Normal file
View file

@ -0,0 +1,27 @@
const { sinon, nextTick, buildBackgroundDom } = require("../common");
describe("#1140", () => {
beforeEach(async () => {
this.background = await buildBackgroundDom();
});
describe("removing containers", () => {
beforeEach(async () => {
this.background.browser.contextualIdentities.onRemoved.addListener = sinon.stub();
const [promise] = this.background.browser.runtime.onMessage.addListener.yield({
method: "deleteContainer",
message: {
userContextId: "1"
}
});
await promise;
await nextTick();
});
it("should remove the identitystate from storage as well", async () => {
this.background.browser.storage.local.remove.should.have.been.calledWith([
"identitiesState@@_firefox-container-1"
]);
});
});
});