Skip to content

Commit edbe96a

Browse files
committed
Add logging ability to acs scriptlet, for the benefit of filter list
maintainers. To enable logging, use the JSON approach to pass parameters to `acs` scriptlet. Example: ..##+js(acs, { "target": "document.oncontextmenu", "log": true }) Whereas "target", "needle", and "context" correspond to their respective positional argument. Using JSON form to pass parameters allows to specify extra paramters to facilitate debugging of that scriptlet: - `"log": true` => output useful information at the dev console. - `"debug": true` => break at key locations in the scriptlet. The added logging/debugging capabilities work only in the dev build of uBO or if the advanced setting `filterAuthorMode` is set to `true`.
1 parent 95bd52d commit edbe96a

File tree

2 files changed

+80
-31
lines changed

2 files changed

+80
-31
lines changed

assets/resources/scriptlets.js

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ function safeSelf() {
4949
'RegExp': self.RegExp,
5050
'RegExp_test': self.RegExp.prototype.test,
5151
'RegExp_exec': self.RegExp.prototype.exec,
52+
'safeLog': console.log.bind(console),
53+
'uboLog': function(msg) {
54+
if ( msg !== '' ) {
55+
this.safeLog(`[uBO] ${msg}`);
56+
}
57+
},
5258
};
5359
scriptletGlobals.set('safeSelf', safe);
5460
return safe;
@@ -90,6 +96,28 @@ function getExceptionToken() {
9096
return token;
9197
}
9298

99+
/******************************************************************************/
100+
101+
builtinScriptlets.push({
102+
name: 'should-debug.fn',
103+
fn: shouldDebug,
104+
});
105+
function shouldDebug(details) {
106+
if ( details instanceof Object === false ) { return false; }
107+
return scriptletGlobals.has('canDebug') && details.debug;
108+
}
109+
110+
/******************************************************************************/
111+
112+
builtinScriptlets.push({
113+
name: 'should-log.fn',
114+
fn: shouldLog,
115+
});
116+
function shouldLog(details) {
117+
if ( details instanceof Object === false ) { return false; }
118+
return scriptletGlobals.has('canDebug') && details.log;
119+
}
120+
93121
/*******************************************************************************
94122
95123
Injectable scriptlets
@@ -105,6 +133,9 @@ builtinScriptlets.push({
105133
dependencies: [
106134
'pattern-to-regex.fn',
107135
'get-exception-token.fn',
136+
'safe-self.fn',
137+
'should-debug.fn',
138+
'should-log.fn',
108139
],
109140
});
110141
// Issues to mind before changing anything:
@@ -117,9 +148,10 @@ function abortCurrentScript(
117148
const details = typeof arg1 !== 'object'
118149
? { target: arg1, needle: arg2, context: arg3 }
119150
: arg1;
120-
const { target, needle, context } = details;
151+
const { target = '', needle = '', context = '' } = details;
121152
if ( typeof target !== 'string' ) { return; }
122153
if ( target === '' ) { return; }
154+
const safe = safeSelf();
123155
const reNeedle = patternToRegex(needle);
124156
const reContext = patternToRegex(context);
125157
const thisScript = document.currentScript;
@@ -141,6 +173,8 @@ function abortCurrentScript(
141173
value = owner[prop];
142174
desc = undefined;
143175
}
176+
const log = shouldLog(details);
177+
const debug = shouldDebug(details);
144178
const exceptionToken = getExceptionToken();
145179
const scriptTexts = new WeakMap();
146180
const getScriptText = elem => {
@@ -165,29 +199,38 @@ function abortCurrentScript(
165199
return text;
166200
};
167201
const validate = ( ) => {
202+
if ( debug ) { debugger; } // jshint ignore: line
168203
const e = document.currentScript;
169204
if ( e instanceof HTMLScriptElement === false ) { return; }
170205
if ( e === thisScript ) { return; }
206+
if ( e.src !== '' && log ) { safe.uboLog(`src: ${e.src}`); }
171207
if ( reContext.test(e.src) === false ) { return; }
172-
if ( reNeedle.test(getScriptText(e)) === false ) { return; }
208+
const scriptText = getScriptText(e);
209+
if ( log ) { safe.uboLog(`script text: ${scriptText}`); }
210+
if ( reNeedle.test(scriptText) === false ) { return; }
173211
throw new ReferenceError(exceptionToken);
174212
};
175-
Object.defineProperty(owner, prop, {
176-
get: function() {
177-
validate();
178-
return desc instanceof Object
179-
? desc.get.call(owner)
180-
: value;
181-
},
182-
set: function(a) {
183-
validate();
184-
if ( desc instanceof Object ) {
185-
desc.set.call(owner, a);
186-
} else {
187-
value = a;
213+
if ( debug ) { debugger; } // jshint ignore: line
214+
try {
215+
Object.defineProperty(owner, prop, {
216+
get: function() {
217+
validate();
218+
return desc instanceof Object
219+
? desc.get.call(owner)
220+
: value;
221+
},
222+
set: function(a) {
223+
validate();
224+
if ( desc instanceof Object ) {
225+
desc.set.call(owner, a);
226+
} else {
227+
value = a;
228+
}
188229
}
189-
}
190-
});
230+
});
231+
} catch(ex) {
232+
if ( log ) { safe.uboLog(ex); }
233+
}
191234
}
192235

193236
/******************************************************************************/
@@ -298,7 +341,6 @@ function abortOnStackTrace(
298341
const safe = safeSelf();
299342
const reNeedle = patternToRegex(needle);
300343
const exceptionToken = getExceptionToken();
301-
const log = console.log.bind(console);
302344
const ErrorCtor = self.Error;
303345
const mustAbort = function(err) {
304346
let docURL = self.location.href;
@@ -336,7 +378,7 @@ function abortOnStackTrace(
336378
logLevel === '2' && r ||
337379
logLevel === '3' && !r
338380
) {
339-
log(stack.replace(/\t/g, '\n'));
381+
safe.uboLog(stack.replace(/\t/g, '\n'));
340382
}
341383
return r;
342384
};
@@ -392,6 +434,8 @@ builtinScriptlets.push({
392434
dependencies: [
393435
'pattern-to-regex.fn',
394436
'safe-self.fn',
437+
'should-debug.fn',
438+
'should-log.fn',
395439
],
396440
});
397441
// https://github.com/uBlockOrigin/uAssets/issues/9123#issuecomment-848255120
@@ -408,7 +452,8 @@ function addEventListenerDefuser(
408452
const safe = safeSelf();
409453
const reType = patternToRegex(type);
410454
const rePattern = patternToRegex(pattern);
411-
const logfn = console.log.bind(console);
455+
const log = shouldLog(details);
456+
const debug = shouldDebug(details);
412457
const proto = self.EventTarget.prototype;
413458
proto.addEventListener = new Proxy(proto.addEventListener, {
414459
apply: function(target, thisArg, args) {
@@ -422,17 +467,10 @@ function addEventListenerDefuser(
422467
const matchesHandler = safe.RegExp_test.call(rePattern, handler);
423468
const matchesEither = matchesType || matchesHandler;
424469
const matchesBoth = matchesType && matchesHandler;
425-
if (
426-
details.log === 1 && matchesBoth ||
427-
details.log === 2 && matchesEither ||
428-
details.log === 3
429-
) {
430-
logfn(`uBO: addEventListener('${type}', ${handler})`);
470+
if ( log === 1 && matchesBoth || log === 2 && matchesEither || log === 3 ) {
471+
safe.uboLog(`addEventListener('${type}', ${handler})`);
431472
}
432-
if (
433-
details.debug === 1 && matchesBoth ||
434-
details.debug === 2 && matchesEither
435-
) {
473+
if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) {
436474
debugger; // jshint ignore:line
437475
}
438476
if ( matchesBoth ) { return; }

src/js/scriptlet-filtering.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ const scriptletDB = new StaticExtFilteringHostnameDB(1);
4747
let acceptedCount = 0;
4848
let discardedCount = 0;
4949

50+
let isDevBuild;
51+
5052
const scriptletFilteringEngine = {
5153
get acceptedCount() {
5254
return acceptedCount;
@@ -386,14 +388,23 @@ scriptletFilteringEngine.retrieve = function(request, options = {}) {
386388

387389
if ( cacheDetails.code === '' ) { return; }
388390

391+
const scriptletGlobals = [];
392+
393+
if ( isDevBuild === undefined ) {
394+
isDevBuild = vAPI.webextFlavor.soup.has('devbuild');
395+
}
396+
if ( isDevBuild || µb.hiddenSettings.filterAuthorMode ) {
397+
scriptletGlobals.push([ 'canDebug', true ]);
398+
}
399+
389400
const out = [
390401
'(function() {',
391402
'// >>>> start of private namespace',
392403
'',
393404
µb.hiddenSettings.debugScriptlets ? 'debugger;' : ';',
394405
'',
395406
// For use by scriptlets to share local data among themselves
396-
'const scriptletGlobals = new Map();',
407+
`const scriptletGlobals = new Map(${JSON.stringify(scriptletGlobals, null, 2)});`,
397408
'',
398409
cacheDetails.code,
399410
'',

0 commit comments

Comments
 (0)