mirror of https://github.com/gorhill/uBlock.git
Remove `assets` dependency from redirect engine
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/1664 This change allows to add the redirect engine into the nodejs package. The purpose of the redirect engine is to resolve a redirect token into a path to a local resource, to be used by the caller as wished.
This commit is contained in:
parent
3879835324
commit
f8daea085b
|
@ -23,8 +23,6 @@
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
import io from './assets.js';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
LineIterator,
|
LineIterator,
|
||||||
orphanizeString,
|
orphanizeString,
|
||||||
|
@ -204,6 +202,14 @@ const mimeFromName = function(name) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// vAPI.warSecret() is optional, it could be absent in some environments,
|
||||||
|
// i.e. nodejs for example. Probably the best approach is to have the
|
||||||
|
// "web_accessible_resources secret" added outside by the client of this
|
||||||
|
// module, but for now I just want to remove an obstacle to modularization.
|
||||||
|
const warSecret = typeof vAPI === 'object' && vAPI !== null
|
||||||
|
? vAPI.warSecret
|
||||||
|
: ( ) => '';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -230,14 +236,20 @@ const RedirectEntry = class {
|
||||||
fctxt instanceof Object &&
|
fctxt instanceof Object &&
|
||||||
fctxt.type !== 'xmlhttprequest'
|
fctxt.type !== 'xmlhttprequest'
|
||||||
) {
|
) {
|
||||||
let url = `${this.warURL}?secret=${vAPI.warSecret()}`;
|
const params = [];
|
||||||
|
const secret = warSecret();
|
||||||
|
if ( secret !== '' ) { params.push(`secret=${secret}`); }
|
||||||
if ( this.params !== undefined ) {
|
if ( this.params !== undefined ) {
|
||||||
for ( const name of this.params ) {
|
for ( const name of this.params ) {
|
||||||
const value = fctxt[name];
|
const value = fctxt[name];
|
||||||
if ( value === undefined ) { continue; }
|
if ( value === undefined ) { continue; }
|
||||||
url += `&${name}=${encodeURIComponent(value)}`;
|
params.push(`${name}=${encodeURIComponent(value)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let url = `${this.warURL}`;
|
||||||
|
if ( params.length !== 0 ) {
|
||||||
|
url += `?${params.join('&')}`;
|
||||||
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
if ( this.data === undefined ) { return; }
|
if ( this.data === undefined ) { return; }
|
||||||
|
@ -439,18 +451,18 @@ const removeTopCommentBlock = function(text) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
RedirectEngine.prototype.loadBuiltinResources = function() {
|
RedirectEngine.prototype.loadBuiltinResources = function(fetcher) {
|
||||||
this.resources = new Map();
|
this.resources = new Map();
|
||||||
this.aliases = new Map();
|
this.aliases = new Map();
|
||||||
|
|
||||||
const fetches = [
|
const fetches = [
|
||||||
io.fetchText(
|
fetcher(
|
||||||
'/assets/resources/scriptlets.js'
|
'/assets/resources/scriptlets.js'
|
||||||
).then(result => {
|
).then(result => {
|
||||||
const content = result.content;
|
const content = result.content;
|
||||||
if ( typeof content === 'string' && content.length !== 0 ) {
|
if ( typeof content !== 'string' ) { return; }
|
||||||
|
if ( content.length === 0 ) { return; }
|
||||||
this.resourcesFromString(content);
|
this.resourcesFromString(content);
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -459,7 +471,7 @@ RedirectEngine.prototype.loadBuiltinResources = function() {
|
||||||
const entry = RedirectEntry.fromSelfie({
|
const entry = RedirectEntry.fromSelfie({
|
||||||
mime: mimeFromName(name),
|
mime: mimeFromName(name),
|
||||||
data,
|
data,
|
||||||
warURL: vAPI.getURL(`/web_accessible_resources/${name}`),
|
warURL: `/web_accessible_resources/${name}`,
|
||||||
params: details.params,
|
params: details.params,
|
||||||
});
|
});
|
||||||
this.resources.set(name, entry);
|
this.resources.set(name, entry);
|
||||||
|
@ -506,10 +518,9 @@ RedirectEngine.prototype.loadBuiltinResources = function() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fetches.push(
|
fetches.push(
|
||||||
io.fetch(
|
fetcher(`/web_accessible_resources/${name}`, {
|
||||||
`/web_accessible_resources/${name}?secret=${vAPI.warSecret()}`,
|
responseType: details.data
|
||||||
{ responseType: details.data }
|
}).then(
|
||||||
).then(
|
|
||||||
result => process(result)
|
result => process(result)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -545,21 +556,22 @@ RedirectEngine.prototype.getResourceDetails = function() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const resourcesSelfieVersion = 5;
|
const RESOURCES_SELFIE_VERSION = 6;
|
||||||
|
const RESOURCES_SELFIE_NAME = 'compiled/redirectEngine/resources';
|
||||||
|
|
||||||
RedirectEngine.prototype.selfieFromResources = function() {
|
RedirectEngine.prototype.selfieFromResources = function(storage) {
|
||||||
io.put(
|
storage.put(
|
||||||
'compiled/redirectEngine/resources',
|
RESOURCES_SELFIE_NAME,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
version: resourcesSelfieVersion,
|
version: RESOURCES_SELFIE_VERSION,
|
||||||
aliases: Array.from(this.aliases),
|
aliases: Array.from(this.aliases),
|
||||||
resources: Array.from(this.resources),
|
resources: Array.from(this.resources),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
RedirectEngine.prototype.resourcesFromSelfie = async function() {
|
RedirectEngine.prototype.resourcesFromSelfie = async function(storage) {
|
||||||
const result = await io.get('compiled/redirectEngine/resources');
|
const result = await storage.get(RESOURCES_SELFIE_NAME);
|
||||||
let selfie;
|
let selfie;
|
||||||
try {
|
try {
|
||||||
selfie = JSON.parse(result.content);
|
selfie = JSON.parse(result.content);
|
||||||
|
@ -567,7 +579,7 @@ RedirectEngine.prototype.resourcesFromSelfie = async function() {
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
selfie instanceof Object === false ||
|
selfie instanceof Object === false ||
|
||||||
selfie.version !== resourcesSelfieVersion ||
|
selfie.version !== RESOURCES_SELFIE_VERSION ||
|
||||||
Array.isArray(selfie.resources) === false
|
Array.isArray(selfie.resources) === false
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -580,8 +592,8 @@ RedirectEngine.prototype.resourcesFromSelfie = async function() {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
RedirectEngine.prototype.invalidateResourcesSelfie = function() {
|
RedirectEngine.prototype.invalidateResourcesSelfie = function(storage) {
|
||||||
io.remove('compiled/redirectEngine/resources');
|
storage.remove(RESOURCES_SELFIE_NAME);
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -140,7 +140,7 @@ const onVersionReady = function(lastVersion) {
|
||||||
|
|
||||||
// Since built-in resources may have changed since last version, we
|
// Since built-in resources may have changed since last version, we
|
||||||
// force a reload of all resources.
|
// force a reload of all resources.
|
||||||
redirectEngine.invalidateResourcesSelfie();
|
redirectEngine.invalidateResourcesSelfie(io);
|
||||||
|
|
||||||
// https://github.com/LiCybora/NanoDefenderFirefox/issues/196
|
// https://github.com/LiCybora/NanoDefenderFirefox/issues/196
|
||||||
// Toggle on the blocking of CSP reports by default for Firefox.
|
// Toggle on the blocking of CSP reports by default for Firefox.
|
||||||
|
|
|
@ -35,7 +35,6 @@ import {
|
||||||
hostnameFromNetworkURL,
|
hostnameFromNetworkURL,
|
||||||
} from './uri-utils.js';
|
} from './uri-utils.js';
|
||||||
|
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
|
||||||
//
|
//
|
||||||
// This import would be best done dynamically, but since dynamic imports are
|
// This import would be best done dynamically, but since dynamic imports are
|
||||||
|
@ -4287,22 +4286,20 @@ FilterContainer.prototype.redirectRequest = function(redirectEngine, fctxt) {
|
||||||
const highest = directives.length - 1;
|
const highest = directives.length - 1;
|
||||||
// More than a single directive means more work.
|
// More than a single directive means more work.
|
||||||
if ( highest !== 0 ) {
|
if ( highest !== 0 ) {
|
||||||
directives.sort(
|
directives.sort((a, b) => compareRedirectRequests(redirectEngine, a, b));
|
||||||
FilterContainer.compareRedirectRequests.bind(this, redirectEngine)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// Redirect to highest-ranked directive
|
// Redirect to highest-ranked directive
|
||||||
const directive = directives[highest];
|
const directive = directives[highest];
|
||||||
if ( (directive.bits & AllowAction) === 0 ) {
|
if ( (directive.bits & AllowAction) === 0 ) {
|
||||||
const { token } =
|
const { token } =
|
||||||
FilterContainer.parseRedirectRequestValue(directive.modifier);
|
parseRedirectRequestValue(directive.modifier);
|
||||||
fctxt.redirectURL = redirectEngine.tokenToURL(fctxt, token);
|
fctxt.redirectURL = redirectEngine.tokenToURL(fctxt, token);
|
||||||
if ( fctxt.redirectURL === undefined ) { return; }
|
if ( fctxt.redirectURL === undefined ) { return; }
|
||||||
}
|
}
|
||||||
return directives;
|
return directives;
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterContainer.parseRedirectRequestValue = function(modifier) {
|
const parseRedirectRequestValue = function(modifier) {
|
||||||
if ( modifier.cache === undefined ) {
|
if ( modifier.cache === undefined ) {
|
||||||
modifier.cache =
|
modifier.cache =
|
||||||
StaticFilteringParser.parseRedirectValue(modifier.value);
|
StaticFilteringParser.parseRedirectValue(modifier.value);
|
||||||
|
@ -4310,12 +4307,12 @@ FilterContainer.parseRedirectRequestValue = function(modifier) {
|
||||||
return modifier.cache;
|
return modifier.cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterContainer.compareRedirectRequests = function(redirectEngine, a, b) {
|
const compareRedirectRequests = function(redirectEngine, a, b) {
|
||||||
const { token: atok, priority: aint, bits: abits } =
|
const { token: atok, priority: aint, bits: abits } =
|
||||||
FilterContainer.parseRedirectRequestValue(a.modifier);
|
parseRedirectRequestValue(a.modifier);
|
||||||
if ( redirectEngine.hasToken(atok) === false ) { return -1; }
|
if ( redirectEngine.hasToken(atok) === false ) { return -1; }
|
||||||
const { token: btok, priority: bint, bits: bbits } =
|
const { token: btok, priority: bint, bits: bbits } =
|
||||||
FilterContainer.parseRedirectRequestValue(b.modifier);
|
parseRedirectRequestValue(b.modifier);
|
||||||
if ( redirectEngine.hasToken(btok) === false ) { return 1; }
|
if ( redirectEngine.hasToken(btok) === false ) { return 1; }
|
||||||
if ( abits !== bbits ) {
|
if ( abits !== bbits ) {
|
||||||
if ( (abits & Important) !== 0 ) { return 1; }
|
if ( (abits & Important) !== 0 ) { return 1; }
|
||||||
|
|
|
@ -1151,11 +1151,19 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
|
|
||||||
µb.loadRedirectResources = async function() {
|
µb.loadRedirectResources = async function() {
|
||||||
try {
|
try {
|
||||||
const success = await redirectEngine.resourcesFromSelfie();
|
const success = await redirectEngine.resourcesFromSelfie(io);
|
||||||
if ( success === true ) { return true; }
|
if ( success === true ) { return true; }
|
||||||
|
|
||||||
|
const fetcher = (path, options = undefined) => {
|
||||||
|
if ( path.startsWith('/web_accessible_resources/') ) {
|
||||||
|
path += `?secret=${vAPI.warSecret()}`;
|
||||||
|
return io.fetch(path, options);
|
||||||
|
}
|
||||||
|
return io.fetchText(path);
|
||||||
|
};
|
||||||
|
|
||||||
const fetchPromises = [
|
const fetchPromises = [
|
||||||
redirectEngine.loadBuiltinResources()
|
redirectEngine.loadBuiltinResources(fetcher)
|
||||||
];
|
];
|
||||||
|
|
||||||
const userResourcesLocation = this.hiddenSettings.userResourcesLocation;
|
const userResourcesLocation = this.hiddenSettings.userResourcesLocation;
|
||||||
|
@ -1182,7 +1190,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
redirectEngine.resourcesFromString(content);
|
redirectEngine.resourcesFromString(content);
|
||||||
redirectEngine.selfieFromResources();
|
redirectEngine.selfieFromResources(io);
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
ubolog(ex);
|
ubolog(ex);
|
||||||
return false;
|
return false;
|
||||||
|
@ -1617,7 +1625,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
this.hiddenSettings.userResourcesLocation !== 'unset' ||
|
this.hiddenSettings.userResourcesLocation !== 'unset' ||
|
||||||
vAPI.webextFlavor.soup.has('devbuild')
|
vAPI.webextFlavor.soup.has('devbuild')
|
||||||
) {
|
) {
|
||||||
redirectEngine.invalidateResourcesSelfie();
|
redirectEngine.invalidateResourcesSelfie(io);
|
||||||
}
|
}
|
||||||
this.loadFilterLists();
|
this.loadFilterLists();
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,12 @@ const supportsFloc = document.interestCohort instanceof Function;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
const patchLocalRedirectURL = url => url.charCodeAt(0) === 0x2F /* '/' */
|
||||||
|
? vAPI.getURL(url)
|
||||||
|
: url;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
// Intercept and filter web requests.
|
// Intercept and filter web requests.
|
||||||
|
|
||||||
const onBeforeRequest = function(details) {
|
const onBeforeRequest = function(details) {
|
||||||
|
@ -102,7 +108,7 @@ const onBeforeRequest = function(details) {
|
||||||
// Redirected
|
// Redirected
|
||||||
|
|
||||||
if ( fctxt.redirectURL !== undefined ) {
|
if ( fctxt.redirectURL !== undefined ) {
|
||||||
return { redirectUrl: fctxt.redirectURL };
|
return { redirectUrl: patchLocalRedirectURL(fctxt.redirectURL) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not redirected
|
// Not redirected
|
||||||
|
@ -208,7 +214,7 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
||||||
// Redirected
|
// Redirected
|
||||||
|
|
||||||
if ( fctxt.redirectURL !== undefined ) {
|
if ( fctxt.redirectURL !== undefined ) {
|
||||||
return { redirectUrl: fctxt.redirectURL };
|
return { redirectUrl: patchLocalRedirectURL(fctxt.redirectURL) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not blocked
|
// Not blocked
|
||||||
|
@ -414,7 +420,7 @@ const onBeforeBehindTheSceneRequest = function(fctxt) {
|
||||||
// Redirected
|
// Redirected
|
||||||
|
|
||||||
if ( fctxt.redirectURL !== undefined ) {
|
if ( fctxt.redirectURL !== undefined ) {
|
||||||
return { redirectUrl: fctxt.redirectURL };
|
return { redirectUrl: patchLocalRedirectURL(fctxt.redirectURL) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocked?
|
// Blocked?
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
import contextMenu from './contextmenu.js';
|
import contextMenu from './contextmenu.js';
|
||||||
import cosmeticFilteringEngine from './cosmetic-filtering.js';
|
import cosmeticFilteringEngine from './cosmetic-filtering.js';
|
||||||
|
import io from './assets.js';
|
||||||
import µb from './background.js';
|
import µb from './background.js';
|
||||||
import { hostnameFromURI } from './uri-utils.js';
|
import { hostnameFromURI } from './uri-utils.js';
|
||||||
import { redirectEngine } from './redirect-engine.js';
|
import { redirectEngine } from './redirect-engine.js';
|
||||||
|
@ -423,7 +424,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
||||||
this.hiddenSettings = hs;
|
this.hiddenSettings = hs;
|
||||||
this.saveHiddenSettings();
|
this.saveHiddenSettings();
|
||||||
if ( mustReloadResources ) {
|
if ( mustReloadResources ) {
|
||||||
redirectEngine.invalidateResourcesSelfie();
|
redirectEngine.invalidateResourcesSelfie(io);
|
||||||
this.loadRedirectResources();
|
this.loadRedirectResources();
|
||||||
}
|
}
|
||||||
this.fireDOMEvent('hiddenSettingsChanged');
|
this.fireDOMEvent('hiddenSettingsChanged');
|
||||||
|
|
Loading…
Reference in New Issue