Merge pull request #1903 from mozilla/proxy-support
Updated per-container proxy support
This commit is contained in:
commit
98e3412d68
11 changed files with 321 additions and 59 deletions
|
@ -1,6 +1,6 @@
|
|||
module.exports = {
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
|
@ -18,7 +18,8 @@ module.exports = {
|
|||
"XPCOMUtils": true,
|
||||
"OS": true,
|
||||
"ADDON_UNINSTALL": true,
|
||||
"ADDON_DISABLE": true
|
||||
"ADDON_DISABLE": true,
|
||||
"proxifiedContainers": true
|
||||
},
|
||||
"plugins": [
|
||||
"promise",
|
||||
|
|
|
@ -586,7 +586,7 @@ manage things like container crud */
|
|||
}
|
||||
|
||||
.edit-container-panel fieldset:last-of-type {
|
||||
margin-block-end: 0;
|
||||
margin-block-start: 16px;
|
||||
}
|
||||
|
||||
.edit-container-panel input[type="text"] {
|
||||
|
@ -886,12 +886,11 @@ input {
|
|||
|
||||
.site-isolation {
|
||||
inset-block-end: auto;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.options-label {
|
||||
cursor: pointer;
|
||||
padding-inline-start: 25px;
|
||||
padding-inline-start: 4px;
|
||||
}
|
||||
|
||||
.manage-assigned-sites-list {
|
||||
|
|
|
@ -109,10 +109,10 @@ window.assignManager = {
|
|||
const siteConfigs = await this.area.get();
|
||||
for(const urlKey of Object.keys(siteConfigs)) {
|
||||
if (urlKey.includes("siteContainerMap@@_")) {
|
||||
// For some reason this is stored as string... lets check
|
||||
// For some reason this is stored as string... lets check
|
||||
// them both as that
|
||||
if (!!userContextId &&
|
||||
String(siteConfigs[urlKey].userContextId)
|
||||
if (!!userContextId &&
|
||||
String(siteConfigs[urlKey].userContextId)
|
||||
!== String(userContextId)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ window.assignManager = {
|
|||
},
|
||||
|
||||
/*
|
||||
* Looks for abandoned site assignments. If there is no identity with
|
||||
* Looks for abandoned site assignments. If there is no identity with
|
||||
* the site assignment's userContextId (cookieStoreId), then the assignment
|
||||
* is removed.
|
||||
*/
|
||||
|
@ -136,8 +136,8 @@ window.assignManager = {
|
|||
const macConfigs = await this.area.get();
|
||||
for(const configKey of Object.keys(macConfigs)) {
|
||||
if (configKey.includes("siteContainerMap@@_")) {
|
||||
const cookieStoreId =
|
||||
"firefox-container-" + macConfigs[configKey].userContextId;
|
||||
const cookieStoreId =
|
||||
"firefox-container-" + macConfigs[configKey].userContextId;
|
||||
const match = identitiesList.find(
|
||||
localIdentity => localIdentity.cookieStoreId === cookieStoreId
|
||||
);
|
||||
|
@ -146,7 +146,7 @@ window.assignManager = {
|
|||
continue;
|
||||
}
|
||||
const updatedSiteAssignment = macConfigs[configKey];
|
||||
updatedSiteAssignment.identityMacAddonUUID =
|
||||
updatedSiteAssignment.identityMacAddonUUID =
|
||||
await identityState.lookupMACaddonUUID(match.cookieStoreId);
|
||||
await this.set(
|
||||
configKey,
|
||||
|
@ -164,7 +164,7 @@ window.assignManager = {
|
|||
_neverAsk(m) {
|
||||
const pageUrl = m.pageUrl;
|
||||
if (m.neverAsk === true) {
|
||||
// If we have existing data and for some reason it hasn't been
|
||||
// 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) {
|
||||
|
@ -184,6 +184,17 @@ window.assignManager = {
|
|||
return true;
|
||||
},
|
||||
|
||||
async handleProxifiedRequest(requestInfo) {
|
||||
// The following blocks potentially dangerous requests for privacy that come without a tabId
|
||||
if(requestInfo.tabId === -1)
|
||||
return Utils.getBogusProxy();
|
||||
|
||||
const tab = await browser.tabs.get(requestInfo.tabId);
|
||||
const proxy = await proxifiedContainers.retrieveFromBackground(tab.cookieStoreId);
|
||||
|
||||
return proxy;
|
||||
},
|
||||
|
||||
// Before a request is handled by the browser we decide if we should
|
||||
// route through a different container
|
||||
async onBeforeRequest(options) {
|
||||
|
@ -212,7 +223,7 @@ window.assignManager = {
|
|||
const userContextId = this.getUserContextIdFromCookieStore(tab);
|
||||
|
||||
// https://github.com/mozilla/multi-account-containers/issues/847
|
||||
//
|
||||
//
|
||||
// Handle the case where this request's URL is not assigned to any particular
|
||||
// container. We must do the following check:
|
||||
//
|
||||
|
@ -228,7 +239,7 @@ window.assignManager = {
|
|||
// - the current tab's container is locked and only allows "www.google.com"
|
||||
// - the incoming request is for "www.amazon.com", which has no specific container assignment
|
||||
// - in this case, we must re-open "www.amazon.com" in a new tab in the default container
|
||||
const siteIsolatedReloadInDefault =
|
||||
const siteIsolatedReloadInDefault =
|
||||
await this._maybeSiteIsolatedReloadInDefault(siteSettings, tab);
|
||||
|
||||
if (!siteIsolatedReloadInDefault) {
|
||||
|
@ -246,7 +257,7 @@ window.assignManager = {
|
|||
const openTabId = removeTab ? tab.openerTabId : tab.id;
|
||||
|
||||
if (!this.canceledRequests[tab.id]) {
|
||||
// we decided to cancel the request at this point, register
|
||||
// we decided to cancel the request at this point, register
|
||||
// canceled request
|
||||
this.canceledRequests[tab.id] = {
|
||||
requestIds: {
|
||||
|
@ -313,7 +324,7 @@ window.assignManager = {
|
|||
- As the history won't span from one container to another it
|
||||
seems most sane to not try and reopen a tab on history.back()
|
||||
- When users open a new tab themselves we want to make sure we
|
||||
don't end up with three tabs as per:
|
||||
don't end up with three tabs as per:
|
||||
https://github.com/mozilla/testpilot-containers/issues/421
|
||||
If we are coming from an internal url that are used for the new
|
||||
tab page (NEW_TAB_PAGES), we can safely close as user is unlikely
|
||||
|
@ -348,7 +359,7 @@ window.assignManager = {
|
|||
// I.e. it will be opened in that container anyway, so we don't need to check if the
|
||||
// current tab's container is locked or not.
|
||||
if (siteSettings) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
//tab is alredy reopening in the default container
|
||||
|
@ -363,11 +374,14 @@ window.assignManager = {
|
|||
|
||||
init() {
|
||||
browser.contextMenus.onClicked.addListener((info, tab) => {
|
||||
info.bookmarkId ?
|
||||
this._onClickedBookmark(info) :
|
||||
info.bookmarkId ?
|
||||
this._onClickedBookmark(info) :
|
||||
this._onClickedHandler(info, tab);
|
||||
});
|
||||
|
||||
// Before anything happens we decide if the request should be proxified
|
||||
browser.proxy.onRequest.addListener(this.handleProxifiedRequest, {urls: ["<all_urls>"]});
|
||||
|
||||
// Before a request is handled by the browser we decide if we should
|
||||
// route through a different container
|
||||
this.canceledRequests = {};
|
||||
|
@ -479,7 +493,7 @@ window.assignManager = {
|
|||
async _onClickedBookmark(info) {
|
||||
|
||||
async function _getBookmarksFromInfo(info) {
|
||||
const [bookmarkTreeNode] =
|
||||
const [bookmarkTreeNode] =
|
||||
await browser.bookmarks.get(info.bookmarkId);
|
||||
if (bookmarkTreeNode.type === "folder") {
|
||||
return browser.bookmarks.getChildren(bookmarkTreeNode.id);
|
||||
|
@ -489,9 +503,9 @@ window.assignManager = {
|
|||
|
||||
const bookmarks = await _getBookmarksFromInfo(info);
|
||||
for (const bookmark of bookmarks) {
|
||||
// Some checks on the urls from
|
||||
// Some checks on the urls from
|
||||
// https://github.com/Rob--W/bookmark-container-tab/ thanks!
|
||||
if ( !/^(javascript|place):/i.test(bookmark.url) &&
|
||||
if ( !/^(javascript|place):/i.test(bookmark.url) &&
|
||||
bookmark.type !== "folder") {
|
||||
const openInReaderMode = bookmark.url.startsWith("about:reader");
|
||||
if(openInReaderMode) {
|
||||
|
@ -569,12 +583,12 @@ window.assignManager = {
|
|||
actionName = "removed from assigned sites list";
|
||||
|
||||
// remove site isolation if now empty
|
||||
await this._maybeRemoveSiteIsolation(userContextId);
|
||||
await this._maybeRemoveSiteIsolation(userContextId);
|
||||
}
|
||||
|
||||
if (tabId) {
|
||||
const tab = await browser.tabs.get(tabId);
|
||||
setTimeout(function(){
|
||||
setTimeout(function(){
|
||||
browser.tabs.sendMessage(tabId, {
|
||||
text: `Successfully ${actionName}`
|
||||
});
|
||||
|
@ -677,17 +691,17 @@ window.assignManager = {
|
|||
reloadPageInDefaultContainer(url, index, active, openerTabId) {
|
||||
// To create a new tab in the default container, it is easiest just to omit the
|
||||
// cookieStoreId entirely.
|
||||
//
|
||||
//
|
||||
// Unfortunately, if you create a new tab WITHOUT a cookieStoreId but WITH an openerTabId,
|
||||
// then the new tab automatically inherits the opener tab's cookieStoreId.
|
||||
// I.e. it opens in the wrong container!
|
||||
//
|
||||
//
|
||||
// So we have to explicitly pass in a cookieStoreId when creating the tab, since we
|
||||
// are specifying the openerTabId. There doesn't seem to be any way
|
||||
// to look up the default container's cookieStoreId programatically, so sadly
|
||||
// we have to hardcode it here as "firefox-default". This is potentially
|
||||
// not cross-browser compatible.
|
||||
//
|
||||
//
|
||||
// Note that we could have just omitted BOTH cookieStoreId and openerTabId. But the
|
||||
// drawback then is that if the user later closes the newly-created tab, the browser
|
||||
// does not automatically return to the original opener tab. To get this desired behaviour,
|
||||
|
|
|
@ -45,6 +45,10 @@ const backgroundLogic = {
|
|||
await browser.contextualIdentities.remove(this.cookieStoreId(userContextId));
|
||||
}
|
||||
assignManager.deleteContainer(userContextId);
|
||||
|
||||
// Now remove the identity->proxy association in proxifiedContainers also
|
||||
proxifiedContainers.delete(this.cookieStoreId(userContextId));
|
||||
|
||||
return {done: true, userContextId};
|
||||
},
|
||||
|
||||
|
@ -55,8 +59,17 @@ const backgroundLogic = {
|
|||
this.cookieStoreId(options.userContextId),
|
||||
options.params
|
||||
);
|
||||
|
||||
proxifiedContainers.set(this.cookieStoreId(options.userContextId), options.proxy);
|
||||
} else {
|
||||
donePromise = browser.contextualIdentities.create(options.params);
|
||||
|
||||
// We cannot yet access the new cookieStoreId via this.cookieStoreId(...), so we take this from the resolved promise
|
||||
donePromise.then((identity) => {
|
||||
proxifiedContainers.set(identity.cookieStoreId, options.proxy);
|
||||
}).catch(() => {
|
||||
// Empty because this should never happen theoretically.
|
||||
});
|
||||
}
|
||||
await donePromise;
|
||||
},
|
||||
|
@ -183,7 +196,7 @@ const backgroundLogic = {
|
|||
index: -1
|
||||
});
|
||||
} else {
|
||||
//As we get a blank tab here we will need to await the tabs creation
|
||||
// As we get a blank tab here we will need to await the tabs creation
|
||||
newWindowObj = await browser.windows.create({
|
||||
});
|
||||
hiddenDefaultTabToClose = true;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
"js/background/messageHandler.js",
|
||||
]
|
||||
-->
|
||||
<script type="text/javascript" src="../utils.js"></script>
|
||||
<script type="text/javascript" src="../proxified-containers.js"></script>
|
||||
<script type="text/javascript" src="backgroundLogic.js"></script>
|
||||
<script type="text/javascript" src="assignManager.js"></script>
|
||||
<script type="text/javascript" src="badge.js"></script>
|
||||
|
|
|
@ -307,6 +307,10 @@ const Logic = {
|
|||
return Utils.userContextId(identity.cookieStoreId);
|
||||
},
|
||||
|
||||
cookieStoreId(userContextId) {
|
||||
return `firefox-container-${userContextId}`;
|
||||
},
|
||||
|
||||
currentCookieStoreId() {
|
||||
const identity = Logic.currentIdentity();
|
||||
return identity.cookieStoreId;
|
||||
|
@ -1348,8 +1352,9 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
|||
params: {
|
||||
name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(),
|
||||
icon: formValues.get("container-icon") || DEFAULT_ICON,
|
||||
color: formValues.get("container-color") || DEFAULT_COLOR,
|
||||
}
|
||||
color: formValues.get("container-color") || DEFAULT_COLOR
|
||||
},
|
||||
proxy: proxifiedContainers.parseProxy(document.getElementById("edit-container-panel-proxy").value) || Utils.DEFAULT_PROXY
|
||||
}
|
||||
});
|
||||
await Logic.refreshIdentities();
|
||||
|
@ -1423,6 +1428,37 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
|||
iconInput.checked = iconInput.value === identity.icon;
|
||||
});
|
||||
|
||||
// Clear the proxy field before doing the retrieval requests below
|
||||
document.querySelector("#edit-container-panel-proxy").value = "";
|
||||
|
||||
const edit_proxy_dom = function(result) {
|
||||
const proxyInput = document.querySelector("#edit-container-panel-proxy");
|
||||
if (result.type === "direct" || typeof result.type === "undefined") {
|
||||
proxyInput.value = "";
|
||||
return;
|
||||
}
|
||||
proxyInput.value = `${result.type}://${result.host}:${result.port}`;
|
||||
};
|
||||
|
||||
proxifiedContainers.retrieve(identity.cookieStoreId).then((result) => {
|
||||
edit_proxy_dom(result.proxy);
|
||||
}, (error) => {
|
||||
if(error.error === "uninitialized" || error.error === "doesnotexist") {
|
||||
proxifiedContainers.set(identity.cookieStoreId, Utils.DEFAULT_PROXY, error.error === "uninitialized").then((result) => {
|
||||
edit_proxy_dom(result);
|
||||
}, (error) => {
|
||||
proxifiedContainers.report_proxy_error(error, "popup.js: unexpected set(...) error");
|
||||
}).catch((error) => {
|
||||
proxifiedContainers.report_proxy_error(error, "popup.js: unexpected set(...) exception");
|
||||
});
|
||||
}
|
||||
else {
|
||||
proxifiedContainers.report_proxy_error(error, "popup.js: unknown error");
|
||||
}
|
||||
}).catch((err) => {
|
||||
proxifiedContainers.report_proxy_error(err, "popup.js: unexpected retrieve error");
|
||||
});
|
||||
|
||||
const deleteButton = document.getElementById("delete-container-button");
|
||||
Utils.addEnterHandler(deleteButton, () => {
|
||||
Logic.showPanel(P_CONTAINER_DELETE, identity);
|
||||
|
|
147
src/js/proxified-containers.js
Normal file
147
src/js/proxified-containers.js
Normal file
|
@ -0,0 +1,147 @@
|
|||
// This object allows other scripts to access the list mapping containers to their proxies
|
||||
proxifiedContainers = {
|
||||
|
||||
// Slightly modified version of 'retrieve' which returns a direct proxy whenever an error is met.
|
||||
retrieveFromBackground(cookieStoreId = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
proxifiedContainers.retrieve(cookieStoreId).then((success) => {
|
||||
resolve(success.proxy);
|
||||
}, function() {
|
||||
resolve(Utils.DEFAULT_PROXY);
|
||||
}).catch((error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
report_proxy_error(error, identifier = null) {
|
||||
// Currently I print to console but this is inefficient
|
||||
const relevant_id_str = identifier === null ? "" : ` call supplied with id: ${identifier.toString()}`;
|
||||
browser.extension.getBackgroundPage().console.log(`proxifiedContainers error occured ${relevant_id_str}: ${JSON.stringify(error)}`);
|
||||
},
|
||||
|
||||
// Resolves to a proxy object which can be used in the return of the listener required for browser.proxy.onRequest.addListener
|
||||
retrieve(cookieStoreId = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.local.get("proxifiedContainersKey").then((results) => {
|
||||
// Steps to test:
|
||||
// 1. Is result empty? If so we must inform the caller to intialize proxifiedContainersStore with some initial info.
|
||||
// 2. Is cookieStoreId null? This means the caller probably wants everything currently in the proxifiedContainersStore object store
|
||||
// 3. If there doesn't exist an entry for the associated cookieStoreId, inform the caller of this
|
||||
// 4. Normal operation - if the cookieStoreId exists in the map, we can simply resolve with the correct proxy value
|
||||
|
||||
const results_array = results["proxifiedContainersKey"];
|
||||
|
||||
if (Object.getOwnPropertyNames(results).length === 0) {
|
||||
reject({
|
||||
error: "uninitialized",
|
||||
message: ""
|
||||
});
|
||||
} else if (cookieStoreId === null) {
|
||||
resolve(results_array);
|
||||
} else {
|
||||
const val = results_array.find(o => o.cookieStoreId === cookieStoreId);
|
||||
|
||||
if (typeof val !== "object" || val === null) {
|
||||
reject({
|
||||
error: "doesnotexist",
|
||||
message: ""
|
||||
});
|
||||
} else {
|
||||
resolve(val);
|
||||
}
|
||||
}
|
||||
|
||||
}, (error) => {
|
||||
reject({
|
||||
error: "internal",
|
||||
message: error
|
||||
});
|
||||
}).catch((error) => {
|
||||
proxifiedContainers.report_proxy_error(error, "proxified-containers.js: error 1");
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
set(cookieStoreId, proxy, initialize = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (initialize === true) {
|
||||
const proxifiedContainersStore = [];
|
||||
proxifiedContainersStore.push({
|
||||
cookieStoreId: cookieStoreId,
|
||||
proxy: proxy
|
||||
});
|
||||
|
||||
browser.storage.local.set({
|
||||
proxifiedContainersKey: proxifiedContainersStore
|
||||
});
|
||||
|
||||
resolve(proxy);
|
||||
}
|
||||
|
||||
// Assumes proxy is a properly formatted object
|
||||
proxifiedContainers.retrieve().then((proxifiedContainersStore) => {
|
||||
let index = proxifiedContainersStore.findIndex(i => i.cookieStoreId === cookieStoreId);
|
||||
|
||||
if (index === -1) {
|
||||
proxifiedContainersStore.push({
|
||||
cookieStoreId: cookieStoreId,
|
||||
proxy: proxy
|
||||
});
|
||||
index = proxifiedContainersStore.length - 1;
|
||||
} else {
|
||||
proxifiedContainersStore[index] = {
|
||||
cookieStoreId: cookieStoreId,
|
||||
proxy: proxy
|
||||
};
|
||||
}
|
||||
|
||||
browser.storage.local.set({
|
||||
proxifiedContainersKey: proxifiedContainersStore
|
||||
});
|
||||
|
||||
resolve(proxifiedContainersStore[index]);
|
||||
}, (errorObj) => {
|
||||
reject(errorObj);
|
||||
}).catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
//Parses a proxy description string of the format type://host[:port] or type://username:password@host[:port] (port is optional)
|
||||
parseProxy(proxy_str) {
|
||||
const proxyRegexp = /(?<type>(https?)|(socks4?)):\/\/(\b(?<username>\w+):(?<password>\w+)@)?(?<host>((?:\d{1,3}\.){3}\d{1,3}\b)|(\b([\w.-]+)(\.([\w.-]+))+))(:(?<port>\d+))?/;
|
||||
if (proxyRegexp.test(proxy_str) !== true) {
|
||||
return false;
|
||||
}
|
||||
const matches = proxyRegexp.exec(proxy_str);
|
||||
return matches.groups;
|
||||
},
|
||||
|
||||
// Deletes the proxy information object for a specified cookieStoreId [useful for cleaning]
|
||||
delete(cookieStoreId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Assumes proxy is a properly formatted object
|
||||
proxifiedContainers.retrieve().then((proxifiedContainersStore) => {
|
||||
const index = proxifiedContainersStore.findIndex(i => i.cookieStoreId === cookieStoreId);
|
||||
|
||||
if (index === -1) {
|
||||
reject({error: "not-found", message: `Container '${cookieStoreId}' not found.`});
|
||||
} else {
|
||||
proxifiedContainersStore.splice(index, 1);
|
||||
}
|
||||
|
||||
browser.storage.local.set({
|
||||
proxifiedContainersKey: proxifiedContainersStore
|
||||
});
|
||||
|
||||
resolve();
|
||||
}, (errorObj) => {
|
||||
reject(errorObj);
|
||||
}).catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,3 +1,5 @@
|
|||
/*global getBogusProxy */
|
||||
|
||||
const DEFAULT_FAVICON = "/img/blank-favicon.svg";
|
||||
|
||||
// TODO use export here instead of globals
|
||||
|
@ -19,6 +21,40 @@ const Utils = {
|
|||
imageElement.addEventListener("load", loadListener);
|
||||
return imageElement;
|
||||
},
|
||||
|
||||
// See comment in PR #313 - so far the (hacky) method being used to block proxies is to produce a sufficiently long random address
|
||||
getBogusProxy() {
|
||||
const bogusFailover = 1;
|
||||
const bogusType = "socks4";
|
||||
const bogusPort = 9999;
|
||||
const bogusUsername = "foo";
|
||||
if(typeof window.Utils.pregeneratedString !== "undefined")
|
||||
{
|
||||
return {type:bogusType, host:`w.${window.Utils.pregeneratedString}.coo`, port:bogusPort, username:bogusUsername, failoverTimeout:bogusFailover};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialize Utils.pregeneratedString
|
||||
window.Utils.pregeneratedString = "";
|
||||
|
||||
// We generate a cryptographically random string (of length specified in bogusLength), but we only do so once - thus negating any time delay caused
|
||||
const bogusLength = 8;
|
||||
const array = new Uint8Array(bogusLength);
|
||||
window.crypto.getRandomValues(array);
|
||||
for(let i = 0; i < bogusLength; i++)
|
||||
{
|
||||
const s = array[i].toString(16);
|
||||
if(s.length === 1)
|
||||
window.Utils.pregeneratedString += `0${s}`;
|
||||
else
|
||||
window.Utils.pregeneratedString += s;
|
||||
}
|
||||
|
||||
// The only issue with this approach is that if (for some unknown reason) pregeneratedString is not saved, it will result in an infinite loop - but better than a privacy leak!
|
||||
return getBogusProxy();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Escapes any occurances of &, ", <, > or / with XML entities.
|
||||
*
|
||||
|
@ -62,7 +98,7 @@ const Utils = {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
addEnterHandler(element, handler) {
|
||||
element.addEventListener("click", (e) => {
|
||||
handler(e);
|
||||
|
@ -82,7 +118,7 @@ const Utils = {
|
|||
handler(e);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
userContextId(cookieStoreId = "") {
|
||||
const userContextId = cookieStoreId.replace("firefox-container-", "");
|
||||
|
@ -102,10 +138,10 @@ const Utils = {
|
|||
async reloadInContainer(url, currentUserContextId, newUserContextId, tabIndex, active) {
|
||||
return await browser.runtime.sendMessage({
|
||||
method: "reloadInContainer",
|
||||
url,
|
||||
currentUserContextId,
|
||||
newUserContextId,
|
||||
tabIndex,
|
||||
url,
|
||||
currentUserContextId,
|
||||
newUserContextId,
|
||||
tabIndex,
|
||||
active
|
||||
});
|
||||
},
|
||||
|
@ -116,22 +152,30 @@ const Utils = {
|
|||
if (currentTab.cookieStoreId !== identity.cookieStoreId) {
|
||||
return await browser.runtime.sendMessage({
|
||||
method: "assignAndReloadInContainer",
|
||||
url: currentTab.url,
|
||||
currentUserContextId: false,
|
||||
newUserContextId: assignedUserContextId,
|
||||
tabIndex: currentTab.index +1,
|
||||
url: currentTab.url,
|
||||
currentUserContextId: false,
|
||||
newUserContextId: assignedUserContextId,
|
||||
tabIndex: currentTab.index +1,
|
||||
active:currentTab.active
|
||||
});
|
||||
}
|
||||
await Utils.setOrRemoveAssignment(
|
||||
currentTab.id,
|
||||
currentTab.url,
|
||||
assignedUserContextId,
|
||||
currentTab.id,
|
||||
currentTab.url,
|
||||
assignedUserContextId,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
window.Utils = Utils;
|
||||
|
||||
window.Utils = Utils;
|
||||
// The following creates a fake (but convincing) constant Utils.DEFAULT_PROXY
|
||||
Object.defineProperty(window.Utils, "DEFAULT_PROXY", {
|
||||
value: Object.freeze({type: "direct"}),
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
|
||||
// Setting configurable to false avoids deletion of Utils.DEFAULT_PROXY
|
||||
configurable: false
|
||||
});
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
"unlimitedStorage",
|
||||
"tabs",
|
||||
"webRequestBlocking",
|
||||
"webRequest"
|
||||
"webRequest",
|
||||
"proxy"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"bookmarks"
|
||||
|
|
|
@ -229,7 +229,7 @@
|
|||
<span class="menu-text truncate-text">www.mozillllllllllllllllllllllllllllllllllllla.org</span>
|
||||
<img class="trash-button" src="/img/container-close-tab.svg" />
|
||||
</td>
|
||||
</tr>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="bottom-btn keyboard-nav hover-highlight" id="manage-container-link" tabindex="0" data-i18n-message-id="manageThisContainer"></div>
|
||||
|
@ -277,6 +277,10 @@
|
|||
<fieldset id="edit-container-panel-choose-icon" class="radio-choice">
|
||||
<legend class="form-header" data-i18n-message-id="icon"></legend>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Proxy (Optional)</legend>
|
||||
<input type="text" name="container-proxy" id="edit-container-panel-proxy" maxlength="50" placeholder="type://host:port"/>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div id="edit-container-options">
|
||||
<div class="options-header" data-i18n-message-id="options"></div>
|
||||
|
@ -332,6 +336,7 @@
|
|||
</div>
|
||||
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/proxified-containers.js"></script>
|
||||
<script src="js/popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"rules": {
|
||||
"no-restricted-globals": ["error", "browser"]
|
||||
}
|
||||
}
|
||||
env: {
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"rules": {
|
||||
"no-restricted-globals": ["error", "browser"]
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue