this fixes #1100: ability to inject directly a resource from redirection library

This commit is contained in:
gorhill 2015-12-22 16:32:09 -05:00
parent 520e251112
commit 1fe5a16c32
6 changed files with 163 additions and 35 deletions

View File

@ -1,5 +1,5 @@
4d0e777a82576a2ec771742abb91925b assets/ublock/unbreak.txt 4d0e777a82576a2ec771742abb91925b assets/ublock/unbreak.txt
f2624cc77fae3f1be5a6b5d5b8027bdc assets/ublock/redirect-resources.txt 62111a29f0a5cb361ba8dbae92054adb assets/ublock/redirect-resources.txt
6c077d6d5b39e8a5a407966ad62c9c32 assets/ublock/privacy.txt 6c077d6d5b39e8a5a407966ad62c9c32 assets/ublock/privacy.txt
9bcc718383fec8b2ce0f9c379f45da9a assets/ublock/filters.txt 9bcc718383fec8b2ce0f9c379f45da9a assets/ublock/filters.txt
146704ad1c0393e342afdb416762c183 assets/ublock/badware.txt 146704ad1c0393e342afdb416762c183 assets/ublock/badware.txt

View File

@ -228,3 +228,10 @@ yavli-defuser.js application/javascript
} catch (ex) { } catch (ex) {
} }
})(); })();
# Addefend defuser
uabinject-defuser.js application/javascript
(function() {
window.uabpdl = window.uabInject = window.uabDetect = true;
})();

View File

@ -90,8 +90,8 @@ return {
// read-only // read-only
systemSettings: { systemSettings: {
compiledMagic: 'cxubjrcfrnrq', compiledMagic: 'xtsldiywhvgc',
selfieMagic: 'mnigwksyvgkv' selfieMagic: 'xtsldiywhvgc'
}, },
restoreBackupSettings: { restoreBackupSettings: {

View File

@ -116,6 +116,8 @@ var cosmeticFilters = function(details) {
vAPI.hideCosmeticFilters = hideCosmeticFilters; vAPI.hideCosmeticFilters = hideCosmeticFilters;
}; };
/******************************************************************************/
var netFilters = function(details) { var netFilters = function(details) {
var parent = document.head || document.documentElement; var parent = document.head || document.documentElement;
if ( !parent ) { if ( !parent ) {
@ -131,6 +133,29 @@ var netFilters = function(details) {
//console.debug('document.querySelectorAll("%s") = %o', text, document.querySelectorAll(text)); //console.debug('document.querySelectorAll("%s") = %o', text, document.querySelectorAll(text));
}; };
/******************************************************************************/
// Create script tags and assign data URIs looked up from our library of
// redirection resources: Sometimes it is useful to use these resources as
// standalone scriptlets.
// Library of redirection resources:
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/redirect-resources.txt
var injectScripts = function(dataURIs) {
var parent = document.head || document.documentElement;
if ( !parent ) {
return;
}
var i = dataURIs.length, scriptTag;
while ( i-- ) {
scriptTag = document.createElement('script');
scriptTag.src = dataURIs[i];
parent.appendChild(scriptTag);
}
};
/******************************************************************************/
var filteringHandler = function(details) { var filteringHandler = function(details) {
var styleTagCount = vAPI.styles.length; var styleTagCount = vAPI.styles.length;
@ -144,6 +169,9 @@ var filteringHandler = function(details) {
if ( details.netHide.length !== 0 ) { if ( details.netHide.length !== 0 ) {
netFilters(details); netFilters(details);
} }
if ( details.scripts !== 0 ) {
injectScripts(details.scripts);
}
// The port will never be used again at this point, disconnecting allows // The port will never be used again at this point, disconnecting allows
// the browser to flush this script from memory. // the browser to flush this script from memory.
} }
@ -164,6 +192,8 @@ var filteringHandler = function(details) {
localMessager.close(); localMessager.close();
}; };
/******************************************************************************/
var hideElements = function(selectors) { var hideElements = function(selectors) {
if ( document.body === null ) { if ( document.body === null ) {
return; return;
@ -213,6 +243,8 @@ var hideElements = function(selectors) {
} }
}; };
/******************************************************************************/
var url = window.location.href; var url = window.location.href;
localMessager.send( localMessager.send(
{ {

View File

@ -244,6 +244,7 @@ var FilterParser = function() {
this.hostnames = []; this.hostnames = [];
this.invalid = false; this.invalid = false;
this.cosmetic = true; this.cosmetic = true;
this.reScriptTagFilter = /^script:(contains|inject)\((.+?)\)$/;
}; };
/******************************************************************************/ /******************************************************************************/
@ -353,12 +354,10 @@ FilterParser.prototype.parse = function(raw) {
// Examples: // Examples:
// focus.de##script:contains(/uabInject/) // focus.de##script:contains(/uabInject/)
// focus.de##script:contains(uabInject) // focus.de##script:contains(uabInject)
// focus.de##script:inject(uabinject-defuser.js)
// Inline script tag filter? var matches = this.reScriptTagFilter.exec(this.suffix);
if ( if ( matches === null ) {
this.suffix.startsWith('script:contains(') === false ||
this.suffix.endsWith(')') === false
) {
return this; return this;
} }
@ -369,19 +368,16 @@ FilterParser.prototype.parse = function(raw) {
return this; return this;
} }
var suffix = this.suffix.slice(16, -1); var token = matches[2];
this.suffix = 'script//:';
// Plain string-based? switch ( matches[1] ) {
if ( suffix.startsWith('/') === false || suffix.endsWith('/') === false ) { case 'contains':
this.suffix += suffix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); this.suffix = 'script?';
return this; // Plain string- or regex-based?
} if ( token.startsWith('/') === false || token.endsWith('/') === false ) {
this.suffix += token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// Regex-based } else {
this.suffix += suffix.slice(1, -1); this.suffix += token.slice(1, -1);
// Valid regex?
if ( isBadRegex(this.suffix) ) { if ( isBadRegex(this.suffix) ) {
console.error( console.error(
"uBlock Origin> discarding bad regular expression-based cosmetic filter '%s': '%s'", "uBlock Origin> discarding bad regular expression-based cosmetic filter '%s': '%s'",
@ -389,7 +385,15 @@ FilterParser.prototype.parse = function(raw) {
isBadRegex.message isBadRegex.message
); );
this.invalid = true; this.invalid = true;
return this; }
}
break;
case 'inject':
this.suffix = 'script+' + token;
break;
default:
this.invalid = true;
break;
} }
return this; return this;
@ -661,6 +665,8 @@ FilterContainer.prototype.reset = function() {
this.entityFilters = {}; this.entityFilters = {};
this.scriptTagFilters = {}; this.scriptTagFilters = {};
this.scriptTagFilterCount = 0; this.scriptTagFilterCount = 0;
this.scriptTags = {};
this.scriptTagCount = 0;
}; };
/******************************************************************************/ /******************************************************************************/
@ -686,9 +692,12 @@ FilterContainer.prototype.isValidSelector = (function() {
return true; return true;
} catch (e) { } catch (e) {
} }
if ( s.startsWith('script//:') ) { // We reach this point very rarely.
if ( s.startsWith('script') ) {
if ( s.startsWith('?', 6) || s.startsWith('+', 6) ) {
return true; return true;
} }
}
console.error('uBlock> invalid cosmetic filter:', s); console.error('uBlock> invalid cosmetic filter:', s);
return false; return false;
}; };
@ -914,8 +923,8 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
// h ir twitter.com .promoted-tweet // h ir twitter.com .promoted-tweet
if ( fields[0] === 'h' ) { if ( fields[0] === 'h' ) {
// Special filter: script tags. Not a real CSS selector. // Special filter: script tags. Not a real CSS selector.
if ( fields[3].startsWith('script//:') ) { if ( fields[3].startsWith('script') ) {
this.createScriptTagFilter(fields[2], fields[3].slice(9)); this.createScriptFilter(fields[2], fields[3].slice(6));
continue; continue;
} }
filter = new FilterHostname(fields[3], fields[2]); filter = new FilterHostname(fields[3], fields[2]);
@ -950,8 +959,8 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
// entity selector // entity selector
if ( fields[0] === 'e' ) { if ( fields[0] === 'e' ) {
// Special filter: script tags. Not a real CSS selector. // Special filter: script tags. Not a real CSS selector.
if ( fields[2].startsWith('script//:') ) { if ( fields[2].startsWith('script?') ) {
this.createScriptTagFilter(fields[1], fields[2].slice(9)); this.createScriptFilter(fields[1], fields[2].slice(6));
continue; continue;
} }
bucket = this.entityFilters[fields[1]]; bucket = this.entityFilters[fields[1]];
@ -1019,6 +1028,17 @@ FilterContainer.prototype.skipCompiledContent = function(text, lineBeg) {
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.createScriptFilter = function(hostname, s) {
if ( s.charAt(0) === '?' ) {
return this.createScriptTagFilter(hostname, s.slice(1));
}
if ( s.charAt(0) === '+' ) {
return this.createScriptTagInjector(hostname, s.slice(1));
}
};
/******************************************************************************/
FilterContainer.prototype.createScriptTagFilter = function(hostname, s) { FilterContainer.prototype.createScriptTagFilter = function(hostname, s) {
if ( this.scriptTagFilters.hasOwnProperty(hostname) ) { if ( this.scriptTagFilters.hasOwnProperty(hostname) ) {
this.scriptTagFilters[hostname] += '|' + s; this.scriptTagFilters[hostname] += '|' + s;
@ -1062,6 +1082,61 @@ FilterContainer.prototype.retrieveScriptTagRegex = function(domain, hostname) {
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.createScriptTagInjector = function(hostname, s) {
if ( this.scriptTags.hasOwnProperty(hostname) ) {
this.scriptTags[hostname].push(s);
} else {
this.scriptTags[hostname] = [s];
}
this.scriptTagCount += 1;
};
/******************************************************************************/
FilterContainer.prototype.retrieveScriptTags = function(domain, hostname) {
if ( this.scriptTagCount === 0 ) {
return;
}
var reng = µb.redirectEngine;
if ( !reng ) {
return;
}
var out = [],
hn = hostname, pos, rnames, i, dataURI;
for (;;) {
rnames = this.scriptTags[hn];
i = rnames && rnames.length || 0;
while ( i-- ) {
if ( (dataURI = reng.resourceFromName(rnames[i], 'application/javascript')) ) {
out.push(dataURI);
}
}
if ( hn === domain ) {
break;
}
pos = hn.indexOf('.');
if ( pos === -1 ) {
break;
}
hn = hn.slice(pos + 1);
}
pos = domain.indexOf('.');
if ( pos !== -1 ) {
hn = domain.slice(0, pos);
rnames = this.scriptTags[hn];
i = rnames && rnames.length || 0;
while ( i-- ) {
if ( (dataURI = reng.resourceFromName(rnames[i], 'application/javascript')) ) {
out.push(dataURI);
}
}
}
return out;
};
/******************************************************************************/
FilterContainer.prototype.freeze = function() { FilterContainer.prototype.freeze = function() {
this.duplicateBuster = {}; this.duplicateBuster = {};
@ -1117,7 +1192,9 @@ FilterContainer.prototype.toSelfie = function() {
highHighGenericHideCount: this.highHighGenericHideCount, highHighGenericHideCount: this.highHighGenericHideCount,
genericDonthide: this.genericDonthide, genericDonthide: this.genericDonthide,
scriptTagFilters: this.scriptTagFilters, scriptTagFilters: this.scriptTagFilters,
scriptTagFilterCount: this.scriptTagFilterCount scriptTagFilterCount: this.scriptTagFilterCount,
scriptTags: this.scriptTags,
scriptTagCount: this.scriptTagCount
}; };
}; };
@ -1180,6 +1257,8 @@ FilterContainer.prototype.fromSelfie = function(selfie) {
this.genericDonthide = selfie.genericDonthide; this.genericDonthide = selfie.genericDonthide;
this.scriptTagFilters = selfie.scriptTagFilters; this.scriptTagFilters = selfie.scriptTagFilters;
this.scriptTagFilterCount = selfie.scriptTagFilterCount; this.scriptTagFilterCount = selfie.scriptTagFilterCount;
this.scriptTags = selfie.scriptTags;
this.scriptTagCount = selfie.scriptTagCount;
this.frozen = true; this.frozen = true;
}; };
@ -1361,7 +1440,8 @@ FilterContainer.prototype.retrieveDomainSelectors = function(request) {
cosmeticHide: [], cosmeticHide: [],
cosmeticDonthide: [], cosmeticDonthide: [],
netHide: [], netHide: [],
netCollapse: µb.userSettings.collapseBlocked netCollapse: µb.userSettings.collapseBlocked,
scripts: this.retrieveScriptTags(domain, hostname)
}; };
var hash, bucket; var hash, bucket;

View File

@ -359,6 +359,15 @@ RedirectEngine.prototype.fromSelfie = function(selfie) {
/******************************************************************************/ /******************************************************************************/
RedirectEngine.prototype.resourceFromName = function(name, mime) {
var entry = this.resources[name];
if ( entry && (mime === undefined || entry.mime.startsWith(mime)) ) {
return entry.toURL();
}
};
/******************************************************************************/
// TODO: combine same key-redirect pairs into a single regex. // TODO: combine same key-redirect pairs into a single regex.
RedirectEngine.prototype.resourcesFromString = function(text) { RedirectEngine.prototype.resourcesFromString = function(text) {