Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Synzvato/decentraleyes
  • gkrishnaks/decentraleyes
  • ExE-Boss/decentraleyes
  • whtsky/decentraleyes
  • grtgarrett/decentraleyes
  • An_dz/decentraleyes
  • Alaska/decentraleyes
  • finn/decentraleyes
  • klippy/decentraleyes
9 results
Show changes
Showing
with 787 additions and 414 deletions
{
"extensionDescription": {
"message": "Skyddar dig mot att spåras av \"gratis\", centraliserad, innehållsleverans.",
"message": "Skyddar dig mot att spåras av \"gratis\" centraliserad innehållsleverans.",
"description": "Extension description."
},
"disableProtectionTitle": {
......@@ -16,11 +16,11 @@
"description": "Amount injected title."
},
"amountInjectedDescription": {
"message": "Antalet insatta Content Delivery Network-resurser sedan installationen.",
"message": "Mängden lokala resursinjektioner för innehållsleveransnätverk sedan installationen.",
"description": "Amount injected description."
},
"optionsTitle": {
"message": "Inställningar",
"message": "Alternativ",
"description": "Options title."
},
"showIconBadgeTitle": {
......@@ -36,7 +36,7 @@
"description": "Block requests for missing resources title."
},
"blockMissingDescription": {
"message": "Avbryt avlyssnad begäran om den begärda resursen inte finns lokalt.",
"message": "Avbryt avlyssnad begäran om den nödvändiga resursen inte är lokalt tillgänglig.",
"description": "Block requests for missing resources description."
},
"disablePrefetchTitle": {
......@@ -64,7 +64,7 @@
"description": "Whitelisted domains description."
},
"advancedLabel": {
"message": "Avancerad",
"message": "Avancerat",
"description": "Advanced label."
}
}
\ No newline at end of file
}
......@@ -67,4 +67,4 @@
"message": "Naka-usad",
"description": "Advanced label."
}
}
\ No newline at end of file
}
{
"extensionDescription": {
"message": "Sizi, \"ücretsiz\", merkezi, içerik dağıtımı aracılığıyla yapılan takipten korur.",
"message": "Sizi içerik dağıtımıyla yapılan merkezi ve \"ücretsiz\" takipten korur.",
"description": "Extension description."
},
"disableProtectionTitle": {
......@@ -67,4 +67,4 @@
"message": "Gelişmiş",
"description": "Advanced label."
}
}
\ No newline at end of file
}
{
"extensionDescription": {
"message": "Захищає вас від стеження \"безкоштовними\", централізованими мережами розповсюдження ресурсів.",
"description": "Extension description."
},
"disableProtectionTitle": {
"message": "Вимкнути захист на цій сторінці",
"description": "Disable protection title."
},
"enableProtectionTitle": {
"message": "Увімкнути захист",
"description": "Enable protection title."
},
"amountInjectedTitle": {
"message": "Лічильник ресурсів замінених локальними",
"description": "Amount injected title."
},
"amountInjectedDescription": {
"message": "Кількість ресурсів наданих локальною Мережею Розповсюдження Контенту (CDN) з початку встановлення.",
"description": "Amount injected description."
},
"optionsTitle": {
"message": "Параметри",
"description": "Options title."
},
"showIconBadgeTitle": {
"message": "Показувати кількість ін'єкцій на іконці",
"description": "Show icon badge title."
},
"showIconBadgeDescription": {
"message": "Показувати кількість локально наданих ресурсів на іконці розширення.",
"description": "Show icon badge description."
},
"blockMissingTitle": {
"message": "Блокувати запити для відсутніх ресурсів",
"description": "Block requests for missing resources title."
},
"blockMissingDescription": {
"message": "Скасувати перехоплений запит, якщо необхідний ресурс відсутній локально.",
"description": "Block requests for missing resources description."
},
"disablePrefetchTitle": {
"message": "Відключити попереднє завантаженя посилань",
"description": "Disable prefetch title."
},
"disablePrefetchDescription": {
"message": "Запобігти витік заборонених запитів в мережі розповсюдження.",
"description": "Disable prefetch description."
},
"stripMetadataTitle": {
"message": "Видалити метадані з дозволених запитів",
"description": "Strip metadata title."
},
"stripMetadataDescription": {
"message": "Стерти чутливі дані з запитів до дозволених CDN для кращої приватності.",
"description": "Strip metadata description."
},
"whitelistedDomainsTitle": {
"message": "Вимкнути перевірку для доменів",
"description": "Whitelisted domains title."
},
"whitelistedDomainsDescription": {
"message": "Введіть домени для включення в білий список. У якості розділювача використовуйте крапку з комою (;).",
"description": "Whitelisted domains description."
},
"advancedLabel": {
"message": "Розширені",
"description": "Advanced label."
}
}
{
"extensionDescription": {
"message": "Bảo vệ bạn khỏi bị theo dõi thông qua việc phân phối nội dung \"miễn phí\", tập trung.",
"description": "Extension description."
},
"disableProtectionTitle": {
"message": "Tắt bảo vệ cho trang này",
"description": "Disable protection title."
},
"enableProtectionTitle": {
"message": "Bật bảo vệ",
"description": "Enable protection title."
},
"amountInjectedTitle": {
"message": "Đếm các tài nguyên cục bộ được chèn vào",
"description": "Amount injected title."
},
"amountInjectedDescription": {
"message": "Số lượng tài nguyên cục bộ đã chèn của mạng phân phối nội dung (CDN) kể từ khi cài đặt.",
"description": "Amount injected description."
},
"optionsTitle": {
"message": "Tùy chỉnh",
"description": "Options title."
},
"showIconBadgeTitle": {
"message": "Hển thị số lượng chèn trên biểu tượng",
"description": "Show icon badge title."
},
"showIconBadgeDescription": {
"message": "Hiển thị số tài nguyên đã chèn trên biểu tượng của tiện ích.",
"description": "Show icon badge description."
},
"blockMissingTitle": {
"message": "Chặn yêu cầu cho tài nguyên bị thiếu",
"description": "Block requests for missing resources title."
},
"blockMissingDescription": {
"message": "Hủy yêu cầu bị chặn nếu tài nguyên cần tới không có sẵn.",
"description": "Block requests for missing resources description."
},
"disablePrefetchTitle": {
"message": "Vô hiệu tìm nạp trước liên kết",
"description": "Disable prefetch title."
},
"disablePrefetchDescription": {
"message": "Ngăn chặn các yêu cầu không được phép rò rỉ ra ngoài mạng lưới phân phối.",
"description": "Disable prefetch description."
},
"stripMetadataTitle": {
"message": "Loại bỏ siêu dữ liệu (metadata) khỏi các yêu cầu được phép",
"description": "Strip metadata title."
},
"stripMetadataDescription": {
"message": "Xóa dữ liệu nhạy cảm khỏi các yêu cầu CDN được phép để cải thiện quyền riêng tư.",
"description": "Strip metadata description."
},
"whitelistedDomainsTitle": {
"message": "Loại trừ tên miền khỏi việc giám sát",
"description": "Whitelisted domains title."
},
"whitelistedDomainsDescription": {
"message": "Nhập các miền để đưa vào danh sách trắng. Phân tách các mục nhập bằng dấu chấm phẩy (;).",
"description": "Whitelisted domains description."
},
"advancedLabel": {
"message": "Nâng cao",
"description": "Advanced label."
}
}
{
"extensionDescription": {
"message": "保护免受集中式的内容交付网络(CDN)的跟踪。",
"message": "保护免受中心化的内容分发网络(CDN)的跟踪。",
"description": "Extension description."
},
"disableProtectionTitle": {
......@@ -12,11 +12,11 @@
"description": "Enable protection title."
},
"amountInjectedTitle": {
"message": "本地发送资源的计数器",
"message": "本地注入资源的计数器",
"description": "Amount injected title."
},
"amountInjectedDescription": {
"message": "自安装以来,从本地“内容交付网络”发送的资源总量。",
"message": "自安装以来,从本地“内容分发网络”资源注入数量。",
"description": "Amount injected description."
},
"optionsTitle": {
......@@ -28,7 +28,7 @@
"description": "Show icon badge title."
},
"showIconBadgeDescription": {
"message": "在扩展图标上显示注入资源的数量。",
"message": "在扩展图标上显示注入资源的数量。",
"description": "Show icon badge description."
},
"blockMissingTitle": {
......@@ -36,7 +36,7 @@
"description": "Block requests for missing resources title."
},
"blockMissingDescription": {
"message": "取消被拦截的请求,如果请求的资源在本地不可用。",
"message": "如果请求的资源在本地不可用,则取消被拦截的请求。",
"description": "Block requests for missing resources description."
},
"disablePrefetchTitle": {
......@@ -48,11 +48,11 @@
"description": "Disable prefetch description."
},
"stripMetadataTitle": {
"message": "允许的请求剥去元数据",
"message": "清除被允许的请求中的元数据",
"description": "Strip metadata title."
},
"stripMetadataDescription": {
"message": "被允许的 CDN 请求剥去敏感数据以保护隐私。",
"message": "被允许的 CDN 请求中擦除敏感数据以保护隐私。",
"description": "Strip metadata description."
},
"whitelistedDomainsTitle": {
......@@ -60,11 +60,11 @@
"description": "Whitelisted domains title."
},
"whitelistedDomainsDescription": {
"message": "输入白名单的域名。用分号 (;) 分隔多项。",
"message": "输入要添加到白名单的域名。用分号 (;) 分隔多项。",
"description": "Whitelisted domains description."
},
"advancedLabel": {
"message": "高级",
"description": "Advanced label."
}
}
\ No newline at end of file
}
......@@ -67,4 +67,4 @@
"message": "進階",
"description": "Advanced label."
}
}
\ No newline at end of file
}
{
"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
------------
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.
Usage Instructions (Unix)
------------------
1. Make sure you have Node.js installed on your machine.
2. Open up a terminal and ```cd``` into this directory.
3. Execute ```npm install``` to fetch any dependencies.
4. Run the audit script by executing ```node run```.
**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.5.0",
"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="
}
}
}
/**
* Resource Audit Script
* Belongs to Decentraleyes.
*
* @author Thomas Rientjes
* @since 2014-07-24
* @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/.
*/
/**
* Imports
*/
var fileSystem, crypto, https, sourceMappingURL;
fileSystem = require('fs');
crypto = require('crypto');
https = require('https');
sourceMappingURL = require('source-map-url');
/**
* Variables
*/
var localResourceLocation = '../resources';
var localResourceLocationLength = localResourceLocation.length;
var localResourcePaths = [];
var comparedResourceAmount = 0;
var resourceAmount = 0;
/**
* Functions
*/
function _fetchLocalResourcePaths (folderPath) {
fileSystem.readdirSync(folderPath).forEach(function (resourceName) {
var resourcePath = `${folderPath}/${resourceName}`;
var resourceStatistics = fileSystem.statSync(resourcePath);
if (resourceStatistics && resourceStatistics.isDirectory()) {
_fetchLocalResourcePaths(resourcePath);
} else {
localResourcePaths.push(resourcePath);
}
});
return localResourcePaths;
}
function _getLocalResourceContents (fileLocation, callback) {
fileSystem.exists(fileLocation, function (exists) {
if (exists) {
fileSystem.stat(fileLocation, function (error, statistics) {
fileSystem.open(fileLocation, 'r', function (error, fileDescriptor) {
var buffer = new Buffer(statistics.size);
fileSystem.read(fileDescriptor, buffer, 0, buffer.length, null, function (error, bytesRead, buffer) {
var localFileContents = buffer.toString('utf8', 0, buffer.length);
fileSystem.close(fileDescriptor, function () {});
callback(localFileContents);
});
});
});
}
});
}
function _getRemoteResourceContents (remoteResourceRoute, callback) {
var resourceURL = `https://ajax.googleapis.com/ajax/libs/${remoteResourceRoute}`;
https.get(resourceURL, function (response) {
var resourceContents = '';
response.on('data', function (chunk) {
resourceContents += chunk;
});
response.on('end', function () {
if (response.statusCode === 200) {
callback(resourceContents, resourceURL);
} else {
resourceURL = `https://cdnjs.cloudflare.com/ajax/libs/${remoteResourceRoute}`;
https.get(resourceURL, function (response) {
resourceContents = '';
response.on('data', function (chunk) {
resourceContents += chunk;
});
response.on('end', function () {
if (response.statusCode !== 200) {
throw `Error: Resource ${remoteResourceRoute} could not be fetched.`;
}
callback(resourceContents, resourceURL);
});
});
}
});
});
}
function _hashFileContents (fileContents) {
var hash;
hash = crypto.createHash('sha512');
hash.setEncoding('hex');
hash.write(fileContents);
hash.end();
return hash.read();
}
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';
if (hasSourceMappingURL) {
remoteResourceContents = sourceMappingURL.removeFrom(remoteResourceContents);
sourceMappingNotice = '[X] REMOTE RESOURCE HAD SOURCE MAPPING URL';
}
var localResourceHash = _hashFileContents(localResourceContents);
var remoteResourceHash = _hashFileContents(remoteResourceContents);
console.log(`RESOURCE HASH (SHA512): ${localResourceHash}`);
console.log(`RESOURCE HASH (SHA512): ${remoteResourceHash}`);
var fileHashesMatch = (localResourceHash === remoteResourceHash);
if (!fileHashesMatch) {
console.log(URL);
console.log(remoteResourceContents);
throw 'Error: Decentraleyes resource hash mismatch.';
}
console.log();
console.log('[X] LOCAL AND REMOTE RESOURCE HASHES MATCH');
console.log(sourceMappingNotice);
_incrementComparedResourceAmount();
}
/**
* Initializations
*/
_fetchLocalResourcePaths(localResourceLocation);
resourceAmount = localResourcePaths.length;
/**
* Script
*/
localResourcePaths.forEach(function (resourcePath) {
var resourceRoute = resourcePath.substr(localResourceLocationLength + 1);
resourceRoute = resourceRoute.substring(0, resourceRoute.length - 4);
_getLocalResourceContents(resourcePath, function (localResourceContents) {
_getRemoteResourceContents(resourceRoute, function (remoteResourceContents, URL) {
console.log();
console.log(resourceRoute.toUpperCase());
console.log();
// Compare resource content hashes.
_compareResources(localResourceContents, remoteResourceContents, URL);
console.log();
console.log('------------------------------------------');
});
});
});
report.txt
# Decentraleyes Audit
This resource auditor allows any user and extension reviewer to verify the integrity of the bundled resources. It provides a quick and reliable way to compare all bundled libraries to their original sources.
## Prerequisites
* Node.js 20.0.0 *(or higher)*.
## Usage Instructions
1. Open up a terminal, or a command prompt, and `cd` into its directory.
2. Run the audit script by executing *one* of the following commands:
```bash
node run -r # Validate recently updated resources.
node run # Validate all bundled resources.
```
***Note:** Append ` > report.txt` to write the output to a file.*
import globals from 'globals';
import js from '@eslint/js';
import {baseConfiguration} from '../eslint.config.mjs';
export default [
js.configs.recommended,
baseConfiguration,
{
'languageOptions': {
'globals': {
...globals.node
}
}
}
];
{
"name": "decentraleyes-audit",
"version": "2.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "decentraleyes-audit",
"version": "2.0.0",
"license": "MPL-2.0",
"engines": {
"node": ">= 20"
}
}
}
}
{
"name": "decentraleyes-audit",
"version": "1.5.0",
"version": "2.0.0",
"author": "Thomas Rientjes",
"license": "MPL-2.0",
"description": "Library audit tool for Decentraleyes.",
"repository": "https://addons.mozilla.org/firefox/addon/decentraleyes",
"description": "Resource auditor for Decentraleyes.",
"repository": "https://git.synz.io/Synzvato/decentraleyes.git",
"keywords": [
"decentraleyes",
"audit"
"auditor"
],
"main": "run.js",
"dependencies": {
"source-map-url": "~0.4.0"
"type": "module",
"engines": {
"node": ">= 20"
}
}
/**
* Resource Auditor
* Belongs to Decentraleyes.
*
* @author Thomas Rientjes
* @since 2014-07-24 (originally "audit")
* @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/.
*/
import crypto from 'crypto';
import {promises as fileSystem} from 'fs';
/**
* Constants
*/
const mappingUrlBlockExpression = /\/\*(?:\s*\r?\n(?:\/\/)?)?[#@] sourceMappingURL=([^\s'"]*)\s*\*\/\s*/;
const mappingUrlLineExpression = /\/\/[#@] sourceMappingURL=([^\s'"]*)\s*/;
const localResourceLocation = '../resources';
const localResourceLocationLength = localResourceLocation.length;
const recentlyUpdatedResources = [
'backbone.js/1.4.0',
'jquery/3.6.0',
'jquery/3.6.1',
'jquery/3.6.4',
'jquery/3.7.0',
'jquery/3.7.1',
'moment.js/2.24.0',
'moment.js/2.29.1',
'moment.js/2.29.4',
'underscore.js/1.13.4'
];
/**
* Variables
*/
let verifyAllResources = true;
/**
* Functions
*/
const resourceHasSourceMappingUrl = (resourceContents) => {
return mappingUrlBlockExpression.test(resourceContents) || mappingUrlLineExpression.test(resourceContents);
};
const removeSourceMappingUrlsFromResource = (resourceContents) => {
resourceContents = resourceContents.replace(mappingUrlBlockExpression, '');
resourceContents = resourceContents.replace(mappingUrlLineExpression, '');
return resourceContents;
};
const filterLocalResourcePaths = (localResourcePaths) => {
return localResourcePaths.filter((path) => {
for (const recentlyUpdatedResource of recentlyUpdatedResources) {
if (path.includes(recentlyUpdatedResource)) {
return true;
}
}
return false;
});
};
const determineLocalResourcePaths = async (folderPath) => {
let resourceNames, localResourcePaths;
resourceNames = await fileSystem.readdir(folderPath);
localResourcePaths = [];
for (const resourceName of resourceNames) {
let resourcePath, resourceNodeStatus;
resourcePath = `${folderPath}/${resourceName}`;
resourceNodeStatus = await fileSystem.stat(resourcePath);
if (resourceNodeStatus && resourceNodeStatus.isDirectory()) {
localResourcePaths = [...localResourcePaths, ...(await determineLocalResourcePaths(resourcePath))];
} else {
localResourcePaths.push(resourcePath);
}
}
if (verifyAllResources === false) {
localResourcePaths = filterLocalResourcePaths(localResourcePaths);
}
return localResourcePaths;
};
const getLocalResourceContents = async (fileLocation) => {
try {
return await fileSystem.readFile(fileLocation, 'utf8');
} catch {
return null;
}
};
const getRemoteResource = async (remoteResourceRoute) => {
const remoteResourceUrls = [
`https://ajax.googleapis.com/ajax/libs/${remoteResourceRoute}`,
`https://cdnjs.cloudflare.com/ajax/libs/${remoteResourceRoute}`
];
for (const remoteResourceUrl of remoteResourceUrls) {
const response = await fetch(remoteResourceUrl);
if (response.status === 200) {
return {
'contents': await response.text(),
'url': remoteResourceUrl
};
}
}
throw new Error(`Resource "${remoteResourceRoute}" could not be fetched.`);
};
const hashFileContents = (fileContents) => {
const hash = crypto.createHash('sha3-512');
hash.update(fileContents);
return hash.digest('hex');
};
const compareResources = (localResourceContents, remoteResourceContents, url) => {
let hasSourceMappingUrl, sourceMappingNotice, localFileHash, remoteFileHash, fileHashesMatch;
hasSourceMappingUrl = resourceHasSourceMappingUrl(remoteResourceContents);
sourceMappingNotice = '[ ] REMOTE RESOURCE HAD SOURCE MAPPING URL';
if (hasSourceMappingUrl) {
remoteResourceContents = removeSourceMappingUrlsFromResource(remoteResourceContents);
sourceMappingNotice = '[X] REMOTE RESOURCE HAD SOURCE MAPPING URL';
}
localFileHash = hashFileContents(localResourceContents);
remoteFileHash = hashFileContents(remoteResourceContents);
console.log(`RESOURCE HASH (SHA3-512): ${localFileHash}`);
console.log(`RESOURCE HASH (SHA3-512): ${remoteFileHash}`);
fileHashesMatch = (localFileHash === remoteFileHash);
if (! fileHashesMatch) {
console.log(url);
console.log(remoteResourceContents);
throw new Error('Error: Decentraleyes resource hash mismatch.');
}
console.log();
console.log('[X] LOCAL AND REMOTE RESOURCE HASHES MATCH');
console.log(sourceMappingNotice);
};
const verifyResourceContents = async (resourcePath) => {
let resourceRoute, localResourceContents, remoteResource;
resourceRoute = resourcePath.substring(localResourceLocationLength + 1);
resourceRoute = resourceRoute.substring(0, resourceRoute.length - 1);
localResourceContents = await getLocalResourceContents(resourcePath);
remoteResource = await getRemoteResource(resourceRoute);
console.log(remoteResource.url);
console.log();
console.log(resourceRoute.toUpperCase());
console.log();
// Compare resource content hashes.
compareResources(localResourceContents, remoteResource.contents, remoteResource.url);
console.log();
console.log('------------------------------------------');
console.log();
};
/**
* Initializations
*/
if (process.argv[2] && process.argv[2] === '-r') {
verifyAllResources = false;
}
/**
* Main
*/
(async () => {
let localResourcePaths, amountOfResources, promises;
localResourcePaths = await determineLocalResourcePaths(localResourceLocation);
amountOfResources = localResourcePaths.length;
promises = localResourcePaths.map((localResourcePath) => {
const randomExecutionDelay = Math.floor(Math.random() * (amountOfResources * 750));
return new Promise((resolve) => {
setTimeout(async () => {
await verifyResourceContents(localResourcePath);
resolve();
}, randomExecutionDelay);
});
});
await Promise.all(promises).then(() => {
console.log(' *** FILE INTEGRITY CHECKS COMPLETED');
console.log(` *** ${amountOfResources}/${amountOfResources} RESOURCES WERE ANALYZED`);
console.log();
});
})();
/**
* Request Analyzer
* Belongs to Decentraleyes.
*
* @author Thomas Rientjes
* @since 2016-04-11
* @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/.
*/
import Constants from '../../data/constants.js';
import Helpers from '../../utilities/helpers.js';
import ResourceAliases from '../../data/resource/aliases.js';
import ResourceMappings from '../../data/resource/mappings.js';
/**
* Private Functions
*/
const _matchBasePath = (hostMappings, channelPath) => {
for (const basePath of Object.keys(hostMappings)) {
if (channelPath.startsWith(basePath)) {
return basePath;
}
}
return null;
};
const _findLocalTarget = (resourceMappings, basePath, channel) => {
let resourcePath, versionNumber, resourcePattern;
resourcePath = channel.path.replace(basePath, '');
versionNumber = resourcePath.match(Constants.Resource.VERSION_EXPRESSION);
resourcePattern = resourcePath.replace(versionNumber, Constants.Resource.VERSION_PLACEHOLDER);
for (const resourceMold of Object.keys(resourceMappings)) {
if (resourcePattern.startsWith(resourceMold)) {
let targetPath, hostAliases, version;
targetPath = resourceMappings[resourceMold].path;
targetPath = targetPath.replace(Constants.Resource.VERSION_PLACEHOLDER, versionNumber);
hostAliases = ResourceAliases[channel.host];
if (hostAliases && hostAliases[targetPath]) {
const alias = hostAliases[targetPath];
targetPath = alias.path;
version = alias.version;
} else {
version = versionNumber?.[0] ?? targetPath.match(Constants.Resource.VERSION_EXPRESSION);
}
// Prepare and return a local target.
return {'source': channel.host, 'version': version, 'path': targetPath};
}
}
return null;
};
/**
* Public Functions
*/
const determineLocalTarget = (requestDetails) => {
let destinationUrl, destination, hostMappings, basePath, resourceMappings;
destinationUrl = new URL(requestDetails.url);
destination = {'host': destinationUrl.host, 'path': destinationUrl.pathname};
// Use the appropriate mappings for the targeted host.
hostMappings = ResourceMappings[destination.host];
// Resource mapping files are never locally available.
if (Constants.Resource.MAPPING_EXPRESSION.test(destination.path)) {
return null;
}
basePath = _matchBasePath(hostMappings, destination.path);
resourceMappings = hostMappings[basePath];
if (! resourceMappings) {
return null;
}
// Return either a local request target or null.
return _findLocalTarget(resourceMappings, basePath, destination);
};
const isValidCandidate = async (requestDetails, tabDetails) => {
let initiatorDomain, isWhitelisted;
initiatorDomain = Helpers.extractDomainFromUrl(tabDetails.url);
if (initiatorDomain === null) {
initiatorDomain = Constants.Address.EXAMPLE;
}
isWhitelisted = await Helpers.domainIsWhitelisted(initiatorDomain);
if (isWhitelisted) {
return false;
}
// Only requests of type GET can be valid candidates.
return requestDetails.method === Constants.WebRequest.GET;
};
/**
* Exports
*/
export default {
determineLocalTarget,
isValidCandidate
};
/**
* Request Interceptor
* Belongs to Decentraleyes.
*
* @author Thomas Rientjes
* @since 2016-04-06
* @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/.
*/
import Constants from '../../data/constants.js';
import DomainExceptions from '../../data/domain/exceptions.js';
import Helpers from '../../utilities/helpers.js';
import RequestAnalyzer from './analyzer.js';
import ResourceEnvironment from '../../data/resource/environments.js';
import State from '../state.js';
import Storage from '../storage.js';
/**
* Private Functions
*/
const _handleMissingCandidate = async (requestUrl, preserveUrl) => {
let blockMissing, requestUrlSegments;
blockMissing = await Storage.getSetting(Constants.Setting.BLOCK_MISSING);
if (blockMissing === true) {
Storage.incrementStatistic(Constants.Statistic.AMOUNT_BLOCKED);
return {'cancel': true};
}
if (preserveUrl === true) {
return {'cancel': false};
}
requestUrlSegments = new URL(requestUrl);
if (requestUrlSegments.protocol === Constants.Address.HTTP) {
requestUrlSegments.protocol = Constants.Address.HTTPS;
requestUrl = requestUrlSegments.toString();
return {'redirectUrl': requestUrl};
} else {
return {'cancel': false};
}
};
const _handleRequest = async (requestDetails) => {
let tab, validCandidate, tabDomain, settings, isSilent, targetDetails, targetPath;
try {
tab = await chrome.tabs.get(requestDetails.tabId);
} catch {
tab = {};
}
validCandidate = await RequestAnalyzer.isValidCandidate(requestDetails, tab);
if (! validCandidate) {
return {'cancel': false};
}
tabDomain = Helpers.extractDomainFromUrl(tab.url);
if (tabDomain === null) {
tabDomain = Constants.Address.EXAMPLE;
}
settings = await Storage.getSettings();
isSilent = false;
if (requestDetails.type === Constants.WebRequestType.XHR) {
if (tabDomain === settings[Constants.Setting.XHR_TEST_DOMAIN]) {
isSilent = true;
} else {
return _handleMissingCandidate(requestDetails.url);
}
}
if (DomainExceptions.literal[tabDomain]) {
return _handleMissingCandidate(requestDetails.url, true);
}
for (const dynamicDomainException of DomainExceptions.dynamic) {
if (dynamicDomainException.test(tabDomain)) {
return _handleMissingCandidate(requestDetails.url, true);
};
}
targetDetails = RequestAnalyzer.determineLocalTarget(requestDetails);
targetPath = targetDetails?.path;
if (! targetPath) {
return _handleMissingCandidate(requestDetails.url);
}
if (! ResourceEnvironment[settings[Constants.ComputedSetting.ENVIRONMENT_NAME]][targetPath]) {
return _handleMissingCandidate(requestDetails.url);
}
State.createRequestContext(requestDetails.requestId, {
'tabIdentifier': requestDetails.tabId, 'targetDetails': targetDetails, 'isSilent': isSilent
});
return {'redirectUrl': await chrome.runtime.getURL(targetPath)};
};
/**
* Event Handlers
*/
chrome.webRequest.onBeforeRequest.addListener(
_handleRequest, {'urls': Helpers.determineValidHosts()},
[Constants.WebRequest.BLOCKING]
);
chrome.webRequest.onErrorOccurred.addListener((requestDetails) => {
State.deleteRequestContext(requestDetails.requestId);
}, {'urls': [Constants.Address.ANY]});
/**
* Request Sanitizer
* Belongs to Decentraleyes.
*
* @author Thomas Rientjes
* @since 2018-01-10
* @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/.
*/
import Constants from '../../data/constants.js';
import Helpers from '../../utilities/helpers.js';
import Storage from '../storage.js';
/**
* Private Functions
*/
const _stripMetadata = async (requestDetails) => {
const stripMetadata = await Storage.getSetting(Constants.Setting.STRIP_METADATA);
if (stripMetadata !== false) {
const sensitiveHeaders = [Constants.Header.COOKIE, Constants.Header.ORIGIN, Constants.Header.REFERER];
Storage.incrementStatistic(Constants.Statistic.AMOUNT_SANITIZED);
requestDetails.requestHeaders = requestDetails.requestHeaders.filter((header) => {
return ! sensitiveHeaders.includes(header.name);
});
}
return {
[Constants.WebRequest.HEADERS]: requestDetails.requestHeaders
};
};
/**
* Event Handlers
*/
chrome.webRequest.onBeforeSendHeaders.addListener(
_stripMetadata, {'urls': Helpers.determineValidHosts()},
[Constants.WebRequest.BLOCKING, Constants.WebRequest.HEADERS]
);