summaryrefslogtreecommitdiff
path: root/data/extensions/https-everywhere@eff.org/pages
diff options
context:
space:
mode:
Diffstat (limited to 'data/extensions/https-everywhere@eff.org/pages')
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/cancel/index.html16
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/cancel/style.css20
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/cancel/ux.js21
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/index.html25
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/style.css40
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/ux.js44
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/devtools/index.html10
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/devtools/panel-ux.js131
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/devtools/panel.html38
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/devtools/ux.js17
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/options/index.html54
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/options/style.css147
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/options/ux.js258
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/popup/index.html84
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/popup/style.css128
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/popup/ux.js281
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/send-message.js7
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/switch-planner/index.html11
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/switch-planner/ux.js88
-rw-r--r--data/extensions/https-everywhere@eff.org/pages/translation.js8
20 files changed, 1428 insertions, 0 deletions
diff --git a/data/extensions/https-everywhere@eff.org/pages/cancel/index.html b/data/extensions/https-everywhere@eff.org/pages/cancel/index.html
new file mode 100644
index 0000000..94a4799
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/cancel/index.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <title>⚠ HTTPS Everywhere ⚠</title>
+ <style type="text/css">code{white-space: pre;}</style>
+ <link rel="stylesheet" href="style.css" type="text/css" />
+ </head>
+ <body>
+ <h1 id="https-everywhere"><img src="../../images/banner-red.png" alt="HTTPS Everywhere" /></h1>
+ <p data-i18n="cancel_he_blocking_explainer"></p>
+ <script src="../translation.js"></script>
+ <script src="ux.js"></script>
+ </body>
+</html>
diff --git a/data/extensions/https-everywhere@eff.org/pages/cancel/style.css b/data/extensions/https-everywhere@eff.org/pages/cancel/style.css
new file mode 100644
index 0000000..80ec5b3
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/cancel/style.css
@@ -0,0 +1,20 @@
+body{
+ margin-top: 6em;
+ left: 50%;
+ position: relative;
+ overflow: hidden;
+}
+
+h1 img{
+ position: relative;
+ left: -289px;
+}
+
+p{
+ width: 600px;
+ position: relative;
+ left: -300px;
+ font-size: 12pt;
+ font-family: sans-serif;
+ line-height: 150%;
+}
diff --git a/data/extensions/https-everywhere@eff.org/pages/cancel/ux.js b/data/extensions/https-everywhere@eff.org/pages/cancel/ux.js
new file mode 100644
index 0000000..d7475dd
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/cancel/ux.js
@@ -0,0 +1,21 @@
+"use strict";
+
+let observer;
+document.addEventListener("DOMContentLoaded", () => {
+ const explainer = document.querySelector("[data-i18n=cancel_he_blocking_explainer]");
+ observer = new MutationObserver(() => {replaceLink(explainer)});
+ if (explainer.innerText.length > 0) {
+ replaceLink(explainer);
+ } else {
+ observer.observe(explainer, {childList: true});
+ }
+});
+
+function replaceLink(explainer){
+ observer.disconnect();
+ const linkText = chrome.i18n.getMessage("cancel_he_blocking_network");
+ const link = document.createElement("a");
+ link.href = "https://en.wikipedia.org/wiki/Downgrade_attack";
+ link.innerText = linkText;
+ explainer.innerHTML = explainer.innerHTML.replace(linkText, link.outerHTML);
+}
diff --git a/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/index.html b/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/index.html
new file mode 100644
index 0000000..bd6f743
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/index.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title></title>
+ <link href="style.css" rel="stylesheet">
+ <script src="/external/codemirror/codemirror-5.31.0.min.js"></script>
+ <link href="/external/codemirror/codemirror-5.31.0.min.css" rel="stylesheet">
+ <script src="/external/codemirror/codemirror-5.31.0.xml.min.js"></script>
+ </head>
+ <body>
+ <div class="section-header"><span class="section-header-span">Debugging Rulesets</span></div>
+ <div class="section-explainer">
+ Enter ruleset XML below and click save when ready. These rulesets will be immediately activated upon saving, and will persist across restarts.<br>
+ <i>Warning</i>: This should only be used for debugging rulesets. This feature is not guaranteed to work reliably for regular usage.<br>
+ <i>Note</i>: Due to a bug in Chromium, it may be necessary to close the options ui before saving.
+ </div>
+ <div id="unsaved-text">There are unsaved changes! Be sure to save them for them to take effect.</div>
+ <textarea id="codemirror-textarea"></textarea>
+ <button type="button" id="save-button">Save</button>
+ <div id="saved-text">Saved!</div>
+ <script src="../send-message.js"></script>
+ <script src="ux.js"></script>
+ </body>
+</html>
diff --git a/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/style.css b/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/style.css
new file mode 100644
index 0000000..e424c70
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/style.css
@@ -0,0 +1,40 @@
+.cm-s-main{
+ width: 100%;
+ height: 500px;
+}
+
+.cm-s-saved{
+ border: 1px solid black;
+}
+
+.cm-s-unsaved{
+ border: 1px solid red;
+}
+
+.section-explainer{
+ margin-bottom: 5px;
+}
+
+.section-header{
+ margin-bottom: 10px;
+}
+
+.section-header-span{
+ border-bottom: 1px solid #ccc;
+ font-size: 15px;
+}
+
+#saved-text{
+ display: none;
+ color: green;
+ font-weight: bold;
+ margin: 30px;
+}
+
+#unsaved-text{
+ font-weight: bold;
+ margin: 10px 0px;
+ color: red;
+ visibility: hidden;
+ text-align: center;
+}
diff --git a/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/ux.js b/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/ux.js
new file mode 100644
index 0000000..be6c8b5
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/debugging-rulesets/ux.js
@@ -0,0 +1,44 @@
+/* global sendMessage, CodeMirror */
+
+"use strict";
+
+const savedTextElement = document.getElementById("saved-text");
+const unsavedTextElement = document.getElementById("unsaved-text");
+const savedTitle = "Debugging Rulesets";
+const unsavedTitle = "* Debugging Rulesets";
+
+document.title = savedTitle;
+
+const cm = CodeMirror.fromTextArea(
+ document.getElementById("codemirror-textarea"),
+ {
+ mode: "xml",
+ theme: "default main saved"
+ }
+);
+
+let valueHasChanged = false;
+sendMessage("get_option", { debugging_rulesets: "" }, item => {
+ cm.setValue(item.debugging_rulesets);
+ cm.on("change", cm => {
+ if (!(valueHasChanged)) {
+ valueHasChanged = true;
+ document.title = unsavedTitle;
+ cm.setOption("theme", "default main unsaved");
+ unsavedTextElement.style.visibility = "visible";
+ }
+ });
+});
+
+document.getElementById("save-button").addEventListener("click", e => {
+ e.preventDefault();
+ sendMessage("set_option", { debugging_rulesets: cm.getValue() }, () => {
+ savedTextElement.style.display = "block";
+ setTimeout(() => { savedTextElement.style.display = "none" }, 1000);
+
+ valueHasChanged = false;
+ document.title = savedTitle;
+ cm.setOption("theme", "default main saved");
+ unsavedTextElement.style.visibility = "hidden";
+ });
+});
diff --git a/data/extensions/https-everywhere@eff.org/pages/devtools/index.html b/data/extensions/https-everywhere@eff.org/pages/devtools/index.html
new file mode 100644
index 0000000..02711dc
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/devtools/index.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title></title>
+ <script src="../send-message.js"></script>
+ <script src="ux.js"></script>
+ </head>
+ <body></body>
+</html>
diff --git a/data/extensions/https-everywhere@eff.org/pages/devtools/panel-ux.js b/data/extensions/https-everywhere@eff.org/pages/devtools/panel-ux.js
new file mode 100644
index 0000000..2cd6a56
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/devtools/panel-ux.js
@@ -0,0 +1,131 @@
+"use strict";
+
+function e(id) {
+ return document.getElementById(id);
+}
+
+/**
+ * Send message to main extension for HTML to display
+ * @param type: enable/disable
+ */
+function sendMessage(type) {
+ chrome.runtime.sendMessage({
+ type: type,
+ tabId: chrome.devtools.inspectedWindow.tabId,
+ });
+}
+
+/**
+ * Turn on the Switch Planner recording mode, and hide the long description.
+ */
+function enableSwitchPlanner() {
+ sendMessage("enable");
+ e("SwitchPlannerDescription").style.display = "none";
+ e("SwitchPlannerDetails").style.display = "block";
+ // Hack: Fetch and display summary information from background page
+ // once per second.
+ setInterval(display, 1000);
+ chrome.devtools.inspectedWindow.reload();
+}
+
+/**
+ * Disable the switch planner and reload, so any state is forgotten and
+ * the long description is restored.
+ */
+function disableSwitchPlanner() {
+ sendMessage("disable");
+ document.location.reload();
+}
+
+/**
+ * Fetch summary HTML of the planner results from the background page for
+ * display in the devtools panel.
+ */
+function display() {
+ chrome.runtime.sendMessage({
+ type: "getHosts",
+ tabId: chrome.devtools.inspectedWindow.tabId,
+ }, function(response) {
+ var switch_planner_details = e("SwitchPlannerDetails");
+ while (switch_planner_details.firstChild) {
+ switch_planner_details.removeChild(switch_planner_details.firstChild);
+ }
+
+ var nrw_text_div = document.createElement("div");
+ nrw_text_div.innerText = "Unrewritten HTTP resources loaded from this tab (enable HTTPS on these domains and add them to HTTPS Everywhere):"
+ var nrw_div = switchPlannerSmallHtmlSection(response.nrw);
+ var rw_text_div = document.createElement("div");
+ rw_text_div.style.marginTop = "20px";
+ rw_text_div.innerText = "Resources rewritten successfully from this tab (update these in your source code):"
+ var rw_div = switchPlannerSmallHtmlSection(response.rw);
+
+ switch_planner_details.appendChild(nrw_text_div);
+ switch_planner_details.appendChild(nrw_div);
+ switch_planner_details.appendChild(rw_text_div);
+ switch_planner_details.appendChild(rw_div);
+
+ e("SwitchPlannerResults").style.display = "block";
+ });
+}
+
+/**
+* Format the switch planner output for presentation to a user.
+* */
+function switchPlannerSmallHtmlSection(asset_host_list) {
+ var wrapper_div = document.createElement("div");
+ if (asset_host_list.length == 0) {
+ wrapper_div.style.fontWeight = "bold";
+ wrapper_div.innerText = "none";
+ return wrapper_div;
+ }
+
+ for (var i = asset_host_list.length - 1; i >= 0; i--) {
+ var host = asset_host_list[i][3];
+ var activeCount = asset_host_list[i][1];
+ var passiveCount = asset_host_list[i][2];
+
+ var div = document.createElement("div");
+ var b = document.createElement("b");
+ b.innerText = host;
+ div.appendChild(b);
+
+ var text_arr = [];
+ if (activeCount > 0) {
+ text_arr.push(activeCount + " active");
+ }
+ if (passiveCount > 0) {
+ text_arr.push(passiveCount + " passive");
+ }
+ div.appendChild(document.createTextNode(": " + text_arr.join(', ')));
+
+ wrapper_div.appendChild(div);
+ }
+ return wrapper_div;
+}
+
+window.onload = function() {
+ // Open a connection to the background page. Right now this is only used
+ // by the background page so it knows when the devtools pane has closed.
+ // We don't receive messages from the background page currently, though that
+ // may be a future improvement. Sending messages to the background page doesn't
+ // require an existing connection.
+ chrome.runtime.connect({ name: "devtools-page" });
+
+ var checkbox = e("SwitchPlannerCheckbox");
+ checkbox.addEventListener("change", function() {
+ if (checkbox.checked) {
+ enableSwitchPlanner();
+ } else {
+ disableSwitchPlanner();
+ }
+ });
+
+ e("SwitchPlannerDetailsLink").addEventListener("click", function() {
+ window.open("/pages/switch-planner/index.html?tab=" + chrome.devtools.inspectedWindow.tabId);
+ });
+ // Since this is rendered in a devtools console, we have to make clicks on the
+ // link open a new window.
+ e("MixedContentLink").addEventListener("click", function(e) {
+ window.open(e.target.href);
+ });
+};
diff --git a/data/extensions/https-everywhere@eff.org/pages/devtools/panel.html b/data/extensions/https-everywhere@eff.org/pages/devtools/panel.html
new file mode 100644
index 0000000..f5f6859
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/devtools/panel.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title></title>
+ <style>
+ html {
+ background: #fff;
+ color: #000;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="SwitchPlanner">
+ <input type="checkbox" id="SwitchPlannerCheckbox">
+ <label for="SwitchPlannerCheckbox">Enable HTTPS Switch Planner mode (reloads page).</label>
+ <br>
+ <div id="SwitchPlannerDescription">
+ <p>Switch Planner mode helps prepare for your site's switch to HTTPS by generating a report of external HTTP
+ resources that might not yet be available on HTTPS.</p>
+ <p>After enabling, navigate around your site and try to exercise all functionality in order to get a
+ comprehensive list of external resources.</p>
+ <p>For each group of resources listed as "Unrewritten," find out whether they are available on HTTPS. If so:
+ add a rule to HTTPS Everywhere! If not: try to make them available over HTTPS or use a different resource or
+ provider. Otherwise your site will generate <a id="MixedContentLink"
+ href="https://developer.mozilla.org/en-US/docs/Security/MixedContent#Mixed_passive.2Fdisplay_content">Mixed
+ Content</a> (passive or active) errors when you turn on HTTPS.</p>
+ <p>For most accurate results, disable ad blockers before using. Closing this panel will deactivate Switch
+ Planner mode and clear stored data.</p>
+ </div>
+ <div id="SwitchPlannerResults" style="display: none">
+ <div id="SwitchPlannerDetails"></div>
+ <a id="SwitchPlannerDetailsLink" href="javascript:void 0">details</a>
+ </div>
+ </div>
+ <script src="panel-ux.js"></script>
+ </body>
+</html>
diff --git a/data/extensions/https-everywhere@eff.org/pages/devtools/ux.js b/data/extensions/https-everywhere@eff.org/pages/devtools/ux.js
new file mode 100644
index 0000000..8244cbf
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/devtools/ux.js
@@ -0,0 +1,17 @@
+/* global sendMessage */
+
+"use strict";
+
+const defaultOptions = {
+ showDevtoolsTab: true
+};
+
+sendMessage("get_option", defaultOptions, item => {
+ if (item.showDevtoolsTab) {
+ chrome.devtools.panels.create("HTTPS Everywhere",
+ "/images/icons/icon-active-38.png",
+ "/pages/devtools/panel.html",
+ function() { }
+ );
+ }
+});
diff --git a/data/extensions/https-everywhere@eff.org/pages/options/index.html b/data/extensions/https-everywhere@eff.org/pages/options/index.html
new file mode 100644
index 0000000..d72d279
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/options/index.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title></title>
+ <link href="style.css" rel="stylesheet">
+ </head>
+ <body>
+ <span class="section-header-span active" data-show="general-settings-wrapper" data-i18n="options_generalSettings"></span>
+ <span class="section-header-span inactive" data-show="advanced-settings-wrapper" data-i18n="options_advancedSettings"></span>
+ <span class="section-header-span inactive" data-show="update-channels-wrapper" data-i18n="options_updateChannels"></span>
+
+ <div class="section-wrapper" id="general-settings-wrapper">
+ <div id="counter-wrapper" class="settings-wrapper">
+ <input type="checkbox" id="showCounter">
+ <label for="showCounter" data-i18n="menu_showCounter"></label>
+ </div>
+ <div id="update-wrapper" class="settings-wrapper">
+ <input type="checkbox" id="autoUpdateRulesets">
+ <label for="autoUpdateRulesets" data-i18n="options_autoUpdateRulesets"></label>
+ </div>
+ </div>
+
+ <div class="section-wrapper" id="advanced-settings-wrapper">
+ <div id="mixed-rulesets-wrapper" class="settings-wrapper">
+ <input type="checkbox" id="enableMixedRulesets">
+ <label for="enableMixedRulesets" data-i18n="options_enableMixedRulesets"></label>
+ </div>
+ <div id="show-devtools-tab-wrapper" class="settings-wrapper">
+ <input type="checkbox" id="showDevtoolsTab">
+ <label for="showDevtoolsTab" data-i18n="options_showDevtoolsTab"></label>
+ </div>
+ </div>
+
+ <div class="section-wrapper" id="update-channels-wrapper">
+ <div id="update-channels-error">
+ <span id="update-channels-error-text"></span>
+ <img id="update-channels-error-hide" src="/images/remove.png">
+ </div>
+ <div id="update-channels-warning" data-i18n="options_updateChannelsWarning"></div>
+ <div id="update-channels-last-checked"></div>
+ <div class="clearer"></div>
+ <div id="update-channels-list"></div>
+ <div id="add-update-channel-wrapper">
+ <button id="add-update-channel" data-i18n="options_addUpdateChannel"></button>
+ <input type="text" id="update-channel-name" />
+ </div>
+ </div>
+
+ <script src="ux.js"></script>
+ <script src="../translation.js"></script>
+ <script src="../send-message.js"></script>
+ </body>
+</html>
diff --git a/data/extensions/https-everywhere@eff.org/pages/options/style.css b/data/extensions/https-everywhere@eff.org/pages/options/style.css
new file mode 100644
index 0000000..0e7b545
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/options/style.css
@@ -0,0 +1,147 @@
+body{
+ min-width: 500px;
+ display: block;
+}
+
+.settings-wrapper{
+ margin: 10px 0 0 0;
+}
+
+.settings-wrapper#update-wrapper{
+ margin-bottom: 20px;
+}
+
+.settings-wrapper#show-devtools-tab-wrapper{
+ margin-bottom: 20px;
+}
+
+.section-header{
+ margin-bottom: 10px;
+}
+
+#import{
+ margin-bottom: 10px;
+ float: right;
+}
+
+#import-confirmed{
+ display: none;
+}
+
+.section-header-span{
+ font-size: 15px;
+ border: 0px;
+ border-radius: 13px;
+ padding: 8px;
+ margin-right: 10px;
+ display: inline-block;
+}
+
+.section-header-span.active{
+ background-color: #66ccff;
+}
+
+.section-header-span.inactive{
+ background-color: #ddd;
+}
+
+.update-channel{
+ margin-top: 30px;
+ margin-bottom: 30px;
+ border: 1px solid grey;
+ border-radius: 20px;
+ width: 498px;
+}
+
+.update-channel-name{
+ font-weight: bold;
+ font-size: 14px;
+ margin: 10px;
+}
+
+.update-channel-column-left {
+ width: 89px;
+ float: left;
+ font-size: 13px;
+ text-align: right;
+ margin-right: 10px;
+ min-height: 1px;
+}
+
+.update-channel-column-right {
+ float: left;
+ width: 380px;
+}
+
+textarea.update-channel-jwk {
+ width: 380px;
+ height: 250px;
+}
+
+input.update-channel-path-prefix {
+ width: 367px;
+}
+
+.update-channel-column-right button {
+ float: right;
+ margin: 10px;
+ border-radius: 7px;
+}
+
+button#add-update-channel{
+ float: right;
+ margin: 0px 10px 10px 10px;
+ border-radius: 7px;
+}
+
+input#update-channel-name{
+ float: right;
+}
+
+.clearer{
+ clear: both;
+}
+
+.update-channel-last-updated {
+ float: right;
+ font-weight: lighter;
+ font-size: 10px;
+}
+
+div#update-channels-error, div#update-channels-warning {
+ margin-top: 20px;
+ font-weight: bold;
+ padding: 10px;
+ border-radius: 10px;
+}
+
+div#update-channels-error {
+ background-color: #CC3333;
+ display: none;
+ color: white;
+}
+
+div#update-channels-warning {
+ background-color: #FFCC00;
+ font-color: black;
+}
+
+#update-channels-error-text{
+ display: inline-block;
+ width: 460px;
+}
+
+img#update-channels-error-hide {
+ float: right;
+}
+
+div#update-channels-last-checked {
+ margin-top: 10px;
+ float: right;
+ font-weight: bold;
+ font-size: 10px;
+}
+
+#update-channels-wrapper{
+ width: 500px;
+}
diff --git a/data/extensions/https-everywhere@eff.org/pages/options/ux.js b/data/extensions/https-everywhere@eff.org/pages/options/ux.js
new file mode 100644
index 0000000..7a4306c
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/options/ux.js
@@ -0,0 +1,258 @@
+/* global sendMessage */
+
+"use strict";
+
+document.addEventListener("DOMContentLoaded", () => {
+
+ const showCounter = document.getElementById("showCounter");
+ const autoUpdateRulesets = document.getElementById("autoUpdateRulesets");
+ const enableMixedRulesets = document.getElementById("enableMixedRulesets");
+ const showDevtoolsTab = document.getElementById("showDevtoolsTab");
+
+ const defaultOptions = {
+ showCounter: true,
+ autoUpdateRulesets: false,
+ enableMixedRulesets: false,
+ showDevtoolsTab: true
+ };
+
+ sendMessage("get_option", defaultOptions, item => {
+ showCounter.checked = item.showCounter;
+ autoUpdateRulesets.checked = item.autoUpdateRulesets;
+ enableMixedRulesets.checked = item.enableMixedRulesets;
+ showDevtoolsTab.checked = item.showDevtoolsTab;
+
+ showCounter.addEventListener("change", () => {
+ sendMessage("set_option", { showCounter: showCounter.checked });
+ });
+
+ autoUpdateRulesets.addEventListener("change", () => {
+ sendMessage("set_option", { autoUpdateRulesets: autoUpdateRulesets.checked });
+ });
+
+ enableMixedRulesets.addEventListener("change", () => {
+ sendMessage("set_option", { enableMixedRulesets: enableMixedRulesets.checked });
+ });
+
+ showDevtoolsTab.addEventListener("change", () => {
+ sendMessage("set_option", { showDevtoolsTab: showDevtoolsTab.checked });
+ });
+ });
+
+ function onlyShowSection(sectionId){
+ document.querySelectorAll('.section-wrapper').forEach(sw => {
+ sw.style.display = "none";
+ });
+ document.getElementById(sectionId).style.display = "block";
+ }
+ onlyShowSection('general-settings-wrapper');
+
+ document.querySelectorAll('.section-header-span').forEach(shs => {
+ shs.addEventListener("click", () => {
+ document.querySelectorAll('.section-header-span').forEach(shs => {
+ shs.classList.remove("active");
+ shs.classList.add("inactive");
+ });
+ shs.classList.remove("inactive");
+ shs.classList.add("active");
+ onlyShowSection(shs.dataset.show);
+ });
+ });
+
+ function create_update_channel_element(update_channel, last_updated, pinned){
+ let ruleset_version_string;
+
+ if(last_updated){
+ const ruleset_date = new Date(last_updated * 1000);
+ ruleset_version_string = ruleset_date.getUTCFullYear() + "." + (ruleset_date.getUTCMonth() + 1) + "." + ruleset_date.getUTCDate();
+ } else {
+ ruleset_version_string = "n/a";
+ }
+
+ const update_channel_div = document.createElement('div');
+ update_channel_div.className = "update-channel";
+
+ const update_channel_name = document.createElement('div');
+ update_channel_name.className = "update-channel-name";
+ update_channel_name.innerText = update_channel.name;
+ update_channel_div.appendChild(update_channel_name);
+ const update_channel_last_updated = document.createElement('div');
+ update_channel_last_updated.className = "update-channel-last-updated";
+ update_channel_last_updated.innerText = chrome.i18n.getMessage("options_storedRulesetsVersion") + ruleset_version_string;
+ update_channel_name.appendChild(update_channel_last_updated);
+
+ const update_channel_row_jwk = document.createElement('div');
+ update_channel_row_jwk.className = "update-channel-row-jwk";
+ update_channel_div.appendChild(update_channel_row_jwk);
+ const update_channel_jwk_column_left = document.createElement('div');
+ update_channel_jwk_column_left.className = "update-channel-column-left";
+ update_channel_jwk_column_left.innerText = "JWK:";
+ update_channel_row_jwk.appendChild(update_channel_jwk_column_left);
+ const update_channel_jwk_column_right = document.createElement('div');
+ update_channel_jwk_column_right.className = "update-channel-column-right";
+ update_channel_row_jwk.appendChild(update_channel_jwk_column_right);
+ const update_channel_jwk = document.createElement('textarea');
+ update_channel_jwk.className = "update-channel-jwk";
+ update_channel_jwk.setAttribute("data-name", update_channel.name);
+ update_channel_jwk.disabled = pinned;
+ update_channel_jwk.innerText = JSON.stringify(update_channel.jwk);
+ update_channel_jwk_column_right.appendChild(update_channel_jwk);
+
+ const update_channel_row_path_prefix = document.createElement('div');
+ update_channel_row_path_prefix.className = "update-channel-row-path-prefix";
+ update_channel_div.appendChild(update_channel_row_path_prefix);
+ const update_channel_path_prefix_column_left = document.createElement('div');
+ update_channel_path_prefix_column_left.className = "update-channel-column-left";
+ update_channel_path_prefix_column_left.innerText = "Path Prefix:";
+ update_channel_row_path_prefix.appendChild(update_channel_path_prefix_column_left);
+ const update_channel_path_prefix_column_right = document.createElement('div');
+ update_channel_path_prefix_column_right.className = "update-channel-column-right";
+ update_channel_row_path_prefix.appendChild(update_channel_path_prefix_column_right);
+ const update_channel_path_prefix = document.createElement('input');
+ update_channel_path_prefix.setAttribute("type", "text");
+ update_channel_path_prefix.className = "update-channel-path-prefix";
+ update_channel_path_prefix.setAttribute("data-name", update_channel.name);
+ update_channel_path_prefix.disabled = pinned;
+ update_channel_path_prefix.value = update_channel.update_path_prefix;
+ update_channel_path_prefix_column_right.appendChild(update_channel_path_prefix);
+
+ const update_channel_row_controls = document.createElement('div');
+ update_channel_row_controls.className = "update-channel-row-controls";
+ update_channel_div.appendChild(update_channel_row_controls);
+ const update_channel_controls_column_left = document.createElement('div');
+ update_channel_controls_column_left.className = "update-channel-column-left";
+ update_channel_controls_column_left.innerText = " ";
+ update_channel_row_controls.appendChild(update_channel_controls_column_left);
+ const update_channel_controls_column_right = document.createElement('div');
+ update_channel_controls_column_right.className = "update-channel-column-right";
+ update_channel_row_controls.appendChild(update_channel_controls_column_right);
+ const update_channel_update = document.createElement('button');
+ update_channel_update.className = "update-channel-update";
+ update_channel_update.setAttribute("data-name", update_channel.name);
+ update_channel_update.disabled = pinned;
+ update_channel_update.innerText = chrome.i18n.getMessage("options_update");
+ update_channel_controls_column_right.appendChild(update_channel_update);
+ const update_channel_delete = document.createElement('button');
+ update_channel_delete.className = "update-channel-update";
+ update_channel_delete.setAttribute("data-name", update_channel.name);
+ update_channel_delete.disabled = pinned;
+ update_channel_delete.innerText = chrome.i18n.getMessage("options_delete");
+ update_channel_controls_column_right.appendChild(update_channel_delete);
+
+ const clearer = document.createElement('div');
+ clearer.className = "clearer";
+ update_channel_div.appendChild(clearer);
+
+ update_channel_delete.addEventListener("click", () => {
+ sendMessage("delete_update_channel", update_channel.name, () => {
+ render_update_channels();
+ });
+ });
+
+ update_channel_update.addEventListener("click", () => {
+ sendMessage("update_update_channel", {
+ name: update_channel.name,
+ jwk: JSON.parse(update_channel_jwk.value),
+ update_path_prefix: update_channel_path_prefix.value
+ }, () => {
+ render_update_channels();
+ });
+ });
+
+ return update_channel_div;
+ }
+
+ function render_update_channels(){
+ const update_channels_list = document.getElementById("update-channels-list");
+ while(update_channels_list.firstChild){
+ update_channels_list.removeChild(update_channels_list.firstChild);
+ }
+
+ sendMessage("get_pinned_update_channels", null, item => {
+ for(const update_channel of item.update_channels){
+ update_channels_list.appendChild(
+ create_update_channel_element(
+ update_channel,
+ item.last_updated[update_channel.name],
+ true
+ )
+ );
+
+ }
+ });
+
+ sendMessage("get_stored_update_channels", null, item => {
+ for(const update_channel of item.update_channels){
+ update_channels_list.appendChild(
+ create_update_channel_element(
+ update_channel,
+ item.last_updated[update_channel.name],
+ false
+ )
+ );
+ }
+ });
+ }
+ render_update_channels();
+
+ const add_update_channel = document.getElementById("add-update-channel");
+ const update_channel_name_div = document.getElementById("update-channel-name");
+ const update_channels_error_text = document.getElementById("update-channels-error-text");
+ const update_channels_error = document.getElementById("update-channels-error");
+ update_channel_name_div.setAttribute("placeholder", chrome.i18n.getMessage("options_enterUpdateChannelName"));
+
+ function displayError(text){
+ update_channels_error_text.innerText = text;
+ update_channels_error.style.display = "block";
+ window.scrollTo(0,0);
+ }
+
+ add_update_channel.addEventListener("click", () => {
+ const update_channel_name = update_channel_name_div.value;
+ if(update_channel_name.trim() == ""){
+ displayError("Error: The update channel name is blank. Please enter another name.");
+ } else {
+ update_channel_name_div.value = "";
+ sendMessage("create_update_channel", update_channel_name, result => {
+ if(result == true){
+ render_update_channels();
+ } else {
+ displayError("Error: There already exists an update channel with this name.");
+ }
+ });
+ }
+ });
+
+ const update_channels_error_hide = document.getElementById("update-channels-error-hide");
+ update_channels_error_hide.addEventListener("click", () => {
+ update_channels_error.style.display = "none";
+ });
+
+ const update_channels_last_checked = document.getElementById("update-channels-last-checked");
+ sendMessage("get_last_checked", null, last_checked => {
+ let last_checked_string;
+ if(last_checked){
+ const last_checked_date = new Date(last_checked * 1000);
+ const options = {
+ year: '2-digit',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ timeZoneName: 'short'
+ };
+ const customDateTime = new Intl.DateTimeFormat('default', options).format;
+ last_checked_string = customDateTime(last_checked_date);
+ } else {
+ last_checked_string = chrome.i18n.getMessage("options_updatesLastCheckedNever");
+ }
+ update_channels_last_checked.innerText = chrome.i18n.getMessage("options_updatesLastChecked") + last_checked_string;
+ });
+
+ document.onkeydown = function(evt) {
+ evt = evt || window.event;
+ if (evt.ctrlKey && evt.keyCode == 90) {
+ window.open("/pages/debugging-rulesets/index.html");
+ }
+ };
+});
diff --git a/data/extensions/https-everywhere@eff.org/pages/popup/index.html b/data/extensions/https-everywhere@eff.org/pages/popup/index.html
new file mode 100644
index 0000000..21dac99
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/popup/index.html
@@ -0,0 +1,84 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title data-i18n="about_ext_name"></title>
+
+ <link href="style.css" rel="stylesheet">
+ <script src="ux.js"></script>
+ <script src="../translation.js"></script>
+ <script src="../send-message.js"></script>
+ </head>
+ <body>
+ <header>
+ <h1 data-i18n="about_ext_name"></h1>
+ </header>
+
+ <section id="disableButton" class="options" style="visibility: hidden;">
+ <div class="onoffswitch">
+ <input id="onoffswitch" type="checkbox" checked><label data-i18n="menu_globalEnable" for="onoffswitch"></label>
+ </div>
+ </section>
+
+ <section id="HttpNowhere" class="options" style="visibility: hidden;">
+ <input id="http-nowhere-checkbox" type="checkbox"><label data-i18n="menu_blockUnencryptedRequests" for="http-nowhere-checkbox"></label>
+ </section>
+
+ <div id="RuleManagement">
+ <section>
+ <a href="javascript:void 0" id="add-rule-link" data-i18n="chrome_add_rule"></a>
+ <div id="add-new-rule-div" style="display: none">
+ <h3 data-i18n="about_add_new_rule"></h3>
+ <p data-i18n="chrome_always_https_for_host"></p>
+ <label for="new-rule-host" data-i18n="chrome_host"></label><br>
+ <input size="50" id="new-rule-host" type="text" disabled><br>
+ <div id="new-rule-regular-text">
+ <a href="javascript:void 0" id="new-rule-show-advanced-link" data-i18n="chrome_show_advanced"></a><br>
+ </div>
+ <div id="new-rule-advanced" style="display: none">
+ <a href="javascript:void 0" id="new-rule-hide-advanced-link" data-i18n="chrome_hide_advanced"></a><br>
+ <br>
+ <label for="new-rule-name" data-i18n="chrome_rule_name"></label><br>
+ <input size="50" id="new-rule-name" type="text"><br>
+ <label for="new-rule-regex" data-i18n="chrome_regex"></label><br>
+ <input size="50" id="new-rule-regex" type="text"><br>
+ <label for="new-rule-redirect" data-i18n="chrome_redirect_to"></label><br>
+ <input size="50" id="new-rule-redirect" type="text"><br>
+ </div>
+ <button id="add-new-rule-button" data-i18n="chrome_add_new_rule"></button><br>
+ <button id="cancel-new-rule" data-i18n="chrome_status_cancel_button"></button>
+ </div>
+ </section>
+
+ <section id="StableRules" class="rules">
+ <h3 data-i18n="chrome_stable_rules"></h3>
+ <p class="description" data-i18n="chrome_stable_rules_description"></p>
+ </section>
+
+ <section id="UnstableRules" class="rules">
+ <h3 data-i18n="chrome_experimental_rules"></h3>
+ <p class="description" data-i18n="chrome_experimental_rules_description"></p>
+ </section>
+
+ <section id="resetButton" class="options">
+ <a href="javascript:void 0" id="reset-to-defaults" data-i18n="prefs_reset_defaults"></a>
+ </section>
+ </div>
+
+ <footer>
+ <a id="viewAllRules" href="https://www.eff.org/https-everywhere/atlas" target="_blank" data-i18n="menu_viewAllRules"></a><br>
+ <br>
+ <a id="aboutTitle" href="https://www.eff.org/https-everywhere" target="_blank" data-i18n="about_title"></a><br>
+ <br>
+ <a id="donateEFF" href="https://supporters.eff.org/donate/support-https-everywhere" target="_blank" data-i18n="menu_donate_eff_imperative"></a>
+ <p>
+ <small>
+ <span data-i18n="about_version">Version</span>: <span id="current-version"></span>
+ <span id="rulesets-versions">
+ </span>
+ </small>
+ </p>
+ </footer>
+
+ </body>
+</html>
diff --git a/data/extensions/https-everywhere@eff.org/pages/popup/style.css b/data/extensions/https-everywhere@eff.org/pages/popup/style.css
new file mode 100644
index 0000000..a1cc358
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/popup/style.css
@@ -0,0 +1,128 @@
+html {
+ background-color: #fff
+}
+
+body {
+ cursor: default;
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-top: 0;
+ margin-bottom: 0;
+ min-width: 20em;
+ font-family: 'Lucida Grande', 'Segoe UI', Tahoma, 'DejaVu Sans', Arial, sans-serif;
+ font-size: 75%;
+ color: #303942;
+}
+
+p {
+ line-height: 1.8em;
+}
+
+h1, h2, h3 {
+ user-select: none;
+ font-weight: normal;
+ line-height: 1;
+}
+
+h1 {
+ font-size: 1.5em;
+}
+
+h2 {
+ font-size: 1.3em;
+ margin-bottom: 0.4em;
+}
+
+h3 {
+ color: black;
+ font-size: 1.2em;
+ margin-bottom: 0.8em;
+}
+
+a {
+ color: #15c;
+ text-decoration: underline;
+}
+
+a:active {
+ color: #052577;
+}
+
+/* Don't wrap text for important stuff. */
+h1, h2, h3, .rule > label {
+ white-space: nowrap;
+}
+
+/* Hide rules & options if the extension is off. */
+.disabled #RuleManagement,.disabled #HttpNowhere {
+ display: none;
+}
+
+/* Initially hide section (until rules get added). */
+section.rules {
+ display: none;
+}
+
+.rule {
+ height: 25px;
+}
+
+.rule label {
+ padding: 0;
+ max-width: 93%;
+ overflow: hidden;
+}
+
+/* Underline rules that have notes. */
+.rule[title] span {
+ border-bottom: 1px dotted;
+ cursor: help;
+}
+
+input[type='checkbox'] {
+ vertical-align: middle;
+}
+
+.rule img.remove {
+ float: right;
+}
+
+header {
+ border-bottom: 1px solid #eee;
+}
+
+header > h1 {
+ margin: 0;
+ padding: 21px 0 13px;
+}
+
+section {
+ padding-left: 18px;
+ padding-top: 9px;
+ padding-bottom: 9px;
+}
+
+section > h3 {
+ margin-left: -18px;
+}
+
+footer {
+ border-top: 1px solid #eee;
+ margin-top: 8px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+}
+
+/* By default the "Add a rule" link is hidden. It's shown on HTTPS sites only. */
+#add-rule-link {
+ display: none;
+}
+
+#rulesets-versions{
+ display: block;
+ clear: both;
+}
+
+.rulesets-version{
+ display: block;
+}
diff --git a/data/extensions/https-everywhere@eff.org/pages/popup/ux.js b/data/extensions/https-everywhere@eff.org/pages/popup/ux.js
new file mode 100644
index 0000000..a35c00c
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/popup/ux.js
@@ -0,0 +1,281 @@
+/* global sendMessage */
+
+"use strict";
+
+function e(id) {
+ return document.getElementById(id);
+}
+
+/**
+ * Handles rule (de)activation in the popup
+ */
+function toggleRuleLine(event) {
+ if (event.target.matches("input[type=checkbox]")) {
+ getTab(activeTab => {
+ const set_ruleset = {
+ active: event.target.checked,
+ name: event.target.nextSibling.innerText,
+ tab_id: activeTab.id,
+ };
+
+ sendMessage("set_ruleset_active_status", set_ruleset, () => {
+ // purge the name from the cache so that this unchecking is persistent.
+ sendMessage("delete_from_ruleset_cache", set_ruleset.name, () => {
+ // Now reload the selected tab of the current window.
+ chrome.tabs.reload(set_ruleset.tab_id);
+ });
+ });
+ });
+ }
+}
+
+
+/**
+ * Creates rule lines (including checkbox and icon) for the popup
+ * @param rulesets
+ * @param list_div
+ * @returns {*}
+ */
+function appendRulesToListDiv(rulesets, list_div) {
+ if (rulesets && rulesets.length) {
+ // template parent block for each ruleset
+ let templateLine = document.createElement("div");
+ templateLine.className = "rule checkbox";
+
+ // label "container"
+ let templateLabel = document.createElement("label");
+
+ // checkbox
+ let templateCheckbox = document.createElement("input");
+ templateCheckbox.type = "checkbox";
+
+ // label text
+ let templateLabelText = document.createElement("span");
+
+ // img "remove" button
+ let templateRemove = document.createElement("img");
+ templateRemove.src = chrome.extension.getURL("images/remove.png");
+ templateRemove.className = "remove";
+
+ templateLabel.appendChild(templateCheckbox);
+ templateLabel.appendChild(templateLabelText);
+ templateLine.appendChild(templateLabel);
+
+ for (const ruleset of rulesets) {
+ let line = templateLine.cloneNode(true);
+ let checkbox = line.querySelector("input[type=checkbox]");
+ let text = line.querySelector("span");
+
+ checkbox.checked = ruleset.active;
+ text.innerText = ruleset.name;
+
+ if (ruleset.note && ruleset.note.length) {
+ line.title = ruleset.note;
+
+ if (ruleset.note === "user rule") {
+ let remove = templateRemove.cloneNode(true);
+ line.appendChild(remove);
+
+ remove.addEventListener("click", () => {
+ sendMessage("remove_rule", ruleset, () => {
+ list_div.removeChild(line);
+ });
+ });
+ }
+ }
+ list_div.appendChild(line);
+ }
+ show(list_div);
+ }
+}
+
+function showHttpNowhereUI() {
+ // Set up checkbox for HTTP nowhere mode
+ getOption_('httpNowhere', false, function(item) {
+ if (item.httpNowhere) {
+ e('http-nowhere-checkbox').checked = true;
+ }
+ e('HttpNowhere').style.visibility = "visible";
+ });
+};
+
+// Change the UI to reflect extension enabled/disabled
+function updateEnabledDisabledUI() {
+ getOption_('globalEnabled', true, function(item) {
+ e('onoffswitch').checked = item.globalEnabled;
+ e('disableButton').style.visibility = "visible";
+ // Hide or show the rules sections
+ if (item.globalEnabled) {
+ document.body.className = ""
+ showHttpNowhereUI()
+ } else {
+ document.body.className = "disabled"
+ }
+ });
+}
+
+// Toggle extension enabled/disabled status
+function toggleEnabledDisabled() {
+ var extension_toggle_effect = function() {
+ updateEnabledDisabledUI();
+ // The extension state changed, so reload this tab.
+ chrome.tabs.reload();
+ window.close();
+ }
+
+ getOption_('globalEnabled', true, function(item) {
+ setOption_('globalEnabled', !item.globalEnabled, extension_toggle_effect);
+ });
+
+}
+
+/**
+ * Create the list of rules for a specific tab
+ * @param activeTab
+ */
+function gotTab(activeTab) {
+ sendMessage("get_active_rulesets", activeTab.id, function(rulesets) {
+ if (rulesets) {
+ const stableRules = rulesets.filter(ruleset => ruleset.default_state);
+ const unstableRules = rulesets.filter(ruleset => !ruleset.default_state);
+
+ appendRulesToListDiv(stableRules, e("StableRules"));
+ appendRulesToListDiv(unstableRules, e("UnstableRules"));
+
+ // Add listener to capture the toggle event
+ e("RuleManagement").addEventListener("click", toggleRuleLine);
+ }
+
+ // Only show the "Add a rule" link if we're on an HTTPS page
+ if (/^https:/.test(activeTab.url)) {
+ show(e("add-rule-link"));
+ }
+ });
+}
+
+/**
+ * Fill in content into the popup on load
+ */
+document.addEventListener("DOMContentLoaded", function () {
+ getTab(gotTab);
+
+ // Set up the enabled/disabled switch & hide/show rules
+ updateEnabledDisabledUI();
+ e('onoffswitch').addEventListener('click', toggleEnabledDisabled);
+ e('http-nowhere-checkbox').addEventListener('click', toggleHttpNowhere, false);
+ e('reset-to-defaults').addEventListener('click', () => {
+ if (confirm(chrome.i18n.getMessage("prefs_reset_defaults_message"))) {
+ sendMessage("reset_to_defaults", null, () => {
+ window.close();
+ });
+ }
+ });
+
+ // Print the extension's current version.
+ var the_manifest = chrome.runtime.getManifest();
+ var version_info = e('current-version');
+ version_info.innerText = the_manifest.version;
+
+ let rulesets_versions = e('rulesets-versions');
+ sendMessage("get_ruleset_timestamps", null, timestamps => {
+ for(let [update_channel, timestamp] of timestamps){
+ if(timestamp > 0){
+ let ruleset_date = new Date(timestamp * 1000);
+ let ruleset_version_string = ruleset_date.getUTCFullYear() + "." + (ruleset_date.getUTCMonth() + 1) + "." + ruleset_date.getUTCDate();
+
+ let timestamp_span = document.createElement("span");
+ timestamp_span.className = "rulesets-version";
+ timestamp_span.innerText = chrome.i18n.getMessage("about_rulesets_version") + " " + update_channel + ": " + ruleset_version_string;
+ rulesets_versions.appendChild(timestamp_span);
+ }
+ }
+ });
+ e("aboutTitle").title = chrome.i18n.getMessage("about_title");
+ e("add-rule-link").addEventListener("click", addManualRule);
+});
+
+
+var escapeForRegex = function( value ) {
+ return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+};
+
+function hide(elem) {
+ elem.style.display = "none";
+}
+
+function show(elem) {
+ elem.style.display = "block";
+}
+
+/**
+ * Handles the manual addition of rules
+ */
+function addManualRule() {
+ getTab(function(tab) {
+ hide(e("add-rule-link"));
+ show(e("add-new-rule-div"));
+
+ const url = new URL(tab.url);
+
+ e("new-rule-host").value = url.host;
+
+ const escapedHost = escapeForRegex(url.host);
+
+ e("new-rule-regex").value = `^http://${escapedHost}/`;
+ e("new-rule-redirect").value = `https://${url.host}/`;
+ e("new-rule-name").value = "Manual rule for " + url.host;
+
+ e("add-new-rule-button").addEventListener("click", function() {
+ const params = {
+ host : e("new-rule-host").value,
+ redirectTo : e("new-rule-redirect").value,
+ urlMatcher : e("new-rule-regex").value
+ };
+ sendMessage("add_new_rule", params, function() {
+ location.reload();
+ });
+ });
+
+ e("cancel-new-rule").addEventListener("click", function() {
+ show(e("add-rule-link"));
+ hide(e("add-new-rule-div"));
+ });
+
+ e("new-rule-show-advanced-link").addEventListener("click", function() {
+ show(e("new-rule-advanced"));
+ hide(e("new-rule-regular-text"));
+ });
+
+ e("new-rule-hide-advanced-link").addEventListener("click", function() {
+ hide(e("new-rule-advanced"));
+ show(e("new-rule-regular-text"));
+ });
+ });
+}
+
+function toggleHttpNowhere() {
+ getOption_('httpNowhere', false, function(item) {
+ setOption_('httpNowhere', !item.httpNowhere);
+ });
+}
+
+function getOption_(opt, defaultOpt, callback) {
+ var details = {};
+ details[opt] = defaultOpt;
+ sendMessage("get_option", details, callback);
+}
+
+function setOption_(opt, value, callback) {
+ var details = {};
+ details[opt] = value;
+ sendMessage("set_option", details, callback);
+}
+
+function getTab(callback) {
+ let url = new URL(window.location.href);
+ if (url.searchParams.has('tabId')) {
+ let parentId = Number(url.searchParams.get('tabId'));
+ return chrome.tabs.get(parentId, callback);
+ }
+ chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => callback(tabs[0]));
+}
diff --git a/data/extensions/https-everywhere@eff.org/pages/send-message.js b/data/extensions/https-everywhere@eff.org/pages/send-message.js
new file mode 100644
index 0000000..da8adf5
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/send-message.js
@@ -0,0 +1,7 @@
+/* exported sendMessage */
+
+"use strict";
+
+function sendMessage(type, object, callback) {
+ chrome.runtime.sendMessage({ type, object }, callback);
+}
diff --git a/data/extensions/https-everywhere@eff.org/pages/switch-planner/index.html b/data/extensions/https-everywhere@eff.org/pages/switch-planner/index.html
new file mode 100644
index 0000000..5150fc2
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/switch-planner/index.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title></title>
+ </head>
+ <body>
+ <div id="content"></div>
+ <script src="ux.js"></script>
+ </body>
+</html>
diff --git a/data/extensions/https-everywhere@eff.org/pages/switch-planner/ux.js b/data/extensions/https-everywhere@eff.org/pages/switch-planner/ux.js
new file mode 100644
index 0000000..1562f8f
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/switch-planner/ux.js
@@ -0,0 +1,88 @@
+"use strict";
+
+document.addEventListener("DOMContentLoaded", () => {
+ const background = chrome.extension.getBackgroundPage().require('./background');
+ var tab = document.location.search.match(/tab=([^&]*)/)[1];
+ var content = document.getElementById("content");
+
+ var nrw_text_div = document.createElement("div");
+ nrw_text_div.innerText = "Unrewritten HTTP resources loaded from this tab (enable HTTPS on these domains and add them to HTTPS Everywhere):"
+ var nrw_div = switchPlannerDetailsHtmlSection(
+ background.sortSwitchPlanner(tab, "nrw"),
+ background.switchPlannerInfo[tab]["nrw"]
+ );
+ var rw_text_div = document.createElement("div");
+ rw_text_div.style.marginTop = "20px";
+ rw_text_div.innerText = "Resources rewritten successfully from this tab (update these in your source code):"
+ var rw_div = switchPlannerDetailsHtmlSection(
+ background.sortSwitchPlanner(tab, "rw"),
+ background.switchPlannerInfo[tab]["rw"]
+ );
+
+ content.appendChild(nrw_text_div);
+ content.appendChild(nrw_div);
+ content.appendChild(rw_text_div);
+ content.appendChild(rw_div);
+});
+
+/**
+ * Generate the detailed html fot the switch planner, by section
+ * */
+function switchPlannerDetailsHtmlSection(asset_host_list, link_keys) {
+ var wrapper_div = document.createElement("div");
+ if (asset_host_list.length == 0) {
+ wrapper_div.style.fontWeight = "bold";
+ wrapper_div.innerText = "none";
+ return wrapper_div;
+ }
+
+ for (var i = asset_host_list.length - 1; i >= 0; i--) {
+ var host = asset_host_list[i][3];
+ var activeCount = asset_host_list[i][1];
+ var passiveCount = asset_host_list[i][2];
+
+ var div = document.createElement("div");
+ div.style.marginTop = "20px";
+ var b = document.createElement("b");
+ b.innerText = host;
+ div.appendChild(b);
+
+ if (activeCount > 0) {
+ var active_div = document.createElement("div");
+ active_div.appendChild(document.createTextNode(activeCount + " active"));
+ for (const link of linksFromKeys(link_keys[host][1])) {
+ active_div.appendChild(link);
+ }
+ div.appendChild(active_div);
+ }
+ if (passiveCount > 0) {
+ var passive_div = document.createElement("div");
+ passive_div.appendChild(document.createTextNode(passiveCount + " passive"));
+ for (const link of linksFromKeys(link_keys[host][0])) {
+ passive_div.appendChild(link);
+ }
+ div.appendChild(passive_div);
+ }
+ wrapper_div.appendChild(div);
+ }
+ return wrapper_div;
+}
+
+/**
+ * Generate a HTML link from urls in map
+ * map: the map containing the urls
+ * */
+function linksFromKeys(map) {
+ if (typeof map == 'undefined') return "";
+ var links = [];
+ for (var key in map) {
+ if (map.hasOwnProperty(key)) {
+ var link = document.createElement("a");
+ link.style.display = "block";
+ link.href = key;
+ link.innerText = key;
+ links.push(link);
+ }
+ }
+ return links;
+}
diff --git a/data/extensions/https-everywhere@eff.org/pages/translation.js b/data/extensions/https-everywhere@eff.org/pages/translation.js
new file mode 100644
index 0000000..5cdbd99
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/pages/translation.js
@@ -0,0 +1,8 @@
+"use strict";
+
+document.addEventListener("DOMContentLoaded", () => {
+ // Auto-translate all elements with data-i18n attributes
+ for (const element of document.querySelectorAll("[data-i18n]")) {
+ element.innerText = chrome.i18n.getMessage(element.getAttribute("data-i18n"));
+ }
+});