5
5
} from '@adguard/tsurlfilter' ;
6
6
import { CosmeticRuleType } from '@adguard/agtree' ;
7
7
8
- import { CUSTOM_FILTERS_START_ID , LF , USER_FILTER_ID } from '../../common/constants' ;
9
8
import { appContext } from './app-context' ;
10
9
import { engineApi } from './engine-api' ;
11
10
import { tabsApi } from '../tabs/tabs-api' ;
@@ -18,7 +17,7 @@ import { defaultFilteringLog, FilteringEventType } from '../../common/filtering-
18
17
import { getDomain } from '../../common/utils/url' ;
19
18
import { type ContentType } from '../../common/request-type' ;
20
19
import { nanoid } from '../nanoid' ;
21
- import { localScriptRulesService , type LocalScriptFunction } from './services/local-script-rules-service' ;
20
+ import { localScriptRulesService } from './services/local-script-rules-service' ;
22
21
23
22
export type ContentScriptCosmeticData = {
24
23
/**
@@ -42,18 +41,9 @@ export type ContentScriptCosmeticData = {
42
41
*/
43
42
type ScriptsAndScriptletsData = {
44
43
/**
45
- * Script text which is combiner from JS rules only from User rules and Custom filters
46
- * since they are added manually by users. That's why they are considered "local".
44
+ * Script texts from JS rules.
47
45
*/
48
- localScriptText : string ,
49
-
50
- /**
51
- * Script functions combined from JS rules from filters which are pre-built into the extension.
52
- * That's why they are considered "local".
53
- *
54
- * Should be executed by chrome scripting api.
55
- */
56
- localScriptFunctions : LocalScriptFunction [ ] ,
46
+ scriptTexts : string [ ] ,
57
47
58
48
/**
59
49
* List of scriptlet data objects. No need to separate them by type since they are all safe.
@@ -179,52 +169,34 @@ export class CosmeticApi extends CosmeticApiCommon {
179
169
` ;
180
170
}
181
171
182
- /**
183
- * Checks whether the cosmetic (JS) rule is added manually by user —
184
- * is it located in User rules or Custom filters.
185
- *
186
- * @param rule Rule to check.
187
- *
188
- * @returns True if rule is added manually by user.
189
- */
190
- private static isUserAddedRule ( rule : CosmeticRule ) : boolean {
191
- const filterListId = rule . getFilterListId ( ) ;
192
- return filterListId >= CUSTOM_FILTERS_START_ID || filterListId === USER_FILTER_ID ;
193
- }
194
-
195
172
/**
196
173
* It is possible to follow all places using this logic by searching JS_RULES_EXECUTION.
197
174
*
198
175
* This is STEP 3: All previously matched script rules are processed and filtered:
199
176
* - JS rules from pre-built filters (previously collected, pre-built and passed to the engine)
200
- * are going to be executed as functions via chrome.scripting API;
201
- * - JS rules manually added by users (from User rules and Custom filters)
202
- * are going to be executed as script text via script tag injection.
177
+ * are going to be executed as functions via chrome.scripting API.
203
178
*/
204
179
/**
205
180
* Generates data for scriptlets and local scripts:
206
181
* - functions for scriptlets,
207
- * - functions for JS rules from pre-built filters,
208
- * - script text for JS rules from User rules and Custom filters.
182
+ * - script texts for JS rules from pre-built filters.
209
183
*
210
184
* @param cosmeticResult Object containing cosmetic rules.
211
185
*
212
- * @returns An object with data for scriptlets and local scripts — script text and functions .
186
+ * @returns An object with data for scriptlets and script texts .
213
187
*/
214
188
public static getScriptsAndScriptletsData ( cosmeticResult : CosmeticResult ) : ScriptsAndScriptletsData {
215
189
const rules = cosmeticResult . getScriptRules ( ) ;
216
190
217
191
if ( rules . length === 0 ) {
218
192
return {
219
- localScriptText : '' ,
220
- localScriptFunctions : [ ] ,
193
+ scriptTexts : [ ] ,
221
194
scriptletDataList : [ ] ,
222
195
} ;
223
196
}
224
197
225
- const uniqueScriptFunctions = new Set < LocalScriptFunction > ( ) ;
198
+ const uniqueScriptTexts = new Set < string > ( ) ;
226
199
const scriptletDataList = [ ] ;
227
- const uniqueScriptStrings = new Set < string > ( ) ;
228
200
229
201
for ( let i = 0 ; i < rules . length ; i += 1 ) {
230
202
const rule = rules [ i ] ;
@@ -233,36 +205,19 @@ export class CosmeticApi extends CosmeticApiCommon {
233
205
if ( scriptletData ) {
234
206
scriptletDataList . push ( scriptletData ) ;
235
207
}
236
- } else if ( CosmeticApi . isUserAddedRule ( rule ) ) {
237
- // JS rule is manually added by user locally in the extension — save its script text.
238
- const scriptText = rule . getScript ( ) ;
239
- if ( scriptText ) {
240
- uniqueScriptStrings . add ( scriptText . trim ( ) ) ;
241
- }
242
208
} else {
243
209
// TODO: Optimize script injection by checking if common scripts (e.g., AG_)
244
210
// are actually used in the rules. If not, avoid injecting them to reduce overhead.
245
211
246
- // JS rule is pre-built into the extension — save its function.
247
- const scriptFunction = localScriptRulesService . getLocalScriptFunction ( rule ) ;
248
- if ( scriptFunction ) {
249
- uniqueScriptFunctions . add ( scriptFunction ) ;
212
+ const ruleScriptText = rule . getContent ( ) ;
213
+ if ( ruleScriptText ) {
214
+ uniqueScriptTexts . add ( ruleScriptText ) ;
250
215
}
251
216
}
252
217
}
253
218
254
- let scriptText = '' ;
255
- uniqueScriptStrings . forEach ( ( script ) => {
256
- scriptText += script . endsWith ( ';' )
257
- ? `${ script } ${ LF } `
258
- : `${ script } ;${ LF } ` ;
259
- } ) ;
260
-
261
- const wrappedScriptText = CosmeticApi . wrapScriptText ( scriptText ) ;
262
-
263
219
return {
264
- localScriptText : wrappedScriptText ,
265
- localScriptFunctions : [ ...uniqueScriptFunctions ] ,
220
+ scriptTexts : [ ...uniqueScriptTexts ] ,
266
221
scriptletDataList,
267
222
} ;
268
223
}
@@ -327,65 +282,48 @@ export class CosmeticApi extends CosmeticApiCommon {
327
282
return ;
328
283
}
329
284
330
- const localScriptFunctions = frameContext . preparedCosmeticResult ?. localScriptFunctions ;
285
+ const scriptTexts = frameContext . preparedCosmeticResult ?. scriptTexts ;
331
286
332
- if ( ! localScriptFunctions || localScriptFunctions . length === 0 ) {
287
+ if ( ! scriptTexts || scriptTexts . length === 0 ) {
333
288
return ;
334
289
}
335
290
336
291
try {
337
- await Promise . all ( localScriptFunctions . map ( ( scriptFunction ) => {
292
+ await Promise . all ( scriptTexts . map ( ( scriptText ) => {
338
293
/**
339
294
* It is possible to follow all places using this logic by searching JS_RULES_EXECUTION.
340
295
*
341
- * This is STEP 4.1: Apply JS rules from pre-built filters — via chrome.scripting API.
296
+ * This is STEP 4.1: Selecting only local script functions which were pre-built into the extension.
297
+ */
298
+
299
+ /**
300
+ * Here we check if the script text is local to guarantee that we don't execute remote code.
342
301
*/
302
+ const isLocal = localScriptRulesService . isLocal ( scriptText ) ;
303
+ if ( ! isLocal ) {
304
+ return ;
305
+ }
306
+
307
+ /**
308
+ * Here we get the function associated with the script text.
309
+ */
310
+ const localScriptFunction = localScriptRulesService . getLocalScriptFunction ( scriptText ) ;
311
+ if ( ! localScriptFunction ) {
312
+ return ;
313
+ }
314
+
315
+ // eslint-disable-next-line consistent-return
343
316
return ScriptingApi . executeScriptFunc ( {
344
317
tabId,
345
318
frameId,
346
- scriptFunction,
319
+ scriptFunction : localScriptFunction ,
347
320
} ) ;
348
321
} ) ) ;
349
322
} catch ( e ) {
350
323
logger . debug ( '[applyJsFuncsByTabAndFrame] error occurred during injection' , getErrorMessage ( e ) ) ;
351
324
}
352
325
}
353
326
354
- /**
355
- * Injects js locally added rules by user to specified tab and frame.
356
- *
357
- * @param tabId Tab id.
358
- * @param frameId Frame id.
359
- */
360
- public static async applyJsTextByTabAndFrame ( tabId : number , frameId : number ) : Promise < void > {
361
- const frameContext = tabsApi . getFrameContext ( tabId , frameId ) ;
362
-
363
- if ( ! frameContext ) {
364
- return ;
365
- }
366
-
367
- const localScriptText = frameContext . preparedCosmeticResult ?. localScriptText ;
368
-
369
- if ( ! localScriptText ) {
370
- return ;
371
- }
372
-
373
- try {
374
- /**
375
- * It is possible to follow all places using this logic by searching JS_RULES_EXECUTION.
376
- *
377
- * This is STEP 4.2: Apply JS rules manually added by users — via script tag injection.
378
- */
379
- await ScriptingApi . executeScriptText ( {
380
- tabId,
381
- frameId,
382
- scriptText : localScriptText ,
383
- } ) ;
384
- } catch ( e ) {
385
- logger . debug ( '[applyJsTextByTabAndFrame] error occurred during injection' , getErrorMessage ( e ) ) ;
386
- }
387
- }
388
-
389
327
/**
390
328
* Injects js to specified tab and frame.
391
329
*
0 commit comments