From e33c0f9d9c0c4cb80169c43caeda7f509bf2a000 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sun, 22 Oct 2023 08:53:01 -0400 Subject: [PATCH] Minor refactoring plus other minor changes Added more evocative error messages to linter. Made the content of _My filters_ trusted by default in dev build. --- src/js/1p-filters.js | 16 +-- src/js/asset-viewer.js | 4 +- src/js/background.js | 4 + src/js/codemirror/ubo-static-filtering.js | 113 +++++++++++----------- src/js/epicker-ui.js | 9 +- src/js/messaging.js | 4 +- src/js/reverselookup.js | 2 - src/js/static-filtering-parser.js | 18 ++-- src/js/storage.js | 4 - 9 files changed, 81 insertions(+), 93 deletions(-) diff --git a/src/js/1p-filters.js b/src/js/1p-filters.js index f352b6869..76be55f91 100644 --- a/src/js/1p-filters.js +++ b/src/js/1p-filters.js @@ -63,20 +63,14 @@ let cachedUserFilters = ''; let hintUpdateToken = 0; const getHints = async function() { - const response = await vAPI.messaging.send('dashboard', { + const hints = await vAPI.messaging.send('dashboard', { what: 'getAutoCompleteDetails', hintUpdateToken }); - if ( response instanceof Object === false ) { return; } - if ( response.hintUpdateToken !== undefined ) { - const mode = cmEditor.getMode(); - if ( mode.setHints instanceof Function ) { - mode.setHints(response); - } - if ( hintUpdateToken === 0 ) { - mode.parser.expertMode = response.expertMode !== false; - } - hintUpdateToken = response.hintUpdateToken; + if ( hints instanceof Object === false ) { return; } + if ( hints.hintUpdateToken !== undefined ) { + cmEditor.setOption('uboHints', hints); + hintUpdateToken = hints.hintUpdateToken; } timer.on(2503); }; diff --git a/src/js/asset-viewer.js b/src/js/asset-viewer.js index a6cc9d09b..dae50f7a6 100644 --- a/src/js/asset-viewer.js +++ b/src/js/asset-viewer.js @@ -72,9 +72,7 @@ import './codemirror/ubo-static-filtering.js'; what: 'getAutoCompleteDetails' }).then(hints => { if ( hints instanceof Object === false ) { return; } - const mode = cmEditor.getMode(); - if ( mode.setHints instanceof Function === false ) { return; } - mode.setHints(hints); + cmEditor.setOption('uboHints', hints); }); vAPI.messaging.send('dashboard', { diff --git a/src/js/background.js b/src/js/background.js index 3975bf7b2..9006bfaf5 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -89,6 +89,10 @@ const hiddenSettingsDefault = { userResourcesLocation: 'unset', }; +if ( vAPI.webextFlavor.soup.has('devbuild') ) { + hiddenSettingsDefault.trustedListPrefixes += ' user-'; +} + const userSettingsDefault = { advancedUserEnabled: false, alwaysDetachLogger: true, diff --git a/src/js/codemirror/ubo-static-filtering.js b/src/js/codemirror/ubo-static-filtering.js index 7b92085f1..e72c361e5 100644 --- a/src/js/codemirror/ubo-static-filtering.js +++ b/src/js/codemirror/ubo-static-filtering.js @@ -39,22 +39,19 @@ let hintHelperRegistered = false; /******************************************************************************/ -const trustedScriptletTokens = new Set(); -let trustedSource = false; - -CodeMirror.defineOption('trustedSource', false, (cm, value) => { - trustedSource = value; - self.dispatchEvent(new Event('trustedSource')); +CodeMirror.defineOption('trustedSource', false, (cm, state) => { + if ( typeof state !== 'boolean' ) { return; } + self.dispatchEvent(new CustomEvent('trustedSource', { + detail: state, + })); }); -CodeMirror.defineOption('trustedScriptletTokens', trustedScriptletTokens, (cm, tokens) => { +CodeMirror.defineOption('trustedScriptletTokens', undefined, (cm, tokens) => { if ( tokens === undefined || tokens === null ) { return; } if ( typeof tokens[Symbol.iterator] !== 'function' ) { return; } - trustedScriptletTokens.clear(); - for ( const token of tokens ) { - trustedScriptletTokens.add(token); - } - self.dispatchEvent(new Event('trustedScriptletTokens')); + self.dispatchEvent(new CustomEvent('trustedScriptletTokens', { + detail: new Set(tokens), + })); }); /******************************************************************************/ @@ -63,8 +60,6 @@ CodeMirror.defineMode('ubo-static-filtering', function() { const astParser = new sfp.AstFilterParser({ interactive: true, nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'), - trustedSource, - trustedScriptletTokens, }); const astWalker = astParser.getWalker(); let currentWalkerNode = 0; @@ -226,12 +221,12 @@ CodeMirror.defineMode('ubo-static-filtering', function() { return '+'; }; - self.addEventListener('trustedSource', ( ) => { - astParser.options.trustedSource = trustedSource; + self.addEventListener('trustedSource', ev => { + astParser.options.trustedSource = ev.detail; }); - self.addEventListener('trustedScriptletTokens', ( ) => { - astParser.options.trustedScriptletTokens = trustedScriptletTokens; + self.addEventListener('trustedScriptletTokens', ev => { + astParser.options.trustedScriptletTokens = ev.detail; }); return { @@ -283,38 +278,6 @@ CodeMirror.defineMode('ubo-static-filtering', function() { style = style.trim(); return style !== '' ? style : null; }, - setHints: function(details) { - if ( Array.isArray(details.redirectResources) ) { - for ( const [ name, desc ] of details.redirectResources ) { - const displayText = desc.aliasOf !== '' - ? `${name} (${desc.aliasOf})` - : ''; - if ( desc.canRedirect ) { - redirectNames.set(name, displayText); - } - if ( desc.canInject && name.endsWith('.js') ) { - scriptletNames.set(name.slice(0, -3), displayText); - } - } - } - if ( Array.isArray(details.preparseDirectiveEnv)) { - preparseDirectiveEnv.length = 0; - preparseDirectiveEnv.push(...details.preparseDirectiveEnv); - } - if ( Array.isArray(details.preparseDirectiveHints)) { - preparseDirectiveHints.push(...details.preparseDirectiveHints); - } - if ( Array.isArray(details.originHints) ) { - originHints.length = 0; - for ( const hint of details.originHints ) { - originHints.push(hint); - } - } - if ( hintHelperRegistered === false ) { - hintHelperRegistered = true; - initHints(); - } - }, parser: astParser, }; }); @@ -324,7 +287,40 @@ CodeMirror.defineMode('ubo-static-filtering', function() { // Following code is for auto-completion. Reference: // https://codemirror.net/demo/complete.html -const initHints = function() { +CodeMirror.defineOption('uboHints', null, (cm, hints) => { + if ( hints instanceof Object === false ) { return; } + if ( Array.isArray(hints.redirectResources) ) { + for ( const [ name, desc ] of hints.redirectResources ) { + const displayText = desc.aliasOf !== '' + ? `${name} (${desc.aliasOf})` + : ''; + if ( desc.canRedirect ) { + redirectNames.set(name, displayText); + } + if ( desc.canInject && name.endsWith('.js') ) { + scriptletNames.set(name.slice(0, -3), displayText); + } + } + } + if ( Array.isArray(hints.preparseDirectiveEnv)) { + preparseDirectiveEnv.length = 0; + preparseDirectiveEnv.push(...hints.preparseDirectiveEnv); + } + if ( Array.isArray(hints.preparseDirectiveHints)) { + preparseDirectiveHints.push(...hints.preparseDirectiveHints); + } + if ( Array.isArray(hints.originHints) ) { + originHints.length = 0; + for ( const hint of hints.originHints ) { + originHints.push(hint); + } + } + if ( hintHelperRegistered ) { return; } + hintHelperRegistered = true; + initHints(); +}); + +function initHints() { const astParser = new sfp.AstFilterParser({ interactive: true, nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'), @@ -629,7 +625,7 @@ const initHints = function() { } return getOriginHints(cursor, line); }); -}; +} /******************************************************************************/ @@ -695,8 +691,6 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => { const astParser = new sfp.AstFilterParser({ interactive: true, nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'), - trustedSource, - trustedScriptletTokens, }); const changeset = []; @@ -724,6 +718,9 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => { case sfp.AST_ERROR_DOMAIN_NAME: msg = `${msg}: Bad domain name`; break; + case sfp.AST_ERROR_OPTION_BADVALUE: + msg = `${msg}: Bad value assigned to a valid option`; + break; case sfp.AST_ERROR_OPTION_DUPLICATE: msg = `${msg}: Duplicate filter option`; break; @@ -1011,12 +1008,12 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => { } }; - self.addEventListener('trustedSource', ( ) => { - astParser.options.trustedSource = trustedSource; + self.addEventListener('trustedSource', ev => { + astParser.options.trustedSource = ev.detail; }); - self.addEventListener('trustedScriptletTokens', ( ) => { - astParser.options.trustedScriptletTokens = trustedScriptletTokens; + self.addEventListener('trustedScriptletTokens', ev => { + astParser.options.trustedScriptletTokens = ev.detail; }); CodeMirror.defineInitHook(cm => { diff --git a/src/js/epicker-ui.js b/src/js/epicker-ui.js index 0c4fbfd88..ccddf95fc 100644 --- a/src/js/epicker-ui.js +++ b/src/js/epicker-ui.js @@ -89,13 +89,10 @@ const cmEditor = new CodeMirror(document.querySelector('.codeMirrorContainer'), vAPI.messaging.send('dashboard', { what: 'getAutoCompleteDetails' -}).then(response => { +}).then(hints => { // For unknown reasons, `instanceof Object` does not work here in Firefox. - if ( typeof response !== 'object' ) { return; } - const mode = cmEditor.getMode(); - if ( mode.setHints instanceof Function ) { - mode.setHints(response); - } + if ( hints instanceof Object === false ) { return; } + cmEditor.setOption('uboHints', hints); }); /******************************************************************************/ diff --git a/src/js/messaging.js b/src/js/messaging.js index 0a4e0c078..c8f5808af 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -1602,9 +1602,7 @@ const onMessage = function(request, sender, callback) { if ( (request.hintUpdateToken || 0) === 0 ) { response.redirectResources = redirectEngine.getResourceDetails(); response.preparseDirectiveEnv = vAPI.webextFlavor.env.slice(); - response.preparseDirectiveHints = - sfp.utils.preparser.getHints(); - response.expertMode = µb.hiddenSettings.filterAuthorMode; + response.preparseDirectiveHints = sfp.utils.preparser.getHints(); } if ( request.hintUpdateToken !== µb.pageStoresToken ) { response.originHints = getOriginHints(); diff --git a/src/js/reverselookup.js b/src/js/reverselookup.js index 773eba97b..9d2045966 100644 --- a/src/js/reverselookup.js +++ b/src/js/reverselookup.js @@ -130,7 +130,6 @@ const fromNetFilter = async function(rawFilter) { const writer = new CompiledListWriter(); const parser = new sfp.AstFilterParser({ - expertMode: true, trustedSource: true, maxTokenLength: staticNetFilteringEngine.MAX_TOKEN_LENGTH, nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'), @@ -169,7 +168,6 @@ const fromExtendedFilter = async function(details) { const hostname = hostnameFromURI(details.url); const parser = new sfp.AstFilterParser({ - expertMode: true, trustedSource: true, nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'), }); diff --git a/src/js/static-filtering-parser.js b/src/js/static-filtering-parser.js index 15cef54fe..0e15e9e53 100644 --- a/src/js/static-filtering-parser.js +++ b/src/js/static-filtering-parser.js @@ -99,6 +99,7 @@ export const AST_ERROR_PATTERN = 1 << iota++; export const AST_ERROR_DOMAIN_NAME = 1 << iota++; export const AST_ERROR_OPTION_DUPLICATE = 1 << iota++; export const AST_ERROR_OPTION_UNKNOWN = 1 << iota++; +export const AST_ERROR_OPTION_BADVALUE = 1 << iota++; export const AST_ERROR_IF_TOKEN_UNKNOWN = 1 << iota++; export const AST_ERROR_UNTRUSTED_SOURCE = 1 << iota++; @@ -845,7 +846,6 @@ export class AstFilterParser { // Options this.options = options; this.interactive = options.interactive || false; - this.expertMode = options.expertMode || false; this.badTypes = new Set(options.badTypes || []); this.maxTokenLength = options.maxTokenLength || 7; // TODO: rethink this @@ -1475,11 +1475,17 @@ export class AstFilterParser { break; } case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: - realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount || - this.options.trustedSource !== true; - if ( realBad !== true ) { - const path = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM); - realBad = path.charCodeAt(0) !== 0x2F /* / */; + realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount; + if ( realBad ) { break; } + if ( this.options.trustedSource !== true ) { + this.astError = AST_ERROR_UNTRUSTED_SOURCE; + realBad = true; + break; + } + const path = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM); + if ( path.charCodeAt(0) !== 0x2F /* / */ ) { + this.astError = AST_ERROR_OPTION_BADVALUE; + realBad = true; } break; case NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM: diff --git a/src/js/storage.js b/src/js/storage.js index a250a5e3e..2b1a81594 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -1069,11 +1069,7 @@ import { writer.properties.set('trustedSource', trustedSource); } const assetName = details.assetKey ? details.assetKey : '?'; - const expertMode = - details.assetKey !== this.userFiltersPath || - this.hiddenSettings.filterAuthorMode !== false; const parser = new sfp.AstFilterParser({ - expertMode, trustedSource, maxTokenLength: staticNetFilteringEngine.MAX_TOKEN_LENGTH, nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'),