Microsoft has acquired GitHub. Decentraleyes has left GitHub. Welcome to its new home!

To participate, please register, or sign in with an existing GitLab.com, Bitbucket, or GitHub account.

Past contributions on GitHub? Be sure to reclaim your Comments, Issues, and Pull Requests.

...
 
Commits (47)
locale
data
preferences
webextension
{
"env": {
"es6": true
},
"globals": {
"exports": true,
"module": true,
"require": true,
"Services": true
},
"extends": [
"eslint:recommended",
"plugin:no-unsanitized/DOM"
],
"overrides": {
"files": [
"test/*"
],
"rules": {
"brace-style": "off",
"function-paren-newline": "off",
"max-len": "off"
}
},
"plugins": [
"no-unsanitized"
],
"rules": {
"array-bracket-newline": "error",
"array-bracket-spacing": "error",
"arrow-body-style": "error",
"arrow-parens": "error",
"arrow-spacing": "error",
"block-spacing": "error",
"brace-style": "error",
"camelcase": "error",
"comma-spacing": "error",
"comma-style": "error",
"computed-property-spacing": "error",
"consistent-this": "error",
"curly": "error",
"eol-last": "error",
"eqeqeq": "error",
"func-call-spacing": "error",
"function-paren-newline": "error",
"generator-star-spacing": "error",
"indent": [
"error",
4
],
"key-spacing": "error",
"keyword-spacing": "error",
"linebreak-style": [
"error",
"unix"
],
"new-parens": "error",
"no-array-constructor": "error",
"no-bitwise": "error",
"no-confusing-arrow": "error",
"no-continue": "error",
"no-duplicate-imports": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-implicit-coercion": "error",
"no-implied-eval": "error",
"no-invalid-this": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-loop-func": "error",
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-multiple-empty-lines": [
"error", {
"max": 1,
"maxEOF": 1,
"maxBOF": 0
}
],
"max-len": [
"error", {
"code": 120
}
],
"no-negated-condition": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-proto": "error",
"no-return-assign": "error",
"no-return-await": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow-restricted-names": "error",
"no-tabs": "error",
"no-ternary": "error",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-undef-init": "error",
"no-unmodified-loop-condition": "error",
"no-unused-expressions": "error",
"no-useless-call": "error",
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-void": "error",
"no-warning-comments": "warn",
"no-whitespace-before-property": "error",
"no-with": "error",
"object-curly-spacing": "error",
"object-shorthand": [
"error",
"consistent-as-needed"
],
"operator-assignment": "error",
"operator-linebreak": "error",
"prefer-numeric-literals": "error",
"prefer-promise-reject-errors": "error",
"quote-props": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
"quotes": [
"error",
"single"
],
"rest-spread-spacing": "error",
"require-await": "error",
"semi": "error",
"semi-spacing": "error",
"semi-style": "error",
"space-before-blocks": "error",
"space-before-function-paren": "error",
"space-in-parens": "error",
"space-infix-ops": "error",
"space-unary-ops": "error",
"strict": [
"error",
"global"
],
"switch-colon-spacing": "error",
"symbol-description": "error",
"template-curly-spacing": "error",
"template-tag-spacing": "error",
"unicode-bom": "error",
"vars-on-top": "error",
"wrap-regex": "error",
"yield-star-spacing": "error",
"yoda": "error"
}
}
data/_audit/node_modules
data/_audit/report.txt
.jpmignore
*.xpi
.eslintignore
.eslintrc
.git
.gitignore
.idea
*.xpi
.jpmignore
data/_audit/.eslintrc
data/_audit/node_modules
data/_audit/report.txt
test
.git
Decentraleyes
Decentraleyes (Legacy)
=============
A [web browser extension](https://decentraleyes.org) that emulates Content Delivery Networks locally by intercepting requests, finding the required resource and injecting it into the environment. This all happens instantaneously, automatically, and no prior configuration is required. Feel free to use this [testing utility](https://decentraleyes.org/test) to see if it's properly installed, enabled, and correctly configured.
A [web browser extension](https://decentraleyes.org) that emulates Content Delivery Networks to improve your online privacy. It intercepts traffic, finds supported resources locally, and injects them into the environment. All of this happens automatically, so no prior configuration is required. Feel free to use the following [testing utility](https://decentraleyes.org/test/) to find out if you are properly protected. For more information, please read this [basic introduction](https://git.synz.io/Synzvato/decentraleyes/wikis/Simple-Introduction).
> **Note:** Decentraleyes is no silver bullet, but it does prevent a lot of websites from making you send these kinds of requests. Ultimately, you can make Decentraleyes block requests for any missing CDN resources, too.
## Roadmap
Now that there's a solid, Mozilla approved, foundation, it's time to move forward. Mobility, extensibility (through support for community-powered resource packages), and usability, will be the main points of attention during this phase.
#### Essential Next Steps
* Start work on a resource bundle standard, to allow users to create and import custom resources. With support for these bundles in place, Decentraleyes will still work out of the box, but can be extended if needed.
* To keep this add-on from turning into bloatware, it's important to find out which versions of which libraries are most commonly used on websites, so that less popular resources can be removed from the default bundle.
#### Planned Features
* Advanced policy management for users who block requests for missing resources.
* Smarter resource version interpretation for handling dynamic notations.
* A minimalistic and non-essential graphical user interface.
* Support for custom, importable, library repositories.
> **Note:** These long-term goals are subjective to change, and can be discussed. That is, as long as the suggestions do not conflict with the ultimate goal of realizing a free and open standard for exchanging web resource bundles.
## Submitting Translations
Do you master a non-supported language? Please help out by translating this add-on on [Crowdin](https://crowdin.com/project/decentraleyes).
## Contributing Code
Suggestions in the form of **Issues** and contributions in the form of **Pull Requests** are highly welcome. You can also use the contact details and PGP key on the add-on [download page](https://addons.mozilla.org/firefox/addon/decentraleyes) to get in touch.
Suggestions in the form of **Issues**, and contributions in the form of **Merge Requests**, are highly welcome. Code **Forks** can be requested from within issues, or via email. You can use the contact details and public PGP key on the extension's [contact page](https://decentraleyes.org/contact/) to get in touch.
#### Prerequisites
* Jetpack Manager [jpm](https://developer.mozilla.org/Add-ons/SDK/Tools/jpm#Installation) (a Node-based replacement for cfx).
* Firefox version 38 or later. *If you need to work with earlier versions of Firefox, you'll need to use the old cfx tool. See instructions for [getting started with cfx](https://developer.mozilla.org/Add-ons/SDK/Tutorials/Getting_started).
* [Jetpack Manager](https://developer.mozilla.org/Add-ons/SDK/Tools/jpm#Installation) ```v1.3.1``` *(or higher)*.
* Mozilla Firefox 38 *(or higher)*.
> **Note:** If you want to contribute to the Firefox Quantum extension, please check out the ```master``` branch. If you are looking for the Chromium-compatible codebase, please see the ```experimental``` branch.
#### Build Instructions (Unix)
#### Building the Code (*nix)
git clone https://github.com/Synzvato/decentraleyes
git clone https://git.synz.io/Synzvato/decentraleyes --branch legacy
cd decentraleyes
jpm xpi
> **Important:** All commits since 26 October 2016 are signed with GPG. It's likely best to ignore unsigned commits, unless you really know what you're doing. Please send an email if you have any questions or security concerns.
> **Important:** All tagged commits since 26 October 2016 are signed with GPG. It's likely best to ignore unsigned commits, unless you really know what you're doing. Please send an email if you have any questions or security concerns.
## Submitting Translations
Do you master a non-supported language? Please help out by translating this add-on on [Crowdin](https://crowdin.com/project/decentraleyes).
## License
......
locale decentraleyes ar locale/ar/
locale decentraleyes bg locale/bg/
locale decentraleyes cs locale/cs/
locale decentraleyes da locale/da/
locale decentraleyes de locale/de/
locale decentraleyes en-GB locale/en-GB/
locale decentraleyes en-US locale/en-US/
locale decentraleyes eo locale/eo/
locale decentraleyes es locale/es/
locale decentraleyes et locale/et/
locale decentraleyes fi locale/fi/
locale decentraleyes fr locale/fr/
locale decentraleyes he locale/he/
locale decentraleyes id locale/id/
locale decentraleyes is locale/is/
locale decentraleyes it locale/it/
locale decentraleyes ja locale/ja/
locale decentraleyes ko locale/ko/
locale decentraleyes nl locale/nl/
locale decentraleyes pl locale/pl/
locale decentraleyes pt-BR locale/pt-BR/
locale decentraleyes pt-PT locale/pt-PT/
locale decentraleyes ro locale/ro/
locale decentraleyes ru locale/ru/
locale decentraleyes sv-SE locale/sv-SE/
locale decentraleyes sr locale/sr/
locale decentraleyes sv locale/sv/
locale decentraleyes tr locale/tr/
locale decentraleyes zh-CN locale/zh-CN/
locale decentraleyes zh-TW locale/zh-TW/
{
"env": {
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"array-bracket-newline": "error",
"array-bracket-spacing": "error",
"arrow-body-style": "error",
"arrow-parens": "error",
"arrow-spacing": "error",
"block-spacing": "error",
"brace-style": "error",
"camelcase": "error",
"comma-spacing": "error",
"comma-style": "error",
"computed-property-spacing": "error",
"consistent-this": "error",
"curly": "error",
"eol-last": "error",
"eqeqeq": "error",
"func-call-spacing": "error",
"function-paren-newline": "error",
"generator-star-spacing": "error",
"indent": [
"error",
4
],
"key-spacing": "error",
"keyword-spacing": "error",
"linebreak-style": [
"error",
"unix"
],
"new-cap": "error",
"new-parens": "error",
"no-array-constructor": "error",
"no-bitwise": "error",
"no-confusing-arrow": "error",
"no-console": "off",
"no-continue": "error",
"no-duplicate-imports": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-implicit-coercion": "error",
"no-implied-eval": "error",
"no-invalid-this": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-loop-func": "error",
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-multiple-empty-lines": [
"error", {
"max": 1,
"maxEOF": 1,
"maxBOF": 0
}
],
"no-negated-condition": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-proto": "error",
"no-return-assign": "error",
"no-return-await": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow-restricted-names": "error",
"no-tabs": "error",
"no-ternary": "error",
"no-trailing-spaces": "error",
"no-undef-init": "error",
"no-unmodified-loop-condition": "error",
"no-unused-expressions": "error",
"no-use-before-define": "error",
"no-useless-call": "error",
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-void": "error",
"no-warning-comments": "warn",
"no-whitespace-before-property": "error",
"no-with": "error",
"object-curly-spacing": "error",
"object-shorthand": [
"error",
"consistent-as-needed"
],
"operator-assignment": "error",
"operator-linebreak": "error",
"prefer-numeric-literals": "error",
"prefer-promise-reject-errors": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
"quote-props": "error",
"quotes": [
"error",
"single"
],
"require-await": "error",
"rest-spread-spacing": "error",
"semi": "error",
"semi-spacing": "error",
"semi-style": "error",
"space-before-blocks": "error",
"space-before-function-paren": "error",
"space-in-parens": "error",
"space-infix-ops": "error",
"space-unary-ops": "error",
"spaced-comment": "error",
"strict": [
"error",
"global"
],
"switch-colon-spacing": "error",
"symbol-description": "error",
"template-curly-spacing": "error",
"template-tag-spacing": "error",
"unicode-bom": "error",
"wrap-regex": "error",
"yield-star-spacing": "error",
"yoda": "error"
}
}
INTRODUCTION
Introduction
------------
This script (first introduced in Decentraleyes v1.1.5) should make reviewing this extension a lot easier than it used to be. It's open source and open for scrutiny, and it automatically compares the bundled libraries (resources) to their original sources (after removing any source mapping URLs).
This audit script allows any user and extension reviewer to verify the integrity of the bundled resources. It automatically, and transparently, compares all bundled libraries to their original sources.
FOR NON-LINUX USERS
-------------------
This usage guide is tailored to Linux based operating systems. If you're on a different type of system, the easiest direct solution might be to launch a free Linux box with Node.js pre-installed on Red Hat OpenShift. You can then SSH into it (after adding your own machine's public key to your account).
Having said that, every terminal command in the usage guide below comes with a description, so it should not be too hard to get this done on practically any type of configuration.
USAGE INSTRUCTIONS
Usage Instructions (Unix)
------------------
1. Make sure you have Node.js installed on your machine (or install it).
1. Make sure you have Node.js installed on your machine.
2. Open up a terminal and 'cd' into this directory.
Description: Navigate to this directory.
2. Open up a terminal and ```cd``` into this directory.
3. Execute 'npm install' to fetch any dependencies.
3. Execute ```npm install``` to fetch any dependencies.
4. Run the audit script by executing 'node run'.
Description: Run the script through Node.js and view the output.
4. Run the audit script by executing ```node run```.
Note: If you'd like to store the report, run 'node run > report.txt'.
Note description: It's possible to write the console output to a file.
**Note:** If you'd like to save the report, run ```node run > report.txt```.
\ No newline at end of file
{
"name": "decentraleyes-audit",
"version": "1.4.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"source-map-url": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
}
}
}
{
"name": "decentraleyes-audit",
"version": "1.4.0",
"version": "1.4.1",
"author": "Thomas Rientjes",
"license": "MPL-2.0",
"description": "Library audit tool for Decentraleyes.",
......
......@@ -15,12 +15,11 @@
* Imports
*/
var fileSystem, crypto, http, path, sourceMappingURL;
var fileSystem, crypto, https, sourceMappingURL;
fileSystem = require('fs');
crypto = require('crypto');
https = require('https');
path = require('path');
sourceMappingURL = require('source-map-url');
......@@ -31,21 +30,18 @@ sourceMappingURL = require('source-map-url');
var localResourceLocation = '../resources';
var localResourceLocationLength = localResourceLocation.length;
var localResourcePaths = [];
var comparedResourceAmount = 0;
var resourceAmount = 0;
/**
* Functions
*/
function _fetchLocalResourcePaths(folderPath) {
function _fetchLocalResourcePaths (folderPath) {
fileSystem.readdirSync(folderPath).forEach(function (resourceName) {
if (resourceName === '_audit') {
return localResourcePaths;
}
var resourcePath = folderPath + '/' + resourceName;
var resourcePath = `${folderPath}/${resourceName}`;
var resourceStatistics = fileSystem.statSync(resourcePath);
if (resourceStatistics && resourceStatistics.isDirectory()) {
......@@ -59,7 +55,7 @@ function _fetchLocalResourcePaths(folderPath) {
return localResourcePaths;
}
function _getLocalResourceContents(fileLocation, callback) {
function _getLocalResourceContents (fileLocation, callback) {
fileSystem.exists(fileLocation, function (exists) {
......@@ -75,7 +71,7 @@ function _getLocalResourceContents(fileLocation, callback) {
var localFileContents = buffer.toString('utf8', 0, buffer.length);
fileSystem.close(fileDescriptor);
fileSystem.close(fileDescriptor, function () {});
callback(localFileContents);
});
});
......@@ -85,16 +81,16 @@ function _getLocalResourceContents(fileLocation, callback) {
});
}
function _getRemoteResourceContents(remoteResourceRoute, callback) {
function _getRemoteResourceContents (remoteResourceRoute, callback) {
var resourceURL = 'https://ajax.googleapis.com/ajax/libs/' + remoteResourceRoute;
var resourceURL = `https://ajax.googleapis.com/ajax/libs/${remoteResourceRoute}`;
https.get(resourceURL, function (response) {
var resourceContents = '';
response.on('data', function (chunk) {
resourceContents = resourceContents + chunk;
resourceContents += chunk;
});
response.on('end', function () {
......@@ -105,20 +101,20 @@ function _getRemoteResourceContents(remoteResourceRoute, callback) {
} else {
resourceURL = 'https://cdnjs.cloudflare.com/ajax/libs/' + remoteResourceRoute;
resourceURL = `https://cdnjs.cloudflare.com/ajax/libs/${remoteResourceRoute}`;
https.get(resourceURL, function (response) {
resourceContents = '';
response.on('data', function (chunk) {
resourceContents = resourceContents + chunk;
resourceContents += chunk;
});
response.on('end', function () {
if (response.statusCode !== 200) {
throw 'Error: Resource ' + remoteResourceRoute + ' could not be fetched.';
throw `Error: Resource ${remoteResourceRoute} could not be fetched.`;
}
callback(resourceContents, resourceURL);
......@@ -133,7 +129,7 @@ function _getRemoteResourceContents(remoteResourceRoute, callback) {
});
}
function _hashFileContents(fileContents) {
function _hashFileContents (fileContents) {
var hash;
......@@ -146,7 +142,27 @@ function _hashFileContents(fileContents) {
return hash.read();
}
function _compareResources(localResourceContents, remoteResourceContents, URL) {
function _showCompletedMessage () {
console.log();
console.log(' *** FILE INTEGRITY CHECKS COMPLETED');
console.log(` *** ${resourceAmount}/${resourceAmount} RESOURCES WERE ANALYZED`);
console.log();
}
function _incrementComparedResourceAmount () {
comparedResourceAmount++;
if (comparedResourceAmount === resourceAmount) {
setTimeout(function () {
_showCompletedMessage();
}, 500);
}
}
function _compareResources (localResourceContents, remoteResourceContents, URL) {
var hasSourceMappingURL = sourceMappingURL.existsIn(remoteResourceContents);
var sourceMappingNotice = '[ ] REMOTE RESOURCE HAD SOURCE MAPPING URL';
......@@ -162,8 +178,8 @@ function _compareResources(localResourceContents, remoteResourceContents, URL) {
var localResourceHash = _hashFileContents(localResourceContents);
var remoteResourceHash = _hashFileContents(remoteResourceContents);
console.log('RESOURCE HASH (SHA512): ' + localResourceHash);
console.log('RESOURCE HASH (SHA512): ' + remoteResourceHash);
console.log(`RESOURCE HASH (SHA512): ${localResourceHash}`);
console.log(`RESOURCE HASH (SHA512): ${remoteResourceHash}`);
var fileHashesMatch = (localResourceHash === remoteResourceHash);
......@@ -176,14 +192,8 @@ function _compareResources(localResourceContents, remoteResourceContents, URL) {
console.log();
console.log('[X] LOCAL AND REMOTE RESOURCE HASHES MATCH');
console.log(sourceMappingNotice);
}
function _showCompletedMessage() {
console.log();
console.log(' *** FILE INTEGRITY CHECKS COMPLETED');
console.log(' *** ' + resourceAmount + '/' + resourceAmount + ' RESOURCES WERE ANALYZED');
console.log();
_incrementComparedResourceAmount();
}
/**
......@@ -197,7 +207,7 @@ resourceAmount = localResourcePaths.length;
* Script
*/
localResourcePaths.forEach(function (resourcePath, index) {
localResourcePaths.forEach(function (resourcePath) {
var resourceRoute = resourcePath.substr(localResourceLocationLength + 1);
resourceRoute = resourceRoute.substring(0, resourceRoute.length - 4);
......@@ -215,13 +225,6 @@ localResourcePaths.forEach(function (resourcePath, index) {
console.log();
console.log('------------------------------------------');
if (index === resourceAmount - 1) {
setTimeout(function () {
_showCompletedMessage();
}, 500);
}
});
});
......
......@@ -17,10 +17,9 @@
* Imports
*/
var { Cc, Ci } = require('chrome');
var {Cc, Ci} = require('chrome');
var self = require('sdk/self');
//noinspection JSUnresolvedFunction
var ioService = Cc['@mozilla.org/network/io-service;1']
.getService(Ci.nsIIOService);
......@@ -34,7 +33,7 @@ var files = require('./files');
* Constants
*/
const DELIVERY_NOTICE = '/**\n * Local delivery by Decentraleyes (' + self.version + ').\n */\n\n';
const DELIVERY_NOTICE = `/**\n * Local delivery by Decentraleyes (${self.version}).\n */\n\n`;
/**
* Variables
......@@ -46,7 +45,7 @@ var resourceData = self.data;
* Public Methods
*/
function getRedirectionURI(targetPath, characterSet, type) {
function getRedirectionURI (targetPath, characterSet, type) {
var data, dataURI, redirectionURI;
......@@ -67,9 +66,7 @@ exports.getRedirectionURI = getRedirectionURI;
* Private Methods
*/
function _loadResource(targetPath) {
var resource;
function _loadResource (targetPath) {
// Find the result inside a static path index.
if (!files[targetPath]) {
......@@ -77,24 +74,23 @@ function _loadResource(targetPath) {
}
// Attempt to load resource contents.
return resource = resourceData.load(targetPath);
return resourceData.load(targetPath);
}
function _buildDataURI(type, characterSet, data) {
function _buildDataURI (type, characterSet, data) {
var addNotice, dataURI;
//noinspection JSUnresolvedVariable
addNotice = require('sdk/simple-prefs').prefs.addNotice;
dataURI = 'data:' + type + ';charset=' + characterSet + ',';
dataURI = `data:${type};charset=${characterSet},`;
// Remove the syntax invalidation character.
data = data.substring(1);
if (!addNotice) {
dataURI = dataURI + encodeURIComponent(data);
if (addNotice) {
dataURI += encodeURIComponent(DELIVERY_NOTICE + data);
} else {
dataURI = dataURI + encodeURIComponent(DELIVERY_NOTICE + data);
dataURI += encodeURIComponent(data);
}
return dataURI;
......
......@@ -17,9 +17,11 @@
* Imports
*/
var { Class } = require('sdk/core/heritage');
var { Unknown } = require('sdk/platform/xpcom');
var { Cc, Ci, Cr } = require('chrome');
var {Class} = require('sdk/core/heritage');
var {Unknown} = require('sdk/platform/xpcom');
var {Cc, Ci, Cr} = require('chrome');
var main = require('./main');
/**
* Gets and sets add-on specific preferences.
......@@ -33,7 +35,6 @@ var simplePreferences = require('sdk/simple-prefs');
*/
var simpleStorage = require('sdk/simple-storage');
//noinspection JSUnresolvedFunction
var observerService = Cc['@mozilla.org/observer-service;1']
.getService(Ci.nsIObserverService);
......@@ -53,15 +54,15 @@ var storage = simpleStorage.storage;
var Interceptor = new Class({
extends: Unknown,
interfaces: ['nsIObserver'],
topic: 'http-on-modify-request',
'extends': Unknown,
'interfaces': ['nsIObserver'],
'topic': 'http-on-modify-request',
register: function () {
'register': function () {
observerService.addObserver(this, this.topic, false);
},
unregister: function () {
'unregister': function () {
observerService.removeObserver(this, this.topic);
},
......@@ -69,9 +70,9 @@ var Interceptor = new Class({
* Called whenever an HTTP request is made.
* @param httpChannel
*/
observe: function (httpChannel) {
'observe': function (httpChannel) {
var validCandidate, target, characterSet, redirectionURI;
var validCandidate, target, characterSet, redirectionURI, initiatorDomain;
// Enable runtime discovery.
httpChannel.QueryInterface(Ci.nsIHttpChannel);
......@@ -83,8 +84,10 @@ var Interceptor = new Class({
return;
}
// Remove referer header from request.
// Remove sensitive headers from the request.
httpChannel.setRequestHeader('Referer', null, false);
httpChannel.setRequestHeader('Origin', null, false);
httpChannel.setRequestHeader('Cookie', null, false);
// Convert the original request URI to a local target.
target = requestAnalyzer.getLocalTarget(httpChannel.URI.host, httpChannel.URI.path);
......@@ -103,28 +106,28 @@ var Interceptor = new Class({
}
// Fix for reported edge-case issues with specific websites.
var initiatorDomain =
httpChannel.loadInfo && httpChannel.loadInfo.loadingDocument && httpChannel.loadInfo.loadingDocument.domain ||
initiatorDomain =
httpChannel.loadInfo && httpChannel.loadInfo.loadingDocument &&
httpChannel.loadInfo.loadingDocument.domain ||
httpChannel.referrer && httpChannel.referrer.host;
if (storage.taintedDomains[initiatorDomain] || /yandex\./.test(initiatorDomain)) {
if (storage.taintedDomains[initiatorDomain] || (/yandex\./).test(initiatorDomain)) {
return this.handleMissingCandidate(httpChannel);
}
// Redirect the HTTP channel to the the local destination.
httpChannel.redirectTo(redirectionURI);
//noinspection JSUnresolvedVariable
preferences.amountInjected++;
main.broadcastInjection();
},
/**
* Called when a valid candidate cannot be injected.
* @param httpChannel
*/
handleMissingCandidate: function (httpChannel) {
'handleMissingCandidate': function (httpChannel) {
//noinspection JSUnresolvedVariable
if (preferences.blockMissing) {
httpChannel.cancel(Cr.NS_ERROR_NOT_AVAILABLE);
}
......
......@@ -17,12 +17,15 @@
* Imports
*/
var { Class } = require('sdk/core/heritage');
var { Unknown, Factory } = require('sdk/platform/xpcom');
var { Cc, Ci, Cu } = require('chrome');
var {Class} = require('sdk/core/heritage');
var {Unknown, Factory} = require('sdk/platform/xpcom');
var {Cc, Ci, Cu} = require('chrome');
var xpcom = require('sdk/platform/xpcom');
var categoryManager = Cc['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager);
/**
* Resource version mappings.
* @var {object} mappings
......@@ -35,10 +38,6 @@ var mappings = require('./mappings');
*/
var simpleStorage = require('sdk/simple-storage');
//noinspection JSUnresolvedFunction
var categoryManager = Cc['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager);
/**
* Constants
*/
......@@ -52,13 +51,14 @@ const REQUEST_ACCEPTATION = Ci.nsIContentPolicy.ACCEPT;
* Variables
*/
var storage = simpleStorage.storage;
var LoadWatcher, storage, undetectableTaintedDomains, factory, unload;
storage = simpleStorage.storage;
/**
* Tainted domains that are not automatically detectable.
* @var {object} undetectableTaintedDomains
*/
var undetectableTaintedDomains = {
undetectableTaintedDomains = {
'identi.ca': true,
'minigames.mail.ru': true,
......@@ -73,7 +73,7 @@ var undetectableTaintedDomains = {
Object.extend = function (destination, source) {
for (var property in source) {
for (let property in source) {
if (source.hasOwnProperty(property)) {
destination[property] = source[property];
......@@ -90,23 +90,35 @@ storage.taintedDomains = Object.extend(storage.taintedDomains, undetectableTaint
* Load Watcher Class
*/
var LoadWatcher = new Class({
LoadWatcher = new Class({
'extends': Unknown,
'interfaces': ['nsIContentPolicy'],
extends: Unknown,
interfaces: ['nsIContentPolicy'],
get wrappedJSObject() {
return this
// eslint-disable-next-line quote-props
get wrappedJSObject () {
return this;
},
register: function () {
'register': function () {
categoryManager.deleteCategoryEntry('content-policy', CONTRACT_ID, false);
categoryManager.addCategoryEntry('content-policy', CONTRACT_ID, CONTRACT_ID, false, true);
},
shouldLoad: function (contentType, contentLocation, requestOrigin, node) {
'shouldLoad': function (contentType, contentLocation, requestOrigin, node) {
let contentHost;
try {
contentHost = contentLocation.host;
} catch (exception) {
// Accept the resource load request.
return REQUEST_ACCEPTATION;
}
if (contentType == SCRIPT_CONTENT_TYPE && mappings[contentLocation.host]) {
if (contentType === SCRIPT_CONTENT_TYPE && mappings[contentHost]) {
if (node instanceof SCRIPT_ELEMENT) {
......@@ -127,22 +139,22 @@ var LoadWatcher = new Class({
* Load Watcher Factory
*/
var factory = Factory({
factory = Factory({
contract: CONTRACT_ID,
Component: LoadWatcher,
unregister: false
'contract': CONTRACT_ID,
'Component': LoadWatcher,
'unregister': false
});
/**
* Unregister
*/
var unload = require('sdk/system/unload');
unload = require('sdk/system/unload');
unload.when(function () {
function trueUnregister() {
function trueUnregister () {
categoryManager.deleteCategoryEntry('content-policy', CONTRACT_ID, false);
......
......@@ -17,15 +17,29 @@
* Imports
*/
var webextension = null;
var self = require('sdk/self');
var tabs = require('sdk/tabs');
/**
* Gets and sets add-on specific preferences.
* @var {object} simplePreferences
*/
var simplePreferences = require('sdk/simple-prefs');
var Interceptor = require('./interceptor');
var LoadWatcher = require('./load-watcher');
var preferences = require('sdk/simple-prefs').prefs;
var self = require('sdk/self');
var tabs = require("sdk/tabs");
/**
* Variables
*/
var preferences = simplePreferences.prefs;
var webextensionPort = null;
/**
* Main
* Initializations
*/
var interceptor = new Interceptor();
......@@ -33,9 +47,14 @@ var loadWatcher = new LoadWatcher();
var featurelessVersions = {
'1.3.7': true
'1.3.7': true,
'1.4.2': true
};
/**
* Main
*/
// Executed as soon as the add-on is loaded.
exports.main = function (options) {
......@@ -43,15 +62,77 @@ exports.main = function (options) {
interceptor.register();
loadWatcher.register();
// Display the release notes if desired.
if (preferences.showReleaseNotes) {
if (options.loadReason === 'install' || (options.loadReason === 'upgrade' && !featurelessVersions[self.version])) {
let loadReason = options.loadReason;
if (loadReason === 'install' || (loadReason === 'upgrade' && !featurelessVersions[self.version])) {
if (preferences['sdk.baseURI']) {
tabs.open(preferences['sdk.baseURI'] + 'static/release-notes.html');
tabs.open(`${preferences['sdk.baseURI']}static/release-notes.html`);
}
}
}
try {
webextension = require('sdk/webextension');
} catch (exception) {
return;
}
// Initialize the embedded WebExtension.
webextension.startup().then(({browser}) => {
browser.runtime.onConnect.addListener((port) => {
if (port.name === 'webextension') {
webextensionPort = port;
simplePreferences.on('', function (preferenceName) {
let content = null;
if (preferenceName === 'amountInjected') {
return;
}
if (preferenceName === 'domainWhitelist') {
let domainWhitelist = preferences['domainWhitelist'];
content = {
'whitelistedDomains': _parseDomainWhitelist(domainWhitelist)
};
} else {
content = {
[preferenceName]: preferences[preferenceName]
};
}
port.postMessage({
'subject': 'update-preferences',
'content': content
});
});
let domainWhitelist = preferences['domainWhitelist'];
port.postMessage({
'subject': 'migrate-preferences',
'content': {
'amountInjected': preferences['amountInjected'],
'blockMissing': preferences['blockMissing'],
'whitelistedDomains': _parseDomainWhitelist(domainWhitelist),
'showReleaseNotes': preferences['showReleaseNotes']
}
});
}
});
});
};
// Executed as soon as the add-on is unloaded.
......@@ -60,3 +141,40 @@ exports.onUnload = function () {
// Clean up add-on state.
interceptor.unregister();
};
// Sends injection updates to the WebExtension.
exports.broadcastInjection = function () {
if (webextensionPort !== null) {
webextensionPort.postMessage({
'subject': 'register-injection'
});
}
};
/**
* Private Methods
*/
function _parseDomainWhitelist (value) {
let whitelistedDomains = {};
value.split(';').forEach(function (domain) {
whitelistedDomains[_normalizeDomain(domain)] = true;
});
return whitelistedDomains;
}
function _normalizeDomain (domain) {
domain = domain.toLowerCase().trim();
if (domain.startsWith('www.')) {
domain = domain.slice(4);
}
return domain;
}
This diff is collapsed.
......@@ -23,6 +23,12 @@
*/
var mappings = require('./mappings');
/**
* Resource version shorthands.
* @var {object} shorthands
*/
var shorthands = require('./shorthands');
/**
* Gets and sets add-on specific preferences.
* @var {object} simplePreferences
......@@ -65,21 +71,32 @@ simplePreferences.on('domainWhitelist', _applyWhitelistPreference);
exports.isValidCandidate = function (httpChannel) {
var initiatorDomain;
// See if the request uses a supported URI scheme.
if (!httpChannel.URI.schemeIs('http') &&
!httpChannel.URI.schemeIs('https')) {
return false;
}
// See if the request is targeted at a Content Delivery Network.
if (mappings[httpChannel.URI.host] === undefined) {
return false;
}
// Attempt to determine the domain of the request initiator.
var initiatorDomain =
initiatorDomain =
httpChannel.loadInfo && httpChannel.loadInfo.loadingDocument && httpChannel.loadInfo.loadingDocument.domain ||
httpChannel.referrer && httpChannel.referrer.host;
// If the request initiator could be determined and is whitelisted.
if (initiatorDomain && whitelistedDomains[_normalizeDomain(initiatorDomain)]) {
// Remove referer header from request.
// Remove sensitive headers from the request.
httpChannel.setRequestHeader('Referer', null, false);
httpChannel.setRequestHeader('Origin', null, false);
httpChannel.setRequestHeader('Cookie', null, false);
return false;
}
......@@ -107,14 +124,14 @@ exports.getLocalTarget = function (channelHost, channelPath) {
}
// Return either the local target's path or false.
return _findLocalTarget(resourceMappings, basePath, channelPath);
return _findLocalTarget(resourceMappings, basePath, channelHost, channelPath);
};
/**
* Private Methods
*/
function _matchBasePath(hostMappings, channelPath) {
function _matchBasePath (hostMappings, channelPath) {
for (let basePath of Object.keys(hostMappings)) {
......@@ -126,7 +143,7 @@ function _matchBasePath(hostMappings, channelPath) {
return false;
}
function _findLocalTarget(resourceMappings, basePath, channelPath) {
function _findLocalTarget (resourceMappings, basePath, channelHost, channelPath) {
var resourcePath, versionNumber, resourcePattern;
......@@ -140,8 +157,8 @@ function _findLocalTarget(resourceMappings, basePath, channelPath) {
// Prepare and return a local target.
return {
path: resourceMappings[resourcePath].path,
type: resourceMappings[resourcePath].type
'path': resourceMappings[resourcePath].path,
'type': resourceMappings[resourcePath].type
};
}
......@@ -150,10 +167,26 @@ function _findLocalTarget(resourceMappings, basePath, channelPath) {
if (resourcePattern.startsWith(resourceMold)) {
let targetPath, targetType, hostShorthands;
targetPath = resourceMappings[resourceMold].path;
targetPath = targetPath.replace(VERSION_PLACEHOLDER, versionNumber);
targetType = resourceMappings[resourceMold].type;
hostShorthands = shorthands[channelHost];
if (hostShorthands && hostShorthands[targetPath]) {
let shorthand = hostShorthands[targetPath];
targetPath = shorthand.path;
targetType = shorthand.type;
}
// Prepare and return a local target.
return {
path: resourceMappings[resourceMold].path.replace(VERSION_PLACEHOLDER, versionNumber),
type: resourceMappings[resourceMold].type
'path': targetPath,
'type': targetType
};
}
}
......@@ -161,7 +194,7 @@ function _findLocalTarget(resourceMappings, basePath, channelPath) {
return false;
}
function _normalizeDomain(domain) {
function _normalizeDomain (domain) {
domain = domain.toLowerCase().trim();
......@@ -172,11 +205,10 @@ function _normalizeDomain(domain) {
return domain;
}
function _applyWhitelistPreference() {
function _applyWhitelistPreference () {
whitelistedDomains = {};
//noinspection JSUnresolvedVariable
preferences.domainWhitelist.split(VALUE_SEPARATOR).forEach(function (domain) {
whitelistedDomains[_normalizeDomain(domain)] = true;
});
......
......@@ -20,74 +20,74 @@
var resources = {
// AngularJS
angular: {
path: 'resources/angularjs/{version}/angular.min.js.dec',
type: 'application/javascript'
'angular': {
'path': 'resources/angularjs/{version}/angular.min.js.dec',
'type': 'application/javascript'
},
// Backbone.js
backbone: {
path: 'resources/backbone.js/{version}/backbone-min.js.dec',
type: 'application/javascript'
'backbone': {
'path': 'resources/backbone.js/{version}/backbone-min.js.dec',
'type': 'application/javascript'
},
// Dojo
dojo: {
path: 'resources/dojo/{version}/dojo/dojo.js.dec',
type: 'application/javascript'
'dojo': {
'path': 'resources/dojo/{version}/dojo/dojo.js.dec',
'type': 'application/javascript'
},
// Ember.js
ember: {
path: 'resources/ember.js/{version}/ember.min.js.dec',
type: 'application/javascript'
'ember': {
'path': 'resources/ember.js/{version}/ember.min.js.dec',
'type': 'application/javascript'
},
// Ext Core
extCore: {
path: 'resources/ext-core/{version}/ext-core.js.dec',
type: 'application/javascript'
'extCore': {
'path': 'resources/ext-core/{version}/ext-core.js.dec',
'type': 'application/javascript'
},
// jQuery
jQuery: {
path: 'resources/jquery/{version}/jquery.min.js.dec',
type: 'application/javascript'
'jQuery': {
'path': 'resources/jquery/{version}/jquery.min.js.dec',
'type': 'application/javascript'
},
// jQuery UI
jQueryUI: {
path: 'resources/jqueryui/{version}/jquery-ui.min.js.dec',
type: 'application/javascript'
'jQueryUI': {
'path': 'resources/jqueryui/{version}/jquery-ui.min.js.dec',
'type': 'application/javascript'
},
// Modernizr
modernizr: {
path: 'resources/modernizr/{version}/modernizr.min.js.dec',
type: 'application/javascript'
'modernizr': {
'path': 'resources/modernizr/{version}/modernizr.min.js.dec',
'type': 'application/javascript'
},
// MooTools
mootools: {
path: 'resources/mootools/{version}/mootools-yui-compressed.js.dec',
type: 'application/javascript'
'mootools': {
'path': 'resources/mootools/{version}/mootools-yui-compressed.js.dec',
'type': 'application/javascript'
},
// Prototype
prototypeJS: {
path: 'resources/prototype/{version}/prototype.js.dec',
type: 'application/javascript'
'prototypeJS': {
'path': 'resources/prototype/{version}/prototype.js.dec',
'type': 'application/javascript'
},
// Scriptaculous
scriptaculous: {
path: 'resources/scriptaculous/{version}/scriptaculous.js.dec',
type: 'application/javascript'
'scriptaculous': {
'path': 'resources/scriptaculous/{version}/scriptaculous.js.dec',
'type': 'application/javascript'
},
// SWFObject
swfobject: {
path: 'resources/swfobject/{version}/swfobject.js.dec',
type: 'application/javascript'
'swfobject': {
'path': 'resources/swfobject/{version}/swfobject.js.dec',
'type': 'application/javascript'
},
// Underscore.js
underscore: {
path: 'resources/underscore.js/{version}/underscore-min.js.dec',
type: 'application/javascript'
'underscore': {
'path': 'resources/underscore.js/{version}/underscore-min.js.dec',
'type': 'application/javascript'
},
// Web Font Loader
webfont: {
path: 'resources/webfont/{version}/webfont.js.dec',
type: 'application/javascript'
'webfont': {
'path': 'resources/webfont/{version}/webfont.js.dec',
'type': 'application/javascript'
}
};
......
/**
* Shorthands
* Belongs to Decentraleyes.
*
* @author Thomas Rientjes
* @since 2018-06-02
* @license MPL 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
'use strict';
/**
* Shorthands
*/
var shorthands = {
// Google Hosted Libraries [Deprecated]
'ajax.googleapis.com': {
'resources/jquery/1.8/jquery.min.js.dec': {
'path': 'resources/jquery/1.8.3/jquery.min.js.dec',
'version': '1.8.3'
},
'resources/jquery/1.7/jquery.min.js.dec': {
'path': 'resources/jquery/1.7.2/jquery.min.js.dec',
'version': '1.7.2'
},
'resources/jquery/1.6/jquery.min.js.dec': {
'path': 'resources/jquery/1.6.4/jquery.min.js.dec',
'version': '1.6.4'
},
'resources/jquery/1.5/jquery.min.js.dec': {
'path': 'resources/jquery/1.5.2/jquery.min.js.dec',
'version': '1.5.2'
},
'resources/jquery/1.4/jquery.min.js.dec': {
'path': 'resources/jquery/1.4.4/jquery.min.js.dec',
'version': '1.4.4'
},
'resources/jquery/1.3/jquery.min.js.dec': {
'path': 'resources/jquery/1.3.2/jquery.min.js.dec',
'version': '1.3.2'
},
'resources/jquery/1.2/jquery.min.js.dec': {
'path': 'resources/jquery/1.2.6/jquery.min.js.dec',
'version': '1.2.6'
}
},
// jQuery CDN [Deprecated]
'code.jquery.com': {
'resources/jquery/1.7/jquery.min.js.dec': {
'path': 'resources/jquery/1.7.0/jquery.min.js.dec',
'version': '1.7.0'
},
'resources/jquery/1.6/jquery.min.js.dec': {
'path': 'resources/jquery/1.6.0/jquery.min.js.dec',
'version': '1.6.0'
},
'resources/jquery/1.5/jquery.min.js.dec': {
'path': 'resources/jquery/1.5.0/jquery.min.js.dec',
'version': '1.5.0'
<