@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) 2019-present Raymond Hill
5
5
 
6
6
  This program is free software: you can redistribute it and/or modify
@@ -52,6 +52,8 @@ function safeSelf() {
52
52
  'Function_toStringFn': self.Function.prototype.toString,
53
53
  'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg),
54
54
  'Math_floor': Math.floor,
55
+ 'Math_max': Math.max,
56
+ 'Math_min': Math.min,
55
57
  'Math_random': Math.random,
56
58
  'Object_defineProperty': Object.defineProperty.bind(Object),
57
59
  'RegExp': self.RegExp,
@@ -85,7 +87,6 @@ function safeSelf() {
85
87
  const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
86
88
  if ( match !== null ) {
87
89
  return {
88
- pattern,
89
90
  re: new this.RegExp(
90
91
  match[1],
91
92
  match[2] || options.flags
@@ -93,18 +94,23 @@ function safeSelf() {
93
94
  expect,
94
95
  };
95
96
  }
96
- return {
97
- pattern,
98
- re: new this.RegExp(pattern.replace(
99
- /[.*+?^${}()|[\]\\]/g, '\\$&'),
100
- options.flags
101
- ),
102
- expect,
103
- };
97
+ if ( options.flags !== undefined ) {
98
+ return {
99
+ re: new this.RegExp(pattern.replace(
100
+ /[.*+?^${}()|[\]\\]/g, '\\$&'),
101
+ options.flags
102
+ ),
103
+ expect,
104
+ };
105
+ }
106
+ return { pattern, expect };
104
107
  },
105
108
  testPattern(details, haystack) {
106
109
  if ( details.matchAll ) { return true; }
107
- return this.RegExp_test.call(details.re, haystack) === details.expect;
110
+ if ( details.re ) {
111
+ return this.RegExp_test.call(details.re, haystack) === details.expect;
112
+ }
113
+ return haystack.includes(details.pattern) === details.expect;
108
114
  },
109
115
  patternToRegex(pattern, flags = undefined, verbatim = false) {
110
116
  if ( pattern === '' ) { return /^/; }
@@ -242,6 +248,73 @@ function runAtHtmlElementFn(fn) {
242
248
 
243
249
  /******************************************************************************/
244
250
 
251
+ // Reference:
252
+ // https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#prevent-xhr
253
+
254
+ builtinScriptlets.push({
255
+ name: 'generate-content.fn',
256
+ fn: generateContentFn,
257
+ dependencies: [
258
+ 'safe-self.fn',
259
+ ],
260
+ });
261
+ function generateContentFn(directive) {
262
+ const safe = safeSelf();
263
+ const randomize = len => {
264
+ const chunks = [];
265
+ let textSize = 0;
266
+ do {
267
+ const s = safe.Math_random().toString(36).slice(2);
268
+ chunks.push(s);
269
+ textSize += s.length;
270
+ }
271
+ while ( textSize < len );
272
+ return chunks.join(' ').slice(0, len);
273
+ };
274
+ if ( directive === 'true' ) {
275
+ return Promise.resolve(randomize(10));
276
+ }
277
+ if ( directive === 'emptyObj' ) {
278
+ return Promise.resolve('{}');
279
+ }
280
+ if ( directive === 'emptyArr' ) {
281
+ return Promise.resolve('[]');
282
+ }
283
+ if ( directive === 'emptyStr' ) {
284
+ return Promise.resolve('');
285
+ }
286
+ if ( directive.startsWith('length:') ) {
287
+ const match = /^length:(\d+)(?:-(\d+))?$/.exec(directive);
288
+ if ( match ) {
289
+ const min = parseInt(match[1], 10);
290
+ const extent = safe.Math_max(parseInt(match[2], 10) || 0, min) - min;
291
+ const len = safe.Math_min(min + extent * safe.Math_random(), 500000);
292
+ return Promise.resolve(randomize(len | 0));
293
+ }
294
+ }
295
+ if ( directive.startsWith('war:') && scriptletGlobals.has('warOrigin') ) {
296
+ return new Promise(resolve => {
297
+ const warOrigin = scriptletGlobals.get('warOrigin');
298
+ const warName = directive.slice(4);
299
+ const fullpath = [ warOrigin, '/', warName ];
300
+ const warSecret = scriptletGlobals.get('warSecret');
301
+ if ( warSecret !== undefined ) {
302
+ fullpath.push('?secret=', warSecret);
303
+ }
304
+ const warXHR = new safe.XMLHttpRequest();
305
+ warXHR.responseType = 'text';
306
+ warXHR.onloadend = ev => {
307
+ resolve(ev.target.responseText || '');
308
+ };
309
+ warXHR.open('GET', fullpath.join(''));
310
+ warXHR.send();
311
+ });
312
+ }
313
+ return Promise.resolve('');
314
+ }
315
+
316
+ /******************************************************************************/
317
+
245
318
  builtinScriptlets.push({
246
319
  name: 'abort-current-script-core.fn',
247
320
  fn: abortCurrentScriptCore,
@@ -898,7 +971,7 @@ builtinScriptlets.push({
898
971
  });
899
972
  function matchesStackTrace(
900
973
  needleDetails,
901
- logLevel = 0
974
+ logLevel = ''
902
975
  ) {
903
976
  const safe = safeSelf();
904
977
  const exceptionToken = getExceptionToken();
@@ -929,11 +1002,12 @@ function matchesStackTrace(
929
1002
  }
930
1003
  lines[0] = `stackDepth:${lines.length-1}`;
931
1004
  const stack = lines.join('\t');
932
- const r = safe.testPattern(needleDetails, stack);
1005
+ const r = needleDetails.matchAll !== true &&
1006
+ safe.testPattern(needleDetails, stack);
933
1007
  if (
934
- logLevel === 1 ||
935
- logLevel === 2 && r ||
936
- logLevel === 3 && !r
1008
+ logLevel === 'all' ||
1009
+ logLevel === 'match' && r ||
1010
+ logLevel === 'nomatch' && !r
937
1011
  ) {
938
1012
  safe.uboLog(stack.replace(/\t/g, '\n'));
939
1013
  }
@@ -1331,6 +1405,7 @@ function abortOnStackTrace(
1331
1405
  const safe = safeSelf();
1332
1406
  const needleDetails = safe.initPattern(needle, { canNegate: true });
1333
1407
  const extraArgs = safe.getExtraArgs(Array.from(arguments), 2);
1408
+ if ( needle === '' ) { extraArgs.log = 'all'; }
1334
1409
  const makeProxy = function(owner, chain) {
1335
1410
  const pos = chain.indexOf('.');
1336
1411
  if ( pos === -1 ) {
@@ -1757,16 +1832,18 @@ builtinScriptlets.push({
1757
1832
  ],
1758
1833
  fn: noFetchIf,
1759
1834
  dependencies: [
1835
+ 'generate-content.fn',
1760
1836
  'safe-self.fn',
1761
1837
  ],
1762
1838
  });
1763
1839
  function noFetchIf(
1764
- arg1 = '',
1840
+ propsToMatch = '',
1841
+ responseBody = ''
1765
1842
  ) {
1766
- if ( typeof arg1 !== 'string' ) { return; }
1843
+ if ( typeof propsToMatch !== 'string' ) { return; }
1767
1844
  const safe = safeSelf();
1768
1845
  const needles = [];
1769
- for ( const condition of arg1.split(/\s+/) ) {
1846
+ for ( const condition of propsToMatch.split(/\s+/) ) {
1770
1847
  if ( condition === '' ) { continue; }
1771
1848
  const pos = condition.indexOf(':');
1772
1849
  let key, value;
@@ -1782,14 +1859,11 @@ function noFetchIf(
1782
1859
  const log = needles.length === 0 ? console.log.bind(console) : undefined;
1783
1860
  self.fetch = new Proxy(self.fetch, {
1784
1861
  apply: function(target, thisArg, args) {
1862
+ const details = args[0] instanceof self.Request
1863
+ ? args[0]
1864
+ : Object.assign({ url: args[0] }, args[1]);
1785
1865
  let proceed = true;
1786
1866
  try {
1787
- let details;
1788
- if ( args[0] instanceof self.Request ) {
1789
- details = args[0];
1790
- } else {
1791
- details = Object.assign({ url: args[0] }, args[1]);
1792
- }
1793
1867
  const props = new Map();
1794
1868
  for ( const prop in details ) {
1795
1869
  let v = details[prop];
@@ -1818,9 +1892,36 @@ function noFetchIf(
1818
1892
  }
1819
1893
  } catch(ex) {
1820
1894
  }
1821
- return proceed
1822
- ? Reflect.apply(target, thisArg, args)
1823
- : Promise.resolve(new Response());
1895
+ if ( proceed ) {
1896
+ return Reflect.apply(target, thisArg, args);
1897
+ }
1898
+ let responseType = '';
1899
+ if ( details.mode === undefined || details.mode === 'cors' ) {
1900
+ try {
1901
+ const desURL = new URL(details.url);
1902
+ responseType = desURL.origin !== document.location.origin
1903
+ ? 'cors'
1904
+ : 'basic';
1905
+ } catch(_) {
1906
+ }
1907
+ }
1908
+ return generateContentFn(responseBody).then(text => {
1909
+ const response = new Response(text, {
1910
+ statusText: 'OK',
1911
+ headers: {
1912
+ 'Content-Length': text.length,
1913
+ }
1914
+ });
1915
+ Object.defineProperty(response, 'url', {
1916
+ value: details.url
1917
+ });
1918
+ if ( responseType !== '' ) {
1919
+ Object.defineProperty(response, 'type', {
1920
+ value: responseType
1921
+ });
1922
+ }
1923
+ return response;
1924
+ });
1824
1925
  }
1825
1926
  });
1826
1927
  }
@@ -2259,6 +2360,7 @@ builtinScriptlets.push({
2259
2360
  ],
2260
2361
  fn: noXhrIf,
2261
2362
  dependencies: [
2363
+ 'generate-content.fn',
2262
2364
  'match-object-properties.fn',
2263
2365
  'parse-properties-to-match.fn',
2264
2366
  'safe-self.fn',
@@ -2269,40 +2371,14 @@ function noXhrIf(
2269
2371
  directive = ''
2270
2372
  ) {
2271
2373
  if ( typeof propsToMatch !== 'string' ) { return; }
2272
- const safe = safeSelf();
2273
2374
  const xhrInstances = new WeakMap();
2274
2375
  const propNeedles = parsePropertiesToMatch(propsToMatch, 'url');
2275
2376
  const log = propNeedles.size === 0 ? console.log.bind(console) : undefined;
2276
2377
  const warOrigin = scriptletGlobals.get('warOrigin');
2277
- const generateRandomString = len => {
2278
- let s = '';
2279
- do { s += safe.Math_random().toString(36).slice(2); }
2280
- while ( s.length < 10 );
2281
- return s.slice(0, len);
2282
- };
2283
- const generateContent = async directive => {
2284
- if ( directive === 'true' ) {
2285
- return generateRandomString(10);
2286
- }
2287
- if ( directive.startsWith('war:') ) {
2288
- if ( warOrigin === undefined ) { return ''; }
2289
- return new Promise(resolve => {
2290
- const warName = directive.slice(4);
2291
- const fullpath = [ warOrigin, '/', warName ];
2292
- const warSecret = scriptletGlobals.get('warSecret');
2293
- if ( warSecret !== undefined ) {
2294
- fullpath.push('?secret=', warSecret);
2295
- }
2296
- const warXHR = new safe.XMLHttpRequest();
2297
- warXHR.responseType = 'text';
2298
- warXHR.onloadend = ev => {
2299
- resolve(ev.target.responseText || '');
2300
- };
2301
- warXHR.open('GET', fullpath.join(''));
2302
- warXHR.send();
2303
- });
2304
- }
2305
- return '';
2378
+ const headers = {
2379
+ 'date': '',
2380
+ 'content-type': '',
2381
+ 'content-length': '',
2306
2382
  };
2307
2383
  self.XMLHttpRequest = class extends self.XMLHttpRequest {
2308
2384
  open(method, url, ...args) {
@@ -2310,6 +2386,7 @@ function noXhrIf(
2310
2386
  log(`uBO: xhr.open(${method}, ${url}, ${args.join(', ')})`);
2311
2387
  return super.open(method, url, ...args);
2312
2388
  }
2389
+ xhrInstances.delete(this);
2313
2390
  if ( warOrigin !== undefined && url.startsWith(warOrigin) ) {
2314
2391
  return super.open(method, url, ...args);
2315
2392
  }
@@ -2317,6 +2394,7 @@ function noXhrIf(
2317
2394
  if ( matchObjectProperties(propNeedles, haystack) ) {
2318
2395
  xhrInstances.set(this, haystack);
2319
2396
  }
2397
+ haystack.headers = Object.assign({}, headers);
2320
2398
  return super.open(method, url, ...args);
2321
2399
  }
2322
2400
  send(...args) {
@@ -2324,6 +2402,7 @@ function noXhrIf(
2324
2402
  if ( haystack === undefined ) {
2325
2403
  return super.send(...args);
2326
2404
  }
2405
+ haystack.headers['date'] = (new Date()).toUTCString();
2327
2406
  let promise = Promise.resolve({
2328
2407
  xhr: this,
2329
2408
  directive,
@@ -2338,53 +2417,81 @@ function noXhrIf(
2338
2417
  },
2339
2418
  });
2340
2419
  switch ( this.responseType ) {
2341
- case 'arraybuffer':
2342
- promise = promise.then(details => {
2343
- details.props.response.value = new ArrayBuffer(0);
2344
- return details;
2345
- });
2346
- break;
2347
- case 'blob':
2348
- promise = promise.then(details => {
2349
- details.props.response.value = new Blob([]);
2350
- return details;
2351
- });
2352
- break;
2353
- case 'document': {
2354
- promise = promise.then(details => {
2355
- const parser = new DOMParser();
2356
- const doc = parser.parseFromString('', 'text/html');
2357
- details.props.response.value = doc;
2358
- details.props.responseXML.value = doc;
2359
- return details;
2360
- });
2361
- break;
2362
- }
2363
- case 'json':
2364
- promise = promise.then(details => {
2365
- details.props.response.value = {};
2366
- details.props.responseText.value = '{}';
2420
+ case 'arraybuffer':
2421
+ promise = promise.then(details => {
2422
+ details.props.response.value = new ArrayBuffer(0);
2423
+ return details;
2424
+ });
2425
+ haystack.headers['content-type'] = 'application/octet-stream';
2426
+ break;
2427
+ case 'blob':
2428
+ promise = promise.then(details => {
2429
+ details.props.response.value = new Blob([]);
2430
+ return details;
2431
+ });
2432
+ haystack.headers['content-type'] = 'application/octet-stream';
2433
+ break;
2434
+ case 'document': {
2435
+ promise = promise.then(details => {
2436
+ const parser = new DOMParser();
2437
+ const doc = parser.parseFromString('', 'text/html');
2438
+ details.props.response.value = doc;
2439
+ details.props.responseXML.value = doc;
2440
+ return details;
2441
+ });
2442
+ haystack.headers['content-type'] = 'text/html';
2443
+ break;
2444
+ }
2445
+ case 'json':
2446
+ promise = promise.then(details => {
2447
+ details.props.response.value = {};
2448
+ details.props.responseText.value = '{}';
2449
+ return details;
2450
+ });
2451
+ haystack.headers['content-type'] = 'application/json';
2452
+ break;
2453
+ default:
2454
+ if ( directive === '' ) { break; }
2455
+ promise = promise.then(details => {
2456
+ return generateContentFn(details.directive).then(text => {
2457
+ details.props.response.value = text;
2458
+ details.props.responseText.value = text;
2367
2459
  return details;
2368
2460
  });
2369
- break;
2370
- default:
2371
- if ( directive === '' ) { break; }
2372
- promise = promise.then(details => {
2373
- return generateContent(details.directive).then(text => {
2374
- details.props.response.value = text;
2375
- details.props.responseText.value = text;
2376
- return details;
2377
- });
2378
- });
2379
- break;
2461
+ });
2462
+ haystack.headers['content-type'] = 'text/plain';
2463
+ break;
2380
2464
  }
2381
2465
  promise.then(details => {
2466
+ haystack.headers['content-length'] = `${details.props.response.value}`.length;
2382
2467
  Object.defineProperties(details.xhr, details.props);
2383
2468
  details.xhr.dispatchEvent(new Event('readystatechange'));
2384
2469
  details.xhr.dispatchEvent(new Event('load'));
2385
2470
  details.xhr.dispatchEvent(new Event('loadend'));
2386
2471
  });
2387
2472
  }
2473
+ getResponseHeader(headerName) {
2474
+ const haystack = xhrInstances.get(this);
2475
+ if ( haystack === undefined || this.readyState < this.HEADERS_RECEIVED ) {
2476
+ return super.getResponseHeader(headerName);
2477
+ }
2478
+ const value = haystack.headers[headerName.toLowerCase()];
2479
+ if ( value !== undefined && value !== '' ) { return value; }
2480
+ return null;
2481
+ }
2482
+ getAllResponseHeaders() {
2483
+ const haystack = xhrInstances.get(this);
2484
+ if ( haystack === undefined || this.readyState < this.HEADERS_RECEIVED ) {
2485
+ return super.getAllResponseHeaders();
2486
+ }
2487
+ const out = [];
2488
+ for ( const [ name, value ] of Object.entries(haystack.headers) ) {
2489
+ if ( !value ) { continue; }
2490
+ out.push(`${name}: ${value}`);
2491
+ }
2492
+ if ( out.length !== 0 ) { out.push(''); }
2493
+ return out.join('\r\n');
2494
+ }
2388
2495
  };
2389
2496
  }
2390
2497
 
@@ -2894,6 +3001,9 @@ function xmlPrune(
2894
3001
  type === '' && thisArg.responseXML instanceof XMLDocument
2895
3002
  ) {
2896
3003
  pruneFromDoc(thisArg.responseXML);
3004
+ const serializer = new XMLSerializer();
3005
+ const textout = serializer.serializeToString(thisArg.responseXML);
3006
+ Object.defineProperty(thisArg, 'responseText', { value: textout });
2897
3007
  return;
2898
3008
  }
2899
3009
  if (
@@ -4036,10 +4146,21 @@ function trustedClickElement(
4036
4146
  ? ((...args) => { safe.uboLog(...args); })
4037
4147
  : (( ) => { });
4038
4148
 
4149
+ const querySelectorEx = (selector, context = document) => {
4150
+ const pos = selector.indexOf(' >>> ');
4151
+ if ( pos === -1 ) { return context.querySelector(selector); }
4152
+ const outside = selector.slice(0, pos).trim();
4153
+ const inside = selector.slice(pos + 5).trim();
4154
+ const elem = context.querySelector(outside);
4155
+ if ( elem === null ) { return null; }
4156
+ const shadowRoot = elem.shadowRoot;
4157
+ return shadowRoot && querySelectorEx(inside, shadowRoot);
4158
+ };
4159
+
4039
4160
  const selectorList = selectors.split(/\s*,\s*/)
4040
4161
  .filter(s => {
4041
4162
  try {
4042
- void document.querySelector(s);
4163
+ void querySelectorEx(s);
4043
4164
  } catch(_) {
4044
4165
  return false;
4045
4166
  }
@@ -4113,7 +4234,7 @@ function trustedClickElement(
4113
4234
  if ( Date.now() < tnext ) { return next(); }
4114
4235
  const selector = selectorList.shift();
4115
4236
  if ( selector === undefined ) { return terminate(); }
4116
- const elem = document.querySelector(selector);
4237
+ const elem = querySelectorEx(selector);
4117
4238
  if ( elem === null ) {
4118
4239
  selectorList.unshift(selector);
4119
4240
  return next(true);