MozillaVPN Integration
This commit is contained in:
parent
de80fe9050
commit
1c0f2d8c5c
19 changed files with 2656 additions and 394 deletions
|
@ -19,7 +19,9 @@ module.exports = {
|
|||
"OS": true,
|
||||
"ADDON_UNINSTALL": true,
|
||||
"ADDON_DISABLE": true,
|
||||
"proxifiedContainers": true
|
||||
"proxifiedContainers": true,
|
||||
"MozillaVPN": true,
|
||||
"MozillaVPN_Background": true
|
||||
},
|
||||
"plugins": [
|
||||
"promise",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
ignoreProperties:
|
||||
["inset-block-end", "inset-block-start"]
|
||||
}],
|
||||
"property-blacklist": [
|
||||
"property-disallowed-list": [
|
||||
"/(min[-]|max[-])height/",
|
||||
"/width/",
|
||||
"/top/",
|
||||
|
|
|
@ -44,33 +44,18 @@
|
|||
"onboarding-1-description": {
|
||||
"message": "Use containers to organize tasks, manage accounts, and keep your focus where you want it."
|
||||
},
|
||||
"onboarding-1-sec-header": {
|
||||
"message": "A simple and secure way to manage your online life"
|
||||
},
|
||||
"onboarding-1-sec-description": {
|
||||
"message" : "Use containers to organize tasks, manage accounts, and store sensitive data."
|
||||
},
|
||||
"onboarding-2-header": {
|
||||
"message": "Put containers to work for you."
|
||||
},
|
||||
"onboarding-2-description": {
|
||||
"message": "Features like color-coding and separate container tabs help you find things easily, focus your attention, and minimize distractions."
|
||||
},
|
||||
"onboarding-2-sec-description": {
|
||||
"message": "Color-coding helps you categorize your online life, find things easily, and minimize distractions."
|
||||
},
|
||||
"onboarding-3-header": {
|
||||
"message": "A place for everything, and everything in its place."
|
||||
},
|
||||
"onboarding-3-description": {
|
||||
"message": "Start with the containers we've created, or create your own."
|
||||
},
|
||||
"onboarding-3-sec-header": {
|
||||
"message": "Set boundaries for your browsing."
|
||||
},
|
||||
"onboarding-3-sec-description": {
|
||||
"message": "Cookies are stored within a container, so you can segment sensitive data and browsing history to stay organized and to limit the impact of online trackers."
|
||||
},
|
||||
"onboarding-4-header": {
|
||||
"message": "Always open sites in the containers you want."
|
||||
},
|
||||
|
@ -95,6 +80,9 @@
|
|||
"onboarding-7-description": {
|
||||
"message": "Click Sign In to confirm that your Firefox Account is active."
|
||||
},
|
||||
"onboarding-8-description": {
|
||||
"message": "This is a really exciting message about how per-container proxies are now supported and about how it's now really easy to do with Mozilla VPN..."
|
||||
},
|
||||
"oneHundredTabsHeader": {
|
||||
"message": "100 tabs!"
|
||||
},
|
||||
|
@ -266,5 +254,59 @@
|
|||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"chooseLocation": {
|
||||
"message": "Choose location"
|
||||
},
|
||||
"hide": {
|
||||
"message": "Hide"
|
||||
},
|
||||
"show": {
|
||||
"message": "Show"
|
||||
},
|
||||
"protectEachContainer": {
|
||||
"message": "Protect each container with Mozilla VPN"
|
||||
},
|
||||
"protectThisContainer": {
|
||||
"message": "Protect this container with Mozilla VPN"
|
||||
},
|
||||
"advancedProxySettings": {
|
||||
"message": "Advanced proxy settings"
|
||||
},
|
||||
"proxyInputLabel": {
|
||||
"message": "Enter custom proxy"
|
||||
},
|
||||
"useCustomLocation": {
|
||||
"message": "Use custom location for this container"
|
||||
},
|
||||
"clearproxylabel": {
|
||||
"message": "Clear proxy"
|
||||
},
|
||||
"moz-vpn-connected": {
|
||||
"message": "Mozilla VPN is on"
|
||||
},
|
||||
"moz-vpn-disconnected": {
|
||||
"message": "Mozilla VPN is off"
|
||||
},
|
||||
"invalidProxyAlert": {
|
||||
"message": "Please enter a valid proxy url"
|
||||
},
|
||||
"mozillaVpnMustBeOn": {
|
||||
"message": "Mozilla VPN app must be on to use this feature."
|
||||
},
|
||||
"learnMore": {
|
||||
"message": "Learn more"
|
||||
},
|
||||
"proxyNowAvailable": {
|
||||
"message": "Mozilla VPN and proxy integration is now available!"
|
||||
},
|
||||
"getMozillaVpn": {
|
||||
"message": "Get Mozilla VPN"
|
||||
},
|
||||
"integratewithmozillavpn": {
|
||||
"message": "Integrate your containers with Mozilla VPN"
|
||||
},
|
||||
"applyToThisContainer": {
|
||||
"message": "Apply to this container"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
main {
|
||||
background: url(/img/onboarding-4.png) no-repeat;
|
||||
background-position: -10px -15px;
|
||||
background-size: 300px;
|
||||
background-position: 200px 0;
|
||||
background-size: 120px;
|
||||
margin-inline-start: -350px;
|
||||
padding-inline-start: 350px;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ button .container-name,
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1300px) {
|
||||
@media only screen and (max-width: 900px) {
|
||||
main {
|
||||
background: none;
|
||||
}
|
||||
|
|
1571
src/css/popup.css
1571
src/css/popup.css
File diff suppressed because it is too large
Load diff
|
@ -186,12 +186,20 @@ window.assignManager = {
|
|||
|
||||
async handleProxifiedRequest(requestInfo) {
|
||||
// The following blocks potentially dangerous requests for privacy that come without a tabId
|
||||
if(requestInfo.tabId === -1)
|
||||
return Utils.getBogusProxy();
|
||||
|
||||
// Dupe of Utils.DEFAULT_PROXY, which was occasionally and unreliably
|
||||
// not being found on startup and causing significant UI grief.
|
||||
if(requestInfo.tabId === -1) {
|
||||
return {
|
||||
value: Object.freeze({type: "direct"}),
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
}
|
||||
|
||||
const tab = await browser.tabs.get(requestInfo.tabId);
|
||||
const proxy = await proxifiedContainers.retrieveFromBackground(tab.cookieStoreId);
|
||||
|
||||
return proxy;
|
||||
},
|
||||
|
||||
|
|
|
@ -41,9 +41,11 @@ const backgroundLogic = {
|
|||
|
||||
async deleteContainer(userContextId, removed = false) {
|
||||
await this._closeTabs(userContextId);
|
||||
|
||||
if (!removed) {
|
||||
await browser.contextualIdentities.remove(this.cookieStoreId(userContextId));
|
||||
}
|
||||
|
||||
assignManager.deleteContainer(userContextId);
|
||||
|
||||
// Now remove the identity->proxy association in proxifiedContainers also
|
||||
|
@ -59,18 +61,16 @@ 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);
|
||||
(identity.cookieStoreId, options.proxy);
|
||||
}).catch(() => {
|
||||
// Empty because this should never happen theoretically.
|
||||
});
|
||||
}
|
||||
|
||||
await donePromise;
|
||||
},
|
||||
|
||||
|
@ -160,7 +160,7 @@ const backgroundLogic = {
|
|||
}
|
||||
return await identityState.storageArea.set(cookieStoreId, containerState);
|
||||
} catch (error) {
|
||||
console.error(`No container: ${cookieStoreId}`);
|
||||
// console.error(`No container: ${cookieStoreId}`);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -376,4 +376,4 @@ const backgroundLogic = {
|
|||
};
|
||||
|
||||
|
||||
backgroundLogic.init();
|
||||
backgroundLogic.init();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const MAJOR_VERSIONS = ["2.3.0", "2.4.0", "6.2.0"];
|
||||
const MAJOR_VERSIONS = ["2.3.0", "2.4.0", "6.2.0", "8.0.0"];
|
||||
const badge = {
|
||||
async init() {
|
||||
const currentWindow = await browser.windows.getCurrent();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<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="mozillaVpnBackground.js"></script>
|
||||
<script type="text/javascript" src="assignManager.js"></script>
|
||||
<script type="text/javascript" src="badge.js"></script>
|
||||
<script type="text/javascript" src="identityState.js"></script>
|
||||
|
|
|
@ -83,18 +83,27 @@ const messageHandler = {
|
|||
break;
|
||||
case "reloadInContainer":
|
||||
response = assignManager.reloadPageInContainer(
|
||||
m.url,
|
||||
m.currentUserContextId,
|
||||
m.newUserContextId,
|
||||
m.url,
|
||||
m.currentUserContextId,
|
||||
m.newUserContextId,
|
||||
m.tabIndex,
|
||||
m.active,
|
||||
true
|
||||
);
|
||||
break;
|
||||
case "mozillaVpnAttemptPort":
|
||||
MozillaVPN_Background.maybeInitPort();
|
||||
break;
|
||||
case "getMozillaVpnServers":
|
||||
MozillaVPN_Background.postToApp("servers");
|
||||
break;
|
||||
case "getMozillaVpnStatus":
|
||||
response = MozillaVPN_Background.postToApp("status");
|
||||
break;
|
||||
case "assignAndReloadInContainer":
|
||||
tab = await assignManager.reloadPageInContainer(
|
||||
m.url,
|
||||
m.currentUserContextId,
|
||||
m.currentUserContextId,
|
||||
m.newUserContextId,
|
||||
m.tabIndex,
|
||||
m.active,
|
||||
|
|
84
src/js/background/mozillaVpnBackground.js
Normal file
84
src/js/background/mozillaVpnBackground.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
const MozillaVPN_Background = {
|
||||
MOZILLA_VPN_INSTALLED_KEY: "mozillaVpnInstalled",
|
||||
MOZILLA_VPN_CONNECTED_KEY: "mozillaVpnConnected",
|
||||
MOZILLA_VPN_COLLAPSE_EDIT_CONTAINER_TOUT_KEY: "mozillaVpnCollapseEditContainerTout",
|
||||
MOZILLA_VPN_HIDE_MAIN_TOUT_KEY: "mozillaVpnHideMainTout",
|
||||
MOZILLA_VPN_SERVERS_KEY: "mozillaVpnServers",
|
||||
|
||||
async maybeInitPort() {
|
||||
if (this.port && this.port.error === null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
/*
|
||||
Find a way to not spam the console when MozillaVPN client is not installed
|
||||
File at path ".../../MozillaVPN/..." is not executable.` thrown by resource://gre/modules/Subprocess.jsm:152`
|
||||
Which does is not caught by this try/catch
|
||||
*/
|
||||
this.port = await browser.runtime.connectNative("mozillavpn");
|
||||
await browser.storage.local.set({ [this.MOZILLA_VPN_INSTALLED_KEY]: true});
|
||||
this.port.onMessage.addListener(this.handleResponse);
|
||||
this.postToApp("status");
|
||||
this.postToApp("servers");
|
||||
|
||||
} catch(e) {
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_INSTALLED_KEY]: false });
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_CONNECTED_KEY]: false });
|
||||
}
|
||||
},
|
||||
|
||||
async init() {
|
||||
const mozillaVpnConnected = await browser.storage.local.get(this.MOZILLA_VPN_CONNECTED_KEY);
|
||||
if (typeof(mozillaVpnConnected) === "undefined") {
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_CONNECTED_KEY]: false });
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_INSTALLED_KEY]: false });
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_SERVERS_KEY]: [] });
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_HIDE_MAIN_TOUT_KEY]: false });
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_COLLAPSE_EDIT_CONTAINER_TOUT_KEY]: false });
|
||||
}
|
||||
this.maybeInitPort();
|
||||
},
|
||||
|
||||
|
||||
// Post messages to MozillaVPN client
|
||||
postToApp(message) {
|
||||
try {
|
||||
this.port.postMessage({t: message});
|
||||
} catch(e) {
|
||||
if (e.message === "Attempt to postMessage on disconnected port") {
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_INSTALLED_KEY]: false });
|
||||
browser.storage.local.set({ [this.MOZILLA_VPN_CONNECTED_KEY]: false });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Handle responses from MozillaVPN client
|
||||
async handleResponse(response) {
|
||||
|
||||
if (response.error && response.error === "vpn-client-down") {
|
||||
browser.storage.local.set({ [MozillaVPN_Background.MOZILLA_VPN_CONNECTED_KEY]: false });
|
||||
return;
|
||||
}
|
||||
if (response.servers) {
|
||||
const servers = response.servers.countries;
|
||||
browser.storage.local.set({ [MozillaVPN_Background.MOZILLA_VPN_SERVERS_KEY]: servers});
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.status && response.status.vpn) {
|
||||
browser.storage.local.set({ [MozillaVPN_Background.MOZILLA_VPN_INSTALLED_KEY]: true });
|
||||
|
||||
const status = response.status.vpn;
|
||||
|
||||
if (status === "StateOn") {
|
||||
browser.storage.local.set({ [MozillaVPN_Background.MOZILLA_VPN_CONNECTED_KEY]: true });
|
||||
}
|
||||
|
||||
if (status === "StateOff" || status === "StateDisconnecting") {
|
||||
browser.storage.local.set({ [MozillaVPN_Background.MOZILLA_VPN_CONNECTED_KEY]: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MozillaVPN_Background.init();
|
240
src/js/mozillaVpn.js
Normal file
240
src/js/mozillaVpn.js
Normal file
|
@ -0,0 +1,240 @@
|
|||
const MozillaVPN = {
|
||||
|
||||
async handleContainerList(identities) {
|
||||
const { mozillaVpnConnected } = await browser.storage.local.get("mozillaVpnConnected");
|
||||
const { mozillaVpnInstalled } = await browser.storage.local.get("mozillaVpnInstalled");
|
||||
this.handleStatusIndicatorsInContainerLists(mozillaVpnInstalled);
|
||||
|
||||
const proxies = await this.getProxies(identities);
|
||||
if (Object.keys(proxies).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const el of document.querySelectorAll("[data-cookie-store-id]")) {
|
||||
const cookieStoreId = el.dataset.cookieStoreId;
|
||||
const { proxy } = proxies[cookieStoreId];
|
||||
|
||||
if (typeof(proxy) !== "undefined") {
|
||||
const flag = el.querySelector(".flag-img");
|
||||
if (proxy.countryCode) {
|
||||
flag.src = `/img/flags/${proxy.countryCode.toUpperCase()}.png`;
|
||||
}
|
||||
if (typeof(proxy.mozProxyEnabled) === "undefined" && typeof(proxy.countryCode) !== "undefined") {
|
||||
flag.classList.add("proxy-disabled");
|
||||
}
|
||||
if (!mozillaVpnConnected && proxy.mozProxyEnabled) {
|
||||
flag.classList.add("proxy-unavailable");
|
||||
el.querySelector(".menu-item-name").dataset.mozProxyWarning = "proxy-unavailable";
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async setStatusIndicatorIcons(mozillaVpnInstalled) {
|
||||
const { mozillaVpnConnected } = await browser.storage.local.get("mozillaVpnConnected");
|
||||
|
||||
const statusIconEls = document.querySelectorAll(".moz-vpn-connection-status-indicator");
|
||||
|
||||
if (!mozillaVpnInstalled) {
|
||||
statusIconEls.forEach(el => {
|
||||
el.style.backgroundImage = "none";
|
||||
if (el.querySelector(".tooltip")) {
|
||||
el.querySelector(".tooltip").textContent = "";
|
||||
}
|
||||
el.textContent = "";
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const connectedIndicatorSrc = "url(./img/moz-vpn-connected.svg)";
|
||||
const disconnectedIndicatorSrc = "url(./img/moz-vpn-disconnected.svg)";
|
||||
|
||||
const connectionStatusStringId = mozillaVpnConnected ? "moz-vpn-connected" : "moz-vpn-disconnected";
|
||||
const connectionStatusLocalizedString = browser.i18n.getMessage(connectionStatusStringId);
|
||||
|
||||
statusIconEls.forEach(el => {
|
||||
el.style.backgroundImage = mozillaVpnConnected ? connectedIndicatorSrc : disconnectedIndicatorSrc;
|
||||
if (el.querySelector(".tooltip")) {
|
||||
el.querySelector(".tooltip").textContent = connectionStatusLocalizedString;
|
||||
} else {
|
||||
el.textContent = connectionStatusLocalizedString;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
async handleStatusIndicatorsInContainerLists(mozillaVpnInstalled) {
|
||||
const mozVpnLogotypes = document.querySelectorAll(".moz-vpn-logotype.vpn-status-container-list");
|
||||
|
||||
try {
|
||||
if (!mozillaVpnInstalled) {
|
||||
mozVpnLogotypes.forEach(el => {
|
||||
el.style.display = "none";
|
||||
});
|
||||
return;
|
||||
}
|
||||
mozVpnLogotypes.forEach(el => {
|
||||
el.style.display = "flex";
|
||||
el.classList.remove("display-none");
|
||||
});
|
||||
this.setStatusIndicatorIcons(mozillaVpnInstalled);
|
||||
} catch (e) {
|
||||
mozVpnLogotypes.forEach(el => {
|
||||
el.style.display = "none";
|
||||
});
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
handleMozillaCtaClick(buttonIdentifier) {
|
||||
browser.tabs.create({
|
||||
url: MozillaVPN.attachUtmParameters("https://www.mozilla.org/products/vpn", buttonIdentifier),
|
||||
});
|
||||
},
|
||||
|
||||
getRandomInteger(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
},
|
||||
|
||||
proxyIsDisabled(proxy) {
|
||||
return (
|
||||
// Mozilla VPN proxy is disabled, last location data is stored
|
||||
(proxy.mozProxyEnabled === undefined && proxy.countryCode !== undefined && proxy.cityName !== undefined) ||
|
||||
// Mozilla VPN proxy is enabled but Mozilla VPN is not connected
|
||||
proxy.mozProxyEnabled !== undefined
|
||||
);
|
||||
},
|
||||
|
||||
attachUtmParameters(baseUrl, utmContent) {
|
||||
const url = new URL(baseUrl);
|
||||
const utmParameters = {
|
||||
utm_source: "multi.account.containers",
|
||||
utm_medium: "mac-browser-addon",
|
||||
utm_content: utmContent,
|
||||
utm_campaign: "vpn-better-together",
|
||||
};
|
||||
|
||||
for (const param in utmParameters) {
|
||||
url.searchParams.append(param, utmParameters[param]);
|
||||
}
|
||||
return url.href;
|
||||
},
|
||||
|
||||
async getProxies(identities) {
|
||||
const { mozillaVpnInstalled } = await browser.storage.local.get("mozillaVpnInstalled");
|
||||
|
||||
const proxies = {};
|
||||
if (mozillaVpnInstalled) {
|
||||
for (const identity of identities) {
|
||||
try {
|
||||
const proxy = await proxifiedContainers.retrieve(identity.cookieStoreId);
|
||||
proxies[identity.cookieStoreId] = proxy;
|
||||
} catch (e) {
|
||||
proxies[identity.cookieStoreId] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
return proxies;
|
||||
},
|
||||
|
||||
getMozillaProxyInfoObj () {
|
||||
return {
|
||||
countryCode: undefined,
|
||||
cityName: undefined,
|
||||
mozProxyEnabled: undefined
|
||||
};
|
||||
},
|
||||
|
||||
async getProxyWarnings(proxyObj) {
|
||||
const { mozillaVpnConnected } = await browser.storage.local.get("mozillaVpnConnected");
|
||||
|
||||
if (!proxyObj) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const { proxy } = proxyObj;
|
||||
|
||||
if (typeof(proxy) === "undefined") {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (typeof(proxy.mozProxyEnabled) !== "undefined" && !mozillaVpnConnected) {
|
||||
return "proxy-unavailable";
|
||||
}
|
||||
},
|
||||
|
||||
async getFlag(proxyObj) {
|
||||
const { mozillaVpnConnected } = await browser.storage.local.get("mozillaVpnConnected");
|
||||
const { mozillaVpnInstalled } = await browser.storage.local.get("mozillaVpnInstalled");
|
||||
|
||||
const flag = {
|
||||
imgCode: "default",
|
||||
elemClasses: "display-none",
|
||||
imgAlt: "",
|
||||
};
|
||||
|
||||
if (!proxyObj) {
|
||||
return flag;
|
||||
}
|
||||
|
||||
const { proxy } = proxyObj;
|
||||
if (typeof(proxy) === "undefined" || !mozillaVpnInstalled) {
|
||||
return flag;
|
||||
}
|
||||
|
||||
if (mozillaVpnInstalled && typeof(proxy.cityName) !== "undefined") {
|
||||
flag.imgCode = proxy.countryCode.toUpperCase();
|
||||
flag.imgAlt = proxy.cityName;
|
||||
flag.elemClasses = typeof(proxy.mozProxyEnabled) === "undefined" || !mozillaVpnConnected ? "proxy-disabled" : "";
|
||||
}
|
||||
|
||||
return flag;
|
||||
},
|
||||
|
||||
getProxy(countryCode, cityName, mozProxyEnabled, mozillaVpnServers) {
|
||||
const selectedServerCountry = mozillaVpnServers.find(({code}) => code === countryCode);
|
||||
const selectedServerCity = selectedServerCountry.cities.find(({name}) => name === cityName);
|
||||
const proxyServer = this.pickServerBasedOnWeight(selectedServerCity.servers);
|
||||
return proxifiedContainers.parseProxy(
|
||||
this.makeProxyString(proxyServer.socksName),
|
||||
{
|
||||
countryCode: countryCode,
|
||||
cityName: cityName,
|
||||
mozProxyEnabled,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
makeProxyString(socksName) {
|
||||
return `socks://${socksName}.mullvad.net:1080`;
|
||||
},
|
||||
|
||||
async pickRandomServer() {
|
||||
const { mozillaVpnServers } = await browser.storage.local.get("mozillaVpnServers");
|
||||
const randomInteger = this.getRandomInteger(0, mozillaVpnServers.length - 1);
|
||||
const randomServerCountry = mozillaVpnServers[randomInteger];
|
||||
|
||||
return {
|
||||
randomServerCountryCode: randomServerCountry.code,
|
||||
randomServerCityName: randomServerCountry.cities[0].name,
|
||||
};
|
||||
|
||||
},
|
||||
|
||||
pickServerBasedOnWeight(serverList) {
|
||||
const filteredServerList = serverList.filter(server => typeof(server.socksName) !== "undefined" && server.socksName !== "");
|
||||
|
||||
const sumWeight = filteredServerList.reduce((sum, { weight }) => sum + weight, 0);
|
||||
let randomInteger = this.getRandomInteger(0, sumWeight);
|
||||
|
||||
let nextServer = {};
|
||||
for (const server of filteredServerList) {
|
||||
if (server.weight >= randomInteger) {
|
||||
return nextServer = server;
|
||||
}
|
||||
randomInteger = (randomInteger - server.weight);
|
||||
}
|
||||
return nextServer;
|
||||
}
|
||||
};
|
||||
|
||||
window.MozillaVPN = MozillaVPN;
|
|
@ -1,22 +1,23 @@
|
|||
async function init() {
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
const identities = await browser.contextualIdentities.query({});
|
||||
|
||||
identities.forEach(identity => {
|
||||
for (const identity of identities) {
|
||||
const tr = document.createElement("tr");
|
||||
tr.classList.add("menu-item", "hover-highlight");
|
||||
tr.setAttribute("data-cookie-store-id", identity.cookieStoreId);
|
||||
const td = document.createElement("td");
|
||||
|
||||
td.innerHTML = Utils.escaped`
|
||||
td.innerHTML = Utils.escaped`
|
||||
<div class="menu-icon">
|
||||
<div class="usercontext-icon"
|
||||
data-identity-icon="${identity.icon}"
|
||||
data-identity-color="${identity.color}">
|
||||
</div>
|
||||
</div>
|
||||
<span class="menu-text">${identity.name}</span>`;
|
||||
|
||||
<span class="menu-text">${identity.name}</span>
|
||||
<img alt="" class="page-action-flag flag-img" src="/img/flags/.png"/>
|
||||
`;
|
||||
|
||||
tr.appendChild(td);
|
||||
fragment.appendChild(tr);
|
||||
|
||||
|
@ -24,12 +25,13 @@ async function init() {
|
|||
Utils.alwaysOpenInContainer(identity);
|
||||
window.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const list = document.querySelector("#picker-identities-list");
|
||||
|
||||
list.innerHTML = "";
|
||||
list.appendChild(fragment);
|
||||
|
||||
MozillaVPN.handleContainerList(identities);
|
||||
}
|
||||
|
||||
init();
|
||||
|
|
772
src/js/popup.js
772
src/js/popup.js
File diff suppressed because it is too large
Load diff
|
@ -2,9 +2,13 @@
|
|||
proxifiedContainers = {
|
||||
|
||||
// Slightly modified version of 'retrieve' which returns a direct proxy whenever an error is met.
|
||||
retrieveFromBackground(cookieStoreId = null) {
|
||||
async retrieveFromBackground(cookieStoreId = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
proxifiedContainers.retrieve(cookieStoreId).then((success) => {
|
||||
// TODO consider better methods of handling containers with MozillaVPN proxy
|
||||
// configs when MozillaVPN is not connected. Currently we are only messaging this
|
||||
// in the main panel.
|
||||
// if (mozProxyIsEnabled && !mozillaVpnConnected) { something better here ? }
|
||||
resolve(success.proxy);
|
||||
}, function() {
|
||||
resolve(Utils.DEFAULT_PROXY);
|
||||
|
@ -31,7 +35,6 @@ proxifiedContainers = {
|
|||
// 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",
|
||||
|
@ -76,6 +79,7 @@ proxifiedContainers = {
|
|||
proxifiedContainersKey: proxifiedContainersStore
|
||||
});
|
||||
|
||||
|
||||
resolve(proxy);
|
||||
}
|
||||
|
||||
|
@ -110,13 +114,22 @@ proxifiedContainers = {
|
|||
},
|
||||
|
||||
//Parses a proxy description string of the format type://host[:port] or type://username:password@host[:port] (port is optional)
|
||||
parseProxy(proxy_str) {
|
||||
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.-]+)(\.([\w.-]+))+))(:(?<port>\d+))?/;
|
||||
if (proxyRegexp.test(proxy_str) !== true) {
|
||||
return false;
|
||||
}
|
||||
const matches = proxyRegexp.exec(proxy_str);
|
||||
return matches.groups;
|
||||
|
||||
if (mozillaVpnData && mozillaVpnData.mozProxyEnabled === undefined) {
|
||||
matches.groups.type = "direct";
|
||||
}
|
||||
|
||||
if (!mozillaVpnData) {
|
||||
mozillaVpnData = MozillaVPN.getMozillaProxyInfoObj();
|
||||
}
|
||||
|
||||
return {...matches.groups,...mozillaVpnData};
|
||||
},
|
||||
|
||||
// Deletes the proxy information object for a specified cookieStoreId [useful for cleaning]
|
||||
|
@ -126,9 +139,7 @@ proxifiedContainers = {
|
|||
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 {
|
||||
if (index !== -1) {
|
||||
proxifiedContainersStore.splice(index, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ const Utils = {
|
|||
assignedUserContextId,
|
||||
false
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
window.Utils = Utils;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Firefox Multi-Account Containers",
|
||||
"version": "7.4.0",
|
||||
"version": "8.0.0",
|
||||
"incognito": "not_allowed",
|
||||
"description": "__MSG_extensionDescription__",
|
||||
"icons": {
|
||||
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "@testpilot-containers",
|
||||
"id": "vpn@mozilla.org",
|
||||
"strict_min_version": "67.0"
|
||||
}
|
||||
},
|
||||
|
@ -24,6 +24,7 @@
|
|||
"history",
|
||||
"idle",
|
||||
"management",
|
||||
"nativeMessaging",
|
||||
"storage",
|
||||
"unlimitedStorage",
|
||||
"tabs",
|
||||
|
@ -34,6 +35,11 @@
|
|||
"optional_permissions": [
|
||||
"bookmarks"
|
||||
],
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "vpn@mozilla.org"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"_execute_browser_action": {
|
||||
"suggested_key": {
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/mozillaVpn.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/pageAction.js"></script>
|
||||
<script src="js/proxified-containers.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
196
src/popup.html
196
src/popup.html
|
@ -13,13 +13,6 @@
|
|||
<a href="#" class="onboarding-button onboarding-start-button keyboard-nav" tabindex="0" data-i18n-message-id="getStarted"></a>
|
||||
</div>
|
||||
|
||||
<div class="hide panel onboarding security-onboarding-panel-1">
|
||||
<img class="onboarding-img" alt="" src="/img/onboarding-1.png" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-1-sec-header"></h3>
|
||||
<p data-i18n-message-id="onboarding-1-sec-description"></p>
|
||||
<a href="#" class="onboarding-button onboarding-start-button keyboard-nav" tabindex="0" data-i18n-message-id="getStarted"></a>
|
||||
</div>
|
||||
|
||||
<div class="panel onboarding onboarding-panel-2 hide">
|
||||
<img class="onboarding-img" alt="" src="/img/onboarding-2.png" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-2-header"></h3>
|
||||
|
@ -27,13 +20,6 @@
|
|||
<a href="#" class="onboarding-button onboarding-next-button keyboard-nav" tabindex="0" data-i18n-message-id="next"></a>
|
||||
</div>
|
||||
|
||||
<div class="panel onboarding security-onboarding-panel-2 hide">
|
||||
<img class="onboarding-img" alt="" src="/img/onboarding-2.png" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-2-header"></h3>
|
||||
<p data-i18n-message-id="onboarding-2-sec-description"></p>
|
||||
<a href="#" class="onboarding-button onboarding-next-button keyboard-nav" tabindex="0" data-i18n-message-id="next"></a>
|
||||
</div>
|
||||
|
||||
<div class="panel onboarding onboarding-panel-3 hide">
|
||||
<img class="onboarding-img" alt="" src="/img/onboarding-3.png" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-3-header"></h3>
|
||||
|
@ -41,13 +27,6 @@
|
|||
<a href="#" class="onboarding-button onboarding-almost-done-button keyboard-nav" tabindex="0" data-i18n-message-id="next"></a>
|
||||
</div>
|
||||
|
||||
<div class="panel onboarding security-onboarding-panel-3 hide">
|
||||
<img class="onboarding-img" alt="" src="/img/onboarding-3-security.png" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-3-sec-header"></h3>
|
||||
<p data-i18n-message-id="onboarding-2-sec-description"></p>
|
||||
<a href="#" class="onboarding-button onboarding-almost-done-button keyboard-nav" tabindex="0" data-i18n-message-id="next"></a>
|
||||
</div>
|
||||
|
||||
<div class="panel onboarding onboarding-panel-4 hide" id="onboarding-panel-4">
|
||||
<img class="onboarding-img" alt="" src="/img/onboarding-4.png" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-4-header"></h3>
|
||||
|
@ -82,6 +61,15 @@
|
|||
</div>
|
||||
</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>
|
||||
</div>
|
||||
|
||||
<div class="panel achievement-panel hide" id="achievement-panel">
|
||||
<img class="onboarding-img" alt="" src="/img/onboarding-3.png" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="oneHundredTabsHeader"></h3>
|
||||
|
@ -110,7 +98,7 @@
|
|||
<div class="panel menu-panel container-panel hide" id="container-panel">
|
||||
<h3 class="title">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-thin-16.svg" / >
|
||||
<img data-i18n-attribute-message-id="info" data-i18n-attribute="alt" alt="" ="info" src="/img/info.svg" / >
|
||||
</a>
|
||||
<hr>
|
||||
<table class="menu">
|
||||
|
@ -132,9 +120,6 @@
|
|||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<table class="menu">
|
||||
<tr class="menu-item hover-highlight keyboard-nav" id="sort-containers-link" tabindex="0">
|
||||
<td>
|
||||
<img class="menu-icon" alt="" src="/img/sort-16_1.svg" />
|
||||
|
@ -154,7 +139,14 @@
|
|||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<div class="sub-header" data-i18n-message-id="containers"></div>
|
||||
<div class="sub-header-wrapper flx-row flx-space-between">
|
||||
<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">
|
||||
<table class="menu" id="identities-list">
|
||||
<tr class="menu-item hover-highlight">
|
||||
|
@ -177,13 +169,26 @@
|
|||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="bottom-btn keyboard-nav hover-highlight" id="manage-containers-link" tabindex="0" data-i18n-message-id="manageContainers"></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="integrateWithMozillaVpn"></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-->
|
||||
<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">
|
||||
<h3 class="title" id="container-info-title" data-i18n-attribute-message-id="personal"></h3>
|
||||
<button class="btn-return arrow-left keyboard-nav-back" id="close-container-info-panel" tabindex="0"></button>
|
||||
<button class="btn-return arrow-left controller keyboard-nav-back" id="close-container-info-panel" tabindex="0"></button>
|
||||
<hr>
|
||||
<table class="menu">
|
||||
<tr class="menu-item hover-highlight keyboard-nav" id="open-new-tab-in-info" tabindex="0">
|
||||
|
@ -220,18 +225,21 @@
|
|||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<div class="sub-header" data-i18n-message-id="openTabs"></div>
|
||||
<div class="sub-header-wrapper">
|
||||
<div class="sub-header" data-i18n-message-id="openTabs"></div>
|
||||
</div>
|
||||
<div class="scrollable">
|
||||
<table class="menu" id="container-info-table">
|
||||
<tr class="menu-item hover-highlight keyboard-nav" tabindex="0">
|
||||
<td>
|
||||
<div class="favicon"><img class="menu-icon" src="https://www.mozilla.org/favicon.ico" /></div>
|
||||
<span class="menu-text truncate-text">www.mozillllllllllllllllllllllllllllllllllllla.org</span>
|
||||
<img class="trash-button" src="/img/container-close-tab.svg" />
|
||||
<img class="trash-button" src="/img/close.svg" />
|
||||
</td>
|
||||
</tr>
|
||||
</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>
|
||||
|
||||
|
@ -240,7 +248,7 @@
|
|||
<h3 class="title" id="picker-title">
|
||||
Multi-Account Containers
|
||||
</h3>
|
||||
<button class="btn-return arrow-left keyboard-nav-back" id="close-container-picker-panel" tabindex="0"></button>
|
||||
<button class="btn-return arrow-left controller keyboard-nav-back" id="close-container-picker-panel" tabindex="0"></button>
|
||||
<hr>
|
||||
<div id="new-container-div"></div>
|
||||
<div class="scrollable identities-list">
|
||||
|
@ -262,39 +270,87 @@
|
|||
|
||||
<div class="panel menu-panel edit-container-panel hide" id="edit-container-panel">
|
||||
<h3 class="title" id="container-edit-title" data-i18n-message-id="default"></h3>
|
||||
<button class="btn-return arrow-left" id="close-container-edit-panel"></button>
|
||||
<button class="btn-return arrow-left controller" id="close-container-edit-panel"></button>
|
||||
<hr>
|
||||
<div class="scrollable edit-form">
|
||||
<div class="edit-form">
|
||||
<form id="edit-container-panel-form">
|
||||
<input type="hidden" name="container-id" id="edit-container-panel-usercontext-input" />
|
||||
<fieldset>
|
||||
<legend class="form-header" data-i18n-message-id="name"></legend>
|
||||
<v-padding-hack-4></v-padding-hack-4>
|
||||
<input type="text" name="container-name" id="edit-container-panel-name-input" class="edit-container-panel-name-input" maxlength="25"/>
|
||||
</fieldset>
|
||||
<legend class="form-header" data-i18n-message-id="color"></legend>
|
||||
<fieldset id="edit-container-panel-choose-color" class="radio-choice">
|
||||
<legend class="form-header" data-i18n-message-id="color"></legend>
|
||||
|
||||
</fieldset>
|
||||
<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 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="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/>
|
||||
</fieldset>
|
||||
</form>
|
||||
<div id="edit-container-options">
|
||||
<div class="options-header" data-i18n-message-id="options"></div>
|
||||
<div class="container-options">
|
||||
<input type="checkbox" class="site-isolation" id="site-isolation" name="site-isolation">
|
||||
<label for="site-isolation" class="options-label" data-i18n-message-id="limitToDesignatedSites"></label>
|
||||
<label class="switch">
|
||||
<input id="site-isolation" class="switch-input" name="site-isolation" type="checkbox">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="container-options options-label manage-assigned-sites-list" id="manage-assigned-sites-list" tabindex="0">
|
||||
</div>
|
||||
<button class="container-options blue-link" id="manage-assigned-sites-list" tabindex="0" data-i18n-message-id="manageSiteList"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="delete-container">
|
||||
<button class="delete-btn" id="delete-container-button" data-i18n-message-id="deleteThisContainer"></button>
|
||||
</div>
|
||||
<moz-vpn-container-ui class="moz-vpn-controller-content expanded">
|
||||
<div class="flx-row button-wrapper">
|
||||
<h4 class="moz-vpn-logotype">Mozilla VPN
|
||||
<span class="moz-vpn-connection-status-indicator"></span>
|
||||
</h4>
|
||||
<button class="expand-collapse blue-link" tab-index="0">
|
||||
<span data-i18n-message-id="hide" class="hide-label hide-show-label"></span>
|
||||
<span data-i18n-message-id="show" class="show-label hide-show-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="collapsible-content flx-col controller-collapsible-conten">
|
||||
<div class="flx-row flx-space-between add-bg-color">
|
||||
<span class="moz-vpn-subtitle"></span>
|
||||
<label class="switch">
|
||||
<input id="moz-vpn-switch" class="moz-vpn-switch switch-input" type="checkbox">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
<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">
|
||||
<span class="advanced-proxy-settings-btn-label" data-i18n-message-id="advancedProxySettings"></span>
|
||||
<span id="advanced-proxy-address"></span>
|
||||
</button>
|
||||
<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 -->
|
||||
<!-- Prevent users from opening containers where proxies are unavailable and which will result in timeouts -->
|
||||
<!-- Provide a way for users to disable Mozilla proxies if they cancel their subscription or somehow lose access -->
|
||||
|
||||
<!-- <div class="modal-warning">
|
||||
<div class="modal-content">
|
||||
<button id="close-proxy-warning" class="x-close modal-clickable">Close</button>
|
||||
<p>This container has been configured to use a Mozilla VPN proxy, but the Mozilla VPN app is off. To access the web via this container, turn Mozilla VPN on or disable the proxy for this container.</p>
|
||||
<button class="disable-proxy modal-clickable">Disable proxy for this container</button>
|
||||
<button id="close-modal" class="modal-clickable" class="disable-proxy">Close</button>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
|
||||
<div class="panel-footer">
|
||||
<a href="#" class="button expanded secondary footer-button cancel-button" id="create-container-cancel-link" data-i18n-message-id="cancel"></a>
|
||||
<a href="#" class="button expanded primary footer-button" id="create-container-ok-link" data-i18n-message-id="ok"></a>
|
||||
|
@ -303,7 +359,7 @@
|
|||
|
||||
<div class="panel menu-panel edit-container-assignments hide" id="edit-container-assignments">
|
||||
<h3 class="title" id="edit-assignments-title" data-i18n-message-id="default"></h3>
|
||||
<button class="btn-return arrow-left" id="close-container-assignment-panel"></button>
|
||||
<button class="btn-return arrow-left controller" id="close-container-assignment-panel"></button>
|
||||
<hr>
|
||||
<div class="scrollable edit-sites-assigned">
|
||||
<div class="sub-header" data-i18n-attribute-message-id="sitesAssignedToThisContainer"></div>
|
||||
|
@ -322,7 +378,8 @@
|
|||
<div class="hide panel delete-container-panel" id="delete-container-panel">
|
||||
<h3 class="title" id="container-delete-title" data-i18n-message-id="default">
|
||||
</h3>
|
||||
<button class="btn-return arrow-left" id="close-container-delete-panel"></button>
|
||||
|
||||
<button class="btn-return arrow-left controller" id="close-container-delete-panel"></button>
|
||||
<hr>
|
||||
<div class="panel-content delete-container-confirm">
|
||||
<h4 class="delete-container-confirm-title" data-i18n-message-id="removeThisContainer"></h4>
|
||||
|
@ -335,8 +392,55 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hide panel moz-vpn-server-list-panel" id="moz-vpn-server-list-panel">
|
||||
<h3 class="title proxy-panel-title" id="vpn-server-list-title" data-i18n-message-id="chooseLocation"></h3>
|
||||
<button class="btn-return arrow-left controller moz-vpn-return" id="moz-vpn-return"></button>
|
||||
<ul id="moz-vpn-server-list" class="moz-vpn-server-list">
|
||||
<template id="server-list-item">
|
||||
<li class="server-list-item" data-country-code="">
|
||||
<button class="flx-row server-city-list-visibility-btn controller">
|
||||
<div class="toggle"></div>
|
||||
<img class="server-country-flag" src="" alt="" />
|
||||
<p class="server-country-name"></p>
|
||||
</button>
|
||||
<ul class="server-city-list"></ul>
|
||||
</li>
|
||||
</template>
|
||||
<template id="server-city-list-items">
|
||||
<li>
|
||||
<label class="server-city-list-item">
|
||||
<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>
|
||||
</label>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="hide panel advanced-proxy-settings-panel" id="advanced-proxy-settings-panel">
|
||||
<h3 class="title proxy-panel-title" id="advanced-proxy-settings-title">
|
||||
<span data-i18n-message-id="advancedProxySettings"></span>
|
||||
<div class="flx-row">
|
||||
<p data-identity-color="" class="proxy-title-container-color"></p>
|
||||
<span id="proxy-title-container-name"></span>
|
||||
</div>
|
||||
</h3>
|
||||
<button class="btn-return arrow-left controller moz-vpn-return" id="advanced-proxy-settings-return"></button>
|
||||
<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" />
|
||||
<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="applyToThisContainer"></button>
|
||||
<a id="advanced-proxy-settings-learn-more" href="" class="blue-link" data-i18n-message-id="learnMore"></a>
|
||||
</form>
|
||||
</div>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/proxified-containers.js"></script>
|
||||
<script src="js/popup.js"></script>
|
||||
<script src="js/mozillaVpn.js"></script>
|
||||
<script src="js/proxified-containers.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Add table
Reference in a new issue