lots of JSlint based cleanup

This commit is contained in:
Peter Snyder 2017-10-14 15:24:18 -05:00
parent 463b9a10b4
commit b8d2eaeca0
14 changed files with 138 additions and 95 deletions

3
.gitignore vendored
View file

@ -2,4 +2,5 @@ node_modules/
.DS_Store
*.swp
content_scripts/dist/*.js
content_scripts/dist/*.js
web-ext-artifacts/

View file

@ -1,6 +1,7 @@
Web API Manager
===
Overview
---
This extension allows users to selectively allow different hosts on the web
@ -9,6 +10,7 @@ security and privacy sensitive web users to limit the attack surface presented
to websites, and to limit websites to the functionality they actually need
to carry out user-serving purposes.
Background
---
Web browsers gain staggering numbers of new features, without their users

View file

@ -1,8 +1,9 @@
/*jslint es6: true*/
/*global chrome, browser, window, URI*/
/*global window*/
(function () {
"use strict";
const {packingLib, standards, storageLib} = window.WEB_API_MANAGER;
const {packingLib, standards, storageLib, domainMatcherLib} = window.WEB_API_MANAGER;
const rootObject = window.browser || window.chrome;
const defaultKey = "(default)";
@ -11,6 +12,9 @@
// that should be blocked on matching domains.
let domainRules;
// The extension depends on this fetch happening before the DOM on any
// pages is loaded. The Chrome and Firefox docs *do not* promise this,
// but in testing this is always the case.
storageLib.get(function (loadedDomainRules) {
domainRules = loadedDomainRules;
});
@ -18,7 +22,7 @@
// Manage the state of the browser activity, by displaying the number
// of origins / frames
const updateBrowserActionBadge = function (activeInfo) {
const {tabId, windowId} = activeInfo;
const tabId = activeInfo.tabId;
rootObject.tabs.executeScript(
tabId,
{
@ -50,39 +54,8 @@
rootObject.tabs.onActivated.addListener(updateBrowserActionBadge);
rootObject.windows.onFocusChanged.addListener(updateBrowserActionBadge);
// Inject the blocking settings for each visited domain / frame.
const extractHostFromUrl = function (url) {
const uri = URI(url);
return uri.hostname();
};
const matchingUrlReduceFunction = function (domain, prev, next) {
if (prev) {
return prev;
}
const domainRegex = new RegExp(next);
if (domainRegex.test(domain)) {
return next;
}
return prev;
};
const whichDomainRuleMatches = function (hostName) {
// of the URL being requested.
const matchingUrlReduceFunctionBound = matchingUrlReduceFunction.bind(undefined, hostName);
const matchingPattern = Object
.keys(domainRules)
.filter((aRule) => aRule !== defaultKey)
.sort()
.reduce(matchingUrlReduceFunctionBound, undefined);
return matchingPattern || defaultKey;
};
// Listen for updates to the domain rules from the config page.
rootObject.runtime.onMessage.addListener(function (request, sender, sendResponse) {
rootObject.runtime.onMessage.addListener(function (request, ignore, sendResponse) {
const [label, data] = request;
if (label === "rulesUpdate") {
domainRules = data;
@ -90,12 +63,16 @@
}
if (label === "rulesForDomains") {
const ruleForDomain = data.map(whichDomainRuleMatches);
const mapping = {};
for (let i = 0; i < ruleForDomain.length; i += 1) {
mapping[data[i]] = ruleForDomain[i];
}
sendResponse(mapping);
const matchHostNameBound = domainMatcherLib.matchHostName.bind(undefined, Object.keys(domainRules));
const rulesForDomains = data.map(matchHostNameBound);
const domainToRuleMapping = {};
data.forEach(function (aHostName, index) {
domainToRuleMapping[aHostName] = rulesForDomains[index] || defaultKey;
});
sendResponse(domainToRuleMapping);
return;
}
});
@ -106,15 +83,15 @@
};
const requestOptions = ["blocking", "responseHeaders"];
chrome.webRequest.onHeadersReceived.addListener(function (details) {
// Inject the blocking settings for each visited domain / frame.
rootObject.webRequest.onHeadersReceived.addListener(function (details) {
const url = details.url;
const hostName = extractHostFromUrl(url);
// Decide which set of blocking rules to use, depending on the host
// of the URL being requested.
const matchingDomainKey = whichDomainRuleMatches(hostName);
const standardsToBlock = domainRules[matchingDomainKey];
const matchingDomainRule = domainMatcherLib.matchUrl(Object.keys(domainRules), url);
const standardsToBlock = domainRules[matchingDomainRule || defaultKey];
const options = Object.keys(standards);
const packedValues = packingLib.pack(options, standardsToBlock);
@ -129,4 +106,4 @@
};
}, requestFilter, requestOptions);
}());
}());

View file

@ -34,9 +34,9 @@
</div>
</section>
<script src="../lib/init.js"></script>
<script src="../lib/storage.js"></script>
<script src="../content_scripts/dist/defaults.js"></script>
<script src="../content_scripts/dist/standards.js"></script>
<script src="../lib/storage.js"></script>
<script src="js/lib/vue.js"></script>
<script src="js/state.js"></script>
<script src="js/components/domain-rules.vue.js"></script>

View file

@ -1,5 +1,5 @@
/*jslint es6: true*/
/*global window, browser, Vue*/
/*jslint es6: true, this: true*/
/*global window, Vue*/
(function () {
"use strict";
@ -65,6 +65,6 @@
isDefault: function (domainName) {
return domainName === "(default)";
}
},
}
});
}());

View file

@ -1,6 +1,7 @@
/*jslint es6: true*/
/*global window, browser, Vue*/
/*jslint es6: true, this: true*/
/*global window, Vue*/
(function () {
"use strict";
const standardsDefaults = window.WEB_API_MANAGER.defaults;

View file

@ -6,25 +6,15 @@
const rootObject = (window.browser || window.chrome);
const doc = window.document;
const standards = window.WEB_API_MANAGER.standards;
const defaultConservativeRules = window.WEB_API_MANAGER.defaults.conservative;
const {storageLib, stateLib} = window.WEB_API_MANAGER;
const defaultDomain = "(default)";
const state = stateLib.generateStateObject(defaultDomain, standards);
const onSettingsLoaded = function (settingsResults) {
let loadedDomainRules;
if (Object.keys(settingsResults).length !== 0) {
loadedDomainRules = settingsResults;
} else {
loadedDomainRules = Object.create(null);
loadedDomainRules[defaultDomain] = defaultConservativeRules;
}
const onSettingsLoaded = function (loadedDomainRules) {
state.setDomainRules(loadedDomainRules);
const vm = new Vue({
el: doc.body,
data: state

View file

@ -1,6 +1,7 @@
/*jslint es6: true*/
/*jslint es6: true, this: true*/
/*global window, browser, Vue*/
(function () {
"use strict";
window.WEB_API_MANAGER.stateLib = {};
@ -12,27 +13,27 @@
domainRules: {},
domainNames: [],
selectedStandards: [],
setDomainRules: function (newDomainRules) {
this.domainRules = newDomainRules;
this.domainNames = Object.keys(newDomainRules);
this.selectedStandards = this.domainRules[this.selectedDomain];
},
setSelectedDomain: function (newDomain) {
this.selectedDomain = newDomain;
this.selectedStandards = this.domainRules[newDomain];
},
setSelectedStandards: function (selectedStandards) {
this.selectedStandards = selectedStandards;
this.domainRules[this.selectedDomain] = selectedStandards;
},
deleteDomainRule: function (domainToDelete) {
delete this.domainRules[domainToDelete];
this.domainNames = Object.keys(this.domainRules);
// If we're deleted the domain thats currently selected, then
// select the default domain.
if (this.selectedDomain === domainToDelete) {

46
lib/domainmatcher.js Normal file
View file

@ -0,0 +1,46 @@
/*jslint es6: true*/
/*global window*/
(function () {
"use strict";
const defaultKey = "(default)";
const extractHostNameFromUrl = function (url) {
const uri = window.URI(url);
return uri.hostname();
};
const matchingUrlReduceFunction = function (hostName, prev, next) {
if (prev) {
return prev;
}
const domainRegex = new RegExp(next);
if (domainRegex.test(hostName)) {
return next;
}
return prev;
};
const matchHostName = function (domainRegExes, hostName) {
// of the URL being requested.
const matchingUrlReduceFunctionBound = matchingUrlReduceFunction.bind(undefined, hostName);
const matchingPattern = domainRegExes
.filter((aRule) => aRule !== defaultKey)
.sort()
.reduce(matchingUrlReduceFunctionBound, undefined);
return matchingPattern || undefined;
};
const matchUrl = function (domainRegExes, url) {
const hostName = extractHostNameFromUrl(url);
return matchHostName(domainRegExes, hostName);
};
window.WEB_API_MANAGER.domainMatcherLib = {
matchHostName,
matchUrl
};
}());

View file

@ -1,3 +1,7 @@
/*global window*/
// Initial content script for the Web API manager extension, that creates
// the "namespace" we'll use for all the content scripts in the extension.
window.WEB_API_MANAGER = {};
(function () {
"use strict";
window.WEB_API_MANAGER = {};
}());

View file

@ -1,8 +1,9 @@
/*jslint es6: true*/
/*jslint es6: true, for: true, bitwise: true*/
/*global window*/
(function () {
"use strict";
const {btoa, atob} = window;
const bucketSize = 8;
const bufferToBase64 = function (buf) {
@ -16,7 +17,7 @@
const binstr = atob(base64);
const buf = new Uint8Array(binstr.length);
Array.prototype.forEach.call(binstr, function (ch, i) {
buf[i] = ch.charCodeAt(0);
buf[i] = ch.charCodeAt(0);
});
return buf;
};
@ -47,11 +48,13 @@
const binnedOptions = options.reduce(binToBucketSizeFunc, []);
const bitFields = new Uint8Array(numBuckets);
for (let i = 0; i < numBuckets; i += 1) {
let i, j;
for (i = 0; i < numBuckets; i += 1) {
let bitfield = 0;
let currentBucket = binnedOptions[i];
for (let j = 0; j < currentBucket.length; j += 1) {
for (j = 0; j < currentBucket.length; j += 1) {
let currentOption = currentBucket[j];
if (selected.indexOf(currentOption) !== -1) {
@ -68,7 +71,6 @@
const unpack = function (options, data) {
const numBuckets = Math.ceil(options.length / bucketSize);
const binToBucketSizeFunc = binOptionsReduceFunction.bind(undefined, bucketSize);
options.sort();
@ -77,11 +79,13 @@
const result = [];
for (let i = 0; i < bitFields.length; i += 1) {
let i, j;
for (i = 0; i < bitFields.length; i += 1) {
let currentBitField = bitFields[i];
let currentOptionsBin = binnedOptions[i];
for (let j = 0; j < bucketSize; j += 1) {
for (j = 0; j < bucketSize; j += 1) {
if (currentBitField & (1 << j)) {
let currentOption = currentOptionsBin[j];
result.push(currentOption);
@ -93,6 +97,7 @@
};
window.WEB_API_MANAGER.packingLib = {
pack, unpack
pack,
unpack
};
}());

View file

@ -3,13 +3,25 @@
(function () {
"use strict";
const browserObj = window.browser || window.chrome;
const rootObject = window.browser || window.chrome;
const defaultConservativeRules = window.WEB_API_MANAGER.defaults.conservative;
const webApiManagerKeySettingsKey = "webApiManagerDomainRules";
const storageObject = browserObj.storage;
const storageObject = rootObject.storage;
const get = function (callback) {
storageObject.local.get(webApiManagerKeySettingsKey, function (results) {
callback(results && results[webApiManagerKeySettingsKey]);
let loadedDomainRules = results && results[webApiManagerKeySettingsKey];
// If there are no currently saved domain rules, then create
// a stubbed out one, using the conservative blocking rule set.
if (!loadedDomainRules || Object.keys(loadedDomainRules).length === 0) {
loadedDomainRules = {
"(default)": defaultConservativeRules
};
}
callback(loadedDomainRules);
});
};

View file

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "WebAPI Manager",
"version": "0.5",
"version": "0.7",
"description": "Improves browser security by restricting page access to parts of the Web API.",
"icons": {
"48": "images/uic-48.png",
@ -37,20 +37,21 @@
"lib/init.js",
"lib/js.cookie.js",
"lib/storage.js",
"lib/URI.js"
"lib/URI.js",
"content_scripts/dist/defaults.js"
],
"background": {
"scripts": [
"lib/init.js",
"lib/pack.js",
"lib/storage.js",
"lib/URI.js",
"content_scripts/dist/standards.js",
"content_scripts/dist/defaults.js",
"lib/storage.js",
"background_scripts/background.js"
]
},
"options_ui": {
"page": "config/index.html",
"chrome_style": true
"page": "config/index.html"
}
}

View file

@ -1,8 +1,11 @@
/*jslint es6: true*/
/*global window*/
(function () {
"use strict";
const rootObject = window.browser || window.chrome;
const configureButton = window.document.getElementById("config-page-link");
const doc = window.document;
const configureButton = doc.getElementById("config-page-link");
configureButton.addEventListener("click", function (event) {
rootObject.runtime.openOptionsPage();
@ -21,26 +24,26 @@
const message = ["rulesForDomains", uniqueDomains];
rootObject.runtime.sendMessage(message, function (response) {
const listGroupElm = document.querySelector("ul.list-group");
const listGroupElm = doc.querySelector("ul.list-group");
const domainNames = Object.keys(response);
domainNames.forEach(function (aDomain) {
const domainRule = response[aDomain];
const liElm = document.createElement("li");
const liElm = doc.createElement("li");
liElm.className = "list-group-item";
if (domainRule !== "(default)") {
liElm.className += " list-group-item-success";
}
const spanElm = document.createElement("span");
const spanElm = doc.createElement("span");
spanElm.className = "badge";
const badgeText = document.createTextNode(domainRule);
const badgeText = doc.createTextNode(domainRule);
spanElm.appendChild(badgeText);
liElm.appendChild(spanElm);
const textElm = document.createTextNode(aDomain);
const textElm = doc.createTextNode(aDomain);
liElm.appendChild(textElm);
listGroupElm.appendChild(liElm);
});