LocalCDN-Firefox-Chrome-Brave/core/request-analyzer.js

250 lines
8.7 KiB
JavaScript
Raw Normal View History

2020-02-27 13:45:29 +01:00
/**
* Request Analyzer
2020-06-30 18:41:58 +02:00
* Belongs to LocalCDN (since 2020-02-26)
* (Origin: Decentraleyes)
2020-02-27 13:45:29 +01:00
*
* @author Thomas Rientjes
* @since 2016-04-11
2020-04-14 07:43:25 +02:00
*
2020-06-30 18:41:58 +02:00
* @author nobody
2020-04-14 07:43:25 +02:00
* @since 2020-02-26
*
2020-02-27 13:45:29 +01:00
* @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';
2021-02-17 07:01:08 +01:00
2020-02-27 13:45:29 +01:00
/**
* Request Analyzer
*/
var requestAnalyzer = {};
2021-02-17 07:01:08 +01:00
2020-02-27 13:45:29 +01:00
/**
* Public Methods
*/
requestAnalyzer.isValidCandidate = function (requestDetails, tabDetails) {
2021-02-07 08:02:45 +01:00
let initiatorDomain, isAllowlisted;
2020-02-27 13:45:29 +01:00
initiatorDomain = helpers.extractDomainFromUrl(tabDetails.url, true);
if (initiatorDomain === null) {
initiatorDomain = Address.EXAMPLE;
}
2021-01-18 19:05:41 +01:00
isAllowlisted = helpers.checkAllowlisted(initiatorDomain);
2020-10-17 07:09:30 +02:00
if (isAllowlisted) {
2020-02-27 13:45:29 +01:00
return false;
}
// Font Awesome injections in Chromium deactivated (https://gitlab.com/nobody42/localcdn/-/issues/67)
if (BrowserType.CHROMIUM) {
if (/(font-awesome|fontawesome)/.test(requestDetails.url)) {
console.warn('[ LocalCDN ] Font Awesome is not fully supported by your browser.');
2021-02-21 19:51:47 +01:00
log.append(tabDetails.url, requestDetails.url, 'Font Awesome is not fully supported by your browser', true);
return false;
} else if (requestDetails.url.startsWith('https://fonts.googleapis.com')) {
// also valid for Google Material icons
console.warn('[ LocalCDN ] Google Material Icons are not fully supported by your browser.');
2021-02-21 19:51:47 +01:00
log.append(tabDetails.url, requestDetails.url, 'Google Material Icons are not fully supported by your browser', true);
return false;
}
}
2020-07-25 20:34:41 +02:00
// Disable LocalCDN if website is 'yandex.com' and CDN is 'yastatic.net', because website and CDN are the same.
if (tabDetails.url.includes('yandex.com') && requestDetails.url.includes('yastatic.net')) {
2021-02-21 19:51:47 +01:00
log.append(tabDetails.url, requestDetails.url, 'Workaround. Disable LocalCDN if website and CDN are the same', true);
2020-07-25 20:34:41 +02:00
return false;
}
2020-02-27 13:45:29 +01:00
// Only requests of type GET can be valid candidates.
return requestDetails.method === WebRequest.GET;
};
requestAnalyzer.getLocalTarget = function (requestDetails, initiator) {
2021-02-17 07:01:08 +01:00
let destinationUrl, destinationHost, destinationPath, hostMappings, basePath,
resourceMappings, destinationSearchString;
2020-02-27 13:45:29 +01:00
2021-02-17 07:01:08 +01:00
destinationSearchString = '';
2020-02-27 13:45:29 +01:00
destinationUrl = new URL(requestDetails.url);
destinationHost = destinationUrl.host;
destinationPath = destinationUrl.pathname;
if (destinationUrl.search) {
destinationSearchString = destinationUrl.search;
}
2020-02-27 13:45:29 +01:00
// Use the proper mappings for the targeted host.
hostMappings = mappings.cdn[destinationHost];
2020-02-27 13:45:29 +01:00
// Resource mapping files are never locally available.
if (Resource.MAPPING_EXPRESSION.test(destinationPath)) {
return false;
}
basePath = requestAnalyzer._matchBasePath(hostMappings, destinationPath);
resourceMappings = hostMappings[basePath];
if (!resourceMappings) {
return false;
}
// Return either the local target's path or false.
2021-02-17 07:01:08 +01:00
// eslint-disable-next-line max-len
return requestAnalyzer._findLocalTarget(resourceMappings, basePath, destinationHost, destinationPath, destinationSearchString, initiator);
2020-02-27 13:45:29 +01:00
};
2021-02-17 07:01:08 +01:00
2020-02-27 13:45:29 +01:00
/**
* Private Methods
*/
requestAnalyzer._matchBasePath = function (hostMappings, channelPath) {
for (let basePath of Object.keys(hostMappings)) {
if (channelPath.startsWith(basePath)) {
return basePath;
}
}
return false;
};
2021-02-17 07:01:08 +01:00
// eslint-disable-next-line max-len
requestAnalyzer._findLocalTarget = function (resourceMappings, basePath, channelHost, channelPath, destinationSearchString, initiator) {
2020-04-14 07:42:56 +02:00
let resourcePath, versionNumber, resourcePattern, filename, shorthandResource;
2020-02-27 13:45:29 +01:00
2020-08-30 18:56:36 +02:00
storageManager.type.get(Setting.LOGGING, function (items) {
2020-03-29 10:23:16 +02:00
requestAnalyzer.logging = items.enableLogging;
});
2020-02-27 13:45:29 +01:00
2020-03-29 10:23:16 +02:00
resourcePath = channelPath.replace(basePath, '');
2021-04-29 06:29:12 +02:00
2021-04-28 05:01:46 +02:00
// Evaluate first in case of version 'latest' and numerals in resource
versionNumber = resourcePath.match(Resource.VERSION_EXPRESSION);
2021-04-29 06:29:12 +02:00
2021-04-28 05:01:46 +02:00
// Handle weird version expressions
2021-04-29 06:29:12 +02:00
if (!versionNumber) {
if (Resource.SINGLE_NUMBER_EXPRESSION.test(channelPath)) {
versionNumber = channelPath.match(/\d/);
resourcePattern = resourcePath.replace(versionNumber, Resource.VERSION_PLACEHOLDER);
versionNumber = [`${versionNumber}.0`];
}
} else {
resourcePattern = resourcePath.replace(versionNumber, Resource.VERSION_PLACEHOLDER);
}
2020-02-27 13:45:29 +01:00
shorthandResource = shorthands.specialFiles(channelHost, channelPath, destinationSearchString);
2020-04-14 07:42:56 +02:00
if (shorthandResource) {
2020-06-27 11:49:45 +02:00
if (requestAnalyzer.logging) {
2021-02-17 07:01:08 +01:00
console.log(`[ LocalCDN ] Replaced resource: ${shorthandResource.path}`);
2021-02-21 19:51:47 +01:00
log.append(initiator, channelHost + channelPath, shorthandResource.path, false);
2020-06-27 11:49:45 +02:00
}
2020-04-14 07:42:56 +02:00
return shorthandResource;
2020-04-05 08:55:04 +02:00
}
2021-04-29 06:29:12 +02:00
if (resourcePattern === undefined) {
return false;
}
2020-02-27 13:45:29 +01:00
for (let resourceMold of Object.keys(resourceMappings)) {
if (resourcePattern.startsWith(resourceMold)) {
2021-02-17 07:01:08 +01:00
let targetPath, versionDelivered, versionRequested, bundle;
2020-02-27 13:45:29 +01:00
targetPath = resourceMappings[resourceMold].path;
targetPath = targetPath.replace(Resource.VERSION_PLACEHOLDER, versionNumber);
2020-03-20 08:14:31 +01:00
// Replace the requested version with the latest depending on major version
2020-11-05 07:07:29 +01:00
versionDelivered = targets.setLastVersion(targetPath, versionNumber);
2020-11-03 20:46:43 +01:00
if (versionDelivered === false) {
return false;
}
versionDelivered = versionDelivered.toString();
targetPath = targetPath.replace(versionNumber, versionDelivered);
2020-08-23 07:35:37 +02:00
if (versionNumber === null) {
versionDelivered = targetPath.match(Resource.VERSION_EXPRESSION).toString();
2021-05-26 06:56:35 +02:00
versionRequested = 'latest';
} else {
versionRequested = versionNumber[0];
2020-02-27 13:45:29 +01:00
}
// Get bundle name
2021-02-17 07:01:08 +01:00
bundle = targets.determineBundle(targetPath);
if (bundle !== '') {
filename = channelPath.split('/').pop();
2021-05-26 06:56:35 +02:00
if (bundle === 'MathJax (Bundle)' && filename !== 'MathJax.js') {
filename = channelPath.replace(Resource.MATHJAX, '');
if (!MathJaxFiles[filename]) {
break;
}
}
2021-02-17 07:01:08 +01:00
targetPath = (filename.endsWith('.js')) ? `${targetPath + filename}m` : targetPath + filename;
2020-10-23 17:25:26 +02:00
targetPath = helpers.formatFilename(targetPath);
}
2020-03-29 10:23:16 +02:00
if (requestAnalyzer.logging) {
2021-02-17 07:01:08 +01:00
console.log(`[ LocalCDN ] Replaced resource: ${targetPath}`);
2021-02-21 19:51:47 +01:00
log.append(initiator, channelHost + channelPath, targetPath, false);
2020-03-29 10:23:16 +02:00
}
2020-02-27 13:45:29 +01:00
// Prepare and return a local target.
return {
'source': channelHost,
'versionRequested': versionRequested,
'versionDelivered': versionDelivered,
'path': targetPath,
'bundle': bundle
2020-02-27 13:45:29 +01:00
};
}
}
2020-11-09 06:18:14 +01:00
if (requestAnalyzer.logging && !IgnoredHost[channelHost]) {
2021-02-17 07:01:08 +01:00
console.warn(`[ LocalCDN ] Missing resource: ${channelHost}${channelPath}`);
2021-02-21 19:51:47 +01:00
log.append(initiator, channelHost + channelPath, '-', true);
2020-03-29 10:23:16 +02:00
}
2020-02-27 13:45:29 +01:00
return false;
};
2020-10-17 07:09:30 +02:00
requestAnalyzer._applyAllowlistedDomains = function () {
storageManager.type.get(Setting.ALLOWLISTED_DOMAINS, function (items) {
requestAnalyzer.allowlistedDomains = items.allowlistedDomains || {};
2020-02-27 13:45:29 +01:00
});
};
requestAnalyzer._applyManipulateDOMDomains = function () {
2020-08-30 18:56:36 +02:00
storageManager.type.get(Setting.DOMAINS_MANIPULATE_DOM, function (items) {
requestAnalyzer.domainsManipulateDOM = items.domainsManipulateDOM || {};
});
};
requestAnalyzer._applyAllowedDomainsGoogleFonts = function () {
2020-08-30 18:56:36 +02:00
storageManager.type.get(Setting.ALLOWED_DOMAINS_GOOGLE_FONTS, function (items) {
requestAnalyzer.domainsGoogleFonts = items.allowedDomainsGoogleFonts || {};
});
};
2020-02-27 13:45:29 +01:00
2021-02-17 07:01:08 +01:00
2020-02-27 13:45:29 +01:00
/**
* Initializations
*/
2020-10-17 07:09:30 +02:00
requestAnalyzer.allowlistedDomains = {};
requestAnalyzer._applyAllowlistedDomains();
2020-02-27 13:45:29 +01:00
requestAnalyzer.domainsManipulateDOM = {};
requestAnalyzer._applyManipulateDOMDomains();
requestAnalyzer.domainsGoogleFonts = {};
requestAnalyzer._applyAllowedDomainsGoogleFonts();
2021-02-17 07:01:08 +01:00
2020-02-27 13:45:29 +01:00
/**
* Event Handlers
*/
2020-10-17 07:09:30 +02:00
chrome.storage.onChanged.addListener(requestAnalyzer._applyAllowlistedDomains);
chrome.storage.onChanged.addListener(requestAnalyzer._applyManipulateDOMDomains);
chrome.storage.onChanged.addListener(requestAnalyzer._applyAllowedDomainsGoogleFonts);