summaryrefslogtreecommitdiff
path: root/data/extensions/https-everywhere@eff.org/background-scripts
diff options
context:
space:
mode:
authorRuben Rodriguez <ruben@trisquel.info>2022-09-08 20:18:54 -0400
committerRuben Rodriguez <ruben@trisquel.info>2022-09-08 20:18:54 -0400
commit5da28b0f8771834ae208d61431d632875e9f8e7d (patch)
tree688ecaff26197bad8abde617b4947b11d617309e /data/extensions/https-everywhere@eff.org/background-scripts
parent4a87716686104266a9cccc2d83cc249e312f3673 (diff)
Updated extensions:
* Upgraded Privacy Redirect to 1.1.49 and configured to use the 10 most reliable invidious instances * Removed ViewTube * Added torproxy@icecat.gnu based on 'Proxy toggle' extension * Added jShelter 0.11.1 * Upgraded LibreJS to 7.21.0 * Upgraded HTTPS Everywhere to 2021.7.13 * Upgraded SubmitMe to 1.9
Diffstat (limited to 'data/extensions/https-everywhere@eff.org/background-scripts')
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/background.js115
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/incognito.js2
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/ip_utils.js20
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/modules/on_before.js0
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/modules/ssl_codes.js48
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/rules.js56
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/store.js11
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/update.js264
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/update_channels.js51
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/util.js23
-rw-r--r--data/extensions/https-everywhere@eff.org/background-scripts/wasm.js3
11 files changed, 429 insertions, 164 deletions
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/background.js b/data/extensions/https-everywhere@eff.org/background-scripts/background.js
index 7d999f7..78a9aca 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/background.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/background.js
@@ -9,10 +9,11 @@ const rules = require('./rules'),
update = require('./update'),
{ update_channels } = require('./update_channels'),
wasm = require('./wasm'),
- ipUtils = require('./ip_utils');
-
+ ipUtils = require('./ip_utils'),
+ ssl_codes = require('./ssl_codes');
let all_rules = new rules.RuleSets();
+let blooms = [];
async function initialize() {
await wasm.initialize();
@@ -22,6 +23,7 @@ async function initialize() {
await getUpgradeToSecureAvailable();
await update.initialize(store, initializeAllRules);
await all_rules.loadFromBrowserStorage(store, update.applyStoredRulesets);
+ await update.applyStoredBlooms(blooms);
await incognito.onIncognitoDestruction(destroy_caches);
}
initialize();
@@ -30,6 +32,8 @@ async function initializeAllRules() {
const r = new rules.RuleSets();
await r.loadFromBrowserStorage(store, update.applyStoredRulesets);
Object.assign(all_rules, r);
+ blooms.length = 0;
+ await update.applyStoredBlooms(blooms);
}
/**
@@ -92,7 +96,8 @@ function initializeStoredGlobals() {
});
}
-let upgradeToSecureAvailable;
+/** @type {boolean} */
+let upgradeToSecureAvailable = false;
function getUpgradeToSecureAvailable() {
if (typeof browser !== 'undefined') {
@@ -181,14 +186,18 @@ function updateState () {
title: 'HTTPS Everywhere' + ((iconState === 'active') ? '' : ' (' + iconState + ')')
});
- chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
- if (!tabs || tabs.length === 0) {
+ const chromeUrl = 'chrome://';
+
+ chrome.tabs.query({ active: true, currentWindow: true, status: 'complete' }, function(tabs) {
+ if (!tabs || tabs.length === 0 || tabs[0].url.startsWith(chromeUrl) ) {
return;
}
+
+ // tabUrl.host instead of hostname should be used to show the "disabled" status properly (#19293)
const tabUrl = new URL(tabs[0].url);
- const hostname = util.getNormalisedHostname(tabUrl.hostname);
+ const host = util.getNormalisedHostname(tabUrl.host);
- if (isExtensionDisabledOnSite(hostname) || iconState == "disabled") {
+ if (isExtensionDisabledOnSite(host) || iconState == "disabled") {
if ('setIcon' in chrome.browserAction) {
chrome.browserAction.setIcon({
path: {
@@ -268,7 +277,7 @@ BrowserSession.prototype = {
// sort by ruleset names alphabetically, case-insensitive
if (this.getTab(tabId, "applied_rulesets", null)) {
- let rulesets = this.getTab(tabId, "applied_rulesets");
+ let rulesets = this.getTab(tabId, "applied_rulesets", null);
let insertIndex = 0;
const ruleset_name = ruleset.name.toLowerCase();
@@ -313,7 +322,7 @@ BrowserSession.prototype = {
this.requests.delete(requestId);
}
}
-}
+};
let browserSession = new BrowserSession();
@@ -360,7 +369,7 @@ function onBeforeRequest(details) {
// Check if an user has disabled HTTPS Everywhere on this site. We should
// ensure that all subresources are not run through HTTPS Everywhere as well.
- browserSession.putTab(details.tabId, 'first_party_host', uri.hostname, true);
+ browserSession.putTab(details.tabId, 'first_party_host', uri.host, true);
}
if (isExtensionDisabledOnSite(browserSession.getTab(details.tabId, 'first_party_host', null))) {
@@ -374,6 +383,7 @@ function onBeforeRequest(details) {
(uri.protocol === 'http:' || uri.protocol === 'ftp:') &&
uri.hostname.slice(-6) !== '.onion' &&
uri.hostname !== 'localhost' &&
+ !uri.hostname.endsWith('.localhost') &&
uri.hostname !== '[::1]' &&
!isLocalIp;
@@ -398,7 +408,7 @@ function onBeforeRequest(details) {
return redirectOnCancel(shouldCancel, details.url);
}
- if (browserSession.getRequest(details.requestId, "redirect_count") >= 8) {
+ if (browserSession.getRequest(details.requestId, "redirect_count", 0) >= 8) {
util.log(util.NOTE, "Redirect counter hit for " + uri.href);
urlBlacklist.add(uri.href);
rules.settings.domainBlacklist.add(uri.hostname);
@@ -421,6 +431,15 @@ function onBeforeRequest(details) {
}
}
+ if (newuristr == null && blooms.length > 0 && uri.protocol === 'http:') {
+ for(let bloom of blooms) {
+ if(bloom.check(uri.hostname)) {
+ newuristr = uri.href.replace(/^http:/, "https:");
+ break;
+ }
+ }
+ }
+
// only use upgradeToSecure for trivial rewrites
if (upgradeToSecureAvailable && newuristr) {
// check rewritten URIs against the trivially upgraded URI
@@ -560,28 +579,9 @@ function onErrorOccurred(details) {
if (httpNowhereOn &&
details.type == "main_frame" &&
browserSession.getRequest(details.requestId, "simple_http_nowhere_redirect", false) &&
- ( // Enumerate a class of errors that are likely due to HTTPS misconfigurations
- details.error.indexOf("net::ERR_SSL_") == 0 ||
- details.error.indexOf("net::ERR_CERT_") == 0 ||
- details.error.indexOf("net::ERR_CONNECTION_") == 0 ||
- details.error.indexOf("net::ERR_ABORTED") == 0 ||
- details.error.indexOf("net::ERR_SSL_PROTOCOL_ERROR") == 0 ||
- details.error.indexOf("NS_ERROR_CONNECTION_REFUSED") == 0 ||
- details.error.indexOf("NS_ERROR_NET_TIMEOUT") == 0 ||
- details.error.indexOf("NS_ERROR_NET_ON_TLS_HANDSHAKE_ENDED") == 0 ||
- details.error.indexOf("SSL received a record that exceeded the maximum permissible length.") == 0 ||
- details.error.indexOf("Peer’s Certificate has expired.") == 0 ||
- details.error.indexOf("Unable to communicate securely with peer: requested domain name does not match the server’s certificate.") == 0 ||
- details.error.indexOf("Peer’s Certificate issuer is not recognized.") == 0 ||
- details.error.indexOf("Peer’s Certificate has been revoked.") == 0 ||
- details.error.indexOf("Peer reports it experienced an internal error.") == 0 ||
- details.error.indexOf("The server uses key pinning (HPKP) but no trusted certificate chain could be constructed that matches the pinset. Key pinning violations cannot be overridden.") == 0 ||
- details.error.indexOf("SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.") == 0 ||
- details.error.indexOf("The certificate was signed using a signature algorithm that is disabled because it is not secure.") == 0 ||
- details.error.indexOf("Unable to communicate securely with peer: requested domain name does not match the server’s certificate.") == 0 ||
- details.error.indexOf("Cannot communicate securely with peer: no common encryption algorithm(s).") == 0 ||
- details.error.indexOf("SSL peer has no certificate for the requested DNS name.") == 0
- )) {
+ // Enumerate errors that are likely due to HTTPS misconfigurations
+ ssl_codes.error_list.some(message => details.error.includes(message))
+ ) {
let url = new URL(details.url);
if (url.protocol == "https:") {
url.protocol = "http:";
@@ -646,7 +646,7 @@ function onHeadersReceived(details) {
const upgradeInsecureRequests = {
name: 'Content-Security-Policy',
value: 'upgrade-insecure-requests'
- }
+ };
details.responseHeaders.push(upgradeInsecureRequests);
responseHeadersChanged = true;
}
@@ -669,7 +669,7 @@ chrome.webRequest.onBeforeRedirect.addListener(onBeforeRedirect, {urls: ["https:
chrome.webRequest.onCompleted.addListener(onCompleted, {urls: ["*://*/*"]});
// Cleanup redirectCounter if necessary
-chrome.webRequest.onErrorOccurred.addListener(onErrorOccurred, {urls: ["*://*/*"]})
+chrome.webRequest.onErrorOccurred.addListener(onErrorOccurred, {urls: ["*://*/*"]});
// Insert upgrade-insecure-requests directive in httpNowhere mode
chrome.webRequest.onHeadersReceived.addListener(onHeadersReceived, {urls: ["https://*/*"]}, ["blocking", "responseHeaders"]);
@@ -685,8 +685,8 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
let last_updated_promises = [];
for(let update_channel of update_channels) {
last_updated_promises.push(new Promise(resolve => {
- store.local.get({['rulesets-timestamp: ' + update_channel.name]: 0}, item => {
- resolve([update_channel.name, item['rulesets-timestamp: ' + update_channel.name]]);
+ store.local.get({['uc-timestamp: ' + update_channel.name]: 0}, item => {
+ resolve([update_channel.name, item['uc-timestamp: ' + update_channel.name]]);
});
}));
}
@@ -792,11 +792,11 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (sendResponse !== null) {
sendResponse(true);
}
- })
+ });
return true;
},
- get_ruleset_timestamps: () => {
- update.getRulesetTimestamps().then(timestamps => sendResponse(timestamps));
+ get_update_channel_timestamps: () => {
+ update.getUpdateChannelTimestamps().then(timestamps => sendResponse(timestamps));
return true;
},
get_pinned_update_channels: () => {
@@ -842,9 +842,16 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
return (update_channel.name != message.object);
})}, () => {
store.local.remove([
- 'rulesets-timestamp: ' + message.object,
- 'rulesets-stored-timestamp: ' + message.object,
- 'rulesets: ' + message.object
+ 'uc-timestamp: ' + message.object,
+ 'uc-stored-timestamp: ' + message.object,
+ 'rulesets: ' + message.object,
+ 'bloom: ' + message.object,
+ 'bloom_bitmap_bits: ' + message.object,
+ 'bloom_k_num: ' + message.object,
+ 'bloom_sip_keys_0_0: ' + message.object,
+ 'bloom_sip_keys_0_1: ' + message.object,
+ 'bloom_sip_keys_1_0: ' + message.object,
+ 'bloom_sip_keys_1_1: ' + message.object,
], () => {
initializeAllRules();
sendResponse(true);
@@ -868,10 +875,8 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
// Ensure that we check for new rulesets from the update channel immediately.
// If the scope has changed, make sure that the rulesets are re-initialized.
+ update.removeStorageListener();
store.set({update_channels: item.update_channels}, () => {
- // Since loadUpdateChannesKeys is already contained in chrome.storage.onChanged
- // within update.js, the below call will make it run twice. This is
- // necesssary to avoid a race condition, see #16673
update.loadUpdateChannelsKeys().then(() => {
update.resetTimer();
if(scope_changed) {
@@ -879,8 +884,8 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
}
sendResponse(true);
});
+ update.addStorageListener();
});
-
});
return true;
},
@@ -934,21 +939,6 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
});
/**
- * @description Upboarding event for visual changelog
- */
-chrome.runtime.onInstalled.addListener(async ({reason, temporary}) => {
- if (temporary) return;
- switch (reason) {
- case "update":
- {
- const url = chrome.runtime.getURL("pages/onboarding/updated.html");
- await chrome.tabs.create({ url });
- }
- break;
- }
-});
-
-/**
* Clear any cache/ blacklist we have.
*/
function destroy_caches() {
@@ -962,6 +952,7 @@ function destroy_caches() {
Object.assign(exports, {
all_rules,
+ blooms,
urlBlacklist
});
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/incognito.js b/data/extensions/https-everywhere@eff.org/background-scripts/incognito.js
index ca52177..7d4bc81 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/incognito.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/incognito.js
@@ -43,7 +43,7 @@ Incognito.prototype = {
}
}
},
-}
+};
/**
* Check if any incognito window still exists
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/ip_utils.js b/data/extensions/https-everywhere@eff.org/background-scripts/ip_utils.js
index be7c1c8..90e0b1a 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/ip_utils.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/ip_utils.js
@@ -2,11 +2,17 @@
(function (exports) {
+/**
+ * Parse and convert literal IP address into numerical IP address.
+ * @param {string} ip
+ * @returns {number}
+ */
const parseIp = ip => {
if (!/^[0-9.]+$/.test(ip)) {
return -1;
}
+ /** @type {string[]} */
const octets = ip.split('.');
if (octets.length !== 4) {
@@ -26,14 +32,21 @@ const parseIp = ip => {
return -1;
}
- ipN = (ipN << 8) | octet;
+ ipN = (ipN << 8) | octetN;
}
return ipN >>> 0;
};
+/**
+ * Check if the numeric IP address is within a certain range.
+ * @param {number} ip
+ * @param {number[]} range
+ * @returns {boolean}
+ */
const isIpInRange = (ip, [rangeIp, mask]) => (ip & mask) >>> 0 === rangeIp;
+// A list of local IP address ranges
const localRanges = [
[/* 0.0.0.0 */ 0x00000000, /* 255.255.255.255 */ 0xffffffff],
[/* 127.0.0.0 */ 0x7f000000, /* 255.0.0.0 */ 0xff000000],
@@ -42,6 +55,11 @@ const localRanges = [
[/* 192.168.0.0 */ 0xc0a80000, /* 255.255.0.0 */ 0xffff0000],
];
+/**
+ * Check if the numeric IP address is inside the local IP address ranges.
+ * @param {number} ip
+ * @returns {boolean}
+ */
const isLocalIp = ip => localRanges.some(range => isIpInRange(ip, range));
Object.assign(exports, {
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/modules/on_before.js b/data/extensions/https-everywhere@eff.org/background-scripts/modules/on_before.js
deleted file mode 100644
index e69de29..0000000
--- a/data/extensions/https-everywhere@eff.org/background-scripts/modules/on_before.js
+++ /dev/null
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/modules/ssl_codes.js b/data/extensions/https-everywhere@eff.org/background-scripts/modules/ssl_codes.js
new file mode 100644
index 0000000..ed955ec
--- /dev/null
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/modules/ssl_codes.js
@@ -0,0 +1,48 @@
+"use strict";
+
+/**
+ * @exports error_list
+ * @type {array}
+ * @description A list of known SSL config errors to filter through and not try to upgrade the user
+ * @see
+ * Chrome SSL errors: https://github.com/chromium/chromium/blob/master/components/domain_reliability/util.cc
+ * Firefox SSL Errors: https://hg.mozilla.org/releases/mozilla-release/file/tip/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
+ */
+
+(function (exports) {
+
+const error_list = [
+ "net::ERR_SSL_PROTOCOL_ERROR",
+ "net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH",
+ "net::ERR_SSL_UNRECOGNIZED_NAME_ALERT",
+ "net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN",
+ "net::ERR_CERT_COMMON_NAME_INVALID",
+ "net::ERR_CERT_DATE_INVALID",
+ "net::ERR_CERT_AUTHORITY_INVALID",
+ "net::ERR_CERT_REVOKED",
+ "net::ERR_CERT_INVALID",
+ "net::ERR_CONNECTION_CLOSED",
+ "net::ERR_CONNECTION_RESET",
+ "net::ERR_CONNECTION_REFUSED",
+ "net::ERR_CONNECTION_ABORTED",
+ "net::ERR_CONNECTION_FAILED",
+ "net::ERR_ABORTED", ,
+ "NS_ERROR_CONNECTION_REFUSED",
+ "NS_ERROR_NET_ON_TLS_HANDSHAKE_ENDED",
+ "NS_BINDING_ABORTED",
+ "SSL received a record that exceeded the maximum permissible length.",
+ "Peer’s Certificate has expired.",
+ "Unable to communicate securely with peer: requested domain name does not match the server’s certificate.",
+ "Peer’s Certificate issuer is not recognized.",
+ "Peer’s Certificate has been revoked.",
+ "Peer reports it experienced an internal error.",
+ "The server uses key pinning (HPKP) but no trusted certificate chain could be constructed that matches the pinset. Key pinning violations cannot be overridden.",
+ "SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.",
+ "The certificate was signed using a signature algorithm that is disabled because it is not secure.",
+ "Cannot communicate securely with peer: no common encryption algorithm(s).",
+ "SSL peer has no certificate for the requested DNS name."
+];
+
+Object.assign(exports, { error_list });
+
+})(typeof exports !== 'undefined' ? exports : require.scopes.ssl_codes = {}); \ No newline at end of file
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/rules.js b/data/extensions/https-everywhere@eff.org/background-scripts/rules.js
index 51da9b7..7f0a5b5 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/rules.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/rules.js
@@ -16,7 +16,11 @@ const trivial_cookie_rule_c = /.+/;
/* A map of all scope RegExp objects */
const scopes = new Map();
-/* Returns the scope object from the map for the given scope string */
+/**
+ * Returns the scope object from the map for the given scope string.
+ * @param {string} scope ruleset scope string
+ * @returns {RegExp}
+ */
function getScope(scope) {
if (!scopes.has(scope)) {
scopes.set(scope, new RegExp(scope));
@@ -75,9 +79,10 @@ function CookieRule(host, cookiename) {
/**
*A collection of rules
- * @param set_name The name of this set
- * @param default_state activity state
- * @param note Note will be displayed in popup
+ * @param {string} set_name The name of this set
+ * @param {boolean} default_state activity state
+ * @param {string} scope ruleset scope string
+ * @param {string} note Note will be displayed in popup
* @constructor
*/
function RuleSet(set_name, default_state, scope, note) {
@@ -87,7 +92,7 @@ function RuleSet(set_name, default_state, scope, note) {
this.cookierules = null;
this.active = default_state;
this.default_state = default_state;
- this.scope = scope;
+ this.scope = getScope(scope);
this.note = note;
}
@@ -124,7 +129,7 @@ RuleSet.prototype = {
isEquivalentTo: function(ruleset) {
if(this.name != ruleset.name ||
this.note != ruleset.note ||
- this.state != ruleset.state ||
+ this.active != ruleset.active ||
this.default_state != ruleset.default_state) {
return false;
}
@@ -176,7 +181,6 @@ RuleSet.prototype = {
/**
* Initialize Rule Sets
- * @param ruleActiveStates default state for rules
* @constructor
*/
function RuleSets() {
@@ -189,7 +193,10 @@ function RuleSets() {
// A cache for cookie hostnames.
this.cookieHostCache = new Map();
- // A hash of rule name -> active status (true/false).
+ /**
+ * A hash of rule name -> active status (true/false).
+ * @type {Object<string, boolean>}
+ */
this.ruleActiveStates = {};
// The key to retrieve user rules from the storage api
@@ -220,6 +227,8 @@ RuleSets.prototype = {
/**
* Convert XML to JS and load rulesets
+ * @param {Document} ruleXml
+ * @param {string} scope
*/
addFromXml: function(ruleXml, scope) {
const rulesets_xml = ruleXml.getElementsByTagName("ruleset");
@@ -232,9 +241,11 @@ RuleSets.prototype = {
this.addFromJson(rulesets, scope);
},
+ /**
+ * @param {*} ruleJson
+ * @param {string} scope
+ */
addFromJson: function(ruleJson, scope) {
- const scope_obj = getScope(scope);
-
if (this.wasm_rs) {
this.wasm_rs.add_all_from_js_array(
ruleJson,
@@ -244,7 +255,7 @@ RuleSets.prototype = {
} else {
for (let ruleset of ruleJson) {
try {
- this.parseOneJsonRuleset(ruleset, scope_obj);
+ this.parseOneJsonRuleset(ruleset, scope);
} catch(e) {
util.log(util.WARN, 'Error processing ruleset:' + e);
}
@@ -252,6 +263,11 @@ RuleSets.prototype = {
}
},
+ /**
+ * Parse one JSON format ruleset element
+ * @param {*} ruletag
+ * @param {string} scope
+ */
parseOneJsonRuleset: function(ruletag, scope) {
var default_state = true;
var note = "";
@@ -266,7 +282,7 @@ RuleSets.prototype = {
// If a ruleset declares a platform, and we don't match it, treat it as
// off-by-default. In practice, this excludes "mixedcontent" rules.
- var platform = ruletag["platform"]
+ var platform = ruletag["platform"];
if (platform) {
default_state = false;
if (platform == "mixedcontent" && settings.enableMixedRulesets) {
@@ -320,6 +336,7 @@ RuleSets.prototype = {
/**
* Load a user rule
* @param params
+ * @param {string} scope
* @returns {boolean}
*/
addUserRule : function(params, scope) {
@@ -365,7 +382,7 @@ RuleSets.prototype = {
if (this.wasm_rs) {
this.wasm_rs.remove_ruleset(ruleset);
} else {
- const tmp = this.targets.get(ruleset.name).filter(r => !r.isEquivalentTo(ruleset))
+ const tmp = this.targets.get(ruleset.name).filter(r => !r.isEquivalentTo(ruleset));
this.targets.set(ruleset.name, tmp);
if (this.targets.get(ruleset.name).length == 0) {
@@ -398,7 +415,7 @@ RuleSets.prototype = {
loadStoredUserRules: function() {
return this.getStoredUserRules()
.then(userRules => {
- this.addFromJson(userRules, getScope());
+ this.addFromJson(userRules, '');
util.log(util.INFO, `loaded ${userRules.length} stored user rules`);
});
},
@@ -409,7 +426,7 @@ RuleSets.prototype = {
* @param cb: Callback to call after success/fail
* */
addNewRuleAndStore: async function(params) {
- if (this.addUserRule(params, getScope())) {
+ if (this.addUserRule(params, '')) {
// If we successfully added the user rule, save it in the storage
// api so it's automatically applied when the extension is
// reloaded.
@@ -466,7 +483,7 @@ RuleSets.prototype = {
},
loadCustomRuleset: function(ruleset_string) {
- this.addFromXml((new DOMParser()).parseFromString(ruleset_string, 'text/xml'));
+ this.addFromXml((new DOMParser()).parseFromString(ruleset_string, 'text/xml'), '');
},
setRuleActiveState: async function(ruleset_name, active) {
@@ -488,7 +505,7 @@ RuleSets.prototype = {
let default_off = ruletag.getAttribute("default_off");
if (default_off) {
- ruleset["default_off"] = platform;
+ ruleset["default_off"] = default_off;
}
let platform = ruletag.getAttribute("platform");
@@ -565,7 +582,7 @@ RuleSets.prototype = {
if (this.wasm_rs) {
let pa = this.wasm_rs.potentially_applicable(host);
results = new Set([...pa].map(ruleset => {
- let rs = new RuleSet(ruleset.name, ruleset.default_state, getScope(ruleset.scope), ruleset.note);
+ let rs = new RuleSet(ruleset.name, ruleset.default_state, ruleset.scope, ruleset.note);
if (ruleset.cookierules) {
let cookierules = ruleset.cookierules.map(cookierule => {
@@ -586,6 +603,9 @@ RuleSets.prototype = {
} else {
rs.exclusions = null;
}
+
+ rs.active = ruleset.active;
+
return rs;
}));
} else {
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/store.js b/data/extensions/https-everywhere@eff.org/background-scripts/store.js
index 3f32d03..e3af7cb 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/store.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/store.js
@@ -86,13 +86,13 @@ async function performMigrations() {
target: [userRule.host],
rule: [{ from: userRule.urlMatcher, to: userRule.redirectTo }],
default_off: "user rule"
- }
- })
+ };
+ });
return userRules;
})
.then(userRules => {
return set_promise(rules.RuleSets().USER_RULE_KEY, userRules);
- })
+ });
migration_version = 2;
await set_promise('migration_version', migration_version);
@@ -103,12 +103,12 @@ async function performMigrations() {
.then(disabledList => {
disabledList = disabledList.map(item => {
return util.getNormalisedHostname(item);
- })
+ });
return disabledList;
})
.then(disabledList => {
return set_promise('disabledList', disabledList);
- })
+ });
migration_version = 3;
await set_promise('migration_version', migration_version);
@@ -132,6 +132,7 @@ function setStorage(store) {
set_promise,
local
});
+ chrome.runtime.sendMessage("store_initialized");
}
Object.assign(exports, {
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/update.js b/data/extensions/https-everywhere@eff.org/background-scripts/update.js
index 1363384..4767f38 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/update.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/update.js
@@ -4,6 +4,7 @@
let combined_update_channels, extension_version;
const { update_channels } = require('./update_channels');
+const wasm = require('./wasm');
// Determine if we're in the tests. If so, define some necessary components.
if (typeof window === "undefined") {
@@ -90,25 +91,25 @@ async function resetTimer() {
await createTimer();
}
-// Check for new rulesets. If found, return the timestamp. If not, return false
-async function checkForNewRulesets(update_channel) {
- let timestamp_result = await fetch(update_channel.update_path_prefix + "/latest-rulesets-timestamp");
+// Check for new updates. If found, return the timestamp. If not, return false
+async function checkForNewUpdates(update_channel) {
+ let timestamp_result = await fetch(update_channel.update_path_prefix + (update_channel.format == "bloom" ? "/latest-bloom-timestamp" : "/latest-rulesets-timestamp"));
if(timestamp_result.status == 200) {
- let rulesets_timestamp = Number(await timestamp_result.text());
+ let uc_timestamp = Number(await timestamp_result.text());
- if((await store.local.get_promise('rulesets-timestamp: ' + update_channel.name, 0)) < rulesets_timestamp) {
- return rulesets_timestamp;
+ if((await store.local.get_promise('uc-timestamp: ' + update_channel.name, 0)) < uc_timestamp) {
+ return uc_timestamp;
}
}
return false;
}
-// Retrieve the timestamp for when a stored ruleset bundle was published
-async function getRulesetTimestamps() {
+// Retrieve the timestamp for when an update channel was published
+async function getUpdateChannelTimestamps() {
let timestamp_promises = [];
for(let update_channel of combined_update_channels) {
timestamp_promises.push(new Promise(async resolve => {
- let timestamp = await store.local.get_promise('rulesets-stored-timestamp: ' + update_channel.name, 0);
+ let timestamp = await store.local.get_promise('uc-stored-timestamp: ' + update_channel.name, 0);
resolve([update_channel, timestamp]);
}));
}
@@ -119,7 +120,7 @@ async function getRulesetTimestamps() {
// Download and return new rulesets
async function getNewRulesets(rulesets_timestamp, update_channel) {
- store.local.set_promise('rulesets-timestamp: ' + update_channel.name, rulesets_timestamp);
+ store.local.set_promise('uc-timestamp: ' + update_channel.name, rulesets_timestamp);
let signature_promise = fetch(update_channel.update_path_prefix + "/rulesets-signature." + rulesets_timestamp + ".sha256");
let rulesets_promise = fetch(update_channel.update_path_prefix + "/default.rulesets." + rulesets_timestamp + ".gz");
@@ -140,6 +141,34 @@ async function getNewRulesets(rulesets_timestamp, update_channel) {
};
}
+// Download and return new bloom
+async function getNewBloom(bloom_timestamp, update_channel) {
+ store.local.set_promise('uc-timestamp: ' + update_channel.name, bloom_timestamp);
+
+ let signature_promise = fetch(update_channel.update_path_prefix + "/bloom-signature." + bloom_timestamp + ".sha256");
+ let bloom_metadata_promise = fetch(update_channel.update_path_prefix + "/bloom-metadata." + bloom_timestamp + ".json");
+ let bloom_promise = fetch(update_channel.update_path_prefix + "/bloom." + bloom_timestamp + ".bin");
+
+ let responses = await Promise.all([
+ signature_promise,
+ bloom_metadata_promise,
+ bloom_promise
+ ]);
+
+ let resolutions = await Promise.all([
+ responses[0].arrayBuffer(),
+ responses[1].arrayBuffer(),
+ responses[2].arrayBuffer()
+ ]);
+
+ return {
+ signature_array_buffer: resolutions[0],
+ bloom_metadata_array_buffer: resolutions[1],
+ bloom_array_buffer: resolutions[2],
+ };
+
+}
+
// Returns a promise which verifies that the rulesets have a valid EFF
// signature, and if so, stores them and returns true.
// Otherwise, it throws an exception.
@@ -177,73 +206,179 @@ function verifyAndStoreNewRulesets(new_rulesets, rulesets_timestamp, update_chan
});
}
-// Unzip and apply the rulesets we have stored.
-async function applyStoredRulesets(rulesets_obj) {
- let rulesets_promises = [];
- for(let update_channel of combined_update_channels) {
- rulesets_promises.push(new Promise(resolve => {
- const key = 'rulesets: ' + update_channel.name;
- chrome.storage.local.get(key, root => {
- if(root[key]) {
- util.log(util.NOTE, update_channel.name + ': Applying stored rulesets.');
-
- const rulesets_gz = window.atob(root[key]);
- const rulesets_byte_array = pako.inflate(rulesets_gz);
- const rulesets_string = new TextDecoder("utf-8").decode(rulesets_byte_array);
- const rulesets_json = JSON.parse(rulesets_string);
-
- resolve({json: rulesets_json, scope: update_channel.scope, replaces: update_channel.replaces_default_rulesets});
+// Returns a promise which verifies that the bloom has a valid EFF
+// signature, and if so, stores it and returns true.
+// Otherwise, it throws an exception.
+function verifyAndStoreNewBloom(new_bloom, bloom_timestamp, update_channel) {
+ return new Promise((resolve, reject) => {
+ window.crypto.subtle.verify(
+ {
+ name: "RSA-PSS",
+ saltLength: 32
+ },
+ imported_keys[update_channel.name],
+ new_bloom.signature_array_buffer,
+ new_bloom.bloom_metadata_array_buffer
+ ).then(async isvalid => {
+ if(isvalid) {
+ util.log(util.NOTE, update_channel.name + ': Bloom filter metadata signature checks out.');
+
+ const bloom_metadata = JSON.parse(util.ArrayBufferToString(new_bloom.bloom_metadata_array_buffer));
+ const bloom_str = util.ArrayBufferToString(new_bloom.bloom_array_buffer);
+
+ if(bloom_metadata.timestamp != bloom_timestamp) {
+ reject(update_channel.name + ': Downloaded bloom filter had an incorrect timestamp. This may be an attempted downgrade attack. Aborting.');
+ } else if(await sha256sum(new_bloom.bloom_array_buffer) != bloom_metadata.sha256sum) {
+ reject(update_channel.name + ': sha256sum of the bloom filter is invalid. Aborting.');
} else {
- resolve();
+ await store.local.set_promise('bloom: ' + update_channel.name, window.btoa(bloom_str));
+ await store.local.set_promise('bloom_bitmap_bits: ' + update_channel.name, bloom_metadata.bitmap_bits);
+ await store.local.set_promise('bloom_k_num: ' + update_channel.name, bloom_metadata.k_num);
+ await store.local.set_promise('bloom_sip_keys_0_0: ' + update_channel.name, bloom_metadata.sip_keys[0][0]);
+ await store.local.set_promise('bloom_sip_keys_0_1: ' + update_channel.name, bloom_metadata.sip_keys[0][1]);
+ await store.local.set_promise('bloom_sip_keys_1_0: ' + update_channel.name, bloom_metadata.sip_keys[1][0]);
+ await store.local.set_promise('bloom_sip_keys_1_1: ' + update_channel.name, bloom_metadata.sip_keys[1][1]);
+ resolve(true);
}
- });
- }));
- }
+ } else {
+ reject(update_channel.name + ': Downloaded bloom filter metadata signature is invalid. Aborting.');
+ }
+ }).catch(() => {
+ reject(update_channel.name + ': Downloaded bloom signature could not be verified. Aborting.');
+ });
+ });
+}
+
+async function sha256sum(buffer) {
+ const hashBuffer = await window.crypto.subtle.digest('SHA-256', buffer);
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
+ return hashHex;
+}
- function isNotUndefined(subject) {
- return (typeof subject != 'undefined');
+function isNotUndefined(subject) {
+ return (typeof subject != 'undefined');
+}
+
+// Apply the rulesets we have stored.
+async function applyStoredRulesets(rulesets_obj) {
+ let rulesets_promises = [];
+ for(let update_channel of combined_update_channels) {
+ if(update_channel.format == "rulesets" || !update_channel.format) {
+ rulesets_promises.push(new Promise(resolve => {
+ const key = 'rulesets: ' + update_channel.name;
+ chrome.storage.local.get(key, root => {
+ if(root[key]) {
+ util.log(util.NOTE, update_channel.name + ': Applying stored rulesets.');
+
+ const rulesets_gz = window.atob(root[key]);
+ const rulesets_byte_array = pako.inflate(rulesets_gz);
+ const rulesets_string = new TextDecoder("utf-8").decode(rulesets_byte_array);
+ const rulesets_json = JSON.parse(rulesets_string);
+
+ resolve({json: rulesets_json, scope: update_channel.scope, replaces: update_channel.replaces_default_rulesets});
+ } else {
+ resolve();
+ }
+ });
+ }));
+ }
}
- const channel_results = (await Promise.all(rulesets_promises)).filter(isNotUndefined);
+ const rulesets_results = (await Promise.all(rulesets_promises)).filter(isNotUndefined);
let replaces = false;
- for(const channel_result of channel_results) {
- if(channel_result.replaces === true) {
+ for(const rulesets_result of rulesets_results) {
+ if(rulesets_result.replaces === true) {
replaces = true;
}
- rulesets_obj.addFromJson(channel_result.json.rulesets, channel_result.scope);
+ rulesets_obj.addFromJson(rulesets_result.json.rulesets, rulesets_result.scope);
}
if(!replaces) {
- rulesets_obj.addFromJson(util.loadExtensionFile('rules/default.rulesets', 'json'));
+ rulesets_obj.addFromJson(util.loadExtensionFile('rules/default.rulesets', 'json'), '');
+ }
+}
+
+// Apply the blooms we have stored.
+async function applyStoredBlooms(bloom_arr) {
+ let bloom_promises = [];
+ for(let update_channel of combined_update_channels) {
+ if(update_channel.format == "bloom") {
+ bloom_promises.push(new Promise(resolve => {
+ const key = 'bloom: ' + update_channel.name;
+ chrome.storage.local.get(key, async root => {
+ if(root[key]) {
+ util.log(util.NOTE, update_channel.name + ': Applying stored bloom filter.');
+ const bloom = util.StringToArrayBuffer(window.atob(root[key]));
+ const bloom_bitmap_bits = await store.local.get_promise('bloom_bitmap_bits: ' + update_channel.name, "");
+ const bloom_k_num = await store.local.get_promise('bloom_k_num: ' + update_channel.name, "");
+ const bloom_sip_keys_0_0 = await store.local.get_promise('bloom_sip_keys_0_0: ' + update_channel.name, "");
+ const bloom_sip_keys_0_1 = await store.local.get_promise('bloom_sip_keys_0_1: ' + update_channel.name, "");
+ const bloom_sip_keys_1_0 = await store.local.get_promise('bloom_sip_keys_1_0: ' + update_channel.name, "");
+ const bloom_sip_keys_1_1 = await store.local.get_promise('bloom_sip_keys_1_1: ' + update_channel.name, "");
+
+ try{
+ resolve(wasm.Bloom.from_existing(bloom, bloom_bitmap_bits, bloom_k_num, [[bloom_sip_keys_0_0, bloom_sip_keys_0_1], [bloom_sip_keys_1_0, bloom_sip_keys_1_1]]));
+ } catch(_) {
+ resolve();
+ }
+ } else {
+ resolve();
+ }
+ });
+ }));
+ }
+ }
+
+ bloom_arr.length = 0;
+ const bloom_results = (await Promise.all(bloom_promises)).filter(isNotUndefined);
+ for(const bloom_result of bloom_results) {
+ bloom_arr.push(bloom_result);
}
}
+
// basic workflow for periodic checks
async function performCheck() {
- util.log(util.NOTE, 'Checking for new rulesets.');
+ util.log(util.NOTE, 'Checking for new updates.');
const current_timestamp = Date.now() / 1000;
store.local.set_promise('last-checked', current_timestamp);
let num_updates = 0;
for(let update_channel of combined_update_channels) {
- let new_rulesets_timestamp = await checkForNewRulesets(update_channel);
- if(new_rulesets_timestamp) {
-
- if(update_channel.replaces_default_rulesets && extension_timestamp > new_rulesets_timestamp) {
- util.log(util.NOTE, update_channel.name + ': A new ruleset bundle has been released, but it is older than the extension-bundled rulesets it replaces. Skipping.');
- continue;
+ if(update_channel.format == "bloom") {
+ let new_bloom_timestamp = await checkForNewUpdates(update_channel);
+ if(new_bloom_timestamp) {
+ util.log(util.NOTE, update_channel.name + ': A new bloom filter has been released. Downloading now.');
+ let new_bloom = await getNewBloom(new_bloom_timestamp, update_channel);
+ try{
+ await verifyAndStoreNewBloom(new_bloom, new_bloom_timestamp, update_channel);
+ store.local.set_promise('uc-stored-timestamp: ' + update_channel.name, new_bloom_timestamp);
+ num_updates++;
+ } catch(err) {
+ util.log(util.WARN, update_channel.name + ': ' + err);
+ }
}
+ } else {
+ let new_rulesets_timestamp = await checkForNewUpdates(update_channel);
+ if(new_rulesets_timestamp) {
+
+ if(update_channel.replaces_default_rulesets && extension_timestamp > new_rulesets_timestamp) {
+ util.log(util.NOTE, update_channel.name + ': A new ruleset bundle has been released, but it is older than the extension-bundled rulesets it replaces. Skipping.');
+ continue;
+ }
- util.log(util.NOTE, update_channel.name + ': A new ruleset bundle has been released. Downloading now.');
- let new_rulesets = await getNewRulesets(new_rulesets_timestamp, update_channel);
- try{
- await verifyAndStoreNewRulesets(new_rulesets, new_rulesets_timestamp, update_channel);
- store.local.set_promise('rulesets-stored-timestamp: ' + update_channel.name, new_rulesets_timestamp);
- num_updates++;
- } catch(err) {
- util.log(util.WARN, update_channel.name + ': ' + err);
+ util.log(util.NOTE, update_channel.name + ': A new ruleset bundle has been released. Downloading now.');
+ let new_rulesets = await getNewRulesets(new_rulesets_timestamp, update_channel);
+ try{
+ await verifyAndStoreNewRulesets(new_rulesets, new_rulesets_timestamp, update_channel);
+ store.local.set_promise('uc-stored-timestamp: ' + update_channel.name, new_rulesets_timestamp);
+ num_updates++;
+ } catch(err) {
+ util.log(util.WARN, update_channel.name + ': ' + err);
+ }
}
}
}
@@ -252,7 +387,7 @@ async function performCheck() {
}
};
-chrome.storage.onChanged.addListener(async function(changes, areaName) {
+async function storageListener(changes, areaName) {
if (areaName === 'sync' || areaName === 'local') {
if ('autoUpdateRulesets' in changes) {
if (changes.autoUpdateRulesets.newValue) {
@@ -266,7 +401,17 @@ chrome.storage.onChanged.addListener(async function(changes, areaName) {
if ('update_channels' in changes) {
await loadUpdateChannelsKeys();
}
-});
+};
+
+function addStorageListener() {
+ chrome.storage.onChanged.addListener(storageListener);
+}
+
+function removeStorageListener() {
+ chrome.storage.onChanged.removeListener(storageListener);
+}
+
+addStorageListener();
let initialCheck,
subsequentChecks;
@@ -294,8 +439,8 @@ function clear_replacement_update_channels() {
for (const update_channel of combined_update_channels) {
if(update_channel.replaces_default_rulesets) {
util.log(util.NOTE, update_channel.name + ': You have a new version of the extension. Clearing any stored rulesets, which replace the new extension-bundled ones.');
- keys.push('rulesets-timestamp: ' + update_channel.name);
- keys.push('rulesets-stored-timestamp: ' + update_channel.name);
+ keys.push('uc-timestamp: ' + update_channel.name);
+ keys.push('uc-stored-timestamp: ' + update_channel.name);
keys.push('rulesets: ' + update_channel.name);
}
}
@@ -323,10 +468,13 @@ async function initialize(store_param, cb) {
Object.assign(exports, {
applyStoredRulesets,
+ applyStoredBlooms,
initialize,
- getRulesetTimestamps,
+ getUpdateChannelTimestamps,
resetTimer,
- loadUpdateChannelsKeys
+ loadUpdateChannelsKeys,
+ addStorageListener,
+ removeStorageListener,
});
})(typeof exports == 'undefined' ? require.scopes.update = {} : exports);
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/update_channels.js b/data/extensions/https-everywhere@eff.org/background-scripts/update_channels.js
index f21b332..80494ef 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/update_channels.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/update_channels.js
@@ -4,22 +4,41 @@
(function (exports) {
-exports.update_channels = [{
- name: 'EFF (Full)',
- jwk: {
- kty: 'RSA',
- e: 'AQAB',
- n: '1cwvFQu3Kw-Pz8bcEFuV5zx0ZheDsc4Tva7Qv6BL90_sDLqCW79Y543nDkPtNVfFH_89pt2kSPp_IcS5XnYiw6zBQeFuILFw5JpvZt14K0s4' +
- 'e025Q9CXfhYKIBKT9PnqihwAacjMa6rQb7RTu7XxVvqxRb3b0vx2CR40LSlYZ8H_KpeaUwq2oz-fyrI6LFTeYvbO3ZuLKeK5xV1a32xeTVMF' +
- 'kIj3LxnQalxq-DRHfj7LRRoTnbRDW4uoDc8aVpLFliuO79jUKbobz4slpiWJ4wjKR_O6OK13HbZUiOSxi8Bms-UqBPOyzbMVpmA7lv_zWdaL' +
- 'u1IVlVXQyLVbbrqI6llRqfHdcJoEl-eC48AofuB-relQtjTEK_hyBf7sPwrbqAarjRjlyEx6Qy5gTXyxM9attfNAeupYR6jm8LKm6TFpfWky' +
- 'DxUmj_f5pJMBWNTomV74f8iQ2M18_KWMUDCOf80tR0t21Q1iCWdvA3K_KJn05tTLyumlwwlQijMqRkYuao-CX9L3DJIaB3VPYPTSIPUr7oi1' +
- '6agsuamOyiOtlZiRpEvoNg2ksJMZtwnj5xhBQydkdhMW2ZpHDzcLuZlhJYZL_l3_7wuzRM7vpyA9obP92CpZRFJErGZmFxJC93I4U9-0B0wg' +
- '-sbyMKGJ5j1BWTnibCklDXtWzXtuiz18EgE'
+exports.update_channels = [
+ {
+ name: 'EFF (Full)',
+ jwk: {
+ kty: 'RSA',
+ e: 'AQAB',
+ n: '1cwvFQu3Kw-Pz8bcEFuV5zx0ZheDsc4Tva7Qv6BL90_sDLqCW79Y543nDkPtNVfFH_89pt2kSPp_IcS5XnYiw6zBQeFuILFw5JpvZt14K0s4' +
+ 'e025Q9CXfhYKIBKT9PnqihwAacjMa6rQb7RTu7XxVvqxRb3b0vx2CR40LSlYZ8H_KpeaUwq2oz-fyrI6LFTeYvbO3ZuLKeK5xV1a32xeTVMF' +
+ 'kIj3LxnQalxq-DRHfj7LRRoTnbRDW4uoDc8aVpLFliuO79jUKbobz4slpiWJ4wjKR_O6OK13HbZUiOSxi8Bms-UqBPOyzbMVpmA7lv_zWdaL' +
+ 'u1IVlVXQyLVbbrqI6llRqfHdcJoEl-eC48AofuB-relQtjTEK_hyBf7sPwrbqAarjRjlyEx6Qy5gTXyxM9attfNAeupYR6jm8LKm6TFpfWky' +
+ 'DxUmj_f5pJMBWNTomV74f8iQ2M18_KWMUDCOf80tR0t21Q1iCWdvA3K_KJn05tTLyumlwwlQijMqRkYuao-CX9L3DJIaB3VPYPTSIPUr7oi1' +
+ '6agsuamOyiOtlZiRpEvoNg2ksJMZtwnj5xhBQydkdhMW2ZpHDzcLuZlhJYZL_l3_7wuzRM7vpyA9obP92CpZRFJErGZmFxJC93I4U9-0B0wg' +
+ '-sbyMKGJ5j1BWTnibCklDXtWzXtuiz18EgE'
+ },
+ update_path_prefix: 'https://www.https-rulesets.org/v1/',
+ scope: '',
+ replaces_default_rulesets: true
},
- update_path_prefix: 'https://www.https-rulesets.org/v1/',
- scope: '',
- replaces_default_rulesets: true
-}];
+ {
+ name: 'DuckDuckGo Smarter Encryption',
+ format: 'bloom',
+ jwk: {
+ kty: 'RSA',
+ e: 'AQAB',
+ n: '1cwvFQu3Kw-Pz8bcEFuV5zx0ZheDsc4Tva7Qv6BL90_sDLqCW79Y543nDkPtNVfFH_89pt2kSPp_IcS5XnYiw6zBQeFuILFw5JpvZt14K0s4' +
+ 'e025Q9CXfhYKIBKT9PnqihwAacjMa6rQb7RTu7XxVvqxRb3b0vx2CR40LSlYZ8H_KpeaUwq2oz-fyrI6LFTeYvbO3ZuLKeK5xV1a32xeTVMF' +
+ 'kIj3LxnQalxq-DRHfj7LRRoTnbRDW4uoDc8aVpLFliuO79jUKbobz4slpiWJ4wjKR_O6OK13HbZUiOSxi8Bms-UqBPOyzbMVpmA7lv_zWdaL' +
+ 'u1IVlVXQyLVbbrqI6llRqfHdcJoEl-eC48AofuB-relQtjTEK_hyBf7sPwrbqAarjRjlyEx6Qy5gTXyxM9attfNAeupYR6jm8LKm6TFpfWky' +
+ 'DxUmj_f5pJMBWNTomV74f8iQ2M18_KWMUDCOf80tR0t21Q1iCWdvA3K_KJn05tTLyumlwwlQijMqRkYuao-CX9L3DJIaB3VPYPTSIPUr7oi1' +
+ '6agsuamOyiOtlZiRpEvoNg2ksJMZtwnj5xhBQydkdhMW2ZpHDzcLuZlhJYZL_l3_7wuzRM7vpyA9obP92CpZRFJErGZmFxJC93I4U9-0B0wg' +
+ '-sbyMKGJ5j1BWTnibCklDXtWzXtuiz18EgE'
+ },
+ update_path_prefix: 'https://www.https-rulesets.org/ddg/',
+ scope: '',
+ }
+];
})(typeof exports === 'undefined' ? require.scopes.update_channels = {} : exports);
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/util.js b/data/extensions/https-everywhere@eff.org/background-scripts/util.js
index 5a4097c..e2b069b 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/util.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/util.js
@@ -62,11 +62,16 @@ function loadExtensionFile(url, returnType) {
/**
* Remove tailing dots from hostname, e.g. "www.example.com."
+ * Preserve port numbers if they are used
*/
-function getNormalisedHostname(hostname) {
+function getNormalisedHostname(host) {
+ let [ hostname, port ] = host.split(":");
while (hostname && hostname[hostname.length - 1] === '.' && hostname !== '.') {
hostname = hostname.slice(0, -1);
}
+ if (port) {
+ return `${hostname}:${port}`;
+ }
return hostname;
}
@@ -143,6 +148,19 @@ function ArrayBufferToString(ab) {
return string;
}
+/**
+ * Convert a string to an ArrayBuffer
+ *
+ * @param string: a string to convert
+ */
+function StringToArrayBuffer(str) {
+ var byteArray = new Uint8Array(str.length);
+ for (var i = 0; i < str.length; i++) {
+ byteArray[i] = str.charCodeAt(i);
+ }
+ return byteArray;
+}
+
Object.assign(exports, {
VERB,
@@ -158,7 +176,8 @@ Object.assign(exports, {
setDefaultLogLevel,
getDefaultLogLevel,
loadExtensionFile,
- ArrayBufferToString
+ ArrayBufferToString,
+ StringToArrayBuffer
});
})(typeof exports == 'undefined' ? require.scopes.util = {} : exports);
diff --git a/data/extensions/https-everywhere@eff.org/background-scripts/wasm.js b/data/extensions/https-everywhere@eff.org/background-scripts/wasm.js
index 3385bb7..551b1d3 100644
--- a/data/extensions/https-everywhere@eff.org/background-scripts/wasm.js
+++ b/data/extensions/https-everywhere@eff.org/background-scripts/wasm.js
@@ -3,7 +3,7 @@
(function(exports) {
const util = require('./util'),
- { RuleSets } = wasm_bindgen;
+ { RuleSets, Bloom } = wasm_bindgen;
async function initialize() {
try {
@@ -20,6 +20,7 @@ function is_enabled() {
Object.assign(exports, {
initialize,
RuleSets,
+ Bloom,
is_enabled,
});