mirror of
https://codeberg.org/nobody/LocalCDN.git
synced 2025-06-05 21:49:31 +02:00
small improvements
This commit is contained in:
@@ -21,7 +21,7 @@
|
|||||||
* File Guard
|
* File Guard
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let fileGuard = {};
|
const fileGuard = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +30,7 @@ let fileGuard = {};
|
|||||||
|
|
||||||
fileGuard._startListening = function () {
|
fileGuard._startListening = function () {
|
||||||
|
|
||||||
let randomHexString = helpers.generateRandomHexString(24);
|
const randomHexString = helpers.generateRandomHexString(24);
|
||||||
fileGuard.secret = `?_=${randomHexString}`;
|
fileGuard.secret = `?_=${randomHexString}`;
|
||||||
|
|
||||||
chrome.webRequest.onBeforeRequest.addListener(
|
chrome.webRequest.onBeforeRequest.addListener(
|
||||||
@@ -42,7 +42,7 @@ fileGuard._startListening = function () {
|
|||||||
|
|
||||||
fileGuard._verifyRequest = function (requestDetails) {
|
fileGuard._verifyRequest = function (requestDetails) {
|
||||||
|
|
||||||
let redirectUrl = chrome.runtime.getURL(Address.ROOT_PATH);
|
const redirectUrl = chrome.runtime.getURL(Address.ROOT_PATH);
|
||||||
|
|
||||||
if (!requestDetails.url.endsWith(fileGuard.secret)) {
|
if (!requestDetails.url.endsWith(fileGuard.secret)) {
|
||||||
return {redirectUrl};
|
return {redirectUrl};
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* Interceptor
|
* Interceptor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let interceptor = {};
|
const interceptor = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,15 +31,13 @@ let interceptor = {};
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
interceptor.handleRequest = function (requestDetails, tabIdentifier, tab) {
|
interceptor.handleRequest = function (requestDetails, tabIdentifier, tab) {
|
||||||
let validCandidate, targetDetails, targetDomain, isGoogleFont, isGoogleMaterialIcons, initiatorDomain, isListed,
|
|
||||||
iframe, isGoogleDomain, isOnAllowlist;
|
|
||||||
|
|
||||||
isOnAllowlist = helpers.checkAllowlisted(
|
const isOnAllowlist = helpers.checkAllowlisted(
|
||||||
helpers.extractDomainFromUrl(tab.url, true),
|
helpers.extractDomainFromUrl(tab.url, true),
|
||||||
requestAnalyzer.allowlistedDomains
|
requestAnalyzer.allowlistedDomains
|
||||||
);
|
);
|
||||||
|
|
||||||
iframe = '';
|
let iframe = '';
|
||||||
if (tab.url !== requestDetails.originUrl) {
|
if (tab.url !== requestDetails.originUrl) {
|
||||||
console.log(`${LogString.PREFIX} ${LogString.IFRAME} ${tab.url} -> ${requestDetails.originUrl}`);
|
console.log(`${LogString.PREFIX} ${LogString.IFRAME} ${tab.url} -> ${requestDetails.originUrl}`);
|
||||||
iframe = requestDetails.originUrl;
|
iframe = requestDetails.originUrl;
|
||||||
@@ -51,11 +49,10 @@ interceptor.handleRequest = function (requestDetails, tabIdentifier, tab) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
targetDetails = requestAnalyzer.getLocalTarget(requestDetails, tab.url);
|
const targetDetails = requestAnalyzer.getLocalTarget(requestDetails, tab.url);
|
||||||
if (targetDetails['result'] === 'blocked') {
|
if (targetDetails['result'] === 'blocked') {
|
||||||
let source, resource;
|
const source = helpers.extractDomainFromUrl(tab.url, true);
|
||||||
source = helpers.extractDomainFromUrl(tab.url, true);
|
const resource = tab.url;
|
||||||
resource = tab.url;
|
|
||||||
return {
|
return {
|
||||||
'redirectUrl': chrome.runtime.getURL(`resources/blocked/index.html?source=${source}&resource=${resource}`)
|
'redirectUrl': chrome.runtime.getURL(`resources/blocked/index.html?source=${source}&resource=${resource}`)
|
||||||
};
|
};
|
||||||
@@ -74,7 +71,7 @@ interceptor.handleRequest = function (requestDetails, tabIdentifier, tab) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
validCandidate = requestAnalyzer.isValidCandidate(requestDetails, tab);
|
const validCandidate = requestAnalyzer.isValidCandidate(requestDetails, tab);
|
||||||
if (!validCandidate) {
|
if (!validCandidate) {
|
||||||
return {
|
return {
|
||||||
'cancel': false
|
'cancel': false
|
||||||
@@ -89,14 +86,14 @@ interceptor.handleRequest = function (requestDetails, tabIdentifier, tab) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
targetDomain = helpers.extractDomainFromUrl(requestDetails.url, true);
|
const targetDomain = helpers.extractDomainFromUrl(requestDetails.url, true);
|
||||||
isGoogleFont = requestAnalyzer.isGoogleFont(targetDomain);
|
const isGoogleFont = requestAnalyzer.isGoogleFont(targetDomain);
|
||||||
isGoogleMaterialIcons = requestAnalyzer.isGoogleMaterialIcons(requestDetails.url);
|
const isGoogleMaterialIcons = requestAnalyzer.isGoogleMaterialIcons(requestDetails.url);
|
||||||
|
|
||||||
if (BrowserType.FIREFOX && isGoogleFont && !isGoogleMaterialIcons) {
|
if (BrowserType.FIREFOX && isGoogleFont && !isGoogleMaterialIcons) {
|
||||||
initiatorDomain = helpers.extractDomainFromUrl(tab.url, true);
|
const initiatorDomain = helpers.extractDomainFromUrl(tab.url, true);
|
||||||
isListed = helpers.checkAllowlisted(initiatorDomain, interceptor.allowedDomainsGoogleFonts);
|
const isListed = helpers.checkAllowlisted(initiatorDomain, interceptor.allowedDomainsGoogleFonts);
|
||||||
isGoogleDomain = helpers.isGoogleDomain(initiatorDomain);
|
const isGoogleDomain = helpers.isGoogleDomain(initiatorDomain);
|
||||||
// Check if the website is allowed to load Google Fonts
|
// Check if the website is allowed to load Google Fonts
|
||||||
if (interceptor.blockGoogleFonts === true && isListed === false && isGoogleDomain === false) {
|
if (interceptor.blockGoogleFonts === true && isListed === false && isGoogleDomain === false) {
|
||||||
console.log(`${LogString.PREFIX} Google fonts blocked ${requestDetails.url}`);
|
console.log(`${LogString.PREFIX} Google fonts blocked ${requestDetails.url}`);
|
||||||
@@ -139,12 +136,10 @@ interceptor.handleRequest = function (requestDetails, tabIdentifier, tab) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
interceptor._handleMissingCandidate = function (requestUrl, tabIdentifier) {
|
interceptor._handleMissingCandidate = function (requestUrl, tabIdentifier) {
|
||||||
let requestUrlSegments, injectionCount, missingCount, blockedCount;
|
|
||||||
|
|
||||||
if (stateManager.showIconBadge === true) {
|
if (stateManager.showIconBadge === true) {
|
||||||
injectionCount = Object.keys(stateManager.tabs[tabIdentifier].injections).length || 0;
|
let injectionCount = Object.keys(stateManager.tabs[tabIdentifier].injections).length || 0;
|
||||||
missingCount = stateManager.tabs[tabIdentifier].missing || 0;
|
const missingCount = stateManager.tabs[tabIdentifier].missing || 0;
|
||||||
blockedCount = stateManager.tabs[tabIdentifier].blocked || 0;
|
const blockedCount = stateManager.tabs[tabIdentifier].blocked || 0;
|
||||||
|
|
||||||
injectionCount = injectionCount + missingCount + blockedCount;
|
injectionCount = injectionCount + missingCount + blockedCount;
|
||||||
|
|
||||||
@@ -164,7 +159,7 @@ interceptor._handleMissingCandidate = function (requestUrl, tabIdentifier) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
requestUrlSegments = new URL(requestUrl);
|
const requestUrlSegments = new URL(requestUrl);
|
||||||
|
|
||||||
if (requestUrlSegments.protocol === Address.HTTP) {
|
if (requestUrlSegments.protocol === Address.HTTP) {
|
||||||
requestUrlSegments.protocol = Address.HTTPS;
|
requestUrlSegments.protocol = Address.HTTPS;
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* Main
|
* Main
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let main = {};
|
const main = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
* Manipulate DOM
|
* Manipulate DOM
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let manipulateDOM = {};
|
const manipulateDOM = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,16 +45,12 @@ manipulateDOM._removeCrossOriginAndIntegrityAttr = function (details) {
|
|||||||
|
|
||||||
if (header && manipulateDOM.checkHtmlFilterEnabled(initiatorDomain)) {
|
if (header && manipulateDOM.checkHtmlFilterEnabled(initiatorDomain)) {
|
||||||
|
|
||||||
let mimeType, isAllowlisted;
|
const mimeType = header.value.replace(/;.*/, '').toLowerCase();
|
||||||
|
const isAllowlisted = stateManager._domainIsListed(initiatorDomain);
|
||||||
mimeType = header.value.replace(/;.*/, '').toLowerCase();
|
|
||||||
isAllowlisted = stateManager._domainIsListed(initiatorDomain);
|
|
||||||
|
|
||||||
if (!isAllowlisted && mimeType === 'text/html') {
|
if (!isAllowlisted && mimeType === 'text/html') {
|
||||||
|
|
||||||
let initDecoder, decoder, encoder, charset, isFirstData, filter, data;
|
const charset = (/charset\s*=/).test(header.value) && header.value.replace(/^.*?charset\s*=\s*/, '').replace(/["']?/g, '');
|
||||||
|
|
||||||
charset = (/charset\s*=/).test(header.value) && header.value.replace(/^.*?charset\s*=\s*/, '').replace(/["']?/g, '');
|
|
||||||
|
|
||||||
// Check if charset is supported by TextDecoder()
|
// Check if charset is supported by TextDecoder()
|
||||||
if ((/charset\s*=/).test(header.value) && !EncodingTypes[charset.toString().toLowerCase()]) {
|
if ((/charset\s*=/).test(header.value) && !EncodingTypes[charset.toString().toLowerCase()]) {
|
||||||
@@ -64,11 +60,13 @@ manipulateDOM._removeCrossOriginAndIntegrityAttr = function (details) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use charset of the response header in the initial TextDecoder. ASCII only as fallback.
|
// Use charset of the response header in the initial TextDecoder. ASCII only as fallback.
|
||||||
initDecoder = new TextDecoder(charset === false ? 'ASCII' : charset);
|
const initDecoder = new TextDecoder(charset === false ? 'ASCII' : charset);
|
||||||
encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
isFirstData = true;
|
const filter = browser.webRequest.filterResponseData(details.requestId);
|
||||||
filter = browser.webRequest.filterResponseData(details.requestId);
|
|
||||||
data = [];
|
let isFirstData = true;
|
||||||
|
let data = [];
|
||||||
|
let decoder;
|
||||||
|
|
||||||
header.value = 'text/html; charset=UTF-8';
|
header.value = 'text/html; charset=UTF-8';
|
||||||
|
|
||||||
@@ -171,9 +169,8 @@ manipulateDOM._startWithUtf8Bom = function (str) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
manipulateDOM.checkHtmlFilterEnabled = function (url) {
|
manipulateDOM.checkHtmlFilterEnabled = function (url) {
|
||||||
let listedToManipulateDOM, negateHtmlFilter;
|
const listedToManipulateDOM = stateManager._domainIsListed(url, 'manipulate-dom');
|
||||||
listedToManipulateDOM = stateManager._domainIsListed(url, 'manipulate-dom');
|
const negateHtmlFilter = stateManager.getInvertOption;
|
||||||
negateHtmlFilter = stateManager.getInvertOption;
|
|
||||||
|
|
||||||
if ((negateHtmlFilter || listedToManipulateDOM) && !(negateHtmlFilter && listedToManipulateDOM)) {
|
if ((negateHtmlFilter || listedToManipulateDOM) && !(negateHtmlFilter && listedToManipulateDOM)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -186,7 +183,7 @@ manipulateDOM.checkHtmlFilterEnabled = function (url) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable one-var */
|
/* eslint-disable one-var */
|
||||||
let cdnDomainsRE = new RegExp(`//(${Object.keys(mappings.cdn).map((m) => m.replace(/\W/g, '\\$&')).join('|')})/`);
|
const cdnDomainsRE = new RegExp(`//(${Object.keys(mappings.cdn).map((m) => m.replace(/\W/g, '\\$&')).join('|')})/`);
|
||||||
/* eslint-enable one-var */
|
/* eslint-enable one-var */
|
||||||
|
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* Mappings
|
* Mappings
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mappings = {};
|
const mappings = {};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Date of last update.
|
* Date of last update.
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* Messenger
|
* Messenger
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let messenger = {};
|
const messenger = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,11 +32,9 @@ let messenger = {};
|
|||||||
|
|
||||||
messenger._handleMessageReceived = function (message, sender, sendResponse) {
|
messenger._handleMessageReceived = function (message, sender, sendResponse) {
|
||||||
|
|
||||||
let topic, value, popup;
|
const topic = message.topic;
|
||||||
|
const value = message.value;
|
||||||
topic = message.topic;
|
const popup = {};
|
||||||
value = message.value;
|
|
||||||
popup = {};
|
|
||||||
|
|
||||||
switch (topic) {
|
switch (topic) {
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* Request Analyzer
|
* Request Analyzer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let requestAnalyzer = {};
|
const requestAnalyzer = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,21 +31,19 @@ let requestAnalyzer = {};
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
requestAnalyzer.isValidCandidate = function (requestDetails, tabDetails) {
|
requestAnalyzer.isValidCandidate = function (requestDetails, tabDetails) {
|
||||||
let initiatorDomain, requestedDomain, isAllowlisted;
|
const initiatorDomain = helpers.extractDomainFromUrl(tabDetails.url, true);
|
||||||
|
|
||||||
initiatorDomain = helpers.extractDomainFromUrl(tabDetails.url, true);
|
|
||||||
|
|
||||||
if (initiatorDomain === null) {
|
if (initiatorDomain === null) {
|
||||||
initiatorDomain = Address.EXAMPLE;
|
initiatorDomain = Address.EXAMPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If requested Domain not in mappings.js it is not relevant
|
// If requested Domain not in mappings.js it is not relevant
|
||||||
requestedDomain = helpers.extractDomainFromUrl(requestDetails.url, true);
|
const requestedDomain = helpers.extractDomainFromUrl(requestDetails.url, true);
|
||||||
if (mappings['cdn'][requestedDomain] === undefined) {
|
if (mappings['cdn'][requestedDomain] === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
isAllowlisted = helpers.checkAllowlisted(initiatorDomain, requestAnalyzer.allowlistedDomains);
|
const isAllowlisted = helpers.checkAllowlisted(initiatorDomain, requestAnalyzer.allowlistedDomains);
|
||||||
if (isAllowlisted) {
|
if (isAllowlisted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -93,20 +91,19 @@ requestAnalyzer.isGoogleFont = function (domain) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
requestAnalyzer.getLocalTarget = function (requestDetails, initiator) {
|
requestAnalyzer.getLocalTarget = function (requestDetails, initiator) {
|
||||||
let destinationUrl, destinationHost, destinationPath, hostMappings, basePath,
|
let destinationSearchString;
|
||||||
resourceMappings, destinationSearchString;
|
|
||||||
|
|
||||||
destinationSearchString = '';
|
destinationSearchString = '';
|
||||||
destinationUrl = new URL(requestDetails.url);
|
const destinationUrl = new URL(requestDetails.url);
|
||||||
|
|
||||||
destinationHost = destinationUrl.host;
|
const destinationHost = destinationUrl.host;
|
||||||
destinationPath = destinationUrl.pathname;
|
const destinationPath = destinationUrl.pathname;
|
||||||
if (destinationUrl.search) {
|
if (destinationUrl.search) {
|
||||||
destinationSearchString = destinationUrl.search;
|
destinationSearchString = destinationUrl.search;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the proper mappings for the targeted host.
|
// Use the proper mappings for the targeted host.
|
||||||
hostMappings = mappings.cdn[destinationHost];
|
const hostMappings = mappings.cdn[destinationHost];
|
||||||
|
|
||||||
// Resource mapping files are never locally available.
|
// Resource mapping files are never locally available.
|
||||||
if (Resource.MAPPING_EXPRESSION.test(destinationPath)) {
|
if (Resource.MAPPING_EXPRESSION.test(destinationPath)) {
|
||||||
@@ -115,8 +112,8 @@ requestAnalyzer.getLocalTarget = function (requestDetails, initiator) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
basePath = requestAnalyzer._matchBasePath(hostMappings, destinationPath)['result'];
|
const basePath = requestAnalyzer._matchBasePath(hostMappings, destinationPath)['result'];
|
||||||
resourceMappings = hostMappings[basePath];
|
const resourceMappings = hostMappings[basePath];
|
||||||
|
|
||||||
if (!resourceMappings) {
|
if (!resourceMappings) {
|
||||||
return {
|
return {
|
||||||
@@ -142,7 +139,7 @@ requestAnalyzer.getLocalTarget = function (requestDetails, initiator) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
requestAnalyzer._matchBasePath = function (hostMappings, channelPath) {
|
requestAnalyzer._matchBasePath = function (hostMappings, channelPath) {
|
||||||
for (let basePath of Object.keys(hostMappings)) {
|
for (const basePath of Object.keys(hostMappings)) {
|
||||||
if (channelPath.startsWith(basePath)) {
|
if (channelPath.startsWith(basePath)) {
|
||||||
return {
|
return {
|
||||||
'result': basePath,
|
'result': basePath,
|
||||||
@@ -309,7 +306,7 @@ requestAnalyzer._handleUncompressedFiles = function (filename) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
requestAnalyzer._handleTinyMCE = function (channelPath, channelHost, initiator) {
|
requestAnalyzer._handleTinyMCE = function (channelPath, channelHost, initiator) {
|
||||||
let filename = channelPath.replace(Resource.TINYMCE, '');
|
const filename = channelPath.replace(Resource.TINYMCE, '');
|
||||||
if (filename.startsWith('plugins/')) {
|
if (filename.startsWith('plugins/')) {
|
||||||
console.warn(`${LogString.PREFIX} ${LogString.MISSING_RESOURCE} ${channelHost + channelPath}`);
|
console.warn(`${LogString.PREFIX} ${LogString.MISSING_RESOURCE} ${channelHost + channelPath}`);
|
||||||
log.append(initiator, channelHost + channelPath, '-', true);
|
log.append(initiator, channelHost + channelPath, '-', true);
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
* Request Sanitizer
|
* Request Sanitizer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let requestSanitizer = {};
|
const requestSanitizer = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +38,7 @@ const ExtraInfoSpec = BrowserType.FIREFOX
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
requestSanitizer.enable = function () {
|
requestSanitizer.enable = function () {
|
||||||
let onBeforeSendHeaders = chrome.webRequest.onBeforeSendHeaders;
|
const onBeforeSendHeaders = chrome.webRequest.onBeforeSendHeaders;
|
||||||
|
|
||||||
onBeforeSendHeaders.addListener(requestSanitizer._stripMetadata, {
|
onBeforeSendHeaders.addListener(requestSanitizer._stripMetadata, {
|
||||||
'urls': stateManager.validHosts
|
'urls': stateManager.validHosts
|
||||||
@@ -46,7 +46,7 @@ requestSanitizer.enable = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
requestSanitizer.disable = function () {
|
requestSanitizer.disable = function () {
|
||||||
let onBeforeSendHeaders = chrome.webRequest.onBeforeSendHeaders;
|
const onBeforeSendHeaders = chrome.webRequest.onBeforeSendHeaders;
|
||||||
|
|
||||||
onBeforeSendHeaders.removeListener(requestSanitizer._stripMetadata, {
|
onBeforeSendHeaders.removeListener(requestSanitizer._stripMetadata, {
|
||||||
'urls': stateManager.validHosts
|
'urls': stateManager.validHosts
|
||||||
@@ -59,11 +59,9 @@ requestSanitizer.disable = function () {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
requestSanitizer._stripMetadata = function (requestDetails) {
|
requestSanitizer._stripMetadata = function (requestDetails) {
|
||||||
let sensitiveHeaders, initiatorDomain, allowlistedDomains;
|
const sensitiveHeaders = [Header.COOKIE, Header.ORIGIN, Header.REFERER];
|
||||||
|
const initiatorDomain = helpers.extractDomainFromUrl(requestDetails.initiator, true);
|
||||||
sensitiveHeaders = [Header.COOKIE, Header.ORIGIN, Header.REFERER];
|
const allowlistedDomains = helpers.checkAllowlisted(initiatorDomain, requestAnalyzer.allowlistedDomains);
|
||||||
initiatorDomain = helpers.extractDomainFromUrl(requestDetails.initiator, true);
|
|
||||||
allowlistedDomains = helpers.checkAllowlisted(initiatorDomain, requestAnalyzer.allowlistedDomains);
|
|
||||||
|
|
||||||
if (allowlistedDomains) {
|
if (allowlistedDomains) {
|
||||||
return {
|
return {
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* Resources
|
* Resources
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let resources = {
|
const resources = {
|
||||||
|
|
||||||
// Ajax Bootstrap Select
|
// Ajax Bootstrap Select
|
||||||
'ajaxBootstrapSelect': {
|
'ajaxBootstrapSelect': {
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* Shorthands
|
* Shorthands
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let shorthands = {};
|
const shorthands = {};
|
||||||
|
|
||||||
shorthands.specialFiles = function (channelHost, channelPath, searchString) {
|
shorthands.specialFiles = function (channelHost, channelPath, searchString) {
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* State Manager
|
* State Manager
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let stateManager = {};
|
const stateManager = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,26 +31,24 @@ let stateManager = {};
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
stateManager.registerInjection = function (tabIdentifier, injection, url) {
|
stateManager.registerInjection = function (tabIdentifier, injection, url) {
|
||||||
let injectionIdentifier, registeredTab, injectionCount, missingCount, blockedCount,
|
let registeredTab;
|
||||||
initiatorDomain, htmlFilterIsActive;
|
|
||||||
|
|
||||||
if (injection['result'] !== false) {
|
if (injection['result'] !== false) {
|
||||||
injectionIdentifier = injection.source + injection.path;
|
const injectionIdentifier = injection.source + injection.path;
|
||||||
registeredTab = stateManager.tabs[tabIdentifier];
|
registeredTab = stateManager.tabs[tabIdentifier];
|
||||||
registeredTab.injections[injectionIdentifier] = injection;
|
registeredTab.injections[injectionIdentifier] = injection;
|
||||||
}
|
}
|
||||||
|
|
||||||
initiatorDomain = helpers.extractDomainFromUrl(url, true) || Address.EXAMPLE;
|
if (registeredTab === undefined) {
|
||||||
htmlFilterIsActive = manipulateDOM.checkHtmlFilterEnabled(initiatorDomain);
|
|
||||||
|
|
||||||
if (registeredTab !== undefined) {
|
|
||||||
injectionCount = Object.keys(registeredTab.injections).length || 0;
|
|
||||||
missingCount = registeredTab.missing || 0;
|
|
||||||
blockedCount = registeredTab.blocked || 0;
|
|
||||||
} else {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initiatorDomain = helpers.extractDomainFromUrl(url, true) || Address.EXAMPLE;
|
||||||
|
const htmlFilterIsActive = manipulateDOM.checkHtmlFilterEnabled(initiatorDomain);
|
||||||
|
const injectionCount = Object.keys(registeredTab.injections).length || 0;
|
||||||
|
const missingCount = registeredTab.missing || 0;
|
||||||
|
const blockedCount = registeredTab.blocked || 0;
|
||||||
|
|
||||||
if (injectionCount > 0) {
|
if (injectionCount > 0) {
|
||||||
chrome.browserAction.setTitle({
|
chrome.browserAction.setTitle({
|
||||||
'tabId': tabIdentifier,
|
'tabId': tabIdentifier,
|
||||||
@@ -96,9 +94,7 @@ stateManager.addDomainToAllowlist = function (domain) {
|
|||||||
|
|
||||||
stateManager.removeDomainFromAllowlist = function (domain) {
|
stateManager.removeDomainFromAllowlist = function (domain) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let allowlistedDomains;
|
const allowlistedDomains = requestAnalyzer.allowlistedDomains;
|
||||||
|
|
||||||
allowlistedDomains = requestAnalyzer.allowlistedDomains;
|
|
||||||
|
|
||||||
if (allowlistedDomains[domain]) {
|
if (allowlistedDomains[domain]) {
|
||||||
delete allowlistedDomains[domain];
|
delete allowlistedDomains[domain];
|
||||||
@@ -117,7 +113,7 @@ stateManager.removeDomainFromAllowlist = function (domain) {
|
|||||||
|
|
||||||
stateManager.addDomainToManipulateDOMlist = function (domain) {
|
stateManager.addDomainToManipulateDOMlist = function (domain) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let domainsManipulateDOM = requestAnalyzer.domainsManipulateDOM;
|
const domainsManipulateDOM = requestAnalyzer.domainsManipulateDOM;
|
||||||
|
|
||||||
domainsManipulateDOM[domain] = true;
|
domainsManipulateDOM[domain] = true;
|
||||||
|
|
||||||
@@ -127,7 +123,7 @@ stateManager.addDomainToManipulateDOMlist = function (domain) {
|
|||||||
|
|
||||||
stateManager.removeDomainFromManipulateDOMlist = function (domain) {
|
stateManager.removeDomainFromManipulateDOMlist = function (domain) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let domainsManipulateDOM = requestAnalyzer.domainsManipulateDOM;
|
const domainsManipulateDOM = requestAnalyzer.domainsManipulateDOM;
|
||||||
|
|
||||||
delete domainsManipulateDOM[domain];
|
delete domainsManipulateDOM[domain];
|
||||||
|
|
||||||
@@ -137,7 +133,7 @@ stateManager.removeDomainFromManipulateDOMlist = function (domain) {
|
|||||||
|
|
||||||
stateManager.addDomainToGoogleFontsList = function (domain) {
|
stateManager.addDomainToGoogleFontsList = function (domain) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let allowedDomainsGoogleFonts = interceptor.allowedDomainsGoogleFonts;
|
const allowedDomainsGoogleFonts = interceptor.allowedDomainsGoogleFonts;
|
||||||
|
|
||||||
allowedDomainsGoogleFonts[domain] = true;
|
allowedDomainsGoogleFonts[domain] = true;
|
||||||
|
|
||||||
@@ -147,7 +143,7 @@ stateManager.addDomainToGoogleFontsList = function (domain) {
|
|||||||
|
|
||||||
stateManager.removeDomainFromGoogleFontsList = function (domain) {
|
stateManager.removeDomainFromGoogleFontsList = function (domain) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let allowedDomainsGoogleFonts = interceptor.allowedDomainsGoogleFonts;
|
const allowedDomainsGoogleFonts = interceptor.allowedDomainsGoogleFonts;
|
||||||
|
|
||||||
delete allowedDomainsGoogleFonts[domain];
|
delete allowedDomainsGoogleFonts[domain];
|
||||||
|
|
||||||
@@ -160,9 +156,7 @@ stateManager.removeDomainFromGoogleFontsList = function (domain) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
stateManager._createTab = function (tab) {
|
stateManager._createTab = function (tab) {
|
||||||
let tabIdentifier, requestFilters;
|
const tabIdentifier = tab.id;
|
||||||
|
|
||||||
tabIdentifier = tab.id;
|
|
||||||
|
|
||||||
stateManager.tabs[tabIdentifier] = {
|
stateManager.tabs[tabIdentifier] = {
|
||||||
'injections': {},
|
'injections': {},
|
||||||
@@ -170,7 +164,7 @@ stateManager._createTab = function (tab) {
|
|||||||
'blocked': 0
|
'blocked': 0
|
||||||
};
|
};
|
||||||
|
|
||||||
requestFilters = {
|
const requestFilters = {
|
||||||
'tabId': tabIdentifier,
|
'tabId': tabIdentifier,
|
||||||
'urls': stateManager.validHosts
|
'urls': stateManager.validHosts
|
||||||
};
|
};
|
||||||
@@ -185,12 +179,11 @@ stateManager._removeTab = function (tabIdentifier) {
|
|||||||
delete stateManager.tabs[tabIdentifier];
|
delete stateManager.tabs[tabIdentifier];
|
||||||
};
|
};
|
||||||
|
|
||||||
stateManager._updateTab = function (details) {
|
stateManager._updateTab = function (details) {
|
||||||
let tabDomain, domainIsAllowlisted, frameIdentifier, tabIdentifier;
|
const tabDomain = helpers.extractDomainFromUrl(details.url, true);
|
||||||
tabDomain = helpers.extractDomainFromUrl(details.url, true);
|
const domainIsAllowlisted = stateManager._domainIsListed(tabDomain);
|
||||||
domainIsAllowlisted = stateManager._domainIsListed(tabDomain);
|
const frameIdentifier = details.frameId;
|
||||||
frameIdentifier = details.frameId;
|
const tabIdentifier = details.tabId;
|
||||||
tabIdentifier = details.tabId;
|
|
||||||
|
|
||||||
if (frameIdentifier !== 0 || tabIdentifier === -1) {
|
if (frameIdentifier !== 0 || tabIdentifier === -1) {
|
||||||
return;
|
return;
|
||||||
@@ -268,13 +261,13 @@ stateManager._removeIconBadgeFromTab = function (tab) {
|
|||||||
|
|
||||||
stateManager._domainIsListed = function (domain, listname) {
|
stateManager._domainIsListed = function (domain, listname) {
|
||||||
if (domain !== null) {
|
if (domain !== null) {
|
||||||
let allowlistRecord, isAllowlisted;
|
let isAllowlisted;
|
||||||
|
|
||||||
if (listname === 'manipulate-dom') {
|
if (listname === 'manipulate-dom') {
|
||||||
allowlistRecord = helpers.checkAllowlisted(domain, requestAnalyzer.domainsManipulateDOM);
|
const allowlistRecord = helpers.checkAllowlisted(domain, requestAnalyzer.domainsManipulateDOM);
|
||||||
isAllowlisted = Boolean(allowlistRecord);
|
isAllowlisted = Boolean(allowlistRecord);
|
||||||
} else {
|
} else {
|
||||||
allowlistRecord = helpers.checkAllowlisted(domain, requestAnalyzer.allowlistedDomains);
|
const allowlistRecord = helpers.checkAllowlisted(domain, requestAnalyzer.allowlistedDomains);
|
||||||
isAllowlisted = Boolean(allowlistRecord);
|
isAllowlisted = Boolean(allowlistRecord);
|
||||||
}
|
}
|
||||||
return isAllowlisted;
|
return isAllowlisted;
|
||||||
@@ -304,7 +297,7 @@ stateManager.hideDonationButton = false;
|
|||||||
stateManager.changeBadgeColorMissingResources = false;
|
stateManager.changeBadgeColorMissingResources = false;
|
||||||
stateManager.logging = false;
|
stateManager.logging = false;
|
||||||
|
|
||||||
for (let mapping in mappings.cdn) {
|
for (const mapping in mappings.cdn) {
|
||||||
let supportedHost = Address.ANY_PROTOCOL + mapping + Address.ANY_PATH;
|
let supportedHost = Address.ANY_PROTOCOL + mapping + Address.ANY_PATH;
|
||||||
stateManager.validHosts.push(supportedHost);
|
stateManager.validHosts.push(supportedHost);
|
||||||
}
|
}
|
||||||
@@ -374,7 +367,7 @@ chrome.webRequest.onErrorOccurred.addListener(function (requestDetails) {
|
|||||||
}, {'urls': [Address.ANY]});
|
}, {'urls': [Address.ANY]});
|
||||||
|
|
||||||
chrome.webRequest.onBeforeRedirect.addListener(function (requestDetails) {
|
chrome.webRequest.onBeforeRedirect.addListener(function (requestDetails) {
|
||||||
let knownRequest = stateManager.requests[requestDetails.requestId];
|
const knownRequest = stateManager.requests[requestDetails.requestId];
|
||||||
if (knownRequest) {
|
if (knownRequest) {
|
||||||
stateManager.registerInjection(
|
stateManager.registerInjection(
|
||||||
knownRequest.tabIdentifier,
|
knownRequest.tabIdentifier,
|
||||||
|
@@ -26,7 +26,7 @@ const InvalidFile = 'Invalid file!';
|
|||||||
* Storage Manager
|
* Storage Manager
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let storageManager = {};
|
const storageManager = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,10 +120,9 @@ storageManager.startImportFilePicker = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
storageManager.handleImportFilePicker = function () {
|
storageManager.handleImportFilePicker = function () {
|
||||||
let file, reader;
|
const file = document.getElementById('import-file-picker').files[0];
|
||||||
file = document.getElementById('import-file-picker').files[0];
|
const reader = new FileReader();
|
||||||
|
|
||||||
reader = new FileReader();
|
|
||||||
reader.readAsText(file, 'UTF-8');
|
reader.readAsText(file, 'UTF-8');
|
||||||
|
|
||||||
reader.onload = (ev) => {
|
reader.onload = (ev) => {
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
* Helpers
|
* Helpers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let helpers = {};
|
const helpers = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,14 +31,12 @@ let helpers = {};
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
helpers.insertI18nContentIntoDocument = function (document) {
|
helpers.insertI18nContentIntoDocument = function (document) {
|
||||||
let scriptDirection, i18nElements, translationComplete;
|
const translationComplete = true;
|
||||||
|
const scriptDirection = helpers.determineScriptDirection(navigator.language);
|
||||||
translationComplete = true;
|
const i18nElements = document.querySelectorAll('[data-i18n-content]');
|
||||||
scriptDirection = helpers.determineScriptDirection(navigator.language);
|
|
||||||
i18nElements = document.querySelectorAll('[data-i18n-content]');
|
|
||||||
|
|
||||||
i18nElements.forEach(function (i18nElement) {
|
i18nElements.forEach(function (i18nElement) {
|
||||||
let i18nMessageName = i18nElement.getAttribute('data-i18n-content');
|
const i18nMessageName = i18nElement.getAttribute('data-i18n-content');
|
||||||
|
|
||||||
if (chrome.i18n.getMessage(i18nMessageName) !== '') {
|
if (chrome.i18n.getMessage(i18nMessageName) !== '') {
|
||||||
if (i18nElement.type === 'button') {
|
if (i18nElement.type === 'button') {
|
||||||
@@ -56,10 +54,8 @@ helpers.insertI18nContentIntoDocument = function (document) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
helpers.insertI18nTitlesIntoDocument = function (document) {
|
helpers.insertI18nTitlesIntoDocument = function (document) {
|
||||||
let scriptDirection, i18nElements;
|
const scriptDirection = helpers.determineScriptDirection(navigator.language);
|
||||||
|
const i18nElements = document.querySelectorAll('[data-i18n-title]');
|
||||||
scriptDirection = helpers.determineScriptDirection(navigator.language);
|
|
||||||
i18nElements = document.querySelectorAll('[data-i18n-title]');
|
|
||||||
|
|
||||||
i18nElements.forEach(function (i18nElement) {
|
i18nElements.forEach(function (i18nElement) {
|
||||||
let i18nMessageName = i18nElement.getAttribute('data-i18n-title');
|
let i18nMessageName = i18nElement.getAttribute('data-i18n-title');
|
||||||
@@ -70,11 +66,10 @@ helpers.insertI18nTitlesIntoDocument = function (document) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
helpers.languageIsFullySupported = function (language) {
|
helpers.languageIsFullySupported = function (language) {
|
||||||
let languageSupported, supportedLanguages;
|
|
||||||
|
|
||||||
languageSupported = false;
|
let languageSupported = false;
|
||||||
|
|
||||||
supportedLanguages = [
|
const supportedLanguages = [
|
||||||
'ar',
|
'ar',
|
||||||
'bg',
|
'bg',
|
||||||
'ca',
|
'ca',
|
||||||
@@ -126,7 +121,7 @@ helpers.languageIsFullySupported = function (language) {
|
|||||||
'zh_Hant'
|
'zh_Hant'
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let supportedLanguage of supportedLanguages) {
|
for (const supportedLanguage of supportedLanguages) {
|
||||||
if (language.search(supportedLanguage) !== -1) {
|
if (language.search(supportedLanguage) !== -1) {
|
||||||
languageSupported = true;
|
languageSupported = true;
|
||||||
}
|
}
|
||||||
@@ -178,7 +173,7 @@ helpers.getWildcard = function (initiatorDomain) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
helpers.getTopLevelDomain = function (initiatorDomain) {
|
helpers.getTopLevelDomain = function (initiatorDomain) {
|
||||||
let domain = initiatorDomain.split('.');
|
const domain = initiatorDomain.split('.');
|
||||||
|
|
||||||
domain[domain.length - 2] = '*';
|
domain[domain.length - 2] = '*';
|
||||||
return `${domain[domain.length - 2]}.${domain[domain.length - 1]}`;
|
return `${domain[domain.length - 2]}.${domain[domain.length - 1]}`;
|
||||||
@@ -211,23 +206,22 @@ helpers.getAllSubdomains = function (domain) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
helpers.extractFilenameFromPath = function (path) {
|
helpers.extractFilenameFromPath = function (path) {
|
||||||
let pathSegments, filename;
|
|
||||||
|
|
||||||
pathSegments = path.split('/');
|
const pathSegments = path.split('/');
|
||||||
filename = pathSegments[pathSegments.length - 1];
|
const filename = pathSegments[pathSegments.length - 1];
|
||||||
|
|
||||||
return filename === '' ? pathSegments[1] : filename;
|
return filename === '' ? pathSegments[1] : filename;
|
||||||
};
|
};
|
||||||
|
|
||||||
helpers.generateRandomHexString = function (length) {
|
helpers.generateRandomHexString = function (length) {
|
||||||
let randomValues, randomHexString;
|
let randomHexString;
|
||||||
|
|
||||||
randomValues = crypto.getRandomValues(new Uint8Array(length));
|
const randomValues = crypto.getRandomValues(new Uint8Array(length));
|
||||||
randomHexString = '';
|
randomHexString = '';
|
||||||
|
|
||||||
for (let value of randomValues) {
|
for (const value of randomValues) {
|
||||||
// eslint-disable-next-line no-bitwise
|
// eslint-disable-next-line no-bitwise
|
||||||
let hexValue = (0 ^ (value & (15 >> (0 / 4)))).toString(16);
|
const hexValue = (0 ^ (value & (15 >> (0 / 4)))).toString(16);
|
||||||
randomHexString += hexValue;
|
randomHexString += hexValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,9 +233,9 @@ helpers.determineCdnName = function (domainName) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
helpers.determineScriptDirection = function (language) {
|
helpers.determineScriptDirection = function (language) {
|
||||||
let rightToLeftLanguages, scriptDirection;
|
let scriptDirection;
|
||||||
|
|
||||||
rightToLeftLanguages = ['ar', 'he'];
|
const rightToLeftLanguages = ['ar', 'he'];
|
||||||
|
|
||||||
if (rightToLeftLanguages.indexOf(language) === -1) {
|
if (rightToLeftLanguages.indexOf(language) === -1) {
|
||||||
scriptDirection = 'ltr';
|
scriptDirection = 'ltr';
|
||||||
@@ -313,7 +307,7 @@ helpers.compareVersion = function (v1, v2) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
helpers.isGoogleDomain = function (initiatorDomain) {
|
helpers.isGoogleDomain = function (initiatorDomain) {
|
||||||
let parts = initiatorDomain.split('.');
|
const parts = initiatorDomain.split('.');
|
||||||
|
|
||||||
// remove subdomains if exist
|
// remove subdomains if exist
|
||||||
if (parts.length > 2) {
|
if (parts.length > 2) {
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
* Log
|
* Log
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let log = {};
|
const log = {};
|
||||||
|
|
||||||
log.append = function (initiator, resource, target, highlight, iframe = '') {
|
log.append = function (initiator, resource, target, highlight, iframe = '') {
|
||||||
storageManager.type.get(Setting.LOGGING, function (items) {
|
storageManager.type.get(Setting.LOGGING, function (items) {
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
* Updates
|
* Updates
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let ruleGenerator = {};
|
const ruleGenerator = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,13 +27,12 @@ let ruleGenerator = {};
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ruleGenerator.openRuleSet = function ({target}) {
|
ruleGenerator.openRuleSet = function ({target}) {
|
||||||
let urls, key, textArea, btnCopy, content;
|
const urls = mappings.cdn;
|
||||||
|
const key = target.getAttribute('data-ruleset');
|
||||||
urls = mappings.cdn;
|
const textArea = document.getElementById('generated-rules');
|
||||||
key = target.getAttribute('data-ruleset');
|
const btnCopy = document.getElementById('button-copy-rule-set');
|
||||||
textArea = document.getElementById('generated-rules');
|
|
||||||
btnCopy = document.getElementById('button-copy-rule-set');
|
let content = '';
|
||||||
content = '';
|
|
||||||
|
|
||||||
textArea.style.display = 'block';
|
textArea.style.display = 'block';
|
||||||
btnCopy.style.display = 'block';
|
btnCopy.style.display = 'block';
|
||||||
@@ -59,7 +58,7 @@ ruleGenerator.openRuleSet = function ({target}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ruleGenerator.copyRuleSet = function () {
|
ruleGenerator.copyRuleSet = function () {
|
||||||
let textArea = document.getElementById('generated-rules');
|
const textArea = document.getElementById('generated-rules');
|
||||||
navigator.clipboard.writeText(textArea.value).then(
|
navigator.clipboard.writeText(textArea.value).then(
|
||||||
function () {
|
function () {
|
||||||
textArea.select();
|
textArea.select();
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
* Stats
|
* Stats
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let stats = {};
|
const stats = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,12 +28,11 @@ let stats = {};
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
stats.setStats = function (injection) {
|
stats.setStats = function (injection) {
|
||||||
let data, today, cdn, framework, newEntry, pathSegments;
|
const data = storageManager.statistics;
|
||||||
|
const today = new Date().toISOString().slice(0, 10);
|
||||||
data = storageManager.statistics;
|
const cdn = injection.source;
|
||||||
today = new Date().toISOString().slice(0, 10);
|
let framework, pathSegments, newEntry;
|
||||||
cdn = injection.source;
|
|
||||||
|
|
||||||
if (injection.bundle !== '') {
|
if (injection.bundle !== '') {
|
||||||
pathSegments = injection.path.split('/');
|
pathSegments = injection.path.split('/');
|
||||||
framework = `${pathSegments[0]}/${pathSegments[1]}/${pathSegments[2]}/`;
|
framework = `${pathSegments[0]}/${pathSegments[1]}/${pathSegments[2]}/`;
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
* Targets
|
* Targets
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let targets = {};
|
const targets = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
* Wrappers
|
* Wrappers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let wrappers = {};
|
const wrappers = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user