fixed logging into sites on FF, added linting and github/youtube login tests

This commit is contained in:
Peter Snyder 2017-10-22 00:40:39 -05:00
parent 7cd3aedca4
commit 933df5a823
16 changed files with 404 additions and 101 deletions

17
.eslintrc.json Normal file
View file

@ -0,0 +1,17 @@
{
"env": {
"browser": true,
"es6": true,
"webextensions": true,
"node": true,
"mocha": true
},
"extends": [
"eslint:recommended"
],
"rules": {
"no-console": "off",
"no-trailing-spaces": "error",
"no-unused-vars": ["error", {"varsIgnorePattern": "ignore"}]
}
}

4
.gitignore vendored
View file

@ -1,5 +1,5 @@
node_modules/
.DS_Store
*.swp
dist
test.config.js
dist/

View file

@ -36,7 +36,6 @@
function (allHosts) {
if (rootObject.runtime.lastError && !allHosts) {
// rootObject.browserAction.disable();
rootObject.browserAction.setBadgeText({text: "-"});
return;
}
@ -49,7 +48,6 @@
text: numFrames,
tabId: tabId
});
rootObject.browserAction.enable();
}
);
};
@ -102,7 +100,33 @@
urls: ["<all_urls>"],
types: ["main_frame", "sub_frame"]
};
const requestOptions = ["blocking", "responseHeaders"];
const cookieRemoverRegex = new RegExp(constants.cookieName + "=.*?;");
// Make sure we never send the cookie value that contains what
// standards should be blocked to any server, anytime. In the common
// case this will be a NOOP (since the cookie is deleted after being
// read), but there are some inconsitancy / timing situations where
// making multiple, simultanious requests to the same domain where
// we might make a request before deleting the cookie, so the below
// adds at least some (incertain) extra protection.
rootObject.webRequest.onBeforeSendHeaders.addListener(function (details) {
const newHeaders = details.requestHeaders.map(function (header) {
if (header.name.indexOf("Cookie") === -1) {
header;
}
const cookieValue = header.value;
header.value = cookieValue.replace(cookieRemoverRegex, "").trim();
return header;
});
return {
requestHeaders: newHeaders
};
}, requestFilter, ["blocking", "requestHeaders"]);
// Inject the blocking settings for each visited domain / frame.
// This needs to be done syncronously, so that the DOM of the visited
@ -152,22 +176,15 @@
}
}
// If there is already a set-cookie instruction being issued,
// don't overwrite it, but add our cookie to the end of it. Otherwise,
// create a new set-cookie instruction header.
const pathForCookie = window.URI(details.url).pathname();
details.responseHeaders.push({
name: "Set-Cookie",
value: `${constants.cookieName}=${encodedOptions};path=${pathForCookie}`
});
details.responseHeaders.forEach((header) => {
console.log(header.name + ": " + header.value);
});
rootObject.cookies.set({
url: details.url,
name: constants.cookieName,
value: encodedOptions
})
return {
responseHeaders: details.responseHeaders
};
}, requestFilter, requestOptions);
}, requestFilter, ["blocking", "responseHeaders"]);
}());

View file

@ -1,10 +1,7 @@
/*jslint es6: true, this: true*/
/*global window, browser, Vue*/
(function () {
"use strict";
const defaultDomain = "(default)";
const {packingLib, standards} = window.WEB_API_MANAGER;
const generateStateObject = function (initialDomain, standards) {

View file

@ -14,13 +14,18 @@
const rootElm = doc.head || doc.documentElement;
const cookieValue = cookies2.get(standardsCookieName);
console.log(document.cookie);
if (!cookieValue) {
window.console.log(`Unable to find the Web API Manager settings for ${doc.location.href}`);
return;
}
cookies2.remove(standardsCookieName, {path: window.document.location.pathname});
console.log(document.cookie);
if (!cookieValue) {
return;
}
const [standardsToBlock, shouldLog] = cookieEncodingLib.fromCookieValue(cookieValue);
const [scriptToInject, scriptHash] = proxyBlockLib.generateScriptPayload(

View file

@ -1,5 +1,3 @@
/*jslint es6: true*/
/*global window*/
(function () {
"use strict";
const {packingLib, standards, constants} = window.WEB_API_MANAGER;
@ -38,7 +36,7 @@
// Last, replace "=" with "-" in the base64 string, to avoid
// silly ambiguities in the cookie value.
return packedValues.replace(/\=/g, "-");
return packedValues.replace(/=/g, "-");
};
/**

View file

@ -11,37 +11,37 @@
if (typeof aString !== 'string') {
throw new TypeError('Expected a string');
}
return aString.replace(matchOperatorsRe, '\\$&');
};
// From https://www.npmjs.com/package/matcher
const reCache = new Map();
const makeRe = function (pattern, shouldNegate) {
const cacheKey = pattern + shouldNegate;
if (reCache.has(cacheKey)) {
return reCache.get(cacheKey);
}
const negated = pattern[0] === '!';
if (negated) {
pattern = pattern.slice(1);
}
pattern = escapeStringRegexp(pattern).replace(/\\\*/g, '.*');
if (negated && shouldNegate) {
pattern = `(?!${pattern})`;
}
const re = new RegExp(`^${pattern}$`, 'i');
re.negated = negated;
reCache.set(cacheKey, re);
return re;
};
@ -83,5 +83,4 @@
matchHostName,
matchUrl
};
}());

View file

@ -5,7 +5,7 @@
"use strict";
window.WEB_API_MANAGER = {
constants: {
cookieName: "__wamtc",
cookieName: "_wamtcstandards",
shouldLogKey: "shouldLogKey"
}
};

View file

@ -109,7 +109,7 @@
logKeyPath();
return blockingProxy;
},
ownKeys: function (ignore) {
ownKeys: function () {
return unconfigurablePropNames;
},
has: function (ignore, property) {

104
package-lock.json generated
View file

@ -72,6 +72,12 @@
"yauzl": "2.8.0"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"ansi-styles": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
@ -92,6 +98,60 @@
"supports-color": "4.5.0"
}
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"eslint": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.8.0.tgz",
"integrity": "sha1-Ip7w41Tg5h2DfHqA/fuoJeGZgV4=",
"dev": true,
"requires": {
"ajv": "5.2.3",
"babel-code-frame": "6.26.0",
"chalk": "2.1.0",
"concat-stream": "1.6.0",
"cross-spawn": "5.1.0",
"debug": "3.1.0",
"doctrine": "2.0.0",
"eslint-scope": "3.7.1",
"espree": "3.5.1",
"esquery": "1.0.0",
"estraverse": "4.2.0",
"esutils": "2.0.2",
"file-entry-cache": "2.0.0",
"functional-red-black-tree": "1.0.1",
"glob": "7.1.2",
"globals": "9.18.0",
"ignore": "3.3.5",
"imurmurhash": "0.1.4",
"inquirer": "3.3.0",
"is-resolvable": "1.0.0",
"js-yaml": "3.10.0",
"json-stable-stringify": "1.0.1",
"levn": "0.3.0",
"lodash": "4.17.4",
"minimatch": "3.0.4",
"mkdirp": "0.5.1",
"natural-compare": "1.4.0",
"optionator": "0.8.2",
"path-is-inside": "1.0.2",
"pluralize": "7.0.0",
"progress": "2.0.0",
"require-uncached": "1.0.3",
"semver": "5.4.1",
"strip-ansi": "4.0.0",
"strip-json-comments": "2.0.1",
"table": "4.0.2",
"text-table": "0.2.0"
}
},
"first-chunk-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz",
@ -101,12 +161,41 @@
"readable-stream": "2.3.3"
}
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.3.3",
"path-is-absolute": "1.0.1"
}
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
"dev": true
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "1.1.8"
}
},
"readable-stream": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
@ -137,6 +226,15 @@
"safe-buffer": "5.1.1"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "3.0.0"
}
},
"supports-color": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
@ -2049,9 +2147,9 @@
}
},
"eslint": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.8.0.tgz",
"integrity": "sha1-Ip7w41Tg5h2DfHqA/fuoJeGZgV4=",
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.9.0.tgz",
"integrity": "sha1-doedJ0BoJhsZH+Dy9Wx0wvQgjos=",
"dev": true,
"requires": {
"ajv": "5.2.3",

View file

@ -23,9 +23,12 @@
"scripts": {
"bundle": "gulp && web-ext -s add-on -a dist build --overwrite-dest",
"firefox": "web-ext -s add-on run",
"test": "rm dist/* && npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && node_modules/mocha/bin/mocha test/functional/*.js"
"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:func": "rm dist/* && 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"
},
"devDependencies": {
"eslint": "^4.9.0",
"geckodriver": "^1.9.0",
"gulp": "^3.9.1",
"mocha": "^4.0.1",

16
test.config.example.js Normal file
View file

@ -0,0 +1,16 @@
// This file contains the parameters needed for the test suite, primarly
// login credentials for sites that should not be shared.
//
// To run the test suite, copy this file to "test.config.js" and
// fill in the below properties.
module.exports = {
github: {
username: "",
password: ""
},
google: {
username: "",
password: ""
}
};

View file

@ -1,6 +1,5 @@
"use strict";
const assert = require("assert");
const http = require("http");
const utils = require("./lib/utils");
const injected = require("./lib/injected");
@ -40,22 +39,22 @@ describe("Basic", function () {
httpServer.close();
});
describe("Blocking", function () {
describe("blocking", function () {
it("SVG Not Blocking", function (done) {
const standardsToBlock = [];
let driverReference;
utils.promiseGetDriver()
.then(function (driver, addonId) {
.then(function (driver) {
driverReference = driver;
return utils.promiseSetBlockingRules(driver, standardsToBlock);
})
.then(function (result) {
return driverReference.get(testUrl);
})
.then(() => driverReference.get(testUrl))
.then(() => driverReference.executeAsyncScript(svgTestScript))
.then(function () {
return driverReference.executeAsyncScript(svgTestScript);
driverReference.quit();
done(new Error("SVG acted as if it was being blocked"));
})
.catch(function () {
// Since we're not blocking the SVG API, then the sample
@ -65,24 +64,25 @@ describe("Basic", function () {
});
});
it("SVG Blocking", function (done) {
const standardsToBlock = ["Scalable Vector Graphics (SVG) 1.1 (Second Edition)"];
it("SVG blocking", function (done) {
const standardsToBlock = utils.constants.svgBlockRule;
let driverReference;
utils.promiseGetDriver()
.then(function (driver, addonId) {
.then(function (driver) {
driverReference = driver;
return utils.promiseSetBlockingRules(driver, standardsToBlock);
})
.then(function (result) {
return driverReference.get(testUrl);
})
.then(function () {
return driverReference.executeAsyncScript(svgTestScript);
})
.then(() => driverReference.get(testUrl))
.then(() => driverReference.executeAsyncScript(svgTestScript))
.then(function () {
driverReference.quit();
done();
})
.catch(function (e) {
driverReference.quit();
done(e);
});
});
});

View file

@ -20,28 +20,29 @@ module.exports.temporaryAddOnInstallScript = (function () {
const funcToInject = function () {
let fileUtils = Components.utils.import('resource://gre/modules/FileUtils.jsm');
let FileUtils = fileUtils.FileUtils;
let callback = arguments[arguments.length - 1];
Components.utils.import('resource://gre/modules/AddonManager.jsm');
const {Components, AddonManager} = window;
let fileUtils = Components.utils.import('resource://gre/modules/FileUtils.jsm');
let FileUtils = fileUtils.FileUtils;
let callback = arguments[arguments.length - 1];
Components.utils.import('resource://gre/modules/AddonManager.jsm');
let listener = {
onInstallEnded: function(install, addon) {
callback([addon.id, 0]);
let listener = {
onInstallEnded: function(install, addon) {
callback([addon.id, 0]);
},
onInstallFailed: function(install) {
callback([null, install.error]);
onInstallFailed: function(install) {
callback([null, install.error]);
},
onInstalled: function(addon) {
AddonManager.removeAddonListener(listener);
callback([addon.id, 0]);
}
onInstalled: function(addon) {
AddonManager.removeAddonListener(listener);
callback([addon.id, 0]);
}
};
let file = new FileUtils.File(arguments[0]);
let file = new FileUtils.File(arguments[0]);
AddonManager.addAddonListener(listener);
AddonManager.installTemporaryAddon(file).catch(error => {
AddonManager.addAddonListener(listener);
AddonManager.installTemporaryAddon(file).catch(error => {
Components.utils.reportError(error);
callback([null, error]);
});
@ -84,8 +85,8 @@ module.exports.testSVGTestScript = (function () {
};
const funcSource = stripFuncFromSource(funcToInject.toString());
return function (standardsToBlock) {
return function () {
return funcSource;
};
};
}());

View file

@ -6,18 +6,51 @@ require("geckodriver");
const firefox = require("selenium-webdriver/firefox");
const webdriver = require("selenium-webdriver");
const FxRunnerUtils = require("fx-runner/lib/utils");
const injectedScripts = require("./injected");
const fs = require("fs");
const By = webdriver.By;
const by = webdriver.By;
const Context = firefox.Context;
const until = webdriver.until;
const keys = webdriver.Key;
const path = require("path");
module.exports.constants = {
svgBlockRule: ["Scalable Vector Graphics (SVG) 1.1 (Second Edition)"]
};
module.exports.pause = function (ms = 2000) {
return new Promise(function (resolve) {
setTimeout(resolve, ms)
});
};
module.exports.promiseSetFormAndSubmit = function (driver, values) {
driver.setContext(Context.CONTENT);
const numberOfPairs = values.length;
const setFormValue = function (index = 0) {
const [name, value] = values[index];
if (index === numberOfPairs - 1) {
return driver.findElement(by.name(name))
.sendKeys(value, keys.ENTER);
} else {
return driver.findElement(by.name(name))
.sendKeys(value)
.then(() => setFormValue(index + 1));
}
};
return setFormValue();
};
module.exports.promiseAddonButton = function (driver) {
driver.setContext(Context.CHROME);
return driver.wait(until.elementLocated(
By.css("[tooltiptext='WebAPI Manager']")
by.css("[tooltiptext='WebAPI Manager']")
), 2000);
};
@ -36,7 +69,7 @@ module.exports.promiseExtensionConfigPage = function (driver) {
module.exports.promiseAddonConfigButton = function (driver) {
driver.setContext(Context.CHROME);
return driver.wait(until.elementLocated(
By.id("config-page-link")
by.id("config-page-link")
), 2000);
};
@ -48,7 +81,7 @@ module.exports.promiseSetBlockingRules = function (driver, standardsToBlock) {
.then(driver.executeAsyncScript(setStandardsScript));
};
module.exports.promiseGetDriver = function (callback) {
module.exports.promiseGetDriver = function () {
let driver = new webdriver.Builder()
.forBrowser('firefox')
@ -74,6 +107,7 @@ module.exports.promiseGetDriver = function (callback) {
});
}
driver.setContext(Context.CONTENT);
return Promise.resolve(driver, result[0]);
});
};

View file

@ -1,30 +1,148 @@
"use strict";
let assert = require("assert");
let utils = require("./lib/utils");
const utils = require("./lib/utils");
let testParams
try {
testParams = require("../../test.config.js");
} 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";
}
const injected = require("./lib/injected");
const webdriver = require("selenium-webdriver");
const keys = webdriver.Key;
const by = webdriver.By;
const until = webdriver.until;
describe("Test logging into popular sites", function () {
this.timeout = function () {
return 10000;
};
describe("Logging into popular sites", function () {
describe("GitHub", function () {
it("Log into site", function (done) {
const formValues = [
["login", testParams.github.username],
["password", testParams.github.password]
];
this.timeout = function () {
return 10000;
};
it("Log in", function (done) {
let driverReference;
const standardsToBlock = ["Beacon"];
let driver;
utils.promiseGetDriver()
.then(function (driver, addonId) {
driver = driver;
return utils.promiseSetBlockingRules(driver, standardsToBlock);
.then(function (driver) {
driverReference = driver;
return driverReference.get("https://github.com/login");
})
.then(function () {
return driverReference.wait(until.elementLocated(
by.name("password")
), 2000);
})
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
.then(function () {
return driverReference.wait(until.elementLocated(
by.css("body.logged-in")
), 2000);
})
.then(function () {
driverReference.quit();
done();
})
.catch(function () {
driverReference.quit();
done(new Error("Was not able to log in"));
});
});
it("Log in with SVG blocking", function (done) {
const standardsToBlock = utils.constants.svgBlockRule;
const svgTestScript = injected.testSVGTestScript();
let driverReference;
utils.promiseGetDriver()
.then(function (driver) {
driverReference = driver;
return utils.promiseSetBlockingRules(driver, standardsToBlock);
})
.then(() => driverReference.get("https://github.com/login"))
.then(function () {
return driverReference.wait(until.elementLocated(
by.name("password")
), 2000);
})
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
.then(function () {
return driverReference.wait(until.elementLocated(
by.css("body.logged-in")
), 2000);
})
.then(() => driverReference.executeAsyncScript(svgTestScript))
.then(function () {
driverReference.quit();
done();
})
.catch(function (e) {
driverReference.quit();
done(e);
});
});
});
describe("YouTube", function () {
this.timeout = function () {
return 20000;
};
it("Log in", function (done) {
let driverReference;
utils.promiseGetDriver()
.then(function (driver) {
driverReference = driver;
return driverReference.get("https://www.youtube.com");
})
.then(function () {
return driverReference.wait(until.elementsLocated(
by.css("#buttons ytd-button-renderer a")
), 2000);
})
.then(anchors => anchors[anchors.length - 1].click())
.then(() => utils.pause(2000))
.then(function () {
return driverReference.wait(until.elementLocated(
by.name("identifier")
), 3000);
})
.then(identifierElm => driverReference.wait(until.elementIsVisible(identifierElm)))
.then(identifierElm => identifierElm.sendKeys(testParams.google.username, keys.ENTER))
.then(() => utils.pause(2000))
.then(function () {
return driverReference.wait(until.elementLocated(
by.name("password")
), 3000);
})
.then(passwordElm => driverReference.wait(until.elementIsVisible(passwordElm)))
.then(passwordElm => passwordElm.sendKeys(testParams.google.password, keys.ENTER))
.then(function () {
return driverReference.wait(until.elementLocated(
by.css("ytd-app")
), 40000);
})
.then(function () {
driverReference.quit();
done();
})
.catch(function (e) {
driverReference.quit();
console.log(e);
done(new Error("Was not able to log in"));
});
// .then(_ => utils.promiseAddonConfigButton(driver))
// .then(function (configButton) {
// configButton.click();
// });
});
});
});