code cleanup, better eslint rules and related test configuration
This commit is contained in:
parent
5580148632
commit
ae18079a67
35 changed files with 195 additions and 151 deletions
5
.eslintignore
Normal file
5
.eslintignore
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
node_modules/
|
||||||
|
add-on/lib/third_party/
|
||||||
|
add-on/lib/standards.js
|
||||||
|
add-on/config/js/third_party/
|
||||||
|
test.config.js
|
|
@ -7,12 +7,22 @@
|
||||||
"mocha": true
|
"mocha": true
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended"
|
"eslint:recommended"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-console": "off",
|
"no-console": "off",
|
||||||
"no-trailing-spaces": "error",
|
|
||||||
"no-unused-vars": ["error", {"varsIgnorePattern": "ignore"}],
|
"no-unused-vars": ["error", {"varsIgnorePattern": "ignore"}],
|
||||||
"semi": ["error", "always"]
|
"semi": ["error", "always"],
|
||||||
|
"indent": ["error", 4],
|
||||||
|
"eol-last": "error",
|
||||||
|
"quotes": ["error", "double"],
|
||||||
|
"comma-dangle": ["error", "only-multiline"],
|
||||||
|
"function-paren-newline": ["error"],
|
||||||
|
"max-len": ["error", {"ignoreStrings": true, "code": 100}],
|
||||||
|
"require-jsdoc": "error",
|
||||||
|
"valid-jsdoc": "error",
|
||||||
|
"prefer-const": "error",
|
||||||
|
"no-template-curly-in-string": "error",
|
||||||
|
"no-unused-expressions": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,8 @@
|
||||||
|
|
||||||
if (label === "rulesForDomains") {
|
if (label === "rulesForDomains") {
|
||||||
|
|
||||||
const matchHostNameBound = domainMatcherLib.matchHostName.bind(undefined, Object.keys(domainRules));
|
const matchHostName = domainMatcherLib.matchHostName;
|
||||||
|
const matchHostNameBound = matchHostName.bind(undefined, Object.keys(domainRules));
|
||||||
const rulesForDomains = data.map(matchHostNameBound);
|
const rulesForDomains = data.map(matchHostNameBound);
|
||||||
const domainToRuleMapping = {};
|
const domainToRuleMapping = {};
|
||||||
|
|
||||||
|
@ -113,7 +114,7 @@
|
||||||
const newHeaders = details.requestHeaders.map(function (header) {
|
const newHeaders = details.requestHeaders.map(function (header) {
|
||||||
|
|
||||||
if (header.name.indexOf("Cookie") === -1) {
|
if (header.name.indexOf("Cookie") === -1) {
|
||||||
header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cookieValue = header.value;
|
const cookieValue = header.value;
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<script src="../lib/defaults.js"></script>
|
<script src="../lib/defaults.js"></script>
|
||||||
<script src="../lib/standards.js"></script>
|
<script src="../lib/standards.js"></script>
|
||||||
<script src="../lib/storage.js"></script>
|
<script src="../lib/storage.js"></script>
|
||||||
<script src="js/lib/vue.js"></script>
|
<script src="js/third_party/vue.js"></script>
|
||||||
<script src="js/state.js"></script>
|
<script src="js/state.js"></script>
|
||||||
<script src="js/components/domain-rules.vue.js"></script>
|
<script src="js/components/domain-rules.vue.js"></script>
|
||||||
<script src="js/components/web-api-standards.vue.js"></script>
|
<script src="js/components/web-api-standards.vue.js"></script>
|
||||||
|
|
|
@ -27,10 +27,15 @@
|
||||||
|
|
||||||
<div class="form-group" v-bind:class="{ 'has-error': errorMessage }">
|
<div class="form-group" v-bind:class="{ 'has-error': errorMessage }">
|
||||||
<label for="newDomainName">Add New Domain Rule</label>
|
<label for="newDomainName">Add New Domain Rule</label>
|
||||||
<input class="form-control" v-model.trim="newDomain" placeholder="*.example.org">
|
<input
|
||||||
|
class="form-control"
|
||||||
|
v-model.trim="newDomain"
|
||||||
|
placeholder="*.example.org">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-default btn-block" @click="newDomainSubmitted">Add Rule</button>
|
<button type="submit"
|
||||||
|
class="btn btn-default btn-block"
|
||||||
|
@click="newDomainSubmitted">Add Rule</button>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
data: function () {
|
data: function () {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
const standardsCookieName = constants.cookieName;
|
const standardsCookieName = constants.cookieName;
|
||||||
|
|
||||||
const doc = window.document;
|
const doc = window.document;
|
||||||
const script = doc.createElement('script');
|
const script = doc.createElement("script");
|
||||||
const rootElm = doc.head || doc.documentElement;
|
const rootElm = doc.head || doc.documentElement;
|
||||||
|
|
||||||
// First see if we can read the standards to block out of the cookie
|
// First see if we can read the standards to block out of the cookie
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
* The `standardsToBlock` array must be a subset of all the standards
|
* The `standardsToBlock` array must be a subset of all the standards
|
||||||
* documented in data/standards.
|
* documented in data/standards.
|
||||||
*
|
*
|
||||||
* @param array standardsToBlock
|
* @param {array} standardsToBlock
|
||||||
* An array of strings, each a standard that should be blocked.
|
* An array of strings, each a standard that should be blocked.
|
||||||
* @param bool shouldLog
|
* @param {boolean} shouldLog
|
||||||
* Whether logging should be enabled.
|
* Whether logging should be enabled.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return {string}
|
||||||
* A cookie safe string encoding the above values.
|
* A cookie safe string encoding the above values.
|
||||||
*/
|
*/
|
||||||
const toCookieValue = function (standardsToBlock, shouldLog) {
|
const toCookieValue = function (standardsToBlock, shouldLog) {
|
||||||
|
@ -45,10 +45,10 @@
|
||||||
* standard names, and two, a boolean flag of whether the logging option
|
* standard names, and two, a boolean flag of whether the logging option
|
||||||
* is enabled.
|
* is enabled.
|
||||||
*
|
*
|
||||||
* @param string data
|
* @param {string} data
|
||||||
* A string created from `toCookieValue`
|
* A string created from `toCookieValue`
|
||||||
*
|
*
|
||||||
* @return [array, bool]
|
* @return {[array, bool]}
|
||||||
* An array of strings of standard names (representing standards to
|
* An array of strings of standard names (representing standards to
|
||||||
* block), and a boolean describing whether to log blocking
|
* block), and a boolean describing whether to log blocking
|
||||||
* behavior.
|
* behavior.
|
||||||
|
|
|
@ -17,7 +17,7 @@ window.WEB_API_MANAGER.defaults.lite = [
|
||||||
"WebRTC 1.0: Real-time Communication Between Browser",
|
"WebRTC 1.0: Real-time Communication Between Browser",
|
||||||
"WebGL Specification",
|
"WebGL Specification",
|
||||||
"Geometry Interfaces Module Level 1",
|
"Geometry Interfaces Module Level 1",
|
||||||
"Web Notifications",
|
"Web Notifications"
|
||||||
];
|
];
|
||||||
|
|
||||||
window.WEB_API_MANAGER.defaults.conservative = [
|
window.WEB_API_MANAGER.defaults.conservative = [
|
||||||
|
@ -35,7 +35,7 @@ window.WEB_API_MANAGER.defaults.conservative = [
|
||||||
"UI Events Specification",
|
"UI Events Specification",
|
||||||
"WebGL Specification",
|
"WebGL Specification",
|
||||||
"Web Audio API",
|
"Web Audio API",
|
||||||
"Scalable Vector Graphics (SVG) 1.1 (Second Edition)",
|
"Scalable Vector Graphics (SVG) 1.1 (Second Edition)"
|
||||||
];
|
];
|
||||||
|
|
||||||
window.WEB_API_MANAGER.defaults.aggressive = window.WEB_API_MANAGER.defaults.conservative.concat([
|
window.WEB_API_MANAGER.defaults.aggressive = window.WEB_API_MANAGER.defaults.conservative.concat([
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
|
const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
|
||||||
|
|
||||||
const escapeStringRegexp = function (aString) {
|
const escapeStringRegexp = function (aString) {
|
||||||
if (typeof aString !== 'string') {
|
if (typeof aString !== "string") {
|
||||||
throw new TypeError('Expected a string');
|
throw new TypeError("Expected a string");
|
||||||
}
|
}
|
||||||
|
|
||||||
return aString.replace(matchOperatorsRe, '\\$&');
|
return aString.replace(matchOperatorsRe, "\\$&");
|
||||||
};
|
};
|
||||||
|
|
||||||
// From https://www.npmjs.com/package/matcher
|
// From https://www.npmjs.com/package/matcher
|
||||||
|
@ -24,19 +24,19 @@
|
||||||
return reCache.get(cacheKey);
|
return reCache.get(cacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
const negated = pattern[0] === '!';
|
const negated = pattern[0] === "!";
|
||||||
|
|
||||||
if (negated) {
|
if (negated) {
|
||||||
pattern = pattern.slice(1);
|
pattern = pattern.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern = escapeStringRegexp(pattern).replace(/\\\*/g, '.*');
|
pattern = escapeStringRegexp(pattern).replace(/\\\*/g, ".*");
|
||||||
|
|
||||||
if (negated && shouldNegate) {
|
if (negated && shouldNegate) {
|
||||||
pattern = `(?!${pattern})`;
|
pattern = `(?!${pattern})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const re = new RegExp(`^${pattern}$`, 'i');
|
const re = new RegExp(`^${pattern}$`, "i");
|
||||||
re.negated = negated;
|
re.negated = negated;
|
||||||
reCache.set(cacheKey, re);
|
reCache.set(cacheKey, re);
|
||||||
|
|
||||||
|
@ -61,10 +61,23 @@
|
||||||
return prev;
|
return prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
const matchHostName = function (domainRegExes, hostName) {
|
/**
|
||||||
// of the URL being requested.
|
* Returns the match patern that matches given host name.
|
||||||
|
*
|
||||||
|
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Match_patterns
|
||||||
|
*
|
||||||
|
* @param {array} matchPatterns
|
||||||
|
* An array of strings, each describing a match patern.
|
||||||
|
* @param {string} hostName
|
||||||
|
* A string depicting a host name.
|
||||||
|
*
|
||||||
|
* @return {string|undefined}
|
||||||
|
* A match patern string that matches the hostname, or undefined if no
|
||||||
|
* patterns match.
|
||||||
|
*/
|
||||||
|
const matchHostName = function (matchPatterns, hostName) {
|
||||||
const matchingUrlReduceFunctionBound = matchingUrlReduceFunction.bind(undefined, hostName);
|
const matchingUrlReduceFunctionBound = matchingUrlReduceFunction.bind(undefined, hostName);
|
||||||
const matchingPattern = domainRegExes
|
const matchingPattern = matchPatterns
|
||||||
.filter((aRule) => aRule !== defaultKey)
|
.filter((aRule) => aRule !== defaultKey)
|
||||||
.sort()
|
.sort()
|
||||||
.reduce(matchingUrlReduceFunctionBound, undefined);
|
.reduce(matchingUrlReduceFunctionBound, undefined);
|
||||||
|
@ -72,9 +85,23 @@
|
||||||
return matchingPattern || undefined;
|
return matchingPattern || undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const matchUrl = function (domainRegExes, url) {
|
/**
|
||||||
|
* Returns the match patern that matches the host of a given url.
|
||||||
|
*
|
||||||
|
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Match_patterns
|
||||||
|
*
|
||||||
|
* @param {array} matchPatterns
|
||||||
|
* An array of strings, each describing a match patern.
|
||||||
|
* @param {string} url
|
||||||
|
* A string depicting a url.
|
||||||
|
*
|
||||||
|
* @return {string|undefined}
|
||||||
|
* A match patern string that matches the host portion of the given
|
||||||
|
* url, or undefined if no patterns match.
|
||||||
|
*/
|
||||||
|
const matchUrl = function (matchPatterns, url) {
|
||||||
const hostName = extractHostNameFromUrl(url);
|
const hostName = extractHostNameFromUrl(url);
|
||||||
return matchHostName(domainRegExes, hostName);
|
return matchHostName(matchPatterns, hostName);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.WEB_API_MANAGER.domainMatcherLib = {
|
window.WEB_API_MANAGER.domainMatcherLib = {
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/HttpHeaders
|
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/HttpHeaders
|
||||||
* @see https://w3c.github.io/webappsec-csp/
|
* @see https://w3c.github.io/webappsec-csp/
|
||||||
*
|
*
|
||||||
* @param object header
|
* @param {object} header
|
||||||
* An object describing a HTTP header
|
* An object describing a HTTP header
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return {boolean}
|
||||||
* true if the given object depicts a CSP policy with the above stated
|
* true if the given object depicts a CSP policy with the above stated
|
||||||
* properties, and false in all other cases.
|
* properties, and false in all other cases.
|
||||||
*/
|
*/
|
||||||
|
@ -63,13 +63,13 @@
|
||||||
* @see https://w3c.github.io/webappsec-csp/#strict-dynamic-usage
|
* @see https://w3c.github.io/webappsec-csp/#strict-dynamic-usage
|
||||||
* @see https://w3c.github.io/webappsec-csp/#grammardef-hash-source
|
* @see https://w3c.github.io/webappsec-csp/#grammardef-hash-source
|
||||||
*
|
*
|
||||||
* @param string cspInstruction
|
* @param {string} cspInstruction
|
||||||
* The value of a HTTP header defining a CSP instruction.
|
* The value of a HTTP header defining a CSP instruction.
|
||||||
* @param string scriptHash
|
* @param {string} scriptHash
|
||||||
* A hash value, in the form of "sha256-<some hash>", that is a valid
|
* A hash value, in the form of "sha256-<some hash>", that is a valid
|
||||||
* hash source description.
|
* hash source description.
|
||||||
*
|
*
|
||||||
* @return string|false
|
* @return {string|false}
|
||||||
* Returns false if the CSP instruction looks malformed (ie we
|
* Returns false if the CSP instruction looks malformed (ie we
|
||||||
* couldn't find either a "script-src" or "default-src" section),
|
* couldn't find either a "script-src" or "default-src" section),
|
||||||
* otherwise, a new value CSP instruction with the given hash allowed.
|
* otherwise, a new value CSP instruction with the given hash allowed.
|
||||||
|
|
|
@ -4,7 +4,13 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
window.WEB_API_MANAGER = {
|
window.WEB_API_MANAGER = {
|
||||||
constants: {
|
constants: {
|
||||||
|
// The name of the cookie that will be used to push domain
|
||||||
|
// configuration information into pages.
|
||||||
cookieName: "_wamtcstandards",
|
cookieName: "_wamtcstandards",
|
||||||
|
|
||||||
|
// The value in the packed array of options thats used to
|
||||||
|
// include the shouldLog option in the in bitfield encoded in
|
||||||
|
// the above cookie.
|
||||||
shouldLogKey: "shouldLogKey"
|
shouldLogKey: "shouldLogKey"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,10 +18,19 @@
|
||||||
|
|
||||||
const bucketSize = 8;
|
const bucketSize = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a buffer (such as a Uint8Array) to a base64 encoded string.
|
||||||
|
*
|
||||||
|
* @param {ArrayBuffer} buf
|
||||||
|
* A buffer of binary data.
|
||||||
|
*
|
||||||
|
* @return {string}
|
||||||
|
* A base64 encoded string.
|
||||||
|
*/
|
||||||
const bufferToBase64 = function (buf) {
|
const bufferToBase64 = function (buf) {
|
||||||
const binstr = Array.prototype.map.call(buf, function (ch) {
|
const binstr = Array.prototype.map.call(buf, function (ch) {
|
||||||
return String.fromCharCode(ch);
|
return String.fromCharCode(ch);
|
||||||
}).join('');
|
}).join("");
|
||||||
return window.btoa(binstr);
|
return window.btoa(binstr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,12 +70,12 @@
|
||||||
*
|
*
|
||||||
* This function is the inverse of the `unpack` function from this module.
|
* This function is the inverse of the `unpack` function from this module.
|
||||||
*
|
*
|
||||||
* @param array options
|
* @param {array} options
|
||||||
* An array of all possible options that might need to be encoded.
|
* An array of all possible options that might need to be encoded.
|
||||||
* @param array selected
|
* @param {array} selected
|
||||||
* An array containing zero or more elements from option.
|
* An array containing zero or more elements from option.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return {string}
|
||||||
* A base64 encoded string, which encodes which elements in `options`
|
* A base64 encoded string, which encodes which elements in `options`
|
||||||
* were in the provided `selected` array.
|
* were in the provided `selected` array.
|
||||||
*/
|
*/
|
||||||
|
@ -83,11 +92,11 @@
|
||||||
|
|
||||||
for (i = 0; i < numBuckets; i += 1) {
|
for (i = 0; i < numBuckets; i += 1) {
|
||||||
let bitfield = 0;
|
let bitfield = 0;
|
||||||
let currentBucket = binnedOptions[i];
|
const currentBucket = binnedOptions[i];
|
||||||
|
|
||||||
for (j = 0; j < currentBucket.length; j += 1) {
|
for (j = 0; j < currentBucket.length; j += 1) {
|
||||||
|
|
||||||
let currentOption = currentBucket[j];
|
const currentOption = currentBucket[j];
|
||||||
if (selected.indexOf(currentOption) !== -1) {
|
if (selected.indexOf(currentOption) !== -1) {
|
||||||
bitfield |= 1 << j;
|
bitfield |= 1 << j;
|
||||||
}
|
}
|
||||||
|
@ -108,13 +117,13 @@
|
||||||
*
|
*
|
||||||
* This function is the inverse of the `pack` function from this module.
|
* This function is the inverse of the `pack` function from this module.
|
||||||
*
|
*
|
||||||
* @param array options
|
* @param {array} options
|
||||||
* An array of all possible options that might need to be encoded.
|
* An array of all possible options that might need to be encoded.
|
||||||
* @param string data
|
* @param {string} data
|
||||||
* A base64 encoded string, generated from the `pack` function in
|
* A base64 encoded string, generated from the `pack` function in
|
||||||
* this module.
|
* this module.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return {array}
|
||||||
* An array of zero or more elements, each of which will be in the
|
* An array of zero or more elements, each of which will be in the
|
||||||
* options array.
|
* options array.
|
||||||
*/
|
*/
|
||||||
|
@ -131,12 +140,12 @@
|
||||||
let i, j;
|
let i, j;
|
||||||
|
|
||||||
for (i = 0; i < bitFields.length; i += 1) {
|
for (i = 0; i < bitFields.length; i += 1) {
|
||||||
let currentBitField = bitFields[i];
|
const currentBitField = bitFields[i];
|
||||||
let currentOptionsBin = binnedOptions[i];
|
const currentOptionsBin = binnedOptions[i];
|
||||||
|
|
||||||
for (j = 0; j < bucketSize; j += 1) {
|
for (j = 0; j < bucketSize; j += 1) {
|
||||||
if (currentBitField & (1 << j)) {
|
if (currentBitField & (1 << j)) {
|
||||||
let currentOption = currentOptionsBin[j];
|
const currentOption = currentOptionsBin[j];
|
||||||
result.push(currentOption);
|
result.push(currentOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,8 +85,7 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let blockingProxy;
|
const blockingProxy = new Proxy(defaultFunction, {
|
||||||
blockingProxy = new Proxy(defaultFunction, {
|
|
||||||
get: function (ignore, property) {
|
get: function (ignore, property) {
|
||||||
logKeyPath();
|
logKeyPath();
|
||||||
|
|
||||||
|
@ -189,16 +188,16 @@
|
||||||
* but with the window.WEB_API_MANAGER_PAGE object set up
|
* but with the window.WEB_API_MANAGER_PAGE object set up
|
||||||
* correctly to block the desired functions.
|
* correctly to block the desired functions.
|
||||||
*
|
*
|
||||||
* @param object standards
|
* @param {object} standards
|
||||||
* A mapping of standard names to information about those standards.
|
* A mapping of standard names to information about those standards.
|
||||||
* The structure of this object should match whats in data/standards.js
|
* The structure of this object should match whats in data/standards.js
|
||||||
* @param array standardNamesToBlock
|
* @param {array} standardNamesToBlock
|
||||||
* An array of strings, which must be a subset of the keys of the
|
* An array of strings, which must be a subset of the keys of the
|
||||||
* standards object.
|
* standards object.
|
||||||
* @param bool shouldLog
|
* @param {boolean} shouldLog
|
||||||
* Whether to log the behavior of the blocking proxy.
|
* Whether to log the behavior of the blocking proxy.
|
||||||
*
|
*
|
||||||
* @return [string, hash]
|
* @return {[string, string]}
|
||||||
* Returns an array containing two values. First, JavaScript code
|
* Returns an array containing two values. First, JavaScript code
|
||||||
* that instruments the DOM of page's its injected into to render the
|
* that instruments the DOM of page's its injected into to render the
|
||||||
* standardNamesToBlock standards un-reachable, and second, a
|
* standardNamesToBlock standards un-reachable, and second, a
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -37,8 +37,8 @@
|
||||||
{
|
{
|
||||||
"matches": ["*://*/*"],
|
"matches": ["*://*/*"],
|
||||||
"js": [
|
"js": [
|
||||||
"lib/vendor/js.cookie.js",
|
"lib/third_party/js.cookie.js",
|
||||||
"lib/vendor/sjcl.js",
|
"lib/third_party/sjcl.js",
|
||||||
"lib/init.js",
|
"lib/init.js",
|
||||||
"lib/standards.js",
|
"lib/standards.js",
|
||||||
"lib/pack.js",
|
"lib/pack.js",
|
||||||
|
@ -52,8 +52,8 @@
|
||||||
],
|
],
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"lib/vendor/URI.js",
|
"lib/third_party/URI.js",
|
||||||
"lib/vendor/sjcl.js",
|
"lib/third_party/sjcl.js",
|
||||||
"lib/init.js",
|
"lib/init.js",
|
||||||
"lib/standards.js",
|
"lib/standards.js",
|
||||||
"lib/pack.js",
|
"lib/pack.js",
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
const configureButton = doc.getElementById("config-page-link");
|
const configureButton = doc.getElementById("config-page-link");
|
||||||
const listGroupElm = doc.querySelector("ul.list-group");
|
const listGroupElm = doc.querySelector("ul.list-group");
|
||||||
|
|
||||||
const addDomainRuleToListElm = function (hostToRuleMapping, listElm, aHostName) {
|
const addRuleToList = function (hostToRuleMapping, listElm, aHostName) {
|
||||||
|
|
||||||
const domainRule = hostToRuleMapping[aHostName];
|
const domainRule = hostToRuleMapping[aHostName];
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@
|
||||||
doc.body.className = "loaded";
|
doc.body.className = "loaded";
|
||||||
|
|
||||||
const domainNames = Object.keys(response);
|
const domainNames = Object.keys(response);
|
||||||
const addDomainRuleToListElmBound = addDomainRuleToListElm.bind(undefined, response, listGroupElm);
|
const addRuleToListBound = addRuleToList.bind(undefined, response, listGroupElm);
|
||||||
|
|
||||||
domainNames.forEach(addDomainRuleToListElmBound);
|
domainNames.forEach(addRuleToListBound);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
22
gulpfile.js
22
gulpfile.js
|
@ -1,17 +1,7 @@
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
gulp.task('default', function () {
|
gulp.task("default", function () {
|
||||||
|
|
||||||
const isLineAComment = function (aLine) {
|
|
||||||
const lineStartsWithComment = (
|
|
||||||
aLine.indexOf("// ") === 0 ||
|
|
||||||
aLine.indexOf("/*") === 0 ||
|
|
||||||
aLine.indexOf(" */") === 0 ||
|
|
||||||
aLine.indexOf(" * ") === 0
|
|
||||||
);
|
|
||||||
return lineStartsWithComment;
|
|
||||||
};
|
|
||||||
|
|
||||||
const builtScriptComment = "/** This file is automatically generated. **/\n";
|
const builtScriptComment = "/** This file is automatically generated. **/\n";
|
||||||
const standardsDefDir = "data/standards";
|
const standardsDefDir = "data/standards";
|
||||||
|
@ -26,14 +16,20 @@ gulp.task('default', function () {
|
||||||
|
|
||||||
const fileContents = fs.readFileSync(standardsDefDir + "/" + next, {encoding: "utf8"});
|
const fileContents = fs.readFileSync(standardsDefDir + "/" + next, {encoding: "utf8"});
|
||||||
const standardContents = JSON.parse(fileContents);
|
const standardContents = JSON.parse(fileContents);
|
||||||
const nameParts = [standardContents.info.name, standardContents.info.subsection_name].filter(part => !!part);
|
|
||||||
|
const stdName = standardContents.info.name;
|
||||||
|
const stdSubName = standardContents.info.subsection_name;
|
||||||
|
const nameParts = [stdName, stdSubName].filter(part => !!part);
|
||||||
|
|
||||||
const standardIdentifier = nameParts.join(": ").trim();
|
const standardIdentifier = nameParts.join(": ").trim();
|
||||||
standardContents.info.identifier = standardIdentifier;
|
standardContents.info.identifier = standardIdentifier;
|
||||||
prev[standardIdentifier] = standardContents;
|
prev[standardIdentifier] = standardContents;
|
||||||
return prev;
|
return prev;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const renderedStandardsModule = builtScriptComment + `window.WEB_API_MANAGER.standards = ${JSON.stringify(combinedStandards)};`;
|
let renderedStandardsModule = builtScriptComment + "\n";
|
||||||
|
renderedStandardsModule += "window.WEB_API_MANAGER.standards = ";
|
||||||
|
renderedStandardsModule += JSON.stringify(combinedStandards) + ";";
|
||||||
|
|
||||||
fs.writeFileSync("add-on/lib/standards.js", renderedStandardsModule);
|
fs.writeFileSync("add-on/lib/standards.js", renderedStandardsModule);
|
||||||
});
|
});
|
||||||
|
|
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "web-api-manager",
|
"name": "web-api-manager",
|
||||||
"version": "0.9.2",
|
"version": "0.9.3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
"clean": "rm -Rf dist/",
|
"clean": "rm -Rf dist/",
|
||||||
"bundle": "gulp && web-ext -s add-on -a dist build --overwrite-dest",
|
"bundle": "gulp && web-ext -s add-on -a dist build --overwrite-dest",
|
||||||
"firefox": "web-ext -s add-on run",
|
"firefox": "web-ext -s add-on run",
|
||||||
"test:lint": "node_modules/eslint/bin/eslint.js test/functional/*.js test/functional/**/*.js add-on/background_scripts/*.js add-on/config/js/*.js add-on/config/js/components/*.js add-on/lib/*.js add-on/content_scripts/*.js",
|
"test:lint": "node_modules/eslint/bin/eslint.js .",
|
||||||
|
"test:lint:fix": "node_modules/eslint/bin/eslint.js --fix .",
|
||||||
"test:func": "npm run clean; npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && node_modules/mocha/bin/mocha test/functional/*.js",
|
"test:func": "npm run clean; npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && node_modules/mocha/bin/mocha test/functional/*.js",
|
||||||
"test": "npm run test:lint && npm run test:func"
|
"test": "npm run test:lint && npm run test:func"
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,7 +14,16 @@ describe("Content-Security-Protocol tests", function () {
|
||||||
|
|
||||||
const [server, testUrl] = testServer.start(function (headers) {
|
const [server, testUrl] = testServer.start(function (headers) {
|
||||||
// Add the CSP header to every request
|
// Add the CSP header to every request
|
||||||
headers['Content-Security-Protocol'] = "default-src https: data: 'unsafe-inline' 'unsafe-eval'; child-src https: data: blob:; connect-src https: data: blob:; font-src https: data:; img-src https: data: blob:; media-src https: data: blob:; object-src https:; script-src https: data: blob: 'unsafe-inline' 'unsafe-eval'; style-src https: 'unsafe-inline'; block-all-mixed-content; upgrade-insecure-requests; report-uri https://capture.condenastdigital.com/csp/pitchfork;";
|
const pitchforkCSP = [
|
||||||
|
"default-src https: data: 'unsafe-inline' 'unsafe-eval';",
|
||||||
|
"child-src https: data: blob:; connect-src https: data: blob:;",
|
||||||
|
"font-src https: data:; img-src https: data: blob:;",
|
||||||
|
"media-src https: data: blob:;",
|
||||||
|
"object-src https:;",
|
||||||
|
"script-src https: data: blob: 'unsafe-inline' 'unsafe-eval';",
|
||||||
|
"style-src https: 'unsafe-inline';",
|
||||||
|
];
|
||||||
|
headers["Content-Security-Protocol"] = pitchforkCSP.join(" ");
|
||||||
});
|
});
|
||||||
|
|
||||||
const svgTestScript = injected.testSVGTestScript();
|
const svgTestScript = injected.testSVGTestScript();
|
||||||
|
|
|
@ -21,12 +21,12 @@ module.exports.temporaryAddOnInstallScript = (function () {
|
||||||
const funcToInject = function () {
|
const funcToInject = function () {
|
||||||
|
|
||||||
const {Components, AddonManager} = window;
|
const {Components, AddonManager} = window;
|
||||||
let fileUtils = Components.utils.import('resource://gre/modules/FileUtils.jsm');
|
const fileUtils = Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||||
let FileUtils = fileUtils.FileUtils;
|
const FileUtils = fileUtils.FileUtils;
|
||||||
let callback = arguments[arguments.length - 1];
|
const callback = arguments[arguments.length - 1];
|
||||||
Components.utils.import('resource://gre/modules/AddonManager.jsm');
|
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||||
|
|
||||||
let listener = {
|
const listener = {
|
||||||
onInstallEnded: function(install, addon) {
|
onInstallEnded: function(install, addon) {
|
||||||
callback([addon.id, 0]);
|
callback([addon.id, 0]);
|
||||||
},
|
},
|
||||||
|
@ -39,7 +39,7 @@ module.exports.temporaryAddOnInstallScript = (function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let file = new FileUtils.File(arguments[0]);
|
const file = new FileUtils.File(arguments[0]);
|
||||||
|
|
||||||
AddonManager.addAddonListener(listener);
|
AddonManager.addAddonListener(listener);
|
||||||
AddonManager.installTemporaryAddon(file).catch(error => {
|
AddonManager.installTemporaryAddon(file).catch(error => {
|
||||||
|
@ -73,7 +73,7 @@ module.exports.setStandardsAsBlockedScript = (function () {
|
||||||
const funcSource = stripFuncFromSource(funcToInject.toString());
|
const funcSource = stripFuncFromSource(funcToInject.toString());
|
||||||
|
|
||||||
return function (standardsToBlock) {
|
return function (standardsToBlock) {
|
||||||
return funcSource.replace('"###REPLACE###"', JSON.stringify(standardsToBlock));
|
return funcSource.replace("\"###REPLACE###\"", JSON.stringify(standardsToBlock));
|
||||||
};
|
};
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ module.exports.start = function (callback) {
|
||||||
|
|
||||||
const httpServer = http.createServer(function (req, res) {
|
const httpServer = http.createServer(function (req, res) {
|
||||||
|
|
||||||
let headers = {"Content-Type": "text/html; charset=utf-8"};
|
const headers = {"Content-Type": "text/html; charset=utf-8"};
|
||||||
|
|
||||||
if (callback !== undefined) {
|
if (callback !== undefined) {
|
||||||
callback(headers);
|
callback(headers);
|
||||||
|
|
|
@ -49,9 +49,7 @@ module.exports.promiseSetFormAndSubmit = function (driver, values) {
|
||||||
|
|
||||||
module.exports.promiseAddonButton = function (driver) {
|
module.exports.promiseAddonButton = function (driver) {
|
||||||
driver.setContext(Context.CHROME);
|
driver.setContext(Context.CHROME);
|
||||||
return driver.wait(until.elementLocated(
|
return driver.wait(until.elementLocated(by.css("[tooltiptext='WebAPI Manager']")), 2000);
|
||||||
by.css("[tooltiptext='WebAPI Manager']")
|
|
||||||
), 2000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.promiseExtensionConfigPage = function (driver) {
|
module.exports.promiseExtensionConfigPage = function (driver) {
|
||||||
|
@ -68,9 +66,7 @@ module.exports.promiseExtensionConfigPage = function (driver) {
|
||||||
|
|
||||||
module.exports.promiseAddonConfigButton = function (driver) {
|
module.exports.promiseAddonConfigButton = function (driver) {
|
||||||
driver.setContext(Context.CHROME);
|
driver.setContext(Context.CHROME);
|
||||||
return driver.wait(until.elementLocated(
|
return driver.wait(until.elementLocated(by.id("config-page-link")), 2000);
|
||||||
by.id("config-page-link")
|
|
||||||
), 2000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.promiseSetBlockingRules = function (driver, standardsToBlock) {
|
module.exports.promiseSetBlockingRules = function (driver, standardsToBlock) {
|
||||||
|
@ -83,18 +79,18 @@ module.exports.promiseSetBlockingRules = function (driver, standardsToBlock) {
|
||||||
|
|
||||||
module.exports.promiseGetDriver = function () {
|
module.exports.promiseGetDriver = function () {
|
||||||
|
|
||||||
let driver = new webdriver.Builder()
|
const driver = new webdriver.Builder()
|
||||||
.forBrowser('firefox')
|
.forBrowser("firefox")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
driver.setContext(Context.CHROME);
|
driver.setContext(Context.CHROME);
|
||||||
|
|
||||||
let fileLocation = path.join(process.cwd(), "dist", "webapi_manager.zip");
|
const fileLocation = path.join(process.cwd(), "dist", "webapi_manager.zip");
|
||||||
|
|
||||||
// This manually installs the add-on as a temporary add-on.
|
// This manually installs the add-on as a temporary add-on.
|
||||||
// Hopefully selenium/geckodriver will get a way to do this soon:
|
// Hopefully selenium/geckodriver will get a way to do this soon:
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1298025
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1298025
|
||||||
let installAddOnPromise = driver.executeAsyncScript(
|
const installAddOnPromise = driver.executeAsyncScript(
|
||||||
injectedScripts.temporaryAddOnInstallScript(),
|
injectedScripts.temporaryAddOnInstallScript(),
|
||||||
fileLocation
|
fileLocation
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,7 +5,7 @@ let testParams;
|
||||||
try {
|
try {
|
||||||
testParams = require("../../test.config.js");
|
testParams = require("../../test.config.js");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw "Unable to load a test.config.js module in the project root. Copy test.config.example.js to test.config.js and try again";
|
throw "Unable to load a test.config.js module in the project root. Copy test.config.example.js to test.config.js.";
|
||||||
}
|
}
|
||||||
const injected = require("./lib/injected");
|
const injected = require("./lib/injected");
|
||||||
const webdriver = require("selenium-webdriver");
|
const webdriver = require("selenium-webdriver");
|
||||||
|
@ -42,15 +42,11 @@ describe("Logging into popular sites", function () {
|
||||||
return driverReference.get("https://github.com/login");
|
return driverReference.get("https://github.com/login");
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementLocated(
|
return driverReference.wait(until.elementLocated(by.name("password")), 2000);
|
||||||
by.name("password")
|
|
||||||
), 2000);
|
|
||||||
})
|
})
|
||||||
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
|
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementLocated(
|
return driverReference.wait(until.elementLocated(by.css("body.logged-in")), 2000);
|
||||||
by.css("body.logged-in")
|
|
||||||
), 2000);
|
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
driverReference.quit();
|
driverReference.quit();
|
||||||
|
@ -75,15 +71,11 @@ describe("Logging into popular sites", function () {
|
||||||
})
|
})
|
||||||
.then(() => driverReference.get("https://github.com/login"))
|
.then(() => driverReference.get("https://github.com/login"))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementLocated(
|
return driverReference.wait(until.elementLocated(by.name("password")), 2000);
|
||||||
by.name("password")
|
|
||||||
), 2000);
|
|
||||||
})
|
})
|
||||||
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
|
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementLocated(
|
return driverReference.wait(until.elementLocated(by.css("body.logged-in")), 2000);
|
||||||
by.css("body.logged-in")
|
|
||||||
), 2000);
|
|
||||||
})
|
})
|
||||||
.then(() => driverReference.executeAsyncScript(svgTestScript))
|
.then(() => driverReference.executeAsyncScript(svgTestScript))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
|
@ -123,15 +115,11 @@ describe("Logging into popular sites", function () {
|
||||||
return driverReference.get("https://www.facebook.com/");
|
return driverReference.get("https://www.facebook.com/");
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementsLocated(
|
return driverReference.wait(until.elementsLocated(by.name("email")), 5000);
|
||||||
by.name("email")
|
|
||||||
), 5000);
|
|
||||||
})
|
})
|
||||||
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
|
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementLocated(
|
return driverReference.wait(until.elementLocated(by.css("div[data-click='profile_icon']")), 10000);
|
||||||
by.css("div[data-click='profile_icon']")
|
|
||||||
), 10000);
|
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
driverReference.quit();
|
driverReference.quit();
|
||||||
|
@ -158,47 +146,38 @@ describe("Logging into popular sites", function () {
|
||||||
|
|
||||||
it("Log in", function (done) {
|
it("Log in", function (done) {
|
||||||
|
|
||||||
let driverReference;
|
let driver;
|
||||||
|
|
||||||
utils.promiseGetDriver()
|
utils.promiseGetDriver()
|
||||||
.then(function (driver) {
|
.then(function (testDriver) {
|
||||||
driverReference = driver;
|
driver = testDriver;
|
||||||
return driverReference.get("https://www.youtube.com");
|
return driver.get("https://www.youtube.com");
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementsLocated(
|
return driver.wait(until.elementsLocated(by.css("#buttons ytd-button-renderer a")), 5000);
|
||||||
by.css("#buttons ytd-button-renderer a")
|
|
||||||
), 5000);
|
|
||||||
})
|
})
|
||||||
.then(anchors => anchors[anchors.length - 1].click())
|
.then(anchors => anchors[anchors.length - 1].click())
|
||||||
.then(() => utils.pause(2000))
|
.then(() => utils.pause(2000))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementLocated(
|
return driver.wait(until.elementLocated(by.name("identifier")), 5000);
|
||||||
by.name("identifier")
|
|
||||||
), 5000);
|
|
||||||
})
|
})
|
||||||
.then(identifierElm => driverReference.wait(until.elementIsVisible(identifierElm)))
|
.then(idElm => driver.wait(until.elementIsVisible(idElm)))
|
||||||
.then(identifierElm => identifierElm.sendKeys(testParams.google.username, keys.ENTER))
|
.then(idElm => idElm.sendKeys(testParams.google.username, keys.ENTER))
|
||||||
.then(() => utils.pause(2000))
|
.then(() => utils.pause(2000))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementLocated(
|
return driver.wait(until.elementLocated(by.name("password")), 5000);
|
||||||
by.name("password")
|
|
||||||
), 5000);
|
|
||||||
})
|
})
|
||||||
.then(passwordElm => driverReference.wait(until.elementIsVisible(passwordElm)))
|
.then(passwordElm => driver.wait(until.elementIsVisible(passwordElm)))
|
||||||
.then(passwordElm => passwordElm.sendKeys(testParams.google.password, keys.ENTER))
|
.then(passwordElm => passwordElm.sendKeys(testParams.google.password, keys.ENTER))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return driverReference.wait(until.elementLocated(
|
return driver.wait(until.elementLocated(by.css("ytd-app")), 10000);
|
||||||
by.css("ytd-app")
|
|
||||||
), 10000);
|
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
driverReference.quit();
|
driver.quit();
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
.catch(function (e) {
|
.catch(function () {
|
||||||
driverReference.quit();
|
driver.quit();
|
||||||
console.log(e);
|
|
||||||
done(new Error("Was not able to log in"));
|
done(new Error("Was not able to log in"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue