@browserless.io/browserless 2.0.0-beta-5 → 2.0.0-beta-7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/LICENSE +2 -0
  2. package/README.md +11 -11
  3. package/bin/browserless.js +169 -11
  4. package/bin/scaffold/README.md +415 -0
  5. package/bin/scaffold/package.json +21 -0
  6. package/bin/scaffold/src/hello-world.http.ts +27 -0
  7. package/bin/scaffold/tsconfig.json +4 -0
  8. package/build/browserless.js +18 -15
  9. package/build/browsers/index.d.ts +2 -18
  10. package/build/browsers/index.js +43 -14
  11. package/build/file-system.d.ts +5 -0
  12. package/build/file-system.js +20 -5
  13. package/build/file-system.spec.d.ts +1 -0
  14. package/build/file-system.spec.js +44 -0
  15. package/build/http.d.ts +3 -3
  16. package/build/http.js +3 -3
  17. package/build/router.js +2 -4
  18. package/build/routes/chromium/http/content-post.body.json +8 -8
  19. package/build/routes/chromium/http/content-post.d.ts +15 -3
  20. package/build/routes/chromium/http/content-post.js +14 -15
  21. package/build/routes/chromium/http/download-post.d.ts +16 -3
  22. package/build/routes/chromium/http/download-post.js +17 -22
  23. package/build/routes/chromium/http/function-post.d.ts +16 -3
  24. package/build/routes/chromium/http/function-post.js +17 -22
  25. package/build/routes/chromium/http/pdf-post.body.json +8 -8
  26. package/build/routes/chromium/http/pdf-post.d.ts +15 -3
  27. package/build/routes/chromium/http/pdf-post.js +19 -15
  28. package/build/routes/chromium/http/performance.d.ts +15 -3
  29. package/build/routes/chromium/http/performance.js +15 -23
  30. package/build/routes/chromium/http/scrape-post.body.json +8 -8
  31. package/build/routes/chromium/http/scrape-post.d.ts +15 -3
  32. package/build/routes/chromium/http/scrape-post.js +15 -16
  33. package/build/routes/chromium/http/screenshot-post.body.json +8 -8
  34. package/build/routes/chromium/http/screenshot-post.d.ts +15 -3
  35. package/build/routes/chromium/http/screenshot-post.js +18 -15
  36. package/build/routes/chromium/tests/websocket.spec.js +20 -1
  37. package/build/routes/chromium/utils/function/handler.js +2 -2
  38. package/build/routes/chromium/ws/browser.d.ts +13 -3
  39. package/build/routes/chromium/ws/browser.js +10 -11
  40. package/build/routes/chromium/ws/cdp-chromium.d.ts +13 -3
  41. package/build/routes/chromium/ws/cdp-chromium.js +10 -11
  42. package/build/routes/chromium/ws/page.d.ts +13 -3
  43. package/build/routes/chromium/ws/page.js +10 -11
  44. package/build/routes/chromium/ws/playwright-chromium.d.ts +13 -3
  45. package/build/routes/chromium/ws/playwright-chromium.js +11 -12
  46. package/build/routes/firefox/ws/playwright-firefox.d.ts +13 -3
  47. package/build/routes/firefox/ws/playwright-firefox.js +11 -12
  48. package/build/routes/management/http/config-get.d.ts +15 -3
  49. package/build/routes/management/http/config-get.js +15 -20
  50. package/build/routes/management/http/metrics-get.d.ts +15 -3
  51. package/build/routes/management/http/metrics-get.js +16 -21
  52. package/build/routes/management/http/metrics-total-get.d.ts +15 -3
  53. package/build/routes/management/http/metrics-total-get.js +16 -21
  54. package/build/routes/management/http/sessions-get.d.ts +15 -3
  55. package/build/routes/management/http/sessions-get.js +16 -20
  56. package/build/routes/management/http/static-get.d.ts +15 -3
  57. package/build/routes/management/http/static-get.js +15 -20
  58. package/build/routes/webkit/ws/playwright-webkit.d.ts +13 -3
  59. package/build/routes/webkit/ws/playwright-webkit.js +11 -12
  60. package/build/server.js +0 -1
  61. package/build/types.d.ts +48 -38
  62. package/build/types.js +135 -0
  63. package/extensions/ublock/1p-filters.html +0 -1
  64. package/extensions/ublock/3p-filters.html +0 -2
  65. package/extensions/ublock/_locales/bg/messages.json +6 -6
  66. package/extensions/ublock/_locales/br_FR/messages.json +14 -14
  67. package/extensions/ublock/_locales/bs/messages.json +8 -8
  68. package/extensions/ublock/_locales/ca/messages.json +1 -1
  69. package/extensions/ublock/_locales/da/messages.json +5 -5
  70. package/extensions/ublock/_locales/fa/messages.json +1 -1
  71. package/extensions/ublock/_locales/fi/messages.json +6 -6
  72. package/extensions/ublock/_locales/hr/messages.json +4 -4
  73. package/extensions/ublock/_locales/nb/messages.json +1 -1
  74. package/extensions/ublock/_locales/no/messages.json +1 -1
  75. package/extensions/ublock/_locales/ro/messages.json +2 -2
  76. package/extensions/ublock/_locales/ru/messages.json +1 -1
  77. package/extensions/ublock/_locales/sk/messages.json +1 -1
  78. package/extensions/ublock/_locales/sv/messages.json +2 -2
  79. package/extensions/ublock/_locales/te/messages.json +17 -17
  80. package/extensions/ublock/_locales/vi/messages.json +12 -12
  81. package/extensions/ublock/_locales/zh_TW/messages.json +13 -13
  82. package/extensions/ublock/assets/assets.json +3 -3
  83. package/extensions/ublock/assets/resources/scriptlets.js +218 -97
  84. package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +3010 -2056
  85. package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +624 -433
  86. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +93 -24
  87. package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +7 -15
  88. package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +795 -777
  89. package/extensions/ublock/assets/ublock/badware.min.txt +138 -72
  90. package/extensions/ublock/assets/ublock/filters.min.txt +1929 -2735
  91. package/extensions/ublock/assets/ublock/privacy.min.txt +57 -26
  92. package/extensions/ublock/assets/ublock/quick-fixes.min.txt +125 -74
  93. package/extensions/ublock/assets/ublock/unbreak.min.txt +46 -53
  94. package/extensions/ublock/css/codemirror.css +8 -7
  95. package/extensions/ublock/css/dom-inspector.css +40 -0
  96. package/extensions/ublock/css/logger-ui-inspector.css +7 -1
  97. package/extensions/ublock/css/logger-ui.css +12 -5
  98. package/extensions/ublock/css/popup-fenix.css +1 -1
  99. package/extensions/ublock/devtools.html +1 -0
  100. package/extensions/ublock/js/1p-filters.js +4 -3
  101. package/extensions/ublock/js/3p-filters.js +25 -31
  102. package/extensions/ublock/js/about.js +1 -1
  103. package/extensions/ublock/js/advanced-settings.js +1 -1
  104. package/extensions/ublock/js/asset-viewer.js +1 -1
  105. package/extensions/ublock/js/assets.js +74 -44
  106. package/extensions/ublock/js/background.js +9 -3
  107. package/extensions/ublock/js/base64-custom.js +1 -1
  108. package/extensions/ublock/js/benchmarks.js +1 -1
  109. package/extensions/ublock/js/biditrie.js +1 -1
  110. package/extensions/ublock/js/broadcast.js +75 -0
  111. package/extensions/ublock/js/cachestorage.js +68 -45
  112. package/extensions/ublock/js/click2load.js +1 -1
  113. package/extensions/ublock/js/cloud-ui.js +1 -1
  114. package/extensions/ublock/js/code-viewer.js +1 -1
  115. package/extensions/ublock/js/codemirror/search-thread.js +1 -1
  116. package/extensions/ublock/js/codemirror/search.js +1 -1
  117. package/extensions/ublock/js/codemirror/ubo-dynamic-filtering.js +1 -1
  118. package/extensions/ublock/js/codemirror/ubo-static-filtering.js +98 -24
  119. package/extensions/ublock/js/commands.js +1 -1
  120. package/extensions/ublock/js/console.js +1 -1
  121. package/extensions/ublock/js/contentscript-extra.js +1 -1
  122. package/extensions/ublock/js/contentscript.js +1 -3
  123. package/extensions/ublock/js/contextmenu.js +1 -1
  124. package/extensions/ublock/js/cosmetic-filtering.js +4 -4
  125. package/extensions/ublock/js/dashboard-common.js +1 -1
  126. package/extensions/ublock/js/dashboard.js +1 -1
  127. package/extensions/ublock/js/devtools.js +23 -15
  128. package/extensions/ublock/js/diff-updater.js +3 -3
  129. package/extensions/ublock/js/document-blocked.js +1 -1
  130. package/extensions/ublock/js/dom-inspector.js +68 -0
  131. package/extensions/ublock/js/dom.js +1 -1
  132. package/extensions/ublock/js/dyna-rules.js +1 -1
  133. package/extensions/ublock/js/dynamic-net-filtering.js +1 -1
  134. package/extensions/ublock/js/epicker-ui.js +35 -59
  135. package/extensions/ublock/js/fa-icons.js +1 -1
  136. package/extensions/ublock/js/filtering-context.js +1 -1
  137. package/extensions/ublock/js/filtering-engines.js +1 -1
  138. package/extensions/ublock/js/hnswitches.js +1 -1
  139. package/extensions/ublock/js/hntrie.js +1 -1
  140. package/extensions/ublock/js/html-filtering.js +1 -1
  141. package/extensions/ublock/js/httpheader-filtering.js +1 -1
  142. package/extensions/ublock/js/i18n.js +1 -1
  143. package/extensions/ublock/js/is-webrtc-supported.js +1 -1
  144. package/extensions/ublock/js/logger-ui-inspector.js +203 -145
  145. package/extensions/ublock/js/logger-ui.js +21 -5
  146. package/extensions/ublock/js/logger.js +6 -2
  147. package/extensions/ublock/js/lz4.js +2 -2
  148. package/extensions/ublock/js/messaging.js +266 -166
  149. package/extensions/ublock/js/mrucache.js +58 -0
  150. package/extensions/ublock/js/pagestore.js +1 -1
  151. package/extensions/ublock/js/popup-fenix.js +2 -1
  152. package/extensions/ublock/js/redirect-engine.js +1 -1
  153. package/extensions/ublock/js/redirect-resources.js +1 -12
  154. package/extensions/ublock/js/reverselookup-worker.js +1 -1
  155. package/extensions/ublock/js/reverselookup.js +1 -1
  156. package/extensions/ublock/js/scriptlet-filtering-core.js +300 -0
  157. package/extensions/ublock/js/scriptlet-filtering.js +122 -350
  158. package/extensions/ublock/js/scriptlets/cosmetic-logger.js +36 -47
  159. package/extensions/ublock/js/scriptlets/cosmetic-off.js +1 -1
  160. package/extensions/ublock/js/scriptlets/cosmetic-on.js +1 -1
  161. package/extensions/ublock/js/scriptlets/cosmetic-report.js +1 -1
  162. package/extensions/ublock/js/scriptlets/dom-inspector.js +341 -323
  163. package/extensions/ublock/js/scriptlets/dom-survey-elements.js +1 -1
  164. package/extensions/ublock/js/scriptlets/dom-survey-scripts.js +1 -1
  165. package/extensions/ublock/js/scriptlets/epicker.js +80 -89
  166. package/extensions/ublock/js/scriptlets/load-3p-css.js +1 -1
  167. package/extensions/ublock/js/scriptlets/load-large-media-all.js +1 -1
  168. package/extensions/ublock/js/scriptlets/load-large-media-interactive.js +1 -1
  169. package/extensions/ublock/js/scriptlets/noscript-spoof.js +1 -1
  170. package/extensions/ublock/js/scriptlets/should-inject-contentscript.js +1 -1
  171. package/extensions/ublock/js/scriptlets/subscriber.js +1 -1
  172. package/extensions/ublock/js/scriptlets/updater.js +20 -3
  173. package/extensions/ublock/js/settings.js +1 -1
  174. package/extensions/ublock/js/start.js +19 -20
  175. package/extensions/ublock/js/static-dnr-filtering.js +1 -1
  176. package/extensions/ublock/js/static-ext-filtering-db.js +1 -1
  177. package/extensions/ublock/js/static-ext-filtering.js +1 -1
  178. package/extensions/ublock/js/static-filtering-io.js +1 -1
  179. package/extensions/ublock/js/static-filtering-parser.js +5 -3
  180. package/extensions/ublock/js/static-net-filtering.js +57 -37
  181. package/extensions/ublock/js/storage.js +49 -29
  182. package/extensions/ublock/js/support.js +4 -4
  183. package/extensions/ublock/js/tab.js +1 -1
  184. package/extensions/ublock/js/tasks.js +1 -1
  185. package/extensions/ublock/js/text-encode.js +1 -1
  186. package/extensions/ublock/js/text-utils.js +1 -1
  187. package/extensions/ublock/js/theme.js +1 -1
  188. package/extensions/ublock/js/traffic.js +2 -1
  189. package/extensions/ublock/js/ublock.js +15 -11
  190. package/extensions/ublock/js/uri-utils.js +1 -1
  191. package/extensions/ublock/js/url-net-filtering.js +1 -1
  192. package/extensions/ublock/js/utils.js +1 -73
  193. package/extensions/ublock/js/vapi-background-ext.js +1 -1
  194. package/extensions/ublock/js/vapi-background.js +92 -83
  195. package/extensions/ublock/js/vapi-client.js +4 -33
  196. package/extensions/ublock/js/vapi-common.js +16 -30
  197. package/extensions/ublock/js/vapi.js +1 -1
  198. package/extensions/ublock/js/wasm/biditrie.wat +1 -1
  199. package/extensions/ublock/js/wasm/hntrie.wat +1 -1
  200. package/extensions/ublock/js/webext.js +1 -1
  201. package/extensions/ublock/js/whitelist.js +1 -1
  202. package/extensions/ublock/logger-ui.html +2 -2
  203. package/extensions/ublock/manifest.json +1 -1
  204. package/extensions/ublock/support.html +0 -1
  205. package/extensions/ublock/web_accessible_resources/dom-inspector.html +25 -0
  206. package/extensions/ublock/web_accessible_resources/epicker-ui.html +0 -1
  207. package/extensions/ublock/web_accessible_resources/googletagservices_gpt.js +1 -0
  208. package/package.json +7 -19
  209. package/scripts/build-open-api.js +7 -4
  210. package/src/browserless.ts +42 -18
  211. package/src/browsers/index.ts +48 -20
  212. package/src/file-system.spec.ts +58 -0
  213. package/src/file-system.ts +36 -8
  214. package/src/http.ts +3 -3
  215. package/src/router.ts +2 -6
  216. package/src/routes/chromium/http/content-post.ts +13 -16
  217. package/src/routes/chromium/http/download-post.ts +16 -27
  218. package/src/routes/chromium/http/function-post.ts +16 -25
  219. package/src/routes/chromium/http/pdf-post.ts +19 -15
  220. package/src/routes/chromium/http/performance.ts +14 -26
  221. package/src/routes/chromium/http/scrape-post.ts +14 -16
  222. package/src/routes/chromium/http/screenshot-post.ts +18 -15
  223. package/src/routes/chromium/tests/websocket.spec.ts +28 -1
  224. package/src/routes/chromium/utils/function/handler.ts +2 -1
  225. package/src/routes/chromium/ws/browser.ts +10 -12
  226. package/src/routes/chromium/ws/cdp-chromium.ts +10 -12
  227. package/src/routes/chromium/ws/page.ts +10 -12
  228. package/src/routes/chromium/ws/playwright-chromium.ts +10 -12
  229. package/src/routes/firefox/ws/playwright-firefox.ts +10 -12
  230. package/src/routes/management/http/config-get.ts +14 -23
  231. package/src/routes/management/http/metrics-get.ts +15 -24
  232. package/src/routes/management/http/metrics-total-get.ts +15 -26
  233. package/src/routes/management/http/sessions-get.ts +15 -23
  234. package/src/routes/management/http/static-get.ts +14 -22
  235. package/src/routes/webkit/ws/playwright-webkit.ts +10 -12
  236. package/src/server.ts +0 -1
  237. package/src/types.ts +59 -45
  238. package/static/docs/browserless-logo-inline.svg +1 -0
  239. package/static/docs/index.html +27 -0
  240. package/static/docs/swagger.json +33 -33
  241. package/static/function/client.js +626 -78
  242. package/extensions/ublock/js/vapi-client-extra.js +0 -312
  243. package/extensions/ublock/web_accessible_resources/addthis_widget.js +0 -39
  244. package/extensions/ublock/web_accessible_resources/ligatus_angular-tag.js +0 -29
  245. package/extensions/ublock/web_accessible_resources/monkeybroker.js +0 -43
  246. package/extensions/ublock/web_accessible_resources/mxpnl_mixpanel.js +0 -51
@@ -1,6 +1,6 @@
1
1
  /*******************************************************************************
2
2
 
3
- uBlock Origin - a browser extension to block requests.
3
+ uBlock Origin - a comprehensive, efficient content blocker
4
4
  Copyright (C) 2017-present Raymond Hill
5
5
 
6
6
  This program is free software: you can redistribute it and/or modify
@@ -26,9 +26,12 @@
26
26
  /******************************************************************************/
27
27
 
28
28
  import µb from './background.js';
29
+ import logger from './logger.js';
30
+ import { onBroadcast } from './broadcast.js';
29
31
  import { redirectEngine as reng } from './redirect-engine.js';
30
32
  import { sessionFirewall } from './filtering-engines.js';
31
- import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js';
33
+ import { MRUCache } from './mrucache.js';
34
+ import { ScriptletFilteringEngine } from './scriptlet-filtering-core.js';
32
35
 
33
36
  import {
34
37
  domainFromHostname,
@@ -38,41 +41,14 @@ import {
38
41
 
39
42
  /******************************************************************************/
40
43
 
41
- // Increment when internal representation changes
42
- const VERSION = 1;
43
-
44
- const duplicates = new Set();
45
- const scriptletCache = new µb.MRUCache(32);
46
-
47
- const scriptletDB = new StaticExtFilteringHostnameDB(1, VERSION);
48
-
49
- let acceptedCount = 0;
50
- let discardedCount = 0;
51
-
52
- let isDevBuild;
53
-
54
- const scriptletFilteringEngine = {
55
- get acceptedCount() {
56
- return acceptedCount;
57
- },
58
- get discardedCount() {
59
- return discardedCount;
60
- },
61
- getFilterCount() {
62
- return scriptletDB.size;
63
- },
64
- };
65
-
66
44
  const contentScriptRegisterer = new (class {
67
45
  constructor() {
68
46
  this.hostnameToDetails = new Map();
69
47
  if ( browser.contentScripts === undefined ) { return; }
70
- µb.onEvent('filteringBehaviorChanged', ev => {
71
- const details = ev.detail;
72
- if ( details instanceof Object ) {
73
- if ( details.direction > 0 ) { return; }
74
- if ( details.hostname ) { return this.flush(details.hostname); }
75
- }
48
+ onBroadcast(msg => {
49
+ if ( msg.what !== 'filteringBehaviorChanged' ) { return; }
50
+ if ( msg.direction > 0 ) { return; }
51
+ if ( msg.hostname ) { return this.flush(msg.hostname); }
76
52
  this.reset();
77
53
  });
78
54
  }
@@ -133,27 +109,7 @@ const contentScriptRegisterer = new (class {
133
109
  }
134
110
  })();
135
111
 
136
- // Purpose of `contentscriptCode` below is too programmatically inject
137
- // content script code which only purpose is to inject scriptlets. This
138
- // essentially does the same as what uBO's declarative content script does,
139
- // except that this allows to inject the scriptlets earlier than it is
140
- // possible through the declarative content script.
141
- //
142
- // Declaratively:
143
- // 1. Browser injects generic content script =>
144
- // 2. Content script queries scriptlets =>
145
- // 3. Main process sends scriptlets =>
146
- // 4. Content script injects scriptlets
147
- //
148
- // Programmatically:
149
- // 1. uBO injects specific scriptlets-aware content script =>
150
- // 2. Content script injects scriptlets
151
- //
152
- // However currently this programmatic injection works well only on
153
- // Chromium-based browsers, it does not work properly with Firefox. More
154
- // investigations is needed to find out why this fails with Firefox.
155
- // Consequently, the programmatic-injection code path is taken only with
156
- // Chromium-based browsers.
112
+ /******************************************************************************/
157
113
 
158
114
  const mainWorldInjector = (( ) => {
159
115
  const parts = [
@@ -222,335 +178,151 @@ const isolatedWorldInjector = (( ) => {
222
178
  };
223
179
  })();
224
180
 
225
- const normalizeRawFilter = function(parser, sourceIsTrusted = false) {
226
- const args = parser.getScriptletArgs();
227
- if ( args.length !== 0 ) {
228
- let token = `${args[0]}.js`;
229
- if ( reng.aliases.has(token) ) {
230
- token = reng.aliases.get(token);
231
- }
232
- if ( parser.isException() !== true ) {
233
- if ( sourceIsTrusted !== true ) {
234
- if ( reng.tokenRequiresTrust(token) ) { return; }
235
- }
236
- }
237
- args[0] = token.slice(0, -3);
238
- }
239
- return JSON.stringify(args);
240
- };
241
-
242
- const lookupScriptlet = function(rawToken, mainMap, isolatedMap) {
243
- if ( mainMap.has(rawToken) || isolatedMap.has(rawToken) ) { return; }
244
- const args = JSON.parse(rawToken);
245
- const token = `${args[0]}.js`;
246
- const details = reng.contentFromName(token, 'text/javascript');
247
- if ( details === undefined ) { return; }
248
- const targetWorldMap = details.world !== 'ISOLATED' ? mainMap : isolatedMap;
249
- const content = patchScriptlet(details.js, args.slice(1));
250
- const dependencies = details.dependencies || [];
251
- while ( dependencies.length !== 0 ) {
252
- const token = dependencies.shift();
253
- if ( targetWorldMap.has(token) ) { continue; }
254
- const details = reng.contentFromName(token, 'fn/javascript') ||
255
- reng.contentFromName(token, 'text/javascript');
256
- if ( details === undefined ) { continue; }
257
- targetWorldMap.set(token, details.js);
258
- if ( Array.isArray(details.dependencies) === false ) { continue; }
259
- dependencies.push(...details.dependencies);
181
+ /******************************************************************************/
182
+
183
+ export class ScriptletFilteringEngineEx extends ScriptletFilteringEngine {
184
+ constructor() {
185
+ super();
186
+ this.warOrigin = vAPI.getURL('/web_accessible_resources');
187
+ this.warSecret = undefined;
188
+ this.scriptletCache = new MRUCache(32);
189
+ this.isDevBuild = undefined;
190
+ onBroadcast(msg => {
191
+ if ( msg.what !== 'hiddenSettingsChanged' ) { return; }
192
+ this.scriptletCache.reset();
193
+ this.isDevBuild = undefined;
194
+ });
260
195
  }
261
- targetWorldMap.set(rawToken, [
262
- 'try {',
263
- '// >>>> scriptlet start',
264
- content,
265
- '// <<<< scriptlet end',
266
- '} catch (e) {',
267
- isDevBuild ? 'console.error(e);' : '',
268
- '}',
269
- ].join('\n'));
270
- };
271
-
272
- // Fill-in scriptlet argument placeholders.
273
- const patchScriptlet = function(content, arglist) {
274
- if ( content.startsWith('function') && content.endsWith('}') ) {
275
- content = `(${content})({{args}});`;
196
+
197
+ reset() {
198
+ super.reset();
199
+ this.warSecret = vAPI.warSecret.long(this.warSecret);
200
+ this.scriptletCache.reset();
201
+ contentScriptRegisterer.reset();
276
202
  }
277
- for ( let i = 0; i < arglist.length; i++ ) {
278
- content = content.replace(`{{${i+1}}}`, arglist[i]);
203
+
204
+ freeze() {
205
+ super.freeze();
206
+ this.warSecret = vAPI.warSecret.long(this.warSecret);
207
+ this.scriptletCache.reset();
208
+ contentScriptRegisterer.reset();
279
209
  }
280
- return content.replace('{{args}}',
281
- JSON.stringify(arglist).slice(1,-1).replace(/\$/g, '$$$')
282
- );
283
- };
284
210
 
285
- const decompile = function(json) {
286
- const args = JSON.parse(json).map(s => s.replace(/,/g, '\\,'));
287
- if ( args.length === 0 ) { return '+js()'; }
288
- return `+js(${args.join(', ')})`;
289
- };
211
+ retrieve(request) {
212
+ const { hostname } = request;
290
213
 
291
- /******************************************************************************/
214
+ // https://github.com/gorhill/uBlock/issues/2835
215
+ // Do not inject scriptlets if the site is under an `allow` rule.
216
+ if ( µb.userSettings.advancedUserEnabled ) {
217
+ if ( sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2 ) {
218
+ return;
219
+ }
220
+ }
292
221
 
293
- scriptletFilteringEngine.logFilters = function(tabId, url, filters) {
294
- if ( typeof filters !== 'string' ) { return; }
295
- const fctxt = µb.filteringContext
296
- .duplicate()
297
- .fromTabId(tabId)
298
- .setRealm('extended')
299
- .setType('scriptlet')
300
- .setURL(url)
301
- .setDocOriginFromURL(url);
302
- for ( const filter of filters.split('\n') ) {
303
- fctxt.setFilter({ source: 'extended', raw: filter }).toLogger();
304
- }
305
- };
306
-
307
- scriptletFilteringEngine.reset = function() {
308
- scriptletDB.clear();
309
- duplicates.clear();
310
- contentScriptRegisterer.reset();
311
- scriptletCache.reset();
312
- acceptedCount = 0;
313
- discardedCount = 0;
314
- };
315
-
316
- scriptletFilteringEngine.freeze = function() {
317
- duplicates.clear();
318
- scriptletDB.collectGarbage();
319
- scriptletCache.reset();
320
- };
321
-
322
- scriptletFilteringEngine.compile = function(parser, writer) {
323
- writer.select('SCRIPTLET_FILTERS');
324
-
325
- // Only exception filters are allowed to be global.
326
- const isException = parser.isException();
327
- const normalized = normalizeRawFilter(parser, writer.properties.get('trustedSource'));
328
-
329
- // Can fail if there is a mismatch with trust requirement
330
- if ( normalized === undefined ) { return; }
331
-
332
- // Tokenless is meaningful only for exception filters.
333
- if ( normalized === '[]' && isException === false ) { return; }
334
-
335
- if ( parser.hasOptions() === false ) {
336
- if ( isException ) {
337
- writer.push([ 32, '', 1, normalized ]);
222
+ if ( this.scriptletCache.resetTime < reng.modifyTime ) {
223
+ this.warSecret = vAPI.warSecret.long(this.warSecret);
224
+ this.scriptletCache.reset();
338
225
  }
339
- return;
340
- }
341
226
 
342
- // https://github.com/gorhill/uBlock/issues/3375
343
- // Ignore instances of exception filter with negated hostnames,
344
- // because there is no way to create an exception to an exception.
345
-
346
- for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) {
347
- if ( bad ) { continue; }
348
- let kind = 0;
349
- if ( isException ) {
350
- if ( not ) { continue; }
351
- kind |= 1;
352
- } else if ( not ) {
353
- kind |= 1;
227
+ let scriptletDetails = this.scriptletCache.lookup(hostname);
228
+ if ( scriptletDetails !== undefined ) {
229
+ return scriptletDetails || undefined;
354
230
  }
355
- writer.push([ 32, hn, kind, normalized ]);
356
- }
357
- };
358
231
 
359
- scriptletFilteringEngine.fromCompiledContent = function(reader) {
360
- reader.select('SCRIPTLET_FILTERS');
232
+ if ( this.isDevBuild === undefined ) {
233
+ this.isDevBuild = vAPI.webextFlavor.soup.has('devbuild') ||
234
+ µb.hiddenSettings.filterAuthorMode;
235
+ }
361
236
 
362
- while ( reader.next() ) {
363
- acceptedCount += 1;
364
- const fingerprint = reader.fingerprint();
365
- if ( duplicates.has(fingerprint) ) {
366
- discardedCount += 1;
367
- continue;
237
+ if ( this.warSecret === undefined ) {
238
+ this.warSecret = vAPI.warSecret.long();
368
239
  }
369
- duplicates.add(fingerprint);
370
- const args = reader.args();
371
- if ( args.length < 4 ) { continue; }
372
- scriptletDB.store(args[1], args[2], args[3]);
373
- }
374
- };
375
240
 
376
- const $scriptlets = new Set();
377
- const $exceptions = new Set();
378
- const $mainWorldMap = new Map();
379
- const $isolatedWorldMap = new Map();
241
+ const options = {
242
+ scriptletGlobals: [
243
+ [ 'warOrigin', this.warOrigin ],
244
+ [ 'warSecret', this.warSecret ],
245
+ ],
246
+ debug: this.isDevBuild,
247
+ debugScriptlets: µb.hiddenSettings.debugScriptlets,
248
+ };
380
249
 
381
- scriptletFilteringEngine.retrieve = function(request) {
382
- if ( scriptletDB.size === 0 ) { return; }
250
+ scriptletDetails = super.retrieve(request, options);
383
251
 
384
- const hostname = request.hostname;
252
+ this.scriptletCache.add(hostname, scriptletDetails || null);
385
253
 
386
- // https://github.com/gorhill/uBlock/issues/2835
387
- // Do not inject scriptlets if the site is under an `allow` rule.
388
- if (
389
- µb.userSettings.advancedUserEnabled &&
390
- sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2
391
- ) {
392
- return;
254
+ return scriptletDetails;
393
255
  }
394
256
 
395
- if ( scriptletCache.resetTime < reng.modifyTime ) {
396
- scriptletCache.reset();
397
- }
257
+ injectNow(details) {
258
+ if ( typeof details.frameId !== 'number' ) { return; }
398
259
 
399
- let cacheDetails = scriptletCache.lookup(hostname);
400
- if ( cacheDetails === undefined ) {
401
- $scriptlets.clear();
402
- $exceptions.clear();
403
-
404
- scriptletDB.retrieve(hostname, [ $scriptlets, $exceptions ]);
405
- const entity = request.entity !== ''
406
- ? `${hostname.slice(0, -request.domain.length)}${request.entity}`
407
- : '*';
408
- scriptletDB.retrieve(entity, [ $scriptlets, $exceptions ], 1);
409
- if ( $scriptlets.size === 0 ) { return; }
410
-
411
- // Wholly disable scriptlet injection?
412
- if ( $exceptions.has('[]') ) {
413
- return {
414
- filters: [
415
- { tabId: request.tabId, url: request.url, filter: '#@#+js()' }
416
- ]
417
- };
418
- }
260
+ const request = {
261
+ tabId: details.tabId,
262
+ frameId: details.frameId,
263
+ url: details.url,
264
+ hostname: hostnameFromURI(details.url),
265
+ domain: undefined,
266
+ entity: undefined
267
+ };
419
268
 
420
- for ( const token of $exceptions ) {
421
- if ( $scriptlets.has(token) ) {
422
- $scriptlets.delete(token);
423
- } else {
424
- $exceptions.delete(token);
425
- }
269
+ request.domain = domainFromHostname(request.hostname);
270
+ request.entity = entityFromDomain(request.domain);
271
+
272
+ const scriptletDetails = this.retrieve(request);
273
+ if ( scriptletDetails === undefined ) {
274
+ contentScriptRegisterer.unregister(request.hostname);
275
+ return;
426
276
  }
427
- for ( const token of $scriptlets ) {
428
- lookupScriptlet(token, $mainWorldMap, $isolatedWorldMap);
277
+
278
+ const contentScript = [];
279
+ if ( µb.hiddenSettings.debugScriptletInjector ) {
280
+ contentScript.push('debugger');
429
281
  }
430
- const mainWorldCode = [];
431
- for ( const js of $mainWorldMap.values() ) {
432
- mainWorldCode.push(js);
282
+ const { mainWorld = '', isolatedWorld = '', filters } = scriptletDetails;
283
+ if ( mainWorld !== '' ) {
284
+ contentScript.push(mainWorldInjector.assemble(request.hostname, mainWorld, filters));
433
285
  }
434
- const isolatedWorldCode = [];
435
- for ( const js of $isolatedWorldMap.values() ) {
436
- isolatedWorldCode.push(js);
286
+ if ( isolatedWorld !== '' ) {
287
+ contentScript.push(isolatedWorldInjector.assemble(request.hostname, isolatedWorld));
437
288
  }
438
- cacheDetails = {
439
- mainWorld: mainWorldCode.join('\n\n'),
440
- isolatedWorld: isolatedWorldCode.join('\n\n'),
441
- filters: [
442
- ...Array.from($scriptlets).map(s => `##${decompile(s)}`),
443
- ...Array.from($exceptions).map(s => `#@#${decompile(s)}`),
444
- ].join('\n'),
445
- };
446
- scriptletCache.add(hostname, cacheDetails);
447
- $mainWorldMap.clear();
448
- $isolatedWorldMap.clear();
449
- }
450
289
 
451
- if ( cacheDetails.mainWorld === '' && cacheDetails.isolatedWorld === '' ) {
452
- return { filters: cacheDetails.filters };
453
- }
290
+ const code = contentScript.join('\n\n');
454
291
 
455
- const scriptletGlobals = [
456
- [ 'warOrigin', vAPI.getURL('/web_accessible_resources') ],
457
- [ 'warSecret', vAPI.warSecret.long() ],
458
- ];
292
+ const isAlreadyInjected = contentScriptRegisterer.register(request.hostname, code);
293
+ if ( isAlreadyInjected !== true ) {
294
+ vAPI.tabs.executeScript(details.tabId, {
295
+ code,
296
+ frameId: details.frameId,
297
+ matchAboutBlank: true,
298
+ runAt: 'document_start',
299
+ });
300
+ }
459
301
 
460
- if ( isDevBuild === undefined ) {
461
- isDevBuild = vAPI.webextFlavor.soup.has('devbuild');
462
- }
463
- if ( isDevBuild || µb.hiddenSettings.filterAuthorMode ) {
464
- scriptletGlobals.push([ 'canDebug', true ]);
302
+ return scriptletDetails;
465
303
  }
466
304
 
467
- return {
468
- mainWorld: cacheDetails.mainWorld === '' ? '' : [
469
- '(function() {',
470
- '// >>>> start of private namespace',
471
- '',
472
- µb.hiddenSettings.debugScriptlets ? 'debugger;' : ';',
473
- '',
474
- // For use by scriptlets to share local data among themselves
475
- `const scriptletGlobals = new Map(${JSON.stringify(scriptletGlobals, null, 2)});`,
476
- '',
477
- cacheDetails.mainWorld,
478
- '',
479
- '// <<<< end of private namespace',
480
- '})();',
481
- ].join('\n'),
482
- isolatedWorld: cacheDetails.isolatedWorld === '' ? '' : [
483
- 'function() {',
484
- '// >>>> start of private namespace',
485
- '',
486
- µb.hiddenSettings.debugScriptlets ? 'debugger;' : ';',
487
- '',
488
- // For use by scriptlets to share local data among themselves
489
- `const scriptletGlobals = new Map(${JSON.stringify(scriptletGlobals, null, 2)});`,
490
- '',
491
- cacheDetails.isolatedWorld,
492
- '',
493
- '// <<<< end of private namespace',
494
- '}',
495
- ].join('\n'),
496
- filters: cacheDetails.filters,
497
- };
498
- };
499
-
500
- scriptletFilteringEngine.injectNow = function(details) {
501
- if ( typeof details.frameId !== 'number' ) { return; }
502
- const request = {
503
- tabId: details.tabId,
504
- frameId: details.frameId,
505
- url: details.url,
506
- hostname: hostnameFromURI(details.url),
507
- domain: undefined,
508
- entity: undefined
509
- };
510
- request.domain = domainFromHostname(request.hostname);
511
- request.entity = entityFromDomain(request.domain);
512
- const scriptletDetails = this.retrieve(request);
513
- if ( scriptletDetails === undefined ) {
514
- contentScriptRegisterer.unregister(request.hostname);
515
- return;
516
- }
517
- const contentScript = [];
518
- if ( µb.hiddenSettings.debugScriptletInjector ) {
519
- contentScript.push('debugger');
520
- }
521
- const { mainWorld = '', isolatedWorld = '', filters } = scriptletDetails;
522
- if ( mainWorld !== '' ) {
523
- contentScript.push(mainWorldInjector.assemble(request.hostname, mainWorld, filters));
524
- }
525
- if ( isolatedWorld !== '' ) {
526
- contentScript.push(isolatedWorldInjector.assemble(request.hostname, isolatedWorld));
527
- }
528
- const code = contentScript.join('\n\n');
529
- const isAlreadyInjected = contentScriptRegisterer.register(request.hostname, code);
530
- if ( isAlreadyInjected !== true ) {
531
- vAPI.tabs.executeScript(details.tabId, {
532
- code,
533
- frameId: details.frameId,
534
- matchAboutBlank: true,
535
- runAt: 'document_start',
536
- });
305
+ toLogger(request, details) {
306
+ if ( details === undefined ) { return; }
307
+ if ( logger.enabled !== true ) { return; }
308
+ if ( typeof details.filters !== 'string' ) { return; }
309
+ const fctxt = µb.filteringContext
310
+ .duplicate()
311
+ .fromTabId(request.tabId)
312
+ .setRealm('extended')
313
+ .setType('scriptlet')
314
+ .setURL(request.url)
315
+ .setDocOriginFromURL(request.url);
316
+ for ( const raw of details.filters.split('\n') ) {
317
+ fctxt.setFilter({ source: 'extended', raw }).toLogger();
318
+ }
537
319
  }
538
- return scriptletDetails;
539
- };
540
-
541
- scriptletFilteringEngine.toSelfie = function() {
542
- return scriptletDB.toSelfie();
543
- };
544
-
545
- scriptletFilteringEngine.fromSelfie = function(selfie) {
546
- if ( selfie instanceof Object === false ) { return false; }
547
- if ( selfie.version !== VERSION ) { return false; }
548
- scriptletDB.fromSelfie(selfie);
549
- return true;
550
- };
320
+ }
551
321
 
552
322
  /******************************************************************************/
553
323
 
324
+ const scriptletFilteringEngine = new ScriptletFilteringEngineEx();
325
+
554
326
  export default scriptletFilteringEngine;
555
327
 
556
328
  /******************************************************************************/