@browserless.io/browserless 2.0.0-beta-1

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 (875) hide show
  1. package/CHANGELOG.md +674 -0
  2. package/LICENSE +6 -0
  3. package/README.md +132 -0
  4. package/assets/logo.png +0 -0
  5. package/bin/browserless.js +227 -0
  6. package/browser.json +7 -0
  7. package/build/browserless.d.ts +33 -0
  8. package/build/browserless.js +146 -0
  9. package/build/browsers/cdp-chromium.d.ts +41 -0
  10. package/build/browsers/cdp-chromium.js +287 -0
  11. package/build/browsers/index.d.ts +26 -0
  12. package/build/browsers/index.js +183 -0
  13. package/build/browsers/playwright-chromium.d.ts +34 -0
  14. package/build/browsers/playwright-chromium.js +106 -0
  15. package/build/browsers/playwright-firefox.d.ts +34 -0
  16. package/build/browsers/playwright-firefox.js +101 -0
  17. package/build/browsers/playwright-webkit.d.ts +34 -0
  18. package/build/browsers/playwright-webkit.js +101 -0
  19. package/build/config.d.ts +138 -0
  20. package/build/config.js +349 -0
  21. package/build/constants.d.ts +4 -0
  22. package/build/constants.js +4 -0
  23. package/build/data/classes.json +1 -0
  24. package/build/data/selectors.json +1 -0
  25. package/build/exports.d.ts +20 -0
  26. package/build/exports.js +22 -0
  27. package/build/file-system.d.ts +24 -0
  28. package/build/file-system.js +46 -0
  29. package/build/hooks.d.ts +5 -0
  30. package/build/hooks.js +20 -0
  31. package/build/http.d.ts +175 -0
  32. package/build/http.js +104 -0
  33. package/build/index.d.ts +1 -0
  34. package/build/index.js +39 -0
  35. package/build/limiter.d.ts +24 -0
  36. package/build/limiter.js +147 -0
  37. package/build/limiter.spec.d.ts +1 -0
  38. package/build/limiter.spec.js +241 -0
  39. package/build/metrics.d.ts +24 -0
  40. package/build/metrics.js +86 -0
  41. package/build/metrics.spec.d.ts +1 -0
  42. package/build/metrics.spec.js +35 -0
  43. package/build/mime-types.d.ts +1 -0
  44. package/build/mime-types.js +328 -0
  45. package/build/monitoring.d.ts +13 -0
  46. package/build/monitoring.js +38 -0
  47. package/build/routes/chromium/http/content-post.body.json +514 -0
  48. package/build/routes/chromium/http/content-post.d.ts +34 -0
  49. package/build/routes/chromium/http/content-post.js +109 -0
  50. package/build/routes/chromium/http/content-post.query.json +183 -0
  51. package/build/routes/chromium/http/content-post.response.json +5 -0
  52. package/build/routes/chromium/http/download-post.body.json +32 -0
  53. package/build/routes/chromium/http/download-post.d.ts +16 -0
  54. package/build/routes/chromium/http/download-post.js +92 -0
  55. package/build/routes/chromium/http/download-post.query.json +120 -0
  56. package/build/routes/chromium/http/download-post.response.json +4 -0
  57. package/build/routes/chromium/http/function-post.body.json +32 -0
  58. package/build/routes/chromium/http/function-post.d.ts +18 -0
  59. package/build/routes/chromium/http/function-post.js +53 -0
  60. package/build/routes/chromium/http/function-post.query.json +120 -0
  61. package/build/routes/chromium/http/function-post.response.json +4 -0
  62. package/build/routes/chromium/http/pdf-post.body.json +654 -0
  63. package/build/routes/chromium/http/pdf-post.d.ts +35 -0
  64. package/build/routes/chromium/http/pdf-post.js +107 -0
  65. package/build/routes/chromium/http/pdf-post.query.json +120 -0
  66. package/build/routes/chromium/http/pdf-post.response.json +5 -0
  67. package/build/routes/chromium/http/performance.body.json +26 -0
  68. package/build/routes/chromium/http/performance.d.ts +17 -0
  69. package/build/routes/chromium/http/performance.js +30 -0
  70. package/build/routes/chromium/http/performance.query.json +120 -0
  71. package/build/routes/chromium/http/performance.response.json +7 -0
  72. package/build/routes/chromium/http/scrape-post.body.json +561 -0
  73. package/build/routes/chromium/http/scrape-post.d.ts +106 -0
  74. package/build/routes/chromium/http/scrape-post.js +205 -0
  75. package/build/routes/chromium/http/scrape-post.query.json +183 -0
  76. package/build/routes/chromium/http/scrape-post.response.json +325 -0
  77. package/build/routes/chromium/http/screenshot-post.body.json +604 -0
  78. package/build/routes/chromium/http/screenshot-post.d.ts +37 -0
  79. package/build/routes/chromium/http/screenshot-post.js +124 -0
  80. package/build/routes/chromium/http/screenshot-post.query.json +120 -0
  81. package/build/routes/chromium/http/screenshot-post.response.json +5 -0
  82. package/build/routes/chromium/tests/content.spec.d.ts +1 -0
  83. package/build/routes/chromium/tests/content.spec.js +285 -0
  84. package/build/routes/chromium/tests/download.spec.d.ts +1 -0
  85. package/build/routes/chromium/tests/download.spec.js +67 -0
  86. package/build/routes/chromium/tests/function.spec.d.ts +1 -0
  87. package/build/routes/chromium/tests/function.spec.js +245 -0
  88. package/build/routes/chromium/tests/pdf.spec.d.ts +1 -0
  89. package/build/routes/chromium/tests/pdf.spec.js +333 -0
  90. package/build/routes/chromium/tests/performance.spec.d.ts +1 -0
  91. package/build/routes/chromium/tests/performance.spec.js +124 -0
  92. package/build/routes/chromium/tests/scrape.spec.d.ts +1 -0
  93. package/build/routes/chromium/tests/scrape.spec.js +354 -0
  94. package/build/routes/chromium/tests/screenshot.spec.d.ts +1 -0
  95. package/build/routes/chromium/tests/screenshot.spec.js +339 -0
  96. package/build/routes/chromium/tests/websocket.spec.d.ts +1 -0
  97. package/build/routes/chromium/tests/websocket.spec.js +309 -0
  98. package/build/routes/chromium/utils/function/client.d.ts +26 -0
  99. package/build/routes/chromium/utils/function/client.js +66 -0
  100. package/build/routes/chromium/utils/function/handler.d.ts +18 -0
  101. package/build/routes/chromium/utils/function/handler.js +95 -0
  102. package/build/routes/chromium/utils/performance/child.d.ts +1 -0
  103. package/build/routes/chromium/utils/performance/child.js +29 -0
  104. package/build/routes/chromium/utils/performance/main.d.ts +3 -0
  105. package/build/routes/chromium/utils/performance/main.js +65 -0
  106. package/build/routes/chromium/utils/performance/types.d.ts +21 -0
  107. package/build/routes/chromium/utils/performance/types.js +1 -0
  108. package/build/routes/chromium/ws/browser.d.ts +6 -0
  109. package/build/routes/chromium/ws/browser.js +11 -0
  110. package/build/routes/chromium/ws/browser.query.json +120 -0
  111. package/build/routes/chromium/ws/cdp-chromium.d.ts +6 -0
  112. package/build/routes/chromium/ws/cdp-chromium.js +11 -0
  113. package/build/routes/chromium/ws/cdp-chromium.query.json +120 -0
  114. package/build/routes/chromium/ws/page.d.ts +6 -0
  115. package/build/routes/chromium/ws/page.js +11 -0
  116. package/build/routes/chromium/ws/page.query.json +120 -0
  117. package/build/routes/chromium/ws/playwright-chromium.d.ts +6 -0
  118. package/build/routes/chromium/ws/playwright-chromium.js +19 -0
  119. package/build/routes/chromium/ws/playwright-chromium.query.json +100 -0
  120. package/build/routes/firefox/tests/websocket.spec.d.ts +1 -0
  121. package/build/routes/firefox/tests/websocket.spec.js +104 -0
  122. package/build/routes/firefox/ws/playwright-firefox.d.ts +6 -0
  123. package/build/routes/firefox/ws/playwright-firefox.js +19 -0
  124. package/build/routes/firefox/ws/playwright-firefox.query.json +100 -0
  125. package/build/routes/management/http/config-get.d.ts +25 -0
  126. package/build/routes/management/http/config-get.js +43 -0
  127. package/build/routes/management/http/config-get.response.json +107 -0
  128. package/build/routes/management/http/metrics-get.d.ts +4 -0
  129. package/build/routes/management/http/metrics-get.js +24 -0
  130. package/build/routes/management/http/metrics-get.response.json +94 -0
  131. package/build/routes/management/http/metrics-total-get.d.ts +4 -0
  132. package/build/routes/management/http/metrics-total-get.js +60 -0
  133. package/build/routes/management/http/metrics-total-get.response.json +72 -0
  134. package/build/routes/management/http/sessions-get.d.ts +4 -0
  135. package/build/routes/management/http/sessions-get.js +21 -0
  136. package/build/routes/management/http/sessions-get.response.json +221 -0
  137. package/build/routes/management/http/static-get.d.ts +3 -0
  138. package/build/routes/management/http/static-get.js +67 -0
  139. package/build/routes/management/tests/management.spec.d.ts +1 -0
  140. package/build/routes/management/tests/management.spec.js +41 -0
  141. package/build/routes/webkit/tests/websocket.spec.d.ts +1 -0
  142. package/build/routes/webkit/tests/websocket.spec.js +104 -0
  143. package/build/routes/webkit/ws/playwright-webkit.d.ts +6 -0
  144. package/build/routes/webkit/ws/playwright-webkit.js +19 -0
  145. package/build/routes/webkit/ws/playwright-webkit.query.json +100 -0
  146. package/build/server.d.ts +38 -0
  147. package/build/server.js +365 -0
  148. package/build/shim.d.ts +9 -0
  149. package/build/shim.js +54 -0
  150. package/build/shim.spec.d.ts +1 -0
  151. package/build/shim.spec.js +114 -0
  152. package/build/types.d.ts +360 -0
  153. package/build/types.js +6 -0
  154. package/build/utils.d.ts +111 -0
  155. package/build/utils.js +570 -0
  156. package/build/webhooks.d.ts +11 -0
  157. package/build/webhooks.js +43 -0
  158. package/docker/base/.dockerignore +16 -0
  159. package/docker/base/Dockerfile +70 -0
  160. package/docker/chrome/.dockerignore +16 -0
  161. package/docker/chrome/Dockerfile +40 -0
  162. package/docker/firefox/.dockerignore +16 -0
  163. package/docker/firefox/Dockerfile +39 -0
  164. package/docker/multi/.dockerignore +16 -0
  165. package/docker/multi/Dockerfile +37 -0
  166. package/docker/sdk/.dockerignore +16 -0
  167. package/docker/sdk/Dockerfile +34 -0
  168. package/docker/webkit/.dockerignore +16 -0
  169. package/docker/webkit/Dockerfile +40 -0
  170. package/extensions/screencast/background.js +143 -0
  171. package/extensions/screencast/content_script.js +18 -0
  172. package/extensions/screencast/manifest.json +19 -0
  173. package/extensions/ublock/1p-filters.html +69 -0
  174. package/extensions/ublock/3p-filters.html +119 -0
  175. package/extensions/ublock/LICENSE.txt +674 -0
  176. package/extensions/ublock/_locales/ar/messages.json +1290 -0
  177. package/extensions/ublock/_locales/az/messages.json +1290 -0
  178. package/extensions/ublock/_locales/be/messages.json +1290 -0
  179. package/extensions/ublock/_locales/bg/messages.json +1290 -0
  180. package/extensions/ublock/_locales/bn/messages.json +1290 -0
  181. package/extensions/ublock/_locales/br_FR/messages.json +1290 -0
  182. package/extensions/ublock/_locales/bs/messages.json +1290 -0
  183. package/extensions/ublock/_locales/ca/messages.json +1290 -0
  184. package/extensions/ublock/_locales/cs/messages.json +1290 -0
  185. package/extensions/ublock/_locales/cv/messages.json +1290 -0
  186. package/extensions/ublock/_locales/da/messages.json +1290 -0
  187. package/extensions/ublock/_locales/de/messages.json +1290 -0
  188. package/extensions/ublock/_locales/el/messages.json +1290 -0
  189. package/extensions/ublock/_locales/en/messages.json +1292 -0
  190. package/extensions/ublock/_locales/en_GB/messages.json +1290 -0
  191. package/extensions/ublock/_locales/eo/messages.json +1290 -0
  192. package/extensions/ublock/_locales/es/messages.json +1290 -0
  193. package/extensions/ublock/_locales/et/messages.json +1290 -0
  194. package/extensions/ublock/_locales/eu/messages.json +1290 -0
  195. package/extensions/ublock/_locales/fa/messages.json +1290 -0
  196. package/extensions/ublock/_locales/fi/messages.json +1290 -0
  197. package/extensions/ublock/_locales/fil/messages.json +1290 -0
  198. package/extensions/ublock/_locales/fr/messages.json +1290 -0
  199. package/extensions/ublock/_locales/fy/messages.json +1290 -0
  200. package/extensions/ublock/_locales/gl/messages.json +1290 -0
  201. package/extensions/ublock/_locales/gu/messages.json +1290 -0
  202. package/extensions/ublock/_locales/he/messages.json +1290 -0
  203. package/extensions/ublock/_locales/hi/messages.json +1290 -0
  204. package/extensions/ublock/_locales/hr/messages.json +1290 -0
  205. package/extensions/ublock/_locales/hu/messages.json +1290 -0
  206. package/extensions/ublock/_locales/hy/messages.json +1290 -0
  207. package/extensions/ublock/_locales/id/messages.json +1290 -0
  208. package/extensions/ublock/_locales/it/messages.json +1290 -0
  209. package/extensions/ublock/_locales/ja/messages.json +1290 -0
  210. package/extensions/ublock/_locales/ka/messages.json +1290 -0
  211. package/extensions/ublock/_locales/kk/messages.json +1290 -0
  212. package/extensions/ublock/_locales/kn/messages.json +1290 -0
  213. package/extensions/ublock/_locales/ko/messages.json +1290 -0
  214. package/extensions/ublock/_locales/ku/messages.json +1290 -0
  215. package/extensions/ublock/_locales/lt/messages.json +1290 -0
  216. package/extensions/ublock/_locales/lv/messages.json +1290 -0
  217. package/extensions/ublock/_locales/mk/messages.json +1290 -0
  218. package/extensions/ublock/_locales/ml/messages.json +1290 -0
  219. package/extensions/ublock/_locales/mr/messages.json +1290 -0
  220. package/extensions/ublock/_locales/ms/messages.json +1290 -0
  221. package/extensions/ublock/_locales/nb/messages.json +1290 -0
  222. package/extensions/ublock/_locales/nl/messages.json +1290 -0
  223. package/extensions/ublock/_locales/no/messages.json +1290 -0
  224. package/extensions/ublock/_locales/oc/messages.json +1290 -0
  225. package/extensions/ublock/_locales/pa/messages.json +1290 -0
  226. package/extensions/ublock/_locales/pl/messages.json +1290 -0
  227. package/extensions/ublock/_locales/pt_BR/messages.json +1290 -0
  228. package/extensions/ublock/_locales/pt_PT/messages.json +1290 -0
  229. package/extensions/ublock/_locales/ro/messages.json +1290 -0
  230. package/extensions/ublock/_locales/ru/messages.json +1290 -0
  231. package/extensions/ublock/_locales/si/messages.json +1290 -0
  232. package/extensions/ublock/_locales/sk/messages.json +1290 -0
  233. package/extensions/ublock/_locales/sl/messages.json +1290 -0
  234. package/extensions/ublock/_locales/so/messages.json +1290 -0
  235. package/extensions/ublock/_locales/sq/messages.json +1290 -0
  236. package/extensions/ublock/_locales/sr/messages.json +1290 -0
  237. package/extensions/ublock/_locales/sv/messages.json +1290 -0
  238. package/extensions/ublock/_locales/sw/messages.json +1290 -0
  239. package/extensions/ublock/_locales/ta/messages.json +1290 -0
  240. package/extensions/ublock/_locales/te/messages.json +1290 -0
  241. package/extensions/ublock/_locales/th/messages.json +1290 -0
  242. package/extensions/ublock/_locales/tr/messages.json +1290 -0
  243. package/extensions/ublock/_locales/uk/messages.json +1290 -0
  244. package/extensions/ublock/_locales/ur/messages.json +1290 -0
  245. package/extensions/ublock/_locales/vi/messages.json +1290 -0
  246. package/extensions/ublock/_locales/zh_CN/messages.json +1290 -0
  247. package/extensions/ublock/_locales/zh_TW/messages.json +1290 -0
  248. package/extensions/ublock/about.html +63 -0
  249. package/extensions/ublock/advanced-settings.html +42 -0
  250. package/extensions/ublock/asset-viewer.html +50 -0
  251. package/extensions/ublock/assets/assets.json +903 -0
  252. package/extensions/ublock/assets/resources/scriptlets.js +4255 -0
  253. package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +65576 -0
  254. package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +33219 -0
  255. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/README.md +29 -0
  256. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +3732 -0
  257. package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +15431 -0
  258. package/extensions/ublock/assets/thirdparties/urlhaus-filter/LICENSE.md +42 -0
  259. package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +1970 -0
  260. package/extensions/ublock/assets/ublock/badlists.txt +77 -0
  261. package/extensions/ublock/assets/ublock/badware.min.txt +3033 -0
  262. package/extensions/ublock/assets/ublock/filters.min.txt +23419 -0
  263. package/extensions/ublock/assets/ublock/privacy.min.txt +575 -0
  264. package/extensions/ublock/assets/ublock/quick-fixes.min.txt +99 -0
  265. package/extensions/ublock/assets/ublock/unbreak.min.txt +2448 -0
  266. package/extensions/ublock/background.html +12 -0
  267. package/extensions/ublock/cloud-ui.html +23 -0
  268. package/extensions/ublock/code-viewer.html +53 -0
  269. package/extensions/ublock/css/1p-filters.css +26 -0
  270. package/extensions/ublock/css/3p-filters.css +250 -0
  271. package/extensions/ublock/css/about.css +3 -0
  272. package/extensions/ublock/css/advanced-settings.css +26 -0
  273. package/extensions/ublock/css/asset-viewer.css +79 -0
  274. package/extensions/ublock/css/click2load.css +53 -0
  275. package/extensions/ublock/css/cloud-ui.css +104 -0
  276. package/extensions/ublock/css/code-viewer.css +67 -0
  277. package/extensions/ublock/css/codemirror.css +326 -0
  278. package/extensions/ublock/css/common.css +347 -0
  279. package/extensions/ublock/css/dashboard-common.css +55 -0
  280. package/extensions/ublock/css/dashboard.css +115 -0
  281. package/extensions/ublock/css/devtools.css +22 -0
  282. package/extensions/ublock/css/document-blocked.css +146 -0
  283. package/extensions/ublock/css/dyna-rules.css +79 -0
  284. package/extensions/ublock/css/epicker-ui.css +270 -0
  285. package/extensions/ublock/css/fa-icons.css +149 -0
  286. package/extensions/ublock/css/fonts/Inter/Inter-Regular.woff2 +0 -0
  287. package/extensions/ublock/css/fonts/Inter/Inter-SemiBold.woff2 +0 -0
  288. package/extensions/ublock/css/fonts/Inter/LICENSE.txt +93 -0
  289. package/extensions/ublock/css/fonts/Metropolis/Metropolis-Regular.woff2 +0 -0
  290. package/extensions/ublock/css/fonts/Metropolis/Metropolis-SemiBold.woff2 +0 -0
  291. package/extensions/ublock/css/fonts/Metropolis/README.md +25 -0
  292. package/extensions/ublock/css/fonts/Metropolis/UNLICENSE +24 -0
  293. package/extensions/ublock/css/logger-ui-inspector.css +116 -0
  294. package/extensions/ublock/css/logger-ui.css +978 -0
  295. package/extensions/ublock/css/popup-fenix.css +778 -0
  296. package/extensions/ublock/css/settings.css +74 -0
  297. package/extensions/ublock/css/support.css +110 -0
  298. package/extensions/ublock/css/themes/default.css +526 -0
  299. package/extensions/ublock/css/whitelist.css +22 -0
  300. package/extensions/ublock/dashboard.html +47 -0
  301. package/extensions/ublock/devtools.html +58 -0
  302. package/extensions/ublock/document-blocked.html +64 -0
  303. package/extensions/ublock/dyna-rules.html +67 -0
  304. package/extensions/ublock/img/cloud.png +0 -0
  305. package/extensions/ublock/img/flags-of-the-world/README +9 -0
  306. package/extensions/ublock/img/flags-of-the-world/ad.png +0 -0
  307. package/extensions/ublock/img/flags-of-the-world/ae.png +0 -0
  308. package/extensions/ublock/img/flags-of-the-world/af.png +0 -0
  309. package/extensions/ublock/img/flags-of-the-world/ag.png +0 -0
  310. package/extensions/ublock/img/flags-of-the-world/ai.png +0 -0
  311. package/extensions/ublock/img/flags-of-the-world/al.png +0 -0
  312. package/extensions/ublock/img/flags-of-the-world/am.png +0 -0
  313. package/extensions/ublock/img/flags-of-the-world/ao.png +0 -0
  314. package/extensions/ublock/img/flags-of-the-world/aq.png +0 -0
  315. package/extensions/ublock/img/flags-of-the-world/ar.png +0 -0
  316. package/extensions/ublock/img/flags-of-the-world/as.png +0 -0
  317. package/extensions/ublock/img/flags-of-the-world/at.png +0 -0
  318. package/extensions/ublock/img/flags-of-the-world/au.png +0 -0
  319. package/extensions/ublock/img/flags-of-the-world/aw.png +0 -0
  320. package/extensions/ublock/img/flags-of-the-world/ax.png +0 -0
  321. package/extensions/ublock/img/flags-of-the-world/az.png +0 -0
  322. package/extensions/ublock/img/flags-of-the-world/ba.png +0 -0
  323. package/extensions/ublock/img/flags-of-the-world/bb.png +0 -0
  324. package/extensions/ublock/img/flags-of-the-world/bd.png +0 -0
  325. package/extensions/ublock/img/flags-of-the-world/be.png +0 -0
  326. package/extensions/ublock/img/flags-of-the-world/bf.png +0 -0
  327. package/extensions/ublock/img/flags-of-the-world/bg.png +0 -0
  328. package/extensions/ublock/img/flags-of-the-world/bh.png +0 -0
  329. package/extensions/ublock/img/flags-of-the-world/bi.png +0 -0
  330. package/extensions/ublock/img/flags-of-the-world/bj.png +0 -0
  331. package/extensions/ublock/img/flags-of-the-world/bl.png +0 -0
  332. package/extensions/ublock/img/flags-of-the-world/bm.png +0 -0
  333. package/extensions/ublock/img/flags-of-the-world/bn.png +0 -0
  334. package/extensions/ublock/img/flags-of-the-world/bo.png +0 -0
  335. package/extensions/ublock/img/flags-of-the-world/bq.png +0 -0
  336. package/extensions/ublock/img/flags-of-the-world/br.png +0 -0
  337. package/extensions/ublock/img/flags-of-the-world/bs.png +0 -0
  338. package/extensions/ublock/img/flags-of-the-world/bt.png +0 -0
  339. package/extensions/ublock/img/flags-of-the-world/bv.png +0 -0
  340. package/extensions/ublock/img/flags-of-the-world/bw.png +0 -0
  341. package/extensions/ublock/img/flags-of-the-world/by.png +0 -0
  342. package/extensions/ublock/img/flags-of-the-world/bz.png +0 -0
  343. package/extensions/ublock/img/flags-of-the-world/ca.png +0 -0
  344. package/extensions/ublock/img/flags-of-the-world/cc.png +0 -0
  345. package/extensions/ublock/img/flags-of-the-world/cd.png +0 -0
  346. package/extensions/ublock/img/flags-of-the-world/cf.png +0 -0
  347. package/extensions/ublock/img/flags-of-the-world/cg.png +0 -0
  348. package/extensions/ublock/img/flags-of-the-world/ch.png +0 -0
  349. package/extensions/ublock/img/flags-of-the-world/ci.png +0 -0
  350. package/extensions/ublock/img/flags-of-the-world/ck.png +0 -0
  351. package/extensions/ublock/img/flags-of-the-world/cl.png +0 -0
  352. package/extensions/ublock/img/flags-of-the-world/cm.png +0 -0
  353. package/extensions/ublock/img/flags-of-the-world/cn.png +0 -0
  354. package/extensions/ublock/img/flags-of-the-world/co.png +0 -0
  355. package/extensions/ublock/img/flags-of-the-world/cr.png +0 -0
  356. package/extensions/ublock/img/flags-of-the-world/cu.png +0 -0
  357. package/extensions/ublock/img/flags-of-the-world/cv.png +0 -0
  358. package/extensions/ublock/img/flags-of-the-world/cw.png +0 -0
  359. package/extensions/ublock/img/flags-of-the-world/cx.png +0 -0
  360. package/extensions/ublock/img/flags-of-the-world/cy.png +0 -0
  361. package/extensions/ublock/img/flags-of-the-world/cz.png +0 -0
  362. package/extensions/ublock/img/flags-of-the-world/de.png +0 -0
  363. package/extensions/ublock/img/flags-of-the-world/dj.png +0 -0
  364. package/extensions/ublock/img/flags-of-the-world/dk.png +0 -0
  365. package/extensions/ublock/img/flags-of-the-world/dm.png +0 -0
  366. package/extensions/ublock/img/flags-of-the-world/do.png +0 -0
  367. package/extensions/ublock/img/flags-of-the-world/dz.png +0 -0
  368. package/extensions/ublock/img/flags-of-the-world/ec.png +0 -0
  369. package/extensions/ublock/img/flags-of-the-world/ee.png +0 -0
  370. package/extensions/ublock/img/flags-of-the-world/eg.png +0 -0
  371. package/extensions/ublock/img/flags-of-the-world/eh.png +0 -0
  372. package/extensions/ublock/img/flags-of-the-world/er.png +0 -0
  373. package/extensions/ublock/img/flags-of-the-world/es.png +0 -0
  374. package/extensions/ublock/img/flags-of-the-world/et.png +0 -0
  375. package/extensions/ublock/img/flags-of-the-world/fi.png +0 -0
  376. package/extensions/ublock/img/flags-of-the-world/fj.png +0 -0
  377. package/extensions/ublock/img/flags-of-the-world/fk.png +0 -0
  378. package/extensions/ublock/img/flags-of-the-world/fm.png +0 -0
  379. package/extensions/ublock/img/flags-of-the-world/fo.png +0 -0
  380. package/extensions/ublock/img/flags-of-the-world/fr.png +0 -0
  381. package/extensions/ublock/img/flags-of-the-world/ga.png +0 -0
  382. package/extensions/ublock/img/flags-of-the-world/gb-eng.png +0 -0
  383. package/extensions/ublock/img/flags-of-the-world/gb-nir.png +0 -0
  384. package/extensions/ublock/img/flags-of-the-world/gb-sct.png +0 -0
  385. package/extensions/ublock/img/flags-of-the-world/gb-wls.png +0 -0
  386. package/extensions/ublock/img/flags-of-the-world/gb.png +0 -0
  387. package/extensions/ublock/img/flags-of-the-world/gd.png +0 -0
  388. package/extensions/ublock/img/flags-of-the-world/ge.png +0 -0
  389. package/extensions/ublock/img/flags-of-the-world/gf.png +0 -0
  390. package/extensions/ublock/img/flags-of-the-world/gg.png +0 -0
  391. package/extensions/ublock/img/flags-of-the-world/gh.png +0 -0
  392. package/extensions/ublock/img/flags-of-the-world/gi.png +0 -0
  393. package/extensions/ublock/img/flags-of-the-world/gl.png +0 -0
  394. package/extensions/ublock/img/flags-of-the-world/gm.png +0 -0
  395. package/extensions/ublock/img/flags-of-the-world/gn.png +0 -0
  396. package/extensions/ublock/img/flags-of-the-world/gp.png +0 -0
  397. package/extensions/ublock/img/flags-of-the-world/gq.png +0 -0
  398. package/extensions/ublock/img/flags-of-the-world/gr.png +0 -0
  399. package/extensions/ublock/img/flags-of-the-world/gs.png +0 -0
  400. package/extensions/ublock/img/flags-of-the-world/gt.png +0 -0
  401. package/extensions/ublock/img/flags-of-the-world/gu.png +0 -0
  402. package/extensions/ublock/img/flags-of-the-world/gw.png +0 -0
  403. package/extensions/ublock/img/flags-of-the-world/gy.png +0 -0
  404. package/extensions/ublock/img/flags-of-the-world/hk.png +0 -0
  405. package/extensions/ublock/img/flags-of-the-world/hm.png +0 -0
  406. package/extensions/ublock/img/flags-of-the-world/hn.png +0 -0
  407. package/extensions/ublock/img/flags-of-the-world/hr.png +0 -0
  408. package/extensions/ublock/img/flags-of-the-world/ht.png +0 -0
  409. package/extensions/ublock/img/flags-of-the-world/hu.png +0 -0
  410. package/extensions/ublock/img/flags-of-the-world/id.png +0 -0
  411. package/extensions/ublock/img/flags-of-the-world/ie.png +0 -0
  412. package/extensions/ublock/img/flags-of-the-world/il.png +0 -0
  413. package/extensions/ublock/img/flags-of-the-world/im.png +0 -0
  414. package/extensions/ublock/img/flags-of-the-world/in.png +0 -0
  415. package/extensions/ublock/img/flags-of-the-world/io.png +0 -0
  416. package/extensions/ublock/img/flags-of-the-world/iq.png +0 -0
  417. package/extensions/ublock/img/flags-of-the-world/ir.png +0 -0
  418. package/extensions/ublock/img/flags-of-the-world/is.png +0 -0
  419. package/extensions/ublock/img/flags-of-the-world/it.png +0 -0
  420. package/extensions/ublock/img/flags-of-the-world/je.png +0 -0
  421. package/extensions/ublock/img/flags-of-the-world/jm.png +0 -0
  422. package/extensions/ublock/img/flags-of-the-world/jo.png +0 -0
  423. package/extensions/ublock/img/flags-of-the-world/jp.png +0 -0
  424. package/extensions/ublock/img/flags-of-the-world/ke.png +0 -0
  425. package/extensions/ublock/img/flags-of-the-world/kg.png +0 -0
  426. package/extensions/ublock/img/flags-of-the-world/kh.png +0 -0
  427. package/extensions/ublock/img/flags-of-the-world/ki.png +0 -0
  428. package/extensions/ublock/img/flags-of-the-world/km.png +0 -0
  429. package/extensions/ublock/img/flags-of-the-world/kn.png +0 -0
  430. package/extensions/ublock/img/flags-of-the-world/kp.png +0 -0
  431. package/extensions/ublock/img/flags-of-the-world/kr.png +0 -0
  432. package/extensions/ublock/img/flags-of-the-world/kw.png +0 -0
  433. package/extensions/ublock/img/flags-of-the-world/ky.png +0 -0
  434. package/extensions/ublock/img/flags-of-the-world/kz.png +0 -0
  435. package/extensions/ublock/img/flags-of-the-world/la.png +0 -0
  436. package/extensions/ublock/img/flags-of-the-world/lb.png +0 -0
  437. package/extensions/ublock/img/flags-of-the-world/lc.png +0 -0
  438. package/extensions/ublock/img/flags-of-the-world/li.png +0 -0
  439. package/extensions/ublock/img/flags-of-the-world/lk.png +0 -0
  440. package/extensions/ublock/img/flags-of-the-world/lr.png +0 -0
  441. package/extensions/ublock/img/flags-of-the-world/ls.png +0 -0
  442. package/extensions/ublock/img/flags-of-the-world/lt.png +0 -0
  443. package/extensions/ublock/img/flags-of-the-world/lu.png +0 -0
  444. package/extensions/ublock/img/flags-of-the-world/lv.png +0 -0
  445. package/extensions/ublock/img/flags-of-the-world/ly.png +0 -0
  446. package/extensions/ublock/img/flags-of-the-world/ma.png +0 -0
  447. package/extensions/ublock/img/flags-of-the-world/mc.png +0 -0
  448. package/extensions/ublock/img/flags-of-the-world/md.png +0 -0
  449. package/extensions/ublock/img/flags-of-the-world/me.png +0 -0
  450. package/extensions/ublock/img/flags-of-the-world/mf.png +0 -0
  451. package/extensions/ublock/img/flags-of-the-world/mg.png +0 -0
  452. package/extensions/ublock/img/flags-of-the-world/mh.png +0 -0
  453. package/extensions/ublock/img/flags-of-the-world/mk.png +0 -0
  454. package/extensions/ublock/img/flags-of-the-world/ml.png +0 -0
  455. package/extensions/ublock/img/flags-of-the-world/mm.png +0 -0
  456. package/extensions/ublock/img/flags-of-the-world/mn.png +0 -0
  457. package/extensions/ublock/img/flags-of-the-world/mo.png +0 -0
  458. package/extensions/ublock/img/flags-of-the-world/mp.png +0 -0
  459. package/extensions/ublock/img/flags-of-the-world/mq.png +0 -0
  460. package/extensions/ublock/img/flags-of-the-world/mr.png +0 -0
  461. package/extensions/ublock/img/flags-of-the-world/ms.png +0 -0
  462. package/extensions/ublock/img/flags-of-the-world/mt.png +0 -0
  463. package/extensions/ublock/img/flags-of-the-world/mu.png +0 -0
  464. package/extensions/ublock/img/flags-of-the-world/mv.png +0 -0
  465. package/extensions/ublock/img/flags-of-the-world/mw.png +0 -0
  466. package/extensions/ublock/img/flags-of-the-world/mx.png +0 -0
  467. package/extensions/ublock/img/flags-of-the-world/my.png +0 -0
  468. package/extensions/ublock/img/flags-of-the-world/mz.png +0 -0
  469. package/extensions/ublock/img/flags-of-the-world/na.png +0 -0
  470. package/extensions/ublock/img/flags-of-the-world/nc.png +0 -0
  471. package/extensions/ublock/img/flags-of-the-world/ne.png +0 -0
  472. package/extensions/ublock/img/flags-of-the-world/nf.png +0 -0
  473. package/extensions/ublock/img/flags-of-the-world/ng.png +0 -0
  474. package/extensions/ublock/img/flags-of-the-world/ni.png +0 -0
  475. package/extensions/ublock/img/flags-of-the-world/nl.png +0 -0
  476. package/extensions/ublock/img/flags-of-the-world/no.png +0 -0
  477. package/extensions/ublock/img/flags-of-the-world/np.png +0 -0
  478. package/extensions/ublock/img/flags-of-the-world/nr.png +0 -0
  479. package/extensions/ublock/img/flags-of-the-world/nu.png +0 -0
  480. package/extensions/ublock/img/flags-of-the-world/nz.png +0 -0
  481. package/extensions/ublock/img/flags-of-the-world/om.png +0 -0
  482. package/extensions/ublock/img/flags-of-the-world/pa.png +0 -0
  483. package/extensions/ublock/img/flags-of-the-world/pe.png +0 -0
  484. package/extensions/ublock/img/flags-of-the-world/pf.png +0 -0
  485. package/extensions/ublock/img/flags-of-the-world/pg.png +0 -0
  486. package/extensions/ublock/img/flags-of-the-world/ph.png +0 -0
  487. package/extensions/ublock/img/flags-of-the-world/pk.png +0 -0
  488. package/extensions/ublock/img/flags-of-the-world/pl.png +0 -0
  489. package/extensions/ublock/img/flags-of-the-world/pm.png +0 -0
  490. package/extensions/ublock/img/flags-of-the-world/pn.png +0 -0
  491. package/extensions/ublock/img/flags-of-the-world/pr.png +0 -0
  492. package/extensions/ublock/img/flags-of-the-world/ps.png +0 -0
  493. package/extensions/ublock/img/flags-of-the-world/pt.png +0 -0
  494. package/extensions/ublock/img/flags-of-the-world/pw.png +0 -0
  495. package/extensions/ublock/img/flags-of-the-world/py.png +0 -0
  496. package/extensions/ublock/img/flags-of-the-world/qa.png +0 -0
  497. package/extensions/ublock/img/flags-of-the-world/re.png +0 -0
  498. package/extensions/ublock/img/flags-of-the-world/ro.png +0 -0
  499. package/extensions/ublock/img/flags-of-the-world/rs.png +0 -0
  500. package/extensions/ublock/img/flags-of-the-world/ru.png +0 -0
  501. package/extensions/ublock/img/flags-of-the-world/rw.png +0 -0
  502. package/extensions/ublock/img/flags-of-the-world/sa.png +0 -0
  503. package/extensions/ublock/img/flags-of-the-world/sb.png +0 -0
  504. package/extensions/ublock/img/flags-of-the-world/sc.png +0 -0
  505. package/extensions/ublock/img/flags-of-the-world/sd.png +0 -0
  506. package/extensions/ublock/img/flags-of-the-world/se.png +0 -0
  507. package/extensions/ublock/img/flags-of-the-world/sg.png +0 -0
  508. package/extensions/ublock/img/flags-of-the-world/sh.png +0 -0
  509. package/extensions/ublock/img/flags-of-the-world/si.png +0 -0
  510. package/extensions/ublock/img/flags-of-the-world/sj.png +0 -0
  511. package/extensions/ublock/img/flags-of-the-world/sk.png +0 -0
  512. package/extensions/ublock/img/flags-of-the-world/sl.png +0 -0
  513. package/extensions/ublock/img/flags-of-the-world/sm.png +0 -0
  514. package/extensions/ublock/img/flags-of-the-world/sn.png +0 -0
  515. package/extensions/ublock/img/flags-of-the-world/so.png +0 -0
  516. package/extensions/ublock/img/flags-of-the-world/sr.png +0 -0
  517. package/extensions/ublock/img/flags-of-the-world/ss.png +0 -0
  518. package/extensions/ublock/img/flags-of-the-world/st.png +0 -0
  519. package/extensions/ublock/img/flags-of-the-world/sv.png +0 -0
  520. package/extensions/ublock/img/flags-of-the-world/sx.png +0 -0
  521. package/extensions/ublock/img/flags-of-the-world/sy.png +0 -0
  522. package/extensions/ublock/img/flags-of-the-world/sz.png +0 -0
  523. package/extensions/ublock/img/flags-of-the-world/tc.png +0 -0
  524. package/extensions/ublock/img/flags-of-the-world/td.png +0 -0
  525. package/extensions/ublock/img/flags-of-the-world/tf.png +0 -0
  526. package/extensions/ublock/img/flags-of-the-world/tg.png +0 -0
  527. package/extensions/ublock/img/flags-of-the-world/th.png +0 -0
  528. package/extensions/ublock/img/flags-of-the-world/tj.png +0 -0
  529. package/extensions/ublock/img/flags-of-the-world/tk.png +0 -0
  530. package/extensions/ublock/img/flags-of-the-world/tl.png +0 -0
  531. package/extensions/ublock/img/flags-of-the-world/tm.png +0 -0
  532. package/extensions/ublock/img/flags-of-the-world/tn.png +0 -0
  533. package/extensions/ublock/img/flags-of-the-world/to.png +0 -0
  534. package/extensions/ublock/img/flags-of-the-world/tr.png +0 -0
  535. package/extensions/ublock/img/flags-of-the-world/tt.png +0 -0
  536. package/extensions/ublock/img/flags-of-the-world/tv.png +0 -0
  537. package/extensions/ublock/img/flags-of-the-world/tw.png +0 -0
  538. package/extensions/ublock/img/flags-of-the-world/tz.png +0 -0
  539. package/extensions/ublock/img/flags-of-the-world/ua.png +0 -0
  540. package/extensions/ublock/img/flags-of-the-world/ug.png +0 -0
  541. package/extensions/ublock/img/flags-of-the-world/um.png +0 -0
  542. package/extensions/ublock/img/flags-of-the-world/us.png +0 -0
  543. package/extensions/ublock/img/flags-of-the-world/uy.png +0 -0
  544. package/extensions/ublock/img/flags-of-the-world/uz.png +0 -0
  545. package/extensions/ublock/img/flags-of-the-world/va.png +0 -0
  546. package/extensions/ublock/img/flags-of-the-world/vc.png +0 -0
  547. package/extensions/ublock/img/flags-of-the-world/ve.png +0 -0
  548. package/extensions/ublock/img/flags-of-the-world/vg.png +0 -0
  549. package/extensions/ublock/img/flags-of-the-world/vi.png +0 -0
  550. package/extensions/ublock/img/flags-of-the-world/vn.png +0 -0
  551. package/extensions/ublock/img/flags-of-the-world/vu.png +0 -0
  552. package/extensions/ublock/img/flags-of-the-world/wf.png +0 -0
  553. package/extensions/ublock/img/flags-of-the-world/ws.png +0 -0
  554. package/extensions/ublock/img/flags-of-the-world/xk.png +0 -0
  555. package/extensions/ublock/img/flags-of-the-world/ye.png +0 -0
  556. package/extensions/ublock/img/flags-of-the-world/yt.png +0 -0
  557. package/extensions/ublock/img/flags-of-the-world/za.png +0 -0
  558. package/extensions/ublock/img/flags-of-the-world/zm.png +0 -0
  559. package/extensions/ublock/img/flags-of-the-world/zw.png +0 -0
  560. package/extensions/ublock/img/fontawesome/LICENSE.txt +25 -0
  561. package/extensions/ublock/img/fontawesome/fontawesome-defs.svg +79 -0
  562. package/extensions/ublock/img/help16.png +0 -0
  563. package/extensions/ublock/img/icon_128.png +0 -0
  564. package/extensions/ublock/img/icon_16-loading.png +0 -0
  565. package/extensions/ublock/img/icon_16-off.png +0 -0
  566. package/extensions/ublock/img/icon_16.png +0 -0
  567. package/extensions/ublock/img/icon_32-loading.png +0 -0
  568. package/extensions/ublock/img/icon_32-off.png +0 -0
  569. package/extensions/ublock/img/icon_32.png +0 -0
  570. package/extensions/ublock/img/icon_64-loading.png +0 -0
  571. package/extensions/ublock/img/icon_64-off.png +0 -0
  572. package/extensions/ublock/img/icon_64.png +0 -0
  573. package/extensions/ublock/img/material-design.svg +16 -0
  574. package/extensions/ublock/img/photon.svg +16 -0
  575. package/extensions/ublock/img/ublock-defs.svg +27 -0
  576. package/extensions/ublock/img/ublock.svg +44 -0
  577. package/extensions/ublock/is-webrtc-supported.html +9 -0
  578. package/extensions/ublock/js/1p-filters.js +336 -0
  579. package/extensions/ublock/js/3p-filters.js +867 -0
  580. package/extensions/ublock/js/about.js +34 -0
  581. package/extensions/ublock/js/advanced-settings.js +194 -0
  582. package/extensions/ublock/js/asset-viewer.js +112 -0
  583. package/extensions/ublock/js/assets.js +1448 -0
  584. package/extensions/ublock/js/background.js +404 -0
  585. package/extensions/ublock/js/base64-custom.js +246 -0
  586. package/extensions/ublock/js/benchmarks.js +421 -0
  587. package/extensions/ublock/js/biditrie.js +947 -0
  588. package/extensions/ublock/js/cachestorage.js +510 -0
  589. package/extensions/ublock/js/click2load.js +60 -0
  590. package/extensions/ublock/js/cloud-ui.js +238 -0
  591. package/extensions/ublock/js/code-viewer.js +311 -0
  592. package/extensions/ublock/js/codemirror/search-thread.js +199 -0
  593. package/extensions/ublock/js/codemirror/search.js +504 -0
  594. package/extensions/ublock/js/codemirror/ubo-dynamic-filtering.js +239 -0
  595. package/extensions/ublock/js/codemirror/ubo-static-filtering.js +1126 -0
  596. package/extensions/ublock/js/commands.js +181 -0
  597. package/extensions/ublock/js/console.js +59 -0
  598. package/extensions/ublock/js/contentscript-extra.js +662 -0
  599. package/extensions/ublock/js/contentscript.js +1366 -0
  600. package/extensions/ublock/js/contextmenu.js +270 -0
  601. package/extensions/ublock/js/cosmetic-filtering.js +983 -0
  602. package/extensions/ublock/js/dashboard-common.js +215 -0
  603. package/extensions/ublock/js/dashboard.js +166 -0
  604. package/extensions/ublock/js/devtools.js +184 -0
  605. package/extensions/ublock/js/diff-updater.js +288 -0
  606. package/extensions/ublock/js/document-blocked.js +230 -0
  607. package/extensions/ublock/js/dom.js +213 -0
  608. package/extensions/ublock/js/dyna-rules.js +678 -0
  609. package/extensions/ublock/js/dynamic-net-filtering.js +488 -0
  610. package/extensions/ublock/js/epicker-ui.js +924 -0
  611. package/extensions/ublock/js/fa-icons.js +129 -0
  612. package/extensions/ublock/js/filtering-context.js +461 -0
  613. package/extensions/ublock/js/filtering-engines.js +50 -0
  614. package/extensions/ublock/js/hnswitches.js +289 -0
  615. package/extensions/ublock/js/hntrie.js +780 -0
  616. package/extensions/ublock/js/html-filtering.js +465 -0
  617. package/extensions/ublock/js/httpheader-filtering.js +213 -0
  618. package/extensions/ublock/js/i18n.js +346 -0
  619. package/extensions/ublock/js/is-webrtc-supported.js +52 -0
  620. package/extensions/ublock/js/logger-ui-inspector.js +652 -0
  621. package/extensions/ublock/js/logger-ui.js +3028 -0
  622. package/extensions/ublock/js/logger.js +84 -0
  623. package/extensions/ublock/js/lz4.js +190 -0
  624. package/extensions/ublock/js/messaging.js +2095 -0
  625. package/extensions/ublock/js/pagestore.js +1140 -0
  626. package/extensions/ublock/js/popup-fenix.js +1529 -0
  627. package/extensions/ublock/js/redirect-engine.js +494 -0
  628. package/extensions/ublock/js/redirect-resources.js +193 -0
  629. package/extensions/ublock/js/reverselookup-worker.js +287 -0
  630. package/extensions/ublock/js/reverselookup.js +223 -0
  631. package/extensions/ublock/js/scriptlet-filtering.js +556 -0
  632. package/extensions/ublock/js/scriptlets/cosmetic-logger.js +376 -0
  633. package/extensions/ublock/js/scriptlets/cosmetic-off.js +48 -0
  634. package/extensions/ublock/js/scriptlets/cosmetic-on.js +48 -0
  635. package/extensions/ublock/js/scriptlets/cosmetic-report.js +142 -0
  636. package/extensions/ublock/js/scriptlets/dom-inspector.js +906 -0
  637. package/extensions/ublock/js/scriptlets/dom-survey-elements.js +72 -0
  638. package/extensions/ublock/js/scriptlets/dom-survey-scripts.js +126 -0
  639. package/extensions/ublock/js/scriptlets/epicker.js +1365 -0
  640. package/extensions/ublock/js/scriptlets/load-3p-css.js +67 -0
  641. package/extensions/ublock/js/scriptlets/load-large-media-all.js +62 -0
  642. package/extensions/ublock/js/scriptlets/load-large-media-interactive.js +299 -0
  643. package/extensions/ublock/js/scriptlets/noscript-spoof.js +89 -0
  644. package/extensions/ublock/js/scriptlets/should-inject-contentscript.js +40 -0
  645. package/extensions/ublock/js/scriptlets/subscriber.js +113 -0
  646. package/extensions/ublock/js/scriptlets/updater.js +101 -0
  647. package/extensions/ublock/js/settings.js +317 -0
  648. package/extensions/ublock/js/start.js +509 -0
  649. package/extensions/ublock/js/static-dnr-filtering.js +497 -0
  650. package/extensions/ublock/js/static-ext-filtering-db.js +171 -0
  651. package/extensions/ublock/js/static-ext-filtering.js +184 -0
  652. package/extensions/ublock/js/static-filtering-io.js +144 -0
  653. package/extensions/ublock/js/static-filtering-parser.js +4459 -0
  654. package/extensions/ublock/js/static-net-filtering.js +5631 -0
  655. package/extensions/ublock/js/storage.js +1683 -0
  656. package/extensions/ublock/js/support.js +335 -0
  657. package/extensions/ublock/js/tab.js +1178 -0
  658. package/extensions/ublock/js/tasks.js +42 -0
  659. package/extensions/ublock/js/text-encode.js +275 -0
  660. package/extensions/ublock/js/text-utils.js +107 -0
  661. package/extensions/ublock/js/theme.js +151 -0
  662. package/extensions/ublock/js/traffic.js +1260 -0
  663. package/extensions/ublock/js/ublock.js +696 -0
  664. package/extensions/ublock/js/uri-utils.js +175 -0
  665. package/extensions/ublock/js/url-net-filtering.js +336 -0
  666. package/extensions/ublock/js/utils.js +208 -0
  667. package/extensions/ublock/js/vapi-background-ext.js +254 -0
  668. package/extensions/ublock/js/vapi-background.js +1802 -0
  669. package/extensions/ublock/js/vapi-client-extra.js +312 -0
  670. package/extensions/ublock/js/vapi-client.js +280 -0
  671. package/extensions/ublock/js/vapi-common.js +308 -0
  672. package/extensions/ublock/js/vapi.js +89 -0
  673. package/extensions/ublock/js/wasm/README.md +24 -0
  674. package/extensions/ublock/js/wasm/biditrie.wasm +0 -0
  675. package/extensions/ublock/js/wasm/biditrie.wat +728 -0
  676. package/extensions/ublock/js/wasm/hntrie.wasm +0 -0
  677. package/extensions/ublock/js/wasm/hntrie.wat +724 -0
  678. package/extensions/ublock/js/webext.js +164 -0
  679. package/extensions/ublock/js/whitelist.js +258 -0
  680. package/extensions/ublock/lib/codemirror/LICENSE +21 -0
  681. package/extensions/ublock/lib/codemirror/README.md +47 -0
  682. package/extensions/ublock/lib/codemirror/addon/comment/comment.js +211 -0
  683. package/extensions/ublock/lib/codemirror/addon/display/panel.js +133 -0
  684. package/extensions/ublock/lib/codemirror/addon/edit/closebrackets.js +201 -0
  685. package/extensions/ublock/lib/codemirror/addon/edit/matchbrackets.js +160 -0
  686. package/extensions/ublock/lib/codemirror/addon/fold/foldcode.js +157 -0
  687. package/extensions/ublock/lib/codemirror/addon/fold/foldgutter.css +20 -0
  688. package/extensions/ublock/lib/codemirror/addon/fold/foldgutter.js +163 -0
  689. package/extensions/ublock/lib/codemirror/addon/hint/show-hint.css +36 -0
  690. package/extensions/ublock/lib/codemirror/addon/hint/show-hint.js +509 -0
  691. package/extensions/ublock/lib/codemirror/addon/merge/merge.css +119 -0
  692. package/extensions/ublock/lib/codemirror/addon/merge/merge.js +1006 -0
  693. package/extensions/ublock/lib/codemirror/addon/scroll/annotatescrollbar.js +128 -0
  694. package/extensions/ublock/lib/codemirror/addon/search/matchesonscrollbar.css +8 -0
  695. package/extensions/ublock/lib/codemirror/addon/search/searchcursor.js +296 -0
  696. package/extensions/ublock/lib/codemirror/addon/selection/active-line.js +72 -0
  697. package/extensions/ublock/lib/codemirror/lib/codemirror.css +350 -0
  698. package/extensions/ublock/lib/codemirror/lib/codemirror.js +9800 -0
  699. package/extensions/ublock/lib/codemirror/mode/css/css.js +864 -0
  700. package/extensions/ublock/lib/codemirror/mode/htmlmixed/htmlmixed.js +153 -0
  701. package/extensions/ublock/lib/codemirror/mode/javascript/javascript.js +942 -0
  702. package/extensions/ublock/lib/codemirror/mode/xml/xml.js +413 -0
  703. package/extensions/ublock/lib/codemirror/theme/night.css +27 -0
  704. package/extensions/ublock/lib/csstree/LICENSE +19 -0
  705. package/extensions/ublock/lib/csstree/css-tree.js +17 -0
  706. package/extensions/ublock/lib/diff/README.md +34 -0
  707. package/extensions/ublock/lib/diff/swatinem_diff.js +272 -0
  708. package/extensions/ublock/lib/hsluv/LICENSE +20 -0
  709. package/extensions/ublock/lib/hsluv/README +3 -0
  710. package/extensions/ublock/lib/hsluv/hsluv-0.1.0.min.js +8 -0
  711. package/extensions/ublock/lib/js-beautify/LICENSE +9 -0
  712. package/extensions/ublock/lib/js-beautify/README +5 -0
  713. package/extensions/ublock/lib/js-beautify/beautifier.min.js +2 -0
  714. package/extensions/ublock/lib/lz4/README.md +52 -0
  715. package/extensions/ublock/lib/lz4/lz4-block-codec-any.js +151 -0
  716. package/extensions/ublock/lib/lz4/lz4-block-codec-js.js +297 -0
  717. package/extensions/ublock/lib/lz4/lz4-block-codec-wasm.js +195 -0
  718. package/extensions/ublock/lib/lz4/lz4-block-codec.wasm +0 -0
  719. package/extensions/ublock/lib/lz4/lz4-block-codec.wat +745 -0
  720. package/extensions/ublock/lib/publicsuffixlist/publicsuffixlist.js +641 -0
  721. package/extensions/ublock/lib/publicsuffixlist/wasm/README.md +29 -0
  722. package/extensions/ublock/lib/publicsuffixlist/wasm/publicsuffixlist.wasm +0 -0
  723. package/extensions/ublock/lib/publicsuffixlist/wasm/publicsuffixlist.wat +322 -0
  724. package/extensions/ublock/lib/punycode.js +493 -0
  725. package/extensions/ublock/lib/regexanalyzer/CHANGES.md +15 -0
  726. package/extensions/ublock/lib/regexanalyzer/README.md +14 -0
  727. package/extensions/ublock/lib/regexanalyzer/regex.js +2276 -0
  728. package/extensions/ublock/logger-ui.html +232 -0
  729. package/extensions/ublock/managed_storage.json +73 -0
  730. package/extensions/ublock/manifest.json +115 -0
  731. package/extensions/ublock/no-dashboard.html +27 -0
  732. package/extensions/ublock/popup-fenix.html +114 -0
  733. package/extensions/ublock/settings.html +98 -0
  734. package/extensions/ublock/support.html +131 -0
  735. package/extensions/ublock/web_accessible_resources/1x1.gif +0 -0
  736. package/extensions/ublock/web_accessible_resources/2x2.png +0 -0
  737. package/extensions/ublock/web_accessible_resources/32x32.png +0 -0
  738. package/extensions/ublock/web_accessible_resources/3x2.png +0 -0
  739. package/extensions/ublock/web_accessible_resources/README.txt +11 -0
  740. package/extensions/ublock/web_accessible_resources/addthis_widget.js +39 -0
  741. package/extensions/ublock/web_accessible_resources/amazon_ads.js +70 -0
  742. package/extensions/ublock/web_accessible_resources/amazon_apstag.js +62 -0
  743. package/extensions/ublock/web_accessible_resources/ampproject_v0.js +34 -0
  744. package/extensions/ublock/web_accessible_resources/chartbeat.js +30 -0
  745. package/extensions/ublock/web_accessible_resources/click2load.html +28 -0
  746. package/extensions/ublock/web_accessible_resources/doubleclick_instream_ad_status.js +1 -0
  747. package/extensions/ublock/web_accessible_resources/empty +0 -0
  748. package/extensions/ublock/web_accessible_resources/epicker-ui.html +76 -0
  749. package/extensions/ublock/web_accessible_resources/fingerprint2.js +55 -0
  750. package/extensions/ublock/web_accessible_resources/fingerprint3.js +45 -0
  751. package/extensions/ublock/web_accessible_resources/google-analytics_analytics.js +110 -0
  752. package/extensions/ublock/web_accessible_resources/google-analytics_cx_api.js +36 -0
  753. package/extensions/ublock/web_accessible_resources/google-analytics_ga.js +130 -0
  754. package/extensions/ublock/web_accessible_resources/google-analytics_inpage_linkid.js +28 -0
  755. package/extensions/ublock/web_accessible_resources/google-ima.js +855 -0
  756. package/extensions/ublock/web_accessible_resources/googlesyndication_adsbygoogle.js +56 -0
  757. package/extensions/ublock/web_accessible_resources/googletagmanager_gtm.js +43 -0
  758. package/extensions/ublock/web_accessible_resources/googletagservices_gpt.js +153 -0
  759. package/extensions/ublock/web_accessible_resources/hd-main.js +46 -0
  760. package/extensions/ublock/web_accessible_resources/ligatus_angular-tag.js +29 -0
  761. package/extensions/ublock/web_accessible_resources/monkeybroker.js +43 -0
  762. package/extensions/ublock/web_accessible_resources/mxpnl_mixpanel.js +51 -0
  763. package/extensions/ublock/web_accessible_resources/nobab.js +87 -0
  764. package/extensions/ublock/web_accessible_resources/nobab2.js +42 -0
  765. package/extensions/ublock/web_accessible_resources/noeval-silent.js +28 -0
  766. package/extensions/ublock/web_accessible_resources/noeval.js +30 -0
  767. package/extensions/ublock/web_accessible_resources/nofab.js +67 -0
  768. package/extensions/ublock/web_accessible_resources/noop-0.1s.mp3 +0 -0
  769. package/extensions/ublock/web_accessible_resources/noop-0.5s.mp3 +0 -0
  770. package/extensions/ublock/web_accessible_resources/noop-1s.mp4 +0 -0
  771. package/extensions/ublock/web_accessible_resources/noop-vmap1.0.xml +1 -0
  772. package/extensions/ublock/web_accessible_resources/noop.css +1 -0
  773. package/extensions/ublock/web_accessible_resources/noop.html +5 -0
  774. package/extensions/ublock/web_accessible_resources/noop.js +3 -0
  775. package/extensions/ublock/web_accessible_resources/noop.json +1 -0
  776. package/extensions/ublock/web_accessible_resources/noop.txt +1 -0
  777. package/extensions/ublock/web_accessible_resources/outbrain-widget.js +72 -0
  778. package/extensions/ublock/web_accessible_resources/popads-dummy.js +30 -0
  779. package/extensions/ublock/web_accessible_resources/popads.js +40 -0
  780. package/extensions/ublock/web_accessible_resources/prebid-ads.js +26 -0
  781. package/extensions/ublock/web_accessible_resources/scorecardresearch_beacon.js +31 -0
  782. package/extensions/ublock/whitelist.html +63 -0
  783. package/external/.gitkeep +0 -0
  784. package/fonts/Calibri Bold Italic.ttf +0 -0
  785. package/fonts/Calibri Bold.TTF +0 -0
  786. package/fonts/Calibri Italic.ttf +0 -0
  787. package/fonts/Calibri Light Italic.ttf +0 -0
  788. package/fonts/Calibri Light.ttf +0 -0
  789. package/fonts/Calibri Regular.ttf +0 -0
  790. package/fonts/Emoji.ttf +0 -0
  791. package/fonts/SegoeUI-Bold.ttf +0 -0
  792. package/fonts/SegoeUI-Light.ttf +0 -0
  793. package/fonts/SegoeUI-Regular.ttf +0 -0
  794. package/fonts/SegoeUI-Semibold.ttf +0 -0
  795. package/fonts/SegoeUI-Semilight.ttf +0 -0
  796. package/fonts/Tahoma Bold.ttf +0 -0
  797. package/fonts/Tahoma.ttf +0 -0
  798. package/fonts/fonts.conf +21 -0
  799. package/package.json +177 -0
  800. package/scripts/build-function.js +18 -0
  801. package/scripts/build-open-api.js +274 -0
  802. package/scripts/build-schemas.js +86 -0
  803. package/scripts/build-selectors.js +36 -0
  804. package/scripts/clean.js +7 -0
  805. package/scripts/install-adblock.js +45 -0
  806. package/scripts/install-cdp-json.js +37 -0
  807. package/scripts/start.sh +30 -0
  808. package/scripts/test.sh +17 -0
  809. package/src/browserless.ts +253 -0
  810. package/src/browsers/cdp-chromium.ts +422 -0
  811. package/src/browsers/index.ts +296 -0
  812. package/src/browsers/playwright-chromium.ts +168 -0
  813. package/src/browsers/playwright-firefox.ts +161 -0
  814. package/src/browsers/playwright-webkit.ts +161 -0
  815. package/src/config.ts +426 -0
  816. package/src/constants.ts +4 -0
  817. package/src/exports.ts +23 -0
  818. package/src/file-system.ts +54 -0
  819. package/src/hooks.ts +37 -0
  820. package/src/http.ts +157 -0
  821. package/src/index.ts +41 -0
  822. package/src/limiter.spec.ts +365 -0
  823. package/src/limiter.ts +225 -0
  824. package/src/metrics.spec.ts +49 -0
  825. package/src/metrics.ts +108 -0
  826. package/src/mime-types.ts +332 -0
  827. package/src/monitoring.ts +53 -0
  828. package/src/routes/chromium/http/content-post.ts +238 -0
  829. package/src/routes/chromium/http/download-post.ts +162 -0
  830. package/src/routes/chromium/http/function-post.ts +98 -0
  831. package/src/routes/chromium/http/pdf-post.ts +234 -0
  832. package/src/routes/chromium/http/performance.ts +71 -0
  833. package/src/routes/chromium/http/scrape-post.ts +439 -0
  834. package/src/routes/chromium/http/screenshot-post.ts +262 -0
  835. package/src/routes/chromium/tests/content.spec.ts +340 -0
  836. package/src/routes/chromium/tests/download.spec.ts +77 -0
  837. package/src/routes/chromium/tests/function.spec.ts +279 -0
  838. package/src/routes/chromium/tests/pdf.spec.ts +375 -0
  839. package/src/routes/chromium/tests/performance.spec.ts +155 -0
  840. package/src/routes/chromium/tests/scrape.spec.ts +414 -0
  841. package/src/routes/chromium/tests/screenshot.spec.ts +387 -0
  842. package/src/routes/chromium/tests/websocket.spec.ts +407 -0
  843. package/src/routes/chromium/utils/function/client.ts +99 -0
  844. package/src/routes/chromium/utils/function/handler.ts +172 -0
  845. package/src/routes/chromium/utils/performance/child.ts +38 -0
  846. package/src/routes/chromium/utils/performance/main.ts +90 -0
  847. package/src/routes/chromium/utils/performance/types.ts +24 -0
  848. package/src/routes/chromium/ws/browser.ts +31 -0
  849. package/src/routes/chromium/ws/cdp-chromium.ts +31 -0
  850. package/src/routes/chromium/ws/page.ts +31 -0
  851. package/src/routes/chromium/ws/playwright-chromium.ts +44 -0
  852. package/src/routes/firefox/tests/websocket.spec.ts +146 -0
  853. package/src/routes/firefox/ws/playwright-firefox.ts +44 -0
  854. package/src/routes/management/http/config-get.ts +82 -0
  855. package/src/routes/management/http/metrics-get.ts +43 -0
  856. package/src/routes/management/http/metrics-total-get.ts +89 -0
  857. package/src/routes/management/http/sessions-get.ts +39 -0
  858. package/src/routes/management/http/static-get.ts +109 -0
  859. package/src/routes/management/tests/management.spec.ts +71 -0
  860. package/src/routes/webkit/tests/websocket.spec.ts +146 -0
  861. package/src/routes/webkit/ws/playwright-webkit.ts +44 -0
  862. package/src/server.ts +609 -0
  863. package/src/shim.spec.ts +154 -0
  864. package/src/shim.ts +78 -0
  865. package/src/types.ts +470 -0
  866. package/src/utils.ts +787 -0
  867. package/src/webhooks.ts +50 -0
  868. package/static/docs/browserless-logo.png +0 -0
  869. package/static/docs/docs.js +2 -0
  870. package/static/docs/index.html +71 -0
  871. package/static/docs/swagger.json +4232 -0
  872. package/static/favicon-32x32.png +0 -0
  873. package/static/function/client.js +31623 -0
  874. package/static/function/index.html +12 -0
  875. package/tsconfig.json +31 -0
@@ -0,0 +1,4255 @@
1
+ /*******************************************************************************
2
+
3
+ uBlock Origin - a browser extension to block requests.
4
+ Copyright (C) 2019-present Raymond Hill
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
18
+
19
+ Home: https://github.com/gorhill/uBlock
20
+
21
+ The scriptlets below are meant to be injected only into a
22
+ web page context.
23
+ */
24
+
25
+ // Externally added to the private namespace in which scriptlets execute.
26
+ /* global scriptletGlobals */
27
+
28
+ 'use strict';
29
+
30
+ export const builtinScriptlets = [];
31
+
32
+ /*******************************************************************************
33
+
34
+ Helper functions
35
+
36
+ These are meant to be used as dependencies to injectable scriptlets.
37
+
38
+ *******************************************************************************/
39
+
40
+ builtinScriptlets.push({
41
+ name: 'safe-self.fn',
42
+ fn: safeSelf,
43
+ });
44
+ function safeSelf() {
45
+ if ( scriptletGlobals.has('safeSelf') ) {
46
+ return scriptletGlobals.get('safeSelf');
47
+ }
48
+ const self = globalThis;
49
+ const safe = {
50
+ 'Array_from': Array.from,
51
+ 'Error': self.Error,
52
+ 'Function_toStringFn': self.Function.prototype.toString,
53
+ 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg),
54
+ 'Math_floor': Math.floor,
55
+ 'Math_random': Math.random,
56
+ 'Object_defineProperty': Object.defineProperty.bind(Object),
57
+ 'RegExp': self.RegExp,
58
+ 'RegExp_test': self.RegExp.prototype.test,
59
+ 'RegExp_exec': self.RegExp.prototype.exec,
60
+ 'Request_clone': self.Request.prototype.clone,
61
+ 'XMLHttpRequest': self.XMLHttpRequest,
62
+ 'addEventListener': self.EventTarget.prototype.addEventListener,
63
+ 'removeEventListener': self.EventTarget.prototype.removeEventListener,
64
+ 'fetch': self.fetch,
65
+ 'JSON': self.JSON,
66
+ 'JSON_parseFn': self.JSON.parse,
67
+ 'JSON_stringifyFn': self.JSON.stringify,
68
+ 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args),
69
+ 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args),
70
+ 'log': console.log.bind(console),
71
+ uboLog(...args) {
72
+ if ( scriptletGlobals.has('canDebug') === false ) { return; }
73
+ if ( args.length === 0 ) { return; }
74
+ if ( `${args[0]}` === '' ) { return; }
75
+ this.log('[uBO]', ...args);
76
+ },
77
+ initPattern(pattern, options = {}) {
78
+ if ( pattern === '' ) {
79
+ return { matchAll: true };
80
+ }
81
+ const expect = (options.canNegate !== true || pattern.startsWith('!') === false);
82
+ if ( expect === false ) {
83
+ pattern = pattern.slice(1);
84
+ }
85
+ const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
86
+ if ( match !== null ) {
87
+ return {
88
+ pattern,
89
+ re: new this.RegExp(
90
+ match[1],
91
+ match[2] || options.flags
92
+ ),
93
+ expect,
94
+ };
95
+ }
96
+ return {
97
+ pattern,
98
+ re: new this.RegExp(pattern.replace(
99
+ /[.*+?^${}()|[\]\\]/g, '\\$&'),
100
+ options.flags
101
+ ),
102
+ expect,
103
+ };
104
+ },
105
+ testPattern(details, haystack) {
106
+ if ( details.matchAll ) { return true; }
107
+ return this.RegExp_test.call(details.re, haystack) === details.expect;
108
+ },
109
+ patternToRegex(pattern, flags = undefined, verbatim = false) {
110
+ if ( pattern === '' ) { return /^/; }
111
+ const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
112
+ if ( match === null ) {
113
+ const reStr = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
114
+ return new RegExp(verbatim ? `^${reStr}$` : reStr, flags);
115
+ }
116
+ try {
117
+ return new RegExp(match[1], match[2] || undefined);
118
+ }
119
+ catch(ex) {
120
+ }
121
+ return /^/;
122
+ },
123
+ getExtraArgs(args, offset = 0) {
124
+ const entries = args.slice(offset).reduce((out, v, i, a) => {
125
+ if ( (i & 1) === 0 ) {
126
+ const rawValue = a[i+1];
127
+ const value = /^\d+$/.test(rawValue)
128
+ ? parseInt(rawValue, 10)
129
+ : rawValue;
130
+ out.push([ a[i], value ]);
131
+ }
132
+ return out;
133
+ }, []);
134
+ return Object.fromEntries(entries);
135
+ },
136
+ };
137
+ scriptletGlobals.set('safeSelf', safe);
138
+ return safe;
139
+ }
140
+
141
+ /******************************************************************************/
142
+
143
+ builtinScriptlets.push({
144
+ name: 'get-exception-token.fn',
145
+ fn: getExceptionToken,
146
+ dependencies: [
147
+ 'safe-self.fn',
148
+ ],
149
+ });
150
+ function getExceptionToken() {
151
+ const safe = safeSelf();
152
+ const token =
153
+ String.fromCharCode(Date.now() % 26 + 97) +
154
+ safe.Math_floor(safe.Math_random() * 982451653 + 982451653).toString(36);
155
+ const oe = self.onerror;
156
+ self.onerror = function(msg, ...args) {
157
+ if ( typeof msg === 'string' && msg.includes(token) ) { return true; }
158
+ if ( oe instanceof Function ) {
159
+ return oe.call(this, msg, ...args);
160
+ }
161
+ }.bind();
162
+ return token;
163
+ }
164
+
165
+ /******************************************************************************/
166
+
167
+ builtinScriptlets.push({
168
+ name: 'should-debug.fn',
169
+ fn: shouldDebug,
170
+ });
171
+ function shouldDebug(details) {
172
+ if ( details instanceof Object === false ) { return false; }
173
+ return scriptletGlobals.has('canDebug') && details.debug;
174
+ }
175
+
176
+ /******************************************************************************/
177
+
178
+ builtinScriptlets.push({
179
+ name: 'should-log.fn',
180
+ fn: shouldLog,
181
+ });
182
+ function shouldLog(details) {
183
+ if ( details instanceof Object === false ) { return false; }
184
+ return scriptletGlobals.has('canDebug') && details.log;
185
+ }
186
+
187
+ /******************************************************************************/
188
+
189
+ builtinScriptlets.push({
190
+ name: 'run-at.fn',
191
+ fn: runAt,
192
+ dependencies: [
193
+ 'safe-self.fn',
194
+ ],
195
+ });
196
+ function runAt(fn, when) {
197
+ const intFromReadyState = state => {
198
+ const targets = {
199
+ 'loading': 1,
200
+ 'interactive': 2, 'end': 2, '2': 2,
201
+ 'complete': 3, 'idle': 3, '3': 3,
202
+ };
203
+ const tokens = Array.isArray(state) ? state : [ state ];
204
+ for ( const token of tokens ) {
205
+ const prop = `${token}`;
206
+ if ( targets.hasOwnProperty(prop) === false ) { continue; }
207
+ return targets[prop];
208
+ }
209
+ return 0;
210
+ };
211
+ const runAt = intFromReadyState(when);
212
+ if ( intFromReadyState(document.readyState) >= runAt ) {
213
+ fn(); return;
214
+ }
215
+ const onStateChange = ( ) => {
216
+ if ( intFromReadyState(document.readyState) < runAt ) { return; }
217
+ fn();
218
+ safe.removeEventListener.apply(document, args);
219
+ };
220
+ const safe = safeSelf();
221
+ const args = [ 'readystatechange', onStateChange, { capture: true } ];
222
+ safe.addEventListener.apply(document, args);
223
+ }
224
+
225
+ /******************************************************************************/
226
+
227
+ builtinScriptlets.push({
228
+ name: 'run-at-html-element.fn',
229
+ fn: runAtHtmlElementFn,
230
+ });
231
+ function runAtHtmlElementFn(fn) {
232
+ if ( document.documentElement ) {
233
+ fn();
234
+ return;
235
+ }
236
+ const observer = new MutationObserver(( ) => {
237
+ observer.disconnect();
238
+ fn();
239
+ });
240
+ observer.observe(document, { childList: true });
241
+ }
242
+
243
+ /******************************************************************************/
244
+
245
+ builtinScriptlets.push({
246
+ name: 'abort-current-script-core.fn',
247
+ fn: abortCurrentScriptCore,
248
+ dependencies: [
249
+ 'get-exception-token.fn',
250
+ 'safe-self.fn',
251
+ 'should-debug.fn',
252
+ 'should-log.fn',
253
+ ],
254
+ });
255
+ // Issues to mind before changing anything:
256
+ // https://github.com/uBlockOrigin/uBlock-issues/issues/2154
257
+ function abortCurrentScriptCore(
258
+ target = '',
259
+ needle = '',
260
+ context = ''
261
+ ) {
262
+ if ( typeof target !== 'string' ) { return; }
263
+ if ( target === '' ) { return; }
264
+ const safe = safeSelf();
265
+ const reNeedle = safe.patternToRegex(needle);
266
+ const reContext = safe.patternToRegex(context);
267
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
268
+ const thisScript = document.currentScript;
269
+ const chain = target.split('.');
270
+ let owner = window;
271
+ let prop;
272
+ for (;;) {
273
+ prop = chain.shift();
274
+ if ( chain.length === 0 ) { break; }
275
+ if ( prop in owner === false ) { break; }
276
+ owner = owner[prop];
277
+ if ( owner instanceof Object === false ) { return; }
278
+ }
279
+ let value;
280
+ let desc = Object.getOwnPropertyDescriptor(owner, prop);
281
+ if (
282
+ desc instanceof Object === false ||
283
+ desc.get instanceof Function === false
284
+ ) {
285
+ value = owner[prop];
286
+ desc = undefined;
287
+ }
288
+ const log = shouldLog(extraArgs);
289
+ const debug = shouldDebug(extraArgs);
290
+ const exceptionToken = getExceptionToken();
291
+ const scriptTexts = new WeakMap();
292
+ const getScriptText = elem => {
293
+ let text = elem.textContent;
294
+ if ( text.trim() !== '' ) { return text; }
295
+ if ( scriptTexts.has(elem) ) { return scriptTexts.get(elem); }
296
+ const [ , mime, content ] =
297
+ /^data:([^,]*),(.+)$/.exec(elem.src.trim()) ||
298
+ [ '', '', '' ];
299
+ try {
300
+ switch ( true ) {
301
+ case mime.endsWith(';base64'):
302
+ text = self.atob(content);
303
+ break;
304
+ default:
305
+ text = self.decodeURIComponent(content);
306
+ break;
307
+ }
308
+ } catch(ex) {
309
+ }
310
+ scriptTexts.set(elem, text);
311
+ return text;
312
+ };
313
+ const validate = ( ) => {
314
+ const e = document.currentScript;
315
+ if ( e instanceof HTMLScriptElement === false ) { return; }
316
+ if ( e === thisScript ) { return; }
317
+ if ( context !== '' && reContext.test(e.src) === false ) {
318
+ if ( debug === 'nomatch' || debug === 'all' ) { debugger; } // jshint ignore: line
319
+ return;
320
+ }
321
+ if ( log && e.src !== '' ) { safe.uboLog(`matched src: ${e.src}`); }
322
+ const scriptText = getScriptText(e);
323
+ if ( reNeedle.test(scriptText) === false ) {
324
+ if ( debug === 'nomatch' || debug === 'all' ) { debugger; } // jshint ignore: line
325
+ return;
326
+ }
327
+ if ( log ) { safe.uboLog(`matched script text: ${scriptText}`); }
328
+ if ( debug === 'match' || debug === 'all' ) { debugger; } // jshint ignore: line
329
+ throw new ReferenceError(exceptionToken);
330
+ };
331
+ if ( debug === 'install' ) { debugger; } // jshint ignore: line
332
+ try {
333
+ Object.defineProperty(owner, prop, {
334
+ get: function() {
335
+ validate();
336
+ return desc instanceof Object
337
+ ? desc.get.call(owner)
338
+ : value;
339
+ },
340
+ set: function(a) {
341
+ validate();
342
+ if ( desc instanceof Object ) {
343
+ desc.set.call(owner, a);
344
+ } else {
345
+ value = a;
346
+ }
347
+ }
348
+ });
349
+ } catch(ex) {
350
+ if ( log ) { safe.uboLog(ex); }
351
+ }
352
+ }
353
+
354
+ /******************************************************************************/
355
+
356
+ builtinScriptlets.push({
357
+ name: 'set-constant-core.fn',
358
+ fn: setConstantCore,
359
+ dependencies: [
360
+ 'run-at.fn',
361
+ 'safe-self.fn',
362
+ ],
363
+ });
364
+
365
+ function setConstantCore(
366
+ trusted = false,
367
+ chain = '',
368
+ cValue = ''
369
+ ) {
370
+ if ( chain === '' ) { return; }
371
+ const safe = safeSelf();
372
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
373
+ function setConstant(chain, cValue) {
374
+ const trappedProp = (( ) => {
375
+ const pos = chain.lastIndexOf('.');
376
+ if ( pos === -1 ) { return chain; }
377
+ return chain.slice(pos+1);
378
+ })();
379
+ if ( trappedProp === '' ) { return; }
380
+ const thisScript = document.currentScript;
381
+ const cloakFunc = fn => {
382
+ safe.Object_defineProperty(fn, 'name', { value: trappedProp });
383
+ const proxy = new Proxy(fn, {
384
+ defineProperty(target, prop) {
385
+ if ( prop !== 'toString' ) {
386
+ return Reflect.defineProperty(...arguments);
387
+ }
388
+ return true;
389
+ },
390
+ deleteProperty(target, prop) {
391
+ if ( prop !== 'toString' ) {
392
+ return Reflect.deleteProperty(...arguments);
393
+ }
394
+ return true;
395
+ },
396
+ get(target, prop) {
397
+ if ( prop === 'toString' ) {
398
+ return function() {
399
+ return `function ${trappedProp}() { [native code] }`;
400
+ }.bind(null);
401
+ }
402
+ return Reflect.get(...arguments);
403
+ },
404
+ });
405
+ return proxy;
406
+ };
407
+ if ( cValue === 'undefined' ) {
408
+ cValue = undefined;
409
+ } else if ( cValue === 'false' ) {
410
+ cValue = false;
411
+ } else if ( cValue === 'true' ) {
412
+ cValue = true;
413
+ } else if ( cValue === 'null' ) {
414
+ cValue = null;
415
+ } else if ( cValue === "''" || cValue === '' ) {
416
+ cValue = '';
417
+ } else if ( cValue === '[]' || cValue === 'emptyArr' ) {
418
+ cValue = [];
419
+ } else if ( cValue === '{}' || cValue === 'emptyObj' ) {
420
+ cValue = {};
421
+ } else if ( cValue === 'noopFunc' ) {
422
+ cValue = cloakFunc(function(){});
423
+ } else if ( cValue === 'trueFunc' ) {
424
+ cValue = cloakFunc(function(){ return true; });
425
+ } else if ( cValue === 'falseFunc' ) {
426
+ cValue = cloakFunc(function(){ return false; });
427
+ } else if ( /^-?\d+$/.test(cValue) ) {
428
+ cValue = parseInt(cValue);
429
+ if ( isNaN(cValue) ) { return; }
430
+ if ( Math.abs(cValue) > 0x7FFF ) { return; }
431
+ } else if ( trusted ) {
432
+ if ( cValue.startsWith('{') && cValue.endsWith('}') ) {
433
+ try { cValue = safe.JSON_parse(cValue).value; } catch(ex) { return; }
434
+ }
435
+ } else {
436
+ return;
437
+ }
438
+ if ( extraArgs.as !== undefined ) {
439
+ const value = cValue;
440
+ if ( extraArgs.as === 'function' ) {
441
+ cValue = ( ) => value;
442
+ } else if ( extraArgs.as === 'callback' ) {
443
+ cValue = ( ) => (( ) => value);
444
+ } else if ( extraArgs.as === 'resolved' ) {
445
+ cValue = Promise.resolve(value);
446
+ } else if ( extraArgs.as === 'rejected' ) {
447
+ cValue = Promise.reject(value);
448
+ }
449
+ }
450
+ let aborted = false;
451
+ const mustAbort = function(v) {
452
+ if ( trusted ) { return false; }
453
+ if ( aborted ) { return true; }
454
+ aborted =
455
+ (v !== undefined && v !== null) &&
456
+ (cValue !== undefined && cValue !== null) &&
457
+ (typeof v !== typeof cValue);
458
+ return aborted;
459
+ };
460
+ // https://github.com/uBlockOrigin/uBlock-issues/issues/156
461
+ // Support multiple trappers for the same property.
462
+ const trapProp = function(owner, prop, configurable, handler) {
463
+ if ( handler.init(configurable ? owner[prop] : cValue) === false ) { return; }
464
+ const odesc = Object.getOwnPropertyDescriptor(owner, prop);
465
+ let prevGetter, prevSetter;
466
+ if ( odesc instanceof Object ) {
467
+ owner[prop] = cValue;
468
+ if ( odesc.get instanceof Function ) {
469
+ prevGetter = odesc.get;
470
+ }
471
+ if ( odesc.set instanceof Function ) {
472
+ prevSetter = odesc.set;
473
+ }
474
+ }
475
+ try {
476
+ safe.Object_defineProperty(owner, prop, {
477
+ configurable,
478
+ get() {
479
+ if ( prevGetter !== undefined ) {
480
+ prevGetter();
481
+ }
482
+ return handler.getter(); // cValue
483
+ },
484
+ set(a) {
485
+ if ( prevSetter !== undefined ) {
486
+ prevSetter(a);
487
+ }
488
+ handler.setter(a);
489
+ }
490
+ });
491
+ } catch(ex) {
492
+ }
493
+ };
494
+ const trapChain = function(owner, chain) {
495
+ const pos = chain.indexOf('.');
496
+ if ( pos === -1 ) {
497
+ trapProp(owner, chain, false, {
498
+ v: undefined,
499
+ init: function(v) {
500
+ if ( mustAbort(v) ) { return false; }
501
+ this.v = v;
502
+ return true;
503
+ },
504
+ getter: function() {
505
+ return document.currentScript === thisScript
506
+ ? this.v
507
+ : cValue;
508
+ },
509
+ setter: function(a) {
510
+ if ( mustAbort(a) === false ) { return; }
511
+ cValue = a;
512
+ }
513
+ });
514
+ return;
515
+ }
516
+ const prop = chain.slice(0, pos);
517
+ const v = owner[prop];
518
+ chain = chain.slice(pos + 1);
519
+ if ( v instanceof Object || typeof v === 'object' && v !== null ) {
520
+ trapChain(v, chain);
521
+ return;
522
+ }
523
+ trapProp(owner, prop, true, {
524
+ v: undefined,
525
+ init: function(v) {
526
+ this.v = v;
527
+ return true;
528
+ },
529
+ getter: function() {
530
+ return this.v;
531
+ },
532
+ setter: function(a) {
533
+ this.v = a;
534
+ if ( a instanceof Object ) {
535
+ trapChain(a, chain);
536
+ }
537
+ }
538
+ });
539
+ };
540
+ trapChain(window, chain);
541
+ }
542
+ runAt(( ) => {
543
+ setConstant(chain, cValue);
544
+ }, extraArgs.runAt);
545
+ }
546
+
547
+ /******************************************************************************/
548
+
549
+ builtinScriptlets.push({
550
+ name: 'replace-node-text.fn',
551
+ fn: replaceNodeTextFn,
552
+ dependencies: [
553
+ 'run-at.fn',
554
+ 'safe-self.fn',
555
+ ],
556
+ });
557
+ function replaceNodeTextFn(
558
+ nodeName = '',
559
+ pattern = '',
560
+ replacement = ''
561
+ ) {
562
+ const safe = safeSelf();
563
+ const reNodeName = safe.patternToRegex(nodeName, 'i', true);
564
+ const rePattern = safe.patternToRegex(pattern, 'gms');
565
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
566
+ const shouldLog = scriptletGlobals.has('canDebug') && extraArgs.log || 0;
567
+ const reCondition = safe.patternToRegex(extraArgs.condition || '', 'ms');
568
+ const stop = (takeRecord = true) => {
569
+ if ( takeRecord ) {
570
+ handleMutations(observer.takeRecords());
571
+ }
572
+ observer.disconnect();
573
+ if ( shouldLog !== 0 ) {
574
+ safe.uboLog(`replace-node-text-core.fn: quitting "${pattern}" => "${replacement}"`);
575
+ }
576
+ };
577
+ let sedCount = extraArgs.sedCount || 0;
578
+ const handleNode = node => {
579
+ const before = node.textContent;
580
+ reCondition.lastIndex = 0;
581
+ if ( safe.RegExp_test.call(reCondition, before) === false ) { return true; }
582
+ rePattern.lastIndex = 0;
583
+ if ( safe.RegExp_test.call(rePattern, before) === false ) { return true; }
584
+ rePattern.lastIndex = 0;
585
+ const after = pattern !== ''
586
+ ? before.replace(rePattern, replacement)
587
+ : replacement;
588
+ node.textContent = after;
589
+ if ( shouldLog !== 0 ) {
590
+ safe.uboLog('replace-node-text.fn before:\n', before);
591
+ safe.uboLog('replace-node-text.fn after:\n', after);
592
+ }
593
+ return sedCount === 0 || (sedCount -= 1) !== 0;
594
+ };
595
+ const handleMutations = mutations => {
596
+ for ( const mutation of mutations ) {
597
+ for ( const node of mutation.addedNodes ) {
598
+ if ( reNodeName.test(node.nodeName) === false ) { continue; }
599
+ if ( handleNode(node) ) { continue; }
600
+ stop(false); return;
601
+ }
602
+ }
603
+ };
604
+ const observer = new MutationObserver(handleMutations);
605
+ observer.observe(document, { childList: true, subtree: true });
606
+ if ( document.documentElement ) {
607
+ const treeWalker = document.createTreeWalker(
608
+ document.documentElement,
609
+ NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT
610
+ );
611
+ let count = 0;
612
+ for (;;) {
613
+ const node = treeWalker.nextNode();
614
+ count += 1;
615
+ if ( node === null ) { break; }
616
+ if ( reNodeName.test(node.nodeName) === false ) { continue; }
617
+ if ( handleNode(node) ) { continue; }
618
+ stop(); break;
619
+ }
620
+ if ( shouldLog !== 0 ) {
621
+ safe.uboLog(`replace-node-text-core.fn ${count} nodes present before installing mutation observer`);
622
+ }
623
+ }
624
+ if ( extraArgs.stay ) { return; }
625
+ runAt(( ) => {
626
+ const quitAfter = extraArgs.quitAfter || 0;
627
+ if ( quitAfter !== 0 ) {
628
+ setTimeout(( ) => { stop(); }, quitAfter);
629
+ } else {
630
+ stop();
631
+ }
632
+ }, 'interactive');
633
+ }
634
+
635
+ /******************************************************************************/
636
+
637
+ builtinScriptlets.push({
638
+ name: 'object-prune.fn',
639
+ fn: objectPruneFn,
640
+ dependencies: [
641
+ 'matches-stack-trace.fn',
642
+ 'object-find-owner.fn',
643
+ 'safe-self.fn',
644
+ 'should-log.fn',
645
+ ],
646
+ });
647
+ // When no "prune paths" argument is provided, the scriptlet is
648
+ // used for logging purpose and the "needle paths" argument is
649
+ // used to filter logging output.
650
+ //
651
+ // https://github.com/uBlockOrigin/uBlock-issues/issues/1545
652
+ // - Add support for "remove everything if needle matches" case
653
+ function objectPruneFn(
654
+ obj,
655
+ rawPrunePaths,
656
+ rawNeedlePaths,
657
+ stackNeedleDetails = { matchAll: true },
658
+ extraArgs = {}
659
+ ) {
660
+ if ( typeof rawPrunePaths !== 'string' ) { return; }
661
+ const safe = safeSelf();
662
+ const prunePaths = rawPrunePaths !== ''
663
+ ? rawPrunePaths.split(/ +/)
664
+ : [];
665
+ const needlePaths = prunePaths.length !== 0 && rawNeedlePaths !== ''
666
+ ? rawNeedlePaths.split(/ +/)
667
+ : [];
668
+ const logLevel = shouldLog({ log: rawPrunePaths === '' || extraArgs.log });
669
+ const reLogNeedle = safe.patternToRegex(logLevel === true ? rawNeedlePaths : '');
670
+ if ( stackNeedleDetails.matchAll !== true ) {
671
+ if ( matchesStackTrace(stackNeedleDetails, extraArgs.logstack) === false ) {
672
+ return;
673
+ }
674
+ }
675
+ if ( objectPruneFn.mustProcess === undefined ) {
676
+ objectPruneFn.mustProcess = (root, needlePaths) => {
677
+ for ( const needlePath of needlePaths ) {
678
+ if ( objectFindOwnerFn(root, needlePath) === false ) {
679
+ return false;
680
+ }
681
+ }
682
+ return true;
683
+ };
684
+ objectPruneFn.logJson = (json, msg, reNeedle) => {
685
+ if ( reNeedle.test(json) === false ) { return; }
686
+ safeSelf().uboLog(`objectPrune()`, msg, location.hostname, json);
687
+ };
688
+ }
689
+ const jsonBefore = logLevel ? safe.JSON_stringify(obj, null, 2) : '';
690
+ if ( logLevel === true || logLevel === 'all' ) {
691
+ objectPruneFn.logJson(jsonBefore, `prune:"${rawPrunePaths}" log:"${logLevel}"`, reLogNeedle);
692
+ }
693
+ if ( prunePaths.length === 0 ) { return; }
694
+ let outcome = 'nomatch';
695
+ if ( objectPruneFn.mustProcess(obj, needlePaths) ) {
696
+ for ( const path of prunePaths ) {
697
+ if ( objectFindOwnerFn(obj, path, true) ) {
698
+ outcome = 'match';
699
+ }
700
+ }
701
+ }
702
+ if ( logLevel === outcome ) {
703
+ objectPruneFn.logJson(jsonBefore, `prune:"${rawPrunePaths}" log:"${logLevel}"`, reLogNeedle);
704
+ }
705
+ if ( outcome === 'match' ) { return obj; }
706
+ }
707
+
708
+ /******************************************************************************/
709
+
710
+ builtinScriptlets.push({
711
+ name: 'object-find-owner.fn',
712
+ fn: objectFindOwnerFn,
713
+ });
714
+ function objectFindOwnerFn(
715
+ root,
716
+ path,
717
+ prune = false
718
+ ) {
719
+ let owner = root;
720
+ let chain = path;
721
+ for (;;) {
722
+ if ( typeof owner !== 'object' || owner === null ) { return false; }
723
+ const pos = chain.indexOf('.');
724
+ if ( pos === -1 ) {
725
+ if ( prune === false ) {
726
+ return owner.hasOwnProperty(chain);
727
+ }
728
+ let modified = false;
729
+ if ( chain === '*' ) {
730
+ for ( const key in owner ) {
731
+ if ( owner.hasOwnProperty(key) === false ) { continue; }
732
+ delete owner[key];
733
+ modified = true;
734
+ }
735
+ } else if ( owner.hasOwnProperty(chain) ) {
736
+ delete owner[chain];
737
+ modified = true;
738
+ }
739
+ return modified;
740
+ }
741
+ const prop = chain.slice(0, pos);
742
+ if (
743
+ prop === '[]' && Array.isArray(owner) ||
744
+ prop === '*' && owner instanceof Object
745
+ ) {
746
+ const next = chain.slice(pos + 1);
747
+ let found = false;
748
+ for ( const key of Object.keys(owner) ) {
749
+ found = objectFindOwnerFn(owner[key], next, prune) || found;
750
+ }
751
+ return found;
752
+ }
753
+ if ( owner.hasOwnProperty(prop) === false ) { return false; }
754
+ owner = owner[prop];
755
+ chain = chain.slice(pos + 1);
756
+ }
757
+ return true;
758
+ }
759
+
760
+ /******************************************************************************/
761
+
762
+ builtinScriptlets.push({
763
+ name: 'set-cookie.fn',
764
+ fn: setCookieFn,
765
+ });
766
+ function setCookieFn(
767
+ trusted = false,
768
+ name = '',
769
+ value = '',
770
+ expires = '',
771
+ path = '',
772
+ options = {},
773
+ ) {
774
+ const getCookieValue = name => {
775
+ for ( const s of document.cookie.split(/\s*;\s*/) ) {
776
+ const pos = s.indexOf('=');
777
+ if ( pos === -1 ) { continue; }
778
+ if ( s.slice(0, pos) !== name ) { continue; }
779
+ return s.slice(pos+1);
780
+ }
781
+ };
782
+
783
+ const cookieBefore = getCookieValue(name);
784
+ if ( cookieBefore !== undefined && options.dontOverwrite ) { return; }
785
+ if ( cookieBefore === value && options.reload ) { return; }
786
+
787
+ const cookieParts = [ name, '=', value ];
788
+ if ( expires !== '' ) {
789
+ cookieParts.push('; expires=', expires);
790
+ }
791
+
792
+ if ( path === '' ) { path = '/'; }
793
+ else if ( path === 'none' ) { path = ''; }
794
+ if ( path !== '' && path !== '/' ) { return; }
795
+ if ( path === '/' ) {
796
+ cookieParts.push('; path=/');
797
+ }
798
+
799
+ if ( trusted ) {
800
+ if ( options.domain ) {
801
+ cookieParts.push(`; domain=${options.domain}`);
802
+ }
803
+ cookieParts.push('; Secure');
804
+ }
805
+
806
+ try {
807
+ document.cookie = cookieParts.join('');
808
+ } catch(_) {
809
+ }
810
+
811
+ if ( options.reload && getCookieValue(name) === value ) {
812
+ window.location.reload();
813
+ }
814
+ }
815
+
816
+ /******************************************************************************/
817
+
818
+ builtinScriptlets.push({
819
+ name: 'set-local-storage-item.fn',
820
+ fn: setLocalStorageItemFn,
821
+ dependencies: [
822
+ 'safe-self.fn',
823
+ ],
824
+ });
825
+ function setLocalStorageItemFn(
826
+ which = 'local',
827
+ trusted = false,
828
+ key = '',
829
+ value = '',
830
+ ) {
831
+ if ( key === '' ) { return; }
832
+
833
+ // For increased compatibility with AdGuard
834
+ if ( value === 'emptyArr' ) {
835
+ value = '[]';
836
+ } else if ( value === 'emptyObj' ) {
837
+ value = '{}';
838
+ }
839
+
840
+ const trustedValues = [
841
+ '',
842
+ 'undefined', 'null',
843
+ 'false', 'true',
844
+ 'on', 'off',
845
+ 'yes', 'no',
846
+ '{}', '[]', '""',
847
+ '$remove$',
848
+ ];
849
+
850
+ if ( trusted ) {
851
+ if ( value === '$now$' ) {
852
+ value = Date.now();
853
+ } else if ( value === '$currentDate$' ) {
854
+ value = `${Date()}`;
855
+ } else if ( value === '$currentISODate$' ) {
856
+ value = (new Date()).toISOString();
857
+ }
858
+ } else {
859
+ const normalized = value.toLowerCase();
860
+ const match = /^("?)(.+)\1$/.exec(normalized);
861
+ const unquoted = match && match[2] || normalized;
862
+ if ( trustedValues.includes(unquoted) === false ) {
863
+ if ( /^\d+$/.test(unquoted) === false ) { return; }
864
+ const n = parseInt(unquoted, 10);
865
+ if ( n > 32767 ) { return; }
866
+ }
867
+ }
868
+
869
+ try {
870
+ const storage = self[`${which}Storage`];
871
+ if ( value === '$remove$' ) {
872
+ const safe = safeSelf();
873
+ const pattern = safe.patternToRegex(key, undefined, true );
874
+ const toRemove = [];
875
+ for ( let i = 0, n = storage.length; i < n; i++ ) {
876
+ const key = storage.key(i);
877
+ if ( pattern.test(key) ) { toRemove.push(key); }
878
+ }
879
+ for ( const key of toRemove ) {
880
+ storage.removeItem(key);
881
+ }
882
+ } else {
883
+ storage.setItem(key, `${value}`);
884
+ }
885
+ } catch(ex) {
886
+ }
887
+ }
888
+
889
+ /******************************************************************************/
890
+
891
+ builtinScriptlets.push({
892
+ name: 'matches-stack-trace.fn',
893
+ fn: matchesStackTrace,
894
+ dependencies: [
895
+ 'get-exception-token.fn',
896
+ 'safe-self.fn',
897
+ ],
898
+ });
899
+ function matchesStackTrace(
900
+ needleDetails,
901
+ logLevel = 0
902
+ ) {
903
+ const safe = safeSelf();
904
+ const exceptionToken = getExceptionToken();
905
+ const error = new safe.Error(exceptionToken);
906
+ const docURL = new URL(self.location.href);
907
+ docURL.hash = '';
908
+ // Normalize stack trace
909
+ const reLine = /(.*?@)?(\S+)(:\d+):\d+\)?$/;
910
+ const lines = [];
911
+ for ( let line of error.stack.split(/[\n\r]+/) ) {
912
+ if ( line.includes(exceptionToken) ) { continue; }
913
+ line = line.trim();
914
+ const match = safe.RegExp_exec.call(reLine, line);
915
+ if ( match === null ) { continue; }
916
+ let url = match[2];
917
+ if ( url.startsWith('(') ) { url = url.slice(1); }
918
+ if ( url === docURL.href ) {
919
+ url = 'inlineScript';
920
+ } else if ( url.startsWith('<anonymous>') ) {
921
+ url = 'injectedScript';
922
+ }
923
+ let fn = match[1] !== undefined
924
+ ? match[1].slice(0, -1)
925
+ : line.slice(0, match.index).trim();
926
+ if ( fn.startsWith('at') ) { fn = fn.slice(2).trim(); }
927
+ let rowcol = match[3];
928
+ lines.push(' ' + `${fn} ${url}${rowcol}:1`.trim());
929
+ }
930
+ lines[0] = `stackDepth:${lines.length-1}`;
931
+ const stack = lines.join('\t');
932
+ const r = safe.testPattern(needleDetails, stack);
933
+ if (
934
+ logLevel === 1 ||
935
+ logLevel === 2 && r ||
936
+ logLevel === 3 && !r
937
+ ) {
938
+ safe.uboLog(stack.replace(/\t/g, '\n'));
939
+ }
940
+ return r;
941
+ }
942
+
943
+ /******************************************************************************/
944
+
945
+ builtinScriptlets.push({
946
+ name: 'parse-properties-to-match.fn',
947
+ fn: parsePropertiesToMatch,
948
+ dependencies: [
949
+ 'safe-self.fn',
950
+ ],
951
+ });
952
+ function parsePropertiesToMatch(propsToMatch, implicit = '') {
953
+ const safe = safeSelf();
954
+ const needles = new Map();
955
+ if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; }
956
+ const options = { canNegate: true };
957
+ for ( const needle of propsToMatch.split(/\s+/) ) {
958
+ const [ prop, pattern ] = needle.split(':');
959
+ if ( prop === '' ) { continue; }
960
+ if ( pattern !== undefined ) {
961
+ needles.set(prop, safe.initPattern(pattern, options));
962
+ } else if ( implicit !== '' ) {
963
+ needles.set(implicit, safe.initPattern(prop, options));
964
+ }
965
+ }
966
+ return needles;
967
+ }
968
+
969
+ /******************************************************************************/
970
+
971
+ builtinScriptlets.push({
972
+ name: 'match-object-properties.fn',
973
+ fn: matchObjectProperties,
974
+ dependencies: [
975
+ 'safe-self.fn',
976
+ ],
977
+ });
978
+ function matchObjectProperties(propNeedles, ...objs) {
979
+ if ( matchObjectProperties.extractProperties === undefined ) {
980
+ matchObjectProperties.extractProperties = (src, des, props) => {
981
+ for ( const p of props ) {
982
+ const v = src[p];
983
+ if ( v === undefined ) { continue; }
984
+ des[p] = src[p];
985
+ }
986
+ };
987
+ }
988
+ const safe = safeSelf();
989
+ const haystack = {};
990
+ const props = safe.Array_from(propNeedles.keys());
991
+ for ( const obj of objs ) {
992
+ if ( obj instanceof Object === false ) { continue; }
993
+ matchObjectProperties.extractProperties(obj, haystack, props);
994
+ }
995
+ for ( const [ prop, details ] of propNeedles ) {
996
+ let value = haystack[prop];
997
+ if ( value === undefined ) { continue; }
998
+ if ( typeof value !== 'string' ) {
999
+ try { value = JSON.stringify(value); }
1000
+ catch(ex) { }
1001
+ if ( typeof value !== 'string' ) { continue; }
1002
+ }
1003
+ if ( safe.testPattern(details, value) ) { continue; }
1004
+ return false;
1005
+ }
1006
+ return true;
1007
+ }
1008
+
1009
+ /******************************************************************************/
1010
+
1011
+ builtinScriptlets.push({
1012
+ name: 'json-prune-fetch-response.fn',
1013
+ fn: jsonPruneFetchResponseFn,
1014
+ dependencies: [
1015
+ 'match-object-properties.fn',
1016
+ 'object-prune.fn',
1017
+ 'parse-properties-to-match.fn',
1018
+ 'safe-self.fn',
1019
+ 'should-log.fn',
1020
+ ],
1021
+ });
1022
+ function jsonPruneFetchResponseFn(
1023
+ rawPrunePaths = '',
1024
+ rawNeedlePaths = ''
1025
+ ) {
1026
+ const safe = safeSelf();
1027
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 2);
1028
+ const logLevel = shouldLog({ log: rawPrunePaths === '' || extraArgs.log, });
1029
+ const log = logLevel ? ((...args) => { safe.uboLog(...args); }) : (( ) => { });
1030
+ const propNeedles = parsePropertiesToMatch(extraArgs.propsToMatch, 'url');
1031
+ const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true });
1032
+ const applyHandler = function(target, thisArg, args) {
1033
+ const fetchPromise = Reflect.apply(target, thisArg, args);
1034
+ if ( logLevel === true ) {
1035
+ log('json-prune-fetch-response:', JSON.stringify(Array.from(args)).slice(1,-1));
1036
+ }
1037
+ if ( rawPrunePaths === '' ) { return fetchPromise; }
1038
+ let outcome = 'match';
1039
+ if ( propNeedles.size !== 0 ) {
1040
+ const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ];
1041
+ if ( objs[0] instanceof Request ) {
1042
+ try { objs[0] = safe.Request_clone.call(objs[0]); }
1043
+ catch(ex) { log(ex); }
1044
+ }
1045
+ if ( args[1] instanceof Object ) {
1046
+ objs.push(args[1]);
1047
+ }
1048
+ if ( matchObjectProperties(propNeedles, ...objs) === false ) {
1049
+ outcome = 'nomatch';
1050
+ }
1051
+ if ( outcome === logLevel || logLevel === 'all' ) {
1052
+ log(
1053
+ `json-prune-fetch-response (${outcome})`,
1054
+ `\n\tfetchPropsToMatch: ${JSON.stringify(Array.from(propNeedles)).slice(1,-1)}`,
1055
+ '\n\tprops:', ...objs,
1056
+ );
1057
+ }
1058
+ }
1059
+ if ( outcome === 'nomatch' ) { return fetchPromise; }
1060
+ return fetchPromise.then(responseBefore => {
1061
+ const response = responseBefore.clone();
1062
+ return response.json().then(objBefore => {
1063
+ if ( typeof objBefore !== 'object' ) { return responseBefore; }
1064
+ const objAfter = objectPruneFn(
1065
+ objBefore,
1066
+ rawPrunePaths,
1067
+ rawNeedlePaths,
1068
+ stackNeedle,
1069
+ extraArgs
1070
+ );
1071
+ if ( typeof objAfter !== 'object' ) { return responseBefore; }
1072
+ const responseAfter = Response.json(objAfter, {
1073
+ status: responseBefore.status,
1074
+ statusText: responseBefore.statusText,
1075
+ headers: responseBefore.headers,
1076
+ });
1077
+ Object.defineProperties(responseAfter, {
1078
+ ok: { value: responseBefore.ok },
1079
+ redirected: { value: responseBefore.redirected },
1080
+ type: { value: responseBefore.type },
1081
+ url: { value: responseBefore.url },
1082
+ });
1083
+ return responseAfter;
1084
+ }).catch(reason => {
1085
+ log('json-prune-fetch-response:', reason);
1086
+ return responseBefore;
1087
+ });
1088
+ }).catch(reason => {
1089
+ log('json-prune-fetch-response:', reason);
1090
+ return fetchPromise;
1091
+ });
1092
+ };
1093
+ self.fetch = new Proxy(self.fetch, {
1094
+ apply: applyHandler
1095
+ });
1096
+ }
1097
+
1098
+ /******************************************************************************/
1099
+
1100
+ builtinScriptlets.push({
1101
+ name: 'replace-fetch-response.fn',
1102
+ fn: replaceFetchResponseFn,
1103
+ dependencies: [
1104
+ 'match-object-properties.fn',
1105
+ 'parse-properties-to-match.fn',
1106
+ 'safe-self.fn',
1107
+ 'should-log.fn',
1108
+ ],
1109
+ });
1110
+ function replaceFetchResponseFn(
1111
+ trusted = false,
1112
+ pattern = '',
1113
+ replacement = '',
1114
+ propsToMatch = ''
1115
+ ) {
1116
+ if ( trusted !== true ) { return; }
1117
+ const safe = safeSelf();
1118
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 4);
1119
+ const logLevel = shouldLog({
1120
+ log: pattern === '' || extraArgs.log,
1121
+ });
1122
+ const log = logLevel ? ((...args) => { safe.uboLog(...args); }) : (( ) => { });
1123
+ if ( pattern === '*' ) { pattern = '.*'; }
1124
+ const rePattern = safe.patternToRegex(pattern);
1125
+ const propNeedles = parsePropertiesToMatch(propsToMatch, 'url');
1126
+ self.fetch = new Proxy(self.fetch, {
1127
+ apply: function(target, thisArg, args) {
1128
+ if ( logLevel === true ) {
1129
+ log('replace-fetch-response:', JSON.stringify(Array.from(args)).slice(1,-1));
1130
+ }
1131
+ const fetchPromise = Reflect.apply(target, thisArg, args);
1132
+ if ( pattern === '' ) { return fetchPromise; }
1133
+ let outcome = 'match';
1134
+ if ( propNeedles.size !== 0 ) {
1135
+ const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ];
1136
+ if ( objs[0] instanceof Request ) {
1137
+ try { objs[0] = safe.Request_clone.call(objs[0]); }
1138
+ catch(ex) { log(ex); }
1139
+ }
1140
+ if ( args[1] instanceof Object ) {
1141
+ objs.push(args[1]);
1142
+ }
1143
+ if ( matchObjectProperties(propNeedles, ...objs) === false ) {
1144
+ outcome = 'nomatch';
1145
+ }
1146
+ if ( outcome === logLevel || logLevel === 'all' ) {
1147
+ log(
1148
+ `replace-fetch-response (${outcome})`,
1149
+ `\n\tpropsToMatch: ${JSON.stringify(Array.from(propNeedles)).slice(1,-1)}`,
1150
+ '\n\tprops:', ...args,
1151
+ );
1152
+ }
1153
+ }
1154
+ if ( outcome === 'nomatch' ) { return fetchPromise; }
1155
+ return fetchPromise.then(responseBefore => {
1156
+ const response = responseBefore.clone();
1157
+ return response.text().then(textBefore => {
1158
+ const textAfter = textBefore.replace(rePattern, replacement);
1159
+ const outcome = textAfter !== textBefore ? 'match' : 'nomatch';
1160
+ if ( outcome === logLevel || logLevel === 'all' ) {
1161
+ log(
1162
+ `replace-fetch-response (${outcome})`,
1163
+ `\n\tpattern: ${pattern}`,
1164
+ `\n\treplacement: ${replacement}`,
1165
+ );
1166
+ }
1167
+ if ( outcome === 'nomatch' ) { return responseBefore; }
1168
+ const responseAfter = new Response(textAfter, {
1169
+ status: responseBefore.status,
1170
+ statusText: responseBefore.statusText,
1171
+ headers: responseBefore.headers,
1172
+ });
1173
+ Object.defineProperties(responseAfter, {
1174
+ ok: { value: responseBefore.ok },
1175
+ redirected: { value: responseBefore.redirected },
1176
+ type: { value: responseBefore.type },
1177
+ url: { value: responseBefore.url },
1178
+ });
1179
+ return responseAfter;
1180
+ }).catch(reason => {
1181
+ log('replace-fetch-response:', reason);
1182
+ return responseBefore;
1183
+ });
1184
+ }).catch(reason => {
1185
+ log('replace-fetch-response:', reason);
1186
+ return fetchPromise;
1187
+ });
1188
+ }
1189
+ });
1190
+ }
1191
+
1192
+
1193
+ /*******************************************************************************
1194
+
1195
+ Injectable scriptlets
1196
+
1197
+ These are meant to be used in the MAIN (webpage) execution world.
1198
+
1199
+ *******************************************************************************/
1200
+
1201
+ builtinScriptlets.push({
1202
+ name: 'abort-current-script.js',
1203
+ aliases: [
1204
+ 'acs.js',
1205
+ 'abort-current-inline-script.js',
1206
+ 'acis.js',
1207
+ ],
1208
+ fn: abortCurrentScript,
1209
+ dependencies: [
1210
+ 'abort-current-script-core.fn',
1211
+ 'run-at-html-element.fn',
1212
+ ],
1213
+ });
1214
+ // Issues to mind before changing anything:
1215
+ // https://github.com/uBlockOrigin/uBlock-issues/issues/2154
1216
+ function abortCurrentScript(...args) {
1217
+ runAtHtmlElementFn(( ) => {
1218
+ abortCurrentScriptCore(...args);
1219
+ });
1220
+ }
1221
+
1222
+ /******************************************************************************/
1223
+
1224
+ builtinScriptlets.push({
1225
+ name: 'abort-on-property-read.js',
1226
+ aliases: [
1227
+ 'aopr.js',
1228
+ ],
1229
+ fn: abortOnPropertyRead,
1230
+ dependencies: [
1231
+ 'get-exception-token.fn',
1232
+ ],
1233
+ });
1234
+ function abortOnPropertyRead(
1235
+ chain = ''
1236
+ ) {
1237
+ if ( typeof chain !== 'string' ) { return; }
1238
+ if ( chain === '' ) { return; }
1239
+ const exceptionToken = getExceptionToken();
1240
+ const abort = function() {
1241
+ throw new ReferenceError(exceptionToken);
1242
+ };
1243
+ const makeProxy = function(owner, chain) {
1244
+ const pos = chain.indexOf('.');
1245
+ if ( pos === -1 ) {
1246
+ const desc = Object.getOwnPropertyDescriptor(owner, chain);
1247
+ if ( !desc || desc.get !== abort ) {
1248
+ Object.defineProperty(owner, chain, {
1249
+ get: abort,
1250
+ set: function(){}
1251
+ });
1252
+ }
1253
+ return;
1254
+ }
1255
+ const prop = chain.slice(0, pos);
1256
+ let v = owner[prop];
1257
+ chain = chain.slice(pos + 1);
1258
+ if ( v ) {
1259
+ makeProxy(v, chain);
1260
+ return;
1261
+ }
1262
+ const desc = Object.getOwnPropertyDescriptor(owner, prop);
1263
+ if ( desc && desc.set !== undefined ) { return; }
1264
+ Object.defineProperty(owner, prop, {
1265
+ get: function() { return v; },
1266
+ set: function(a) {
1267
+ v = a;
1268
+ if ( a instanceof Object ) {
1269
+ makeProxy(a, chain);
1270
+ }
1271
+ }
1272
+ });
1273
+ };
1274
+ const owner = window;
1275
+ makeProxy(owner, chain);
1276
+ }
1277
+
1278
+ /******************************************************************************/
1279
+
1280
+ builtinScriptlets.push({
1281
+ name: 'abort-on-property-write.js',
1282
+ aliases: [
1283
+ 'aopw.js',
1284
+ ],
1285
+ fn: abortOnPropertyWrite,
1286
+ dependencies: [
1287
+ 'get-exception-token.fn',
1288
+ ],
1289
+ });
1290
+ function abortOnPropertyWrite(
1291
+ prop = ''
1292
+ ) {
1293
+ if ( typeof prop !== 'string' ) { return; }
1294
+ if ( prop === '' ) { return; }
1295
+ const exceptionToken = getExceptionToken();
1296
+ let owner = window;
1297
+ for (;;) {
1298
+ const pos = prop.indexOf('.');
1299
+ if ( pos === -1 ) { break; }
1300
+ owner = owner[prop.slice(0, pos)];
1301
+ if ( owner instanceof Object === false ) { return; }
1302
+ prop = prop.slice(pos + 1);
1303
+ }
1304
+ delete owner[prop];
1305
+ Object.defineProperty(owner, prop, {
1306
+ set: function() {
1307
+ throw new ReferenceError(exceptionToken);
1308
+ }
1309
+ });
1310
+ }
1311
+
1312
+ /******************************************************************************/
1313
+
1314
+ builtinScriptlets.push({
1315
+ name: 'abort-on-stack-trace.js',
1316
+ aliases: [
1317
+ 'aost.js',
1318
+ ],
1319
+ fn: abortOnStackTrace,
1320
+ dependencies: [
1321
+ 'get-exception-token.fn',
1322
+ 'matches-stack-trace.fn',
1323
+ 'safe-self.fn',
1324
+ ],
1325
+ });
1326
+ function abortOnStackTrace(
1327
+ chain = '',
1328
+ needle = ''
1329
+ ) {
1330
+ if ( typeof chain !== 'string' ) { return; }
1331
+ const safe = safeSelf();
1332
+ const needleDetails = safe.initPattern(needle, { canNegate: true });
1333
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 2);
1334
+ const makeProxy = function(owner, chain) {
1335
+ const pos = chain.indexOf('.');
1336
+ if ( pos === -1 ) {
1337
+ let v = owner[chain];
1338
+ Object.defineProperty(owner, chain, {
1339
+ get: function() {
1340
+ if ( matchesStackTrace(needleDetails, extraArgs.log) ) {
1341
+ throw new ReferenceError(getExceptionToken());
1342
+ }
1343
+ return v;
1344
+ },
1345
+ set: function(a) {
1346
+ if ( matchesStackTrace(needleDetails, extraArgs.log) ) {
1347
+ throw new ReferenceError(getExceptionToken());
1348
+ }
1349
+ v = a;
1350
+ },
1351
+ });
1352
+ return;
1353
+ }
1354
+ const prop = chain.slice(0, pos);
1355
+ let v = owner[prop];
1356
+ chain = chain.slice(pos + 1);
1357
+ if ( v ) {
1358
+ makeProxy(v, chain);
1359
+ return;
1360
+ }
1361
+ const desc = Object.getOwnPropertyDescriptor(owner, prop);
1362
+ if ( desc && desc.set !== undefined ) { return; }
1363
+ Object.defineProperty(owner, prop, {
1364
+ get: function() { return v; },
1365
+ set: function(a) {
1366
+ v = a;
1367
+ if ( a instanceof Object ) {
1368
+ makeProxy(a, chain);
1369
+ }
1370
+ }
1371
+ });
1372
+ };
1373
+ const owner = window;
1374
+ makeProxy(owner, chain);
1375
+ }
1376
+
1377
+ /******************************************************************************/
1378
+
1379
+ builtinScriptlets.push({
1380
+ name: 'addEventListener-defuser.js',
1381
+ aliases: [
1382
+ 'aeld.js',
1383
+ 'prevent-addEventListener.js',
1384
+ ],
1385
+ fn: addEventListenerDefuser,
1386
+ dependencies: [
1387
+ 'run-at.fn',
1388
+ 'safe-self.fn',
1389
+ 'should-debug.fn',
1390
+ 'should-log.fn',
1391
+ ],
1392
+ });
1393
+ // https://github.com/uBlockOrigin/uAssets/issues/9123#issuecomment-848255120
1394
+ function addEventListenerDefuser(
1395
+ type = '',
1396
+ pattern = ''
1397
+ ) {
1398
+ const safe = safeSelf();
1399
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 2);
1400
+ const reType = safe.patternToRegex(type, undefined, true);
1401
+ const rePattern = safe.patternToRegex(pattern);
1402
+ const log = shouldLog(extraArgs);
1403
+ const debug = shouldDebug(extraArgs);
1404
+ const trapEddEventListeners = ( ) => {
1405
+ const eventListenerHandler = {
1406
+ apply: function(target, thisArg, args) {
1407
+ let type, handler;
1408
+ try {
1409
+ type = String(args[0]);
1410
+ handler = args[1] instanceof Function
1411
+ ? String(safe.Function_toString(args[1]))
1412
+ : String(args[1]);
1413
+ } catch(ex) {
1414
+ }
1415
+ const matchesType = safe.RegExp_test.call(reType, type);
1416
+ const matchesHandler = safe.RegExp_test.call(rePattern, handler);
1417
+ const matchesEither = matchesType || matchesHandler;
1418
+ const matchesBoth = matchesType && matchesHandler;
1419
+ if ( log === 1 && matchesBoth || log === 2 && matchesEither || log === 3 ) {
1420
+ safe.uboLog(`addEventListener('${type}', ${handler})`);
1421
+ }
1422
+ if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) {
1423
+ debugger; // jshint ignore:line
1424
+ }
1425
+ if ( matchesBoth ) { return; }
1426
+ return Reflect.apply(target, thisArg, args);
1427
+ },
1428
+ get(target, prop, receiver) {
1429
+ if ( prop === 'toString' ) {
1430
+ return target.toString.bind(target);
1431
+ }
1432
+ return Reflect.get(target, prop, receiver);
1433
+ },
1434
+ };
1435
+ self.EventTarget.prototype.addEventListener = new Proxy(
1436
+ self.EventTarget.prototype.addEventListener,
1437
+ eventListenerHandler
1438
+ );
1439
+ };
1440
+ runAt(( ) => {
1441
+ trapEddEventListeners();
1442
+ }, extraArgs.runAt);
1443
+ }
1444
+
1445
+ /******************************************************************************/
1446
+
1447
+ builtinScriptlets.push({
1448
+ name: 'json-prune.js',
1449
+ fn: jsonPrune,
1450
+ dependencies: [
1451
+ 'object-prune.fn',
1452
+ 'safe-self.fn',
1453
+ ],
1454
+ });
1455
+ function jsonPrune(
1456
+ rawPrunePaths = '',
1457
+ rawNeedlePaths = '',
1458
+ stackNeedle = ''
1459
+ ) {
1460
+ const safe = safeSelf();
1461
+ const stackNeedleDetails = safe.initPattern(stackNeedle, { canNegate: true });
1462
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
1463
+ JSON.parse = new Proxy(JSON.parse, {
1464
+ apply: function(target, thisArg, args) {
1465
+ const objBefore = Reflect.apply(target, thisArg, args);
1466
+ const objAfter = objectPruneFn(
1467
+ objBefore,
1468
+ rawPrunePaths,
1469
+ rawNeedlePaths,
1470
+ stackNeedleDetails,
1471
+ extraArgs
1472
+ );
1473
+ return objAfter || objBefore;
1474
+ },
1475
+ });
1476
+ }
1477
+
1478
+ /*******************************************************************************
1479
+ *
1480
+ * json-prune-fetch-response.js
1481
+ *
1482
+ * Prune JSON response of fetch requests.
1483
+ *
1484
+ **/
1485
+
1486
+ builtinScriptlets.push({
1487
+ name: 'json-prune-fetch-response.js',
1488
+ fn: jsonPruneFetchResponse,
1489
+ dependencies: [
1490
+ 'json-prune-fetch-response.fn',
1491
+ ],
1492
+ });
1493
+ function jsonPruneFetchResponse(...args) {
1494
+ jsonPruneFetchResponseFn(...args);
1495
+ }
1496
+
1497
+ /******************************************************************************/
1498
+
1499
+ builtinScriptlets.push({
1500
+ name: 'json-prune-xhr-response.js',
1501
+ fn: jsonPruneXhrResponse,
1502
+ dependencies: [
1503
+ 'match-object-properties.fn',
1504
+ 'object-prune.fn',
1505
+ 'parse-properties-to-match.fn',
1506
+ 'safe-self.fn',
1507
+ 'should-log.fn',
1508
+ ],
1509
+ });
1510
+ function jsonPruneXhrResponse(
1511
+ rawPrunePaths = '',
1512
+ rawNeedlePaths = ''
1513
+ ) {
1514
+ const safe = safeSelf();
1515
+ const xhrInstances = new WeakMap();
1516
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 2);
1517
+ const logLevel = shouldLog({ log: rawPrunePaths === '' || extraArgs.log, });
1518
+ const log = logLevel ? ((...args) => { safe.uboLog(...args); }) : (( ) => { });
1519
+ const propNeedles = parsePropertiesToMatch(extraArgs.propsToMatch, 'url');
1520
+ const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true });
1521
+ self.XMLHttpRequest = class extends self.XMLHttpRequest {
1522
+ open(method, url, ...args) {
1523
+ const xhrDetails = { method, url };
1524
+ let outcome = 'match';
1525
+ if ( propNeedles.size !== 0 ) {
1526
+ if ( matchObjectProperties(propNeedles, xhrDetails) === false ) {
1527
+ outcome = 'nomatch';
1528
+ }
1529
+ }
1530
+ if ( outcome === logLevel || outcome === 'all' ) {
1531
+ log(`xhr.open(${method}, ${url}, ${args.join(', ')})`);
1532
+ }
1533
+ if ( outcome === 'match' ) {
1534
+ xhrInstances.set(this, xhrDetails);
1535
+ }
1536
+ return super.open(method, url, ...args);
1537
+ }
1538
+ get response() {
1539
+ const innerResponse = super.response;
1540
+ const xhrDetails = xhrInstances.get(this);
1541
+ if ( xhrDetails === undefined ) {
1542
+ return innerResponse;
1543
+ }
1544
+ const responseLength = typeof innerResponse === 'string'
1545
+ ? innerResponse.length
1546
+ : undefined;
1547
+ if ( xhrDetails.lastResponseLength !== responseLength ) {
1548
+ xhrDetails.response = undefined;
1549
+ xhrDetails.lastResponseLength = responseLength;
1550
+ }
1551
+ if ( xhrDetails.response !== undefined ) {
1552
+ return xhrDetails.response;
1553
+ }
1554
+ let objBefore;
1555
+ if ( typeof innerResponse === 'object' ) {
1556
+ objBefore = innerResponse;
1557
+ } else if ( typeof innerResponse === 'string' ) {
1558
+ try { objBefore = safe.JSON_parse(innerResponse); }
1559
+ catch(ex) { }
1560
+ }
1561
+ if ( typeof objBefore !== 'object' ) {
1562
+ return (xhrDetails.response = innerResponse);
1563
+ }
1564
+ const objAfter = objectPruneFn(
1565
+ objBefore,
1566
+ rawPrunePaths,
1567
+ rawNeedlePaths,
1568
+ stackNeedle,
1569
+ extraArgs
1570
+ );
1571
+ let outerResponse;
1572
+ if ( typeof objAfter === 'object' ) {
1573
+ outerResponse = typeof innerResponse === 'string'
1574
+ ? safe.JSON_stringify(objAfter)
1575
+ : objAfter;
1576
+ } else {
1577
+ outerResponse = innerResponse;
1578
+ }
1579
+ return (xhrDetails.response = outerResponse);
1580
+ }
1581
+ get responseText() {
1582
+ const response = this.response;
1583
+ return typeof response !== 'string'
1584
+ ? super.responseText
1585
+ : response;
1586
+ }
1587
+ };
1588
+ }
1589
+
1590
+ /******************************************************************************/
1591
+
1592
+ // There is still code out there which uses `eval` in lieu of `JSON.parse`.
1593
+
1594
+ builtinScriptlets.push({
1595
+ name: 'evaldata-prune.js',
1596
+ fn: evaldataPrune,
1597
+ dependencies: [
1598
+ 'object-prune.fn',
1599
+ ],
1600
+ });
1601
+ function evaldataPrune(
1602
+ rawPrunePaths = '',
1603
+ rawNeedlePaths = ''
1604
+ ) {
1605
+ self.eval = new Proxy(self.eval, {
1606
+ apply(target, thisArg, args) {
1607
+ const before = Reflect.apply(target, thisArg, args);
1608
+ if ( typeof before === 'object' ) {
1609
+ const after = objectPruneFn(before, rawPrunePaths, rawNeedlePaths);
1610
+ return after || before;
1611
+ }
1612
+ return before;
1613
+ }
1614
+ });
1615
+ }
1616
+
1617
+ /******************************************************************************/
1618
+
1619
+ builtinScriptlets.push({
1620
+ name: 'adjust-setInterval.js',
1621
+ aliases: [
1622
+ 'nano-setInterval-booster.js',
1623
+ 'nano-sib.js',
1624
+ ],
1625
+ fn: adjustSetInterval,
1626
+ dependencies: [
1627
+ 'safe-self.fn',
1628
+ ],
1629
+ });
1630
+ // Imported from:
1631
+ // https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L126
1632
+ //
1633
+ // Speed up or down setInterval, 3 optional arguments.
1634
+ // The payload matcher, a string literal or a JavaScript RegExp, defaults
1635
+ // to match all.
1636
+ // delayMatcher
1637
+ // The delay matcher, an integer, defaults to 1000.
1638
+ // Use `*` to match any delay.
1639
+ // boostRatio - The delay multiplier when there is a match, 0.5 speeds up by
1640
+ // 2 times and 2 slows down by 2 times, defaults to 0.05 or speed up
1641
+ // 20 times. Speed up and down both cap at 50 times.
1642
+ function adjustSetInterval(
1643
+ needleArg = '',
1644
+ delayArg = '',
1645
+ boostArg = ''
1646
+ ) {
1647
+ if ( typeof needleArg !== 'string' ) { return; }
1648
+ const safe = safeSelf();
1649
+ const reNeedle = safe.patternToRegex(needleArg);
1650
+ let delay = delayArg !== '*' ? parseInt(delayArg, 10) : -1;
1651
+ if ( isNaN(delay) || isFinite(delay) === false ) { delay = 1000; }
1652
+ let boost = parseFloat(boostArg);
1653
+ boost = isNaN(boost) === false && isFinite(boost)
1654
+ ? Math.min(Math.max(boost, 0.001), 50)
1655
+ : 0.05;
1656
+ self.setInterval = new Proxy(self.setInterval, {
1657
+ apply: function(target, thisArg, args) {
1658
+ const [ a, b ] = args;
1659
+ if (
1660
+ (delay === -1 || b === delay) &&
1661
+ reNeedle.test(a.toString())
1662
+ ) {
1663
+ args[1] = b * boost;
1664
+ }
1665
+ return target.apply(thisArg, args);
1666
+ }
1667
+ });
1668
+ }
1669
+
1670
+ /******************************************************************************/
1671
+
1672
+ builtinScriptlets.push({
1673
+ name: 'adjust-setTimeout.js',
1674
+ aliases: [
1675
+ 'nano-setTimeout-booster.js',
1676
+ 'nano-stb.js',
1677
+ ],
1678
+ fn: adjustSetTimeout,
1679
+ dependencies: [
1680
+ 'safe-self.fn',
1681
+ ],
1682
+ });
1683
+ // Imported from:
1684
+ // https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L82
1685
+ //
1686
+ // Speed up or down setTimeout, 3 optional arguments.
1687
+ // funcMatcher
1688
+ // The payload matcher, a string literal or a JavaScript RegExp, defaults
1689
+ // to match all.
1690
+ // delayMatcher
1691
+ // The delay matcher, an integer, defaults to 1000.
1692
+ // Use `*` to match any delay.
1693
+ // boostRatio - The delay multiplier when there is a match, 0.5 speeds up by
1694
+ // 2 times and 2 slows down by 2 times, defaults to 0.05 or speed up
1695
+ // 20 times. Speed up and down both cap at 50 times.
1696
+ function adjustSetTimeout(
1697
+ needleArg = '',
1698
+ delayArg = '',
1699
+ boostArg = ''
1700
+ ) {
1701
+ if ( typeof needleArg !== 'string' ) { return; }
1702
+ const safe = safeSelf();
1703
+ const reNeedle = safe.patternToRegex(needleArg);
1704
+ let delay = delayArg !== '*' ? parseInt(delayArg, 10) : -1;
1705
+ if ( isNaN(delay) || isFinite(delay) === false ) { delay = 1000; }
1706
+ let boost = parseFloat(boostArg);
1707
+ boost = isNaN(boost) === false && isFinite(boost)
1708
+ ? Math.min(Math.max(boost, 0.001), 50)
1709
+ : 0.05;
1710
+ self.setTimeout = new Proxy(self.setTimeout, {
1711
+ apply: function(target, thisArg, args) {
1712
+ const [ a, b ] = args;
1713
+ if (
1714
+ (delay === -1 || b === delay) &&
1715
+ reNeedle.test(a.toString())
1716
+ ) {
1717
+ args[1] = b * boost;
1718
+ }
1719
+ return target.apply(thisArg, args);
1720
+ }
1721
+ });
1722
+ }
1723
+
1724
+ /******************************************************************************/
1725
+
1726
+ builtinScriptlets.push({
1727
+ name: 'noeval-if.js',
1728
+ aliases: [
1729
+ 'prevent-eval-if.js',
1730
+ ],
1731
+ fn: noEvalIf,
1732
+ dependencies: [
1733
+ 'safe-self.fn',
1734
+ ],
1735
+ });
1736
+ function noEvalIf(
1737
+ needle = ''
1738
+ ) {
1739
+ if ( typeof needle !== 'string' ) { return; }
1740
+ const safe = safeSelf();
1741
+ const reNeedle = safe.patternToRegex(needle);
1742
+ window.eval = new Proxy(window.eval, { // jshint ignore: line
1743
+ apply: function(target, thisArg, args) {
1744
+ const a = args[0];
1745
+ if ( reNeedle.test(a.toString()) ) { return; }
1746
+ return target.apply(thisArg, args);
1747
+ }
1748
+ });
1749
+ }
1750
+
1751
+ /******************************************************************************/
1752
+
1753
+ builtinScriptlets.push({
1754
+ name: 'no-fetch-if.js',
1755
+ aliases: [
1756
+ 'prevent-fetch.js',
1757
+ ],
1758
+ fn: noFetchIf,
1759
+ dependencies: [
1760
+ 'safe-self.fn',
1761
+ ],
1762
+ });
1763
+ function noFetchIf(
1764
+ arg1 = '',
1765
+ ) {
1766
+ if ( typeof arg1 !== 'string' ) { return; }
1767
+ const safe = safeSelf();
1768
+ const needles = [];
1769
+ for ( const condition of arg1.split(/\s+/) ) {
1770
+ if ( condition === '' ) { continue; }
1771
+ const pos = condition.indexOf(':');
1772
+ let key, value;
1773
+ if ( pos !== -1 ) {
1774
+ key = condition.slice(0, pos);
1775
+ value = condition.slice(pos + 1);
1776
+ } else {
1777
+ key = 'url';
1778
+ value = condition;
1779
+ }
1780
+ needles.push({ key, re: safe.patternToRegex(value) });
1781
+ }
1782
+ const log = needles.length === 0 ? console.log.bind(console) : undefined;
1783
+ self.fetch = new Proxy(self.fetch, {
1784
+ apply: function(target, thisArg, args) {
1785
+ let proceed = true;
1786
+ 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
+ const props = new Map();
1794
+ for ( const prop in details ) {
1795
+ let v = details[prop];
1796
+ if ( typeof v !== 'string' ) {
1797
+ try { v = JSON.stringify(v); }
1798
+ catch(ex) { }
1799
+ }
1800
+ if ( typeof v !== 'string' ) { continue; }
1801
+ props.set(prop, v);
1802
+ }
1803
+ if ( log !== undefined ) {
1804
+ const out = Array.from(props)
1805
+ .map(a => `${a[0]}:${a[1]}`)
1806
+ .join(' ');
1807
+ log(`uBO: fetch(${out})`);
1808
+ }
1809
+ proceed = needles.length === 0;
1810
+ for ( const { key, re } of needles ) {
1811
+ if (
1812
+ props.has(key) === false ||
1813
+ re.test(props.get(key)) === false
1814
+ ) {
1815
+ proceed = true;
1816
+ break;
1817
+ }
1818
+ }
1819
+ } catch(ex) {
1820
+ }
1821
+ return proceed
1822
+ ? Reflect.apply(target, thisArg, args)
1823
+ : Promise.resolve(new Response());
1824
+ }
1825
+ });
1826
+ }
1827
+
1828
+ /******************************************************************************/
1829
+
1830
+ builtinScriptlets.push({
1831
+ name: 'prevent-refresh.js',
1832
+ aliases: [
1833
+ 'refresh-defuser.js',
1834
+ ],
1835
+ fn: preventRefresh,
1836
+ world: 'ISOLATED',
1837
+ dependencies: [
1838
+ 'run-at.fn',
1839
+ ],
1840
+ });
1841
+ // https://www.reddit.com/r/uBlockOrigin/comments/q0frv0/while_reading_a_sports_article_i_was_redirected/hf7wo9v/
1842
+ function preventRefresh(
1843
+ arg1 = ''
1844
+ ) {
1845
+ if ( typeof arg1 !== 'string' ) { return; }
1846
+ const defuse = ( ) => {
1847
+ const meta = document.querySelector('meta[http-equiv="refresh" i][content]');
1848
+ if ( meta === null ) { return; }
1849
+ const s = arg1 === ''
1850
+ ? meta.getAttribute('content')
1851
+ : arg1;
1852
+ const ms = Math.max(parseFloat(s) || 0, 0) * 1000;
1853
+ setTimeout(( ) => { window.stop(); }, ms);
1854
+ };
1855
+ runAt(( ) => {
1856
+ defuse();
1857
+ }, 'interactive');
1858
+ }
1859
+
1860
+ /******************************************************************************/
1861
+
1862
+ builtinScriptlets.push({
1863
+ name: 'remove-attr.js',
1864
+ aliases: [
1865
+ 'ra.js',
1866
+ ],
1867
+ fn: removeAttr,
1868
+ dependencies: [
1869
+ 'run-at.fn',
1870
+ ],
1871
+ });
1872
+ function removeAttr(
1873
+ token = '',
1874
+ selector = '',
1875
+ behavior = ''
1876
+ ) {
1877
+ if ( typeof token !== 'string' ) { return; }
1878
+ if ( token === '' ) { return; }
1879
+ const tokens = token.split(/\s*\|\s*/);
1880
+ if ( selector === '' ) {
1881
+ selector = `[${tokens.join('],[')}]`;
1882
+ }
1883
+ let timer;
1884
+ const rmattr = ( ) => {
1885
+ timer = undefined;
1886
+ try {
1887
+ const nodes = document.querySelectorAll(selector);
1888
+ for ( const node of nodes ) {
1889
+ for ( const attr of tokens ) {
1890
+ node.removeAttribute(attr);
1891
+ }
1892
+ }
1893
+ } catch(ex) {
1894
+ }
1895
+ };
1896
+ const mutationHandler = mutations => {
1897
+ if ( timer !== undefined ) { return; }
1898
+ let skip = true;
1899
+ for ( let i = 0; i < mutations.length && skip; i++ ) {
1900
+ const { type, addedNodes, removedNodes } = mutations[i];
1901
+ if ( type === 'attributes' ) { skip = false; }
1902
+ for ( let j = 0; j < addedNodes.length && skip; j++ ) {
1903
+ if ( addedNodes[j].nodeType === 1 ) { skip = false; break; }
1904
+ }
1905
+ for ( let j = 0; j < removedNodes.length && skip; j++ ) {
1906
+ if ( removedNodes[j].nodeType === 1 ) { skip = false; break; }
1907
+ }
1908
+ }
1909
+ if ( skip ) { return; }
1910
+ timer = self.requestIdleCallback(rmattr, { timeout: 17 });
1911
+ };
1912
+ const start = ( ) => {
1913
+ rmattr();
1914
+ if ( /\bstay\b/.test(behavior) === false ) { return; }
1915
+ const observer = new MutationObserver(mutationHandler);
1916
+ observer.observe(document, {
1917
+ attributes: true,
1918
+ attributeFilter: tokens,
1919
+ childList: true,
1920
+ subtree: true,
1921
+ });
1922
+ };
1923
+ runAt(( ) => {
1924
+ start();
1925
+ }, /\bcomplete\b/.test(behavior) ? 'idle' : 'interactive');
1926
+ }
1927
+
1928
+ /******************************************************************************/
1929
+
1930
+ builtinScriptlets.push({
1931
+ name: 'remove-class.js',
1932
+ aliases: [
1933
+ 'rc.js',
1934
+ ],
1935
+ fn: removeClass,
1936
+ world: 'ISOLATED',
1937
+ dependencies: [
1938
+ 'run-at.fn',
1939
+ ],
1940
+ });
1941
+ function removeClass(
1942
+ token = '',
1943
+ selector = '',
1944
+ behavior = ''
1945
+ ) {
1946
+ if ( typeof token !== 'string' ) { return; }
1947
+ if ( token === '' ) { return; }
1948
+ const classTokens = token.split(/\s*\|\s*/);
1949
+ if ( selector === '' ) {
1950
+ selector = '.' + classTokens.map(a => CSS.escape(a)).join(',.');
1951
+ }
1952
+ const mustStay = /\bstay\b/.test(behavior);
1953
+ let timer;
1954
+ const rmclass = function() {
1955
+ timer = undefined;
1956
+ try {
1957
+ const nodes = document.querySelectorAll(selector);
1958
+ for ( const node of nodes ) {
1959
+ node.classList.remove(...classTokens);
1960
+ }
1961
+ } catch(ex) {
1962
+ }
1963
+ if ( mustStay ) { return; }
1964
+ if ( document.readyState !== 'complete' ) { return; }
1965
+ observer.disconnect();
1966
+ };
1967
+ const mutationHandler = mutations => {
1968
+ if ( timer !== undefined ) { return; }
1969
+ let skip = true;
1970
+ for ( let i = 0; i < mutations.length && skip; i++ ) {
1971
+ const { type, addedNodes, removedNodes } = mutations[i];
1972
+ if ( type === 'attributes' ) { skip = false; }
1973
+ for ( let j = 0; j < addedNodes.length && skip; j++ ) {
1974
+ if ( addedNodes[j].nodeType === 1 ) { skip = false; break; }
1975
+ }
1976
+ for ( let j = 0; j < removedNodes.length && skip; j++ ) {
1977
+ if ( removedNodes[j].nodeType === 1 ) { skip = false; break; }
1978
+ }
1979
+ }
1980
+ if ( skip ) { return; }
1981
+ timer = self.requestIdleCallback(rmclass, { timeout: 67 });
1982
+ };
1983
+ const observer = new MutationObserver(mutationHandler);
1984
+ const start = ( ) => {
1985
+ rmclass();
1986
+ observer.observe(document, {
1987
+ attributes: true,
1988
+ attributeFilter: [ 'class' ],
1989
+ childList: true,
1990
+ subtree: true,
1991
+ });
1992
+ };
1993
+ runAt(( ) => {
1994
+ start();
1995
+ }, /\bcomplete\b/.test(behavior) ? 'idle' : 'loading');
1996
+ }
1997
+
1998
+ /******************************************************************************/
1999
+
2000
+ builtinScriptlets.push({
2001
+ name: 'no-requestAnimationFrame-if.js',
2002
+ aliases: [
2003
+ 'norafif.js',
2004
+ 'prevent-requestAnimationFrame.js',
2005
+ ],
2006
+ fn: noRequestAnimationFrameIf,
2007
+ dependencies: [
2008
+ 'safe-self.fn',
2009
+ ],
2010
+ });
2011
+ function noRequestAnimationFrameIf(
2012
+ needle = ''
2013
+ ) {
2014
+ if ( typeof needle !== 'string' ) { return; }
2015
+ const safe = safeSelf();
2016
+ const needleNot = needle.charAt(0) === '!';
2017
+ if ( needleNot ) { needle = needle.slice(1); }
2018
+ const log = needleNot === false && needle === '' ? console.log : undefined;
2019
+ const reNeedle = safe.patternToRegex(needle);
2020
+ window.requestAnimationFrame = new Proxy(window.requestAnimationFrame, {
2021
+ apply: function(target, thisArg, args) {
2022
+ const a = args[0] instanceof Function
2023
+ ? String(safe.Function_toString(args[0]))
2024
+ : String(args[0]);
2025
+ let defuse = false;
2026
+ if ( log !== undefined ) {
2027
+ log('uBO: requestAnimationFrame("%s")', a);
2028
+ } else {
2029
+ defuse = reNeedle.test(a) !== needleNot;
2030
+ }
2031
+ if ( defuse ) {
2032
+ args[0] = function(){};
2033
+ }
2034
+ return target.apply(thisArg, args);
2035
+ }
2036
+ });
2037
+ }
2038
+
2039
+ /******************************************************************************/
2040
+
2041
+ builtinScriptlets.push({
2042
+ name: 'set-constant.js',
2043
+ aliases: [
2044
+ 'set.js',
2045
+ ],
2046
+ fn: setConstant,
2047
+ dependencies: [
2048
+ 'set-constant-core.fn'
2049
+ ],
2050
+ });
2051
+ function setConstant(
2052
+ ...args
2053
+ ) {
2054
+ setConstantCore(false, ...args);
2055
+ }
2056
+
2057
+ /******************************************************************************/
2058
+
2059
+ builtinScriptlets.push({
2060
+ name: 'no-setInterval-if.js',
2061
+ aliases: [
2062
+ 'nosiif.js',
2063
+ 'prevent-setInterval.js',
2064
+ 'setInterval-defuser.js',
2065
+ ],
2066
+ fn: noSetIntervalIf,
2067
+ dependencies: [
2068
+ 'safe-self.fn',
2069
+ ],
2070
+ });
2071
+ function noSetIntervalIf(
2072
+ needle = '',
2073
+ delay = ''
2074
+ ) {
2075
+ if ( typeof needle !== 'string' ) { return; }
2076
+ const safe = safeSelf();
2077
+ const needleNot = needle.charAt(0) === '!';
2078
+ if ( needleNot ) { needle = needle.slice(1); }
2079
+ if ( delay === '' ) { delay = undefined; }
2080
+ let delayNot = false;
2081
+ if ( delay !== undefined ) {
2082
+ delayNot = delay.charAt(0) === '!';
2083
+ if ( delayNot ) { delay = delay.slice(1); }
2084
+ delay = parseInt(delay, 10);
2085
+ }
2086
+ const log = needleNot === false && needle === '' && delay === undefined
2087
+ ? console.log
2088
+ : undefined;
2089
+ const reNeedle = safe.patternToRegex(needle);
2090
+ self.setInterval = new Proxy(self.setInterval, {
2091
+ apply: function(target, thisArg, args) {
2092
+ const a = args[0] instanceof Function
2093
+ ? String(safe.Function_toString(args[0]))
2094
+ : String(args[0]);
2095
+ const b = args[1];
2096
+ if ( log !== undefined ) {
2097
+ log('uBO: setInterval("%s", %s)', a, b);
2098
+ } else {
2099
+ let defuse;
2100
+ if ( needle !== '' ) {
2101
+ defuse = reNeedle.test(a) !== needleNot;
2102
+ }
2103
+ if ( defuse !== false && delay !== undefined ) {
2104
+ defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot;
2105
+ }
2106
+ if ( defuse ) {
2107
+ args[0] = function(){};
2108
+ }
2109
+ }
2110
+ return Reflect.apply(target, thisArg, args);
2111
+ },
2112
+ get(target, prop, receiver) {
2113
+ if ( prop === 'toString' ) {
2114
+ return target.toString.bind(target);
2115
+ }
2116
+ return Reflect.get(target, prop, receiver);
2117
+ },
2118
+ });
2119
+ }
2120
+
2121
+ /******************************************************************************/
2122
+
2123
+ builtinScriptlets.push({
2124
+ name: 'no-setTimeout-if.js',
2125
+ aliases: [
2126
+ 'nostif.js',
2127
+ 'prevent-setTimeout.js',
2128
+ 'setTimeout-defuser.js',
2129
+ ],
2130
+ fn: noSetTimeoutIf,
2131
+ dependencies: [
2132
+ 'safe-self.fn',
2133
+ ],
2134
+ });
2135
+ function noSetTimeoutIf(
2136
+ needle = '',
2137
+ delay = ''
2138
+ ) {
2139
+ if ( typeof needle !== 'string' ) { return; }
2140
+ const safe = safeSelf();
2141
+ const needleNot = needle.charAt(0) === '!';
2142
+ if ( needleNot ) { needle = needle.slice(1); }
2143
+ if ( delay === '' ) { delay = undefined; }
2144
+ let delayNot = false;
2145
+ if ( delay !== undefined ) {
2146
+ delayNot = delay.charAt(0) === '!';
2147
+ if ( delayNot ) { delay = delay.slice(1); }
2148
+ delay = parseInt(delay, 10);
2149
+ }
2150
+ const log = needleNot === false && needle === '' && delay === undefined
2151
+ ? console.log
2152
+ : undefined;
2153
+ const reNeedle = safe.patternToRegex(needle);
2154
+ self.setTimeout = new Proxy(self.setTimeout, {
2155
+ apply: function(target, thisArg, args) {
2156
+ const a = args[0] instanceof Function
2157
+ ? String(safe.Function_toString(args[0]))
2158
+ : String(args[0]);
2159
+ const b = args[1];
2160
+ if ( log !== undefined ) {
2161
+ log('uBO: setTimeout("%s", %s)', a, b);
2162
+ } else {
2163
+ let defuse;
2164
+ if ( needle !== '' ) {
2165
+ defuse = reNeedle.test(a) !== needleNot;
2166
+ }
2167
+ if ( defuse !== false && delay !== undefined ) {
2168
+ defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot;
2169
+ }
2170
+ if ( defuse ) {
2171
+ args[0] = function(){};
2172
+ }
2173
+ }
2174
+ return Reflect.apply(target, thisArg, args);
2175
+ },
2176
+ get(target, prop, receiver) {
2177
+ if ( prop === 'toString' ) {
2178
+ return target.toString.bind(target);
2179
+ }
2180
+ return Reflect.get(target, prop, receiver);
2181
+ },
2182
+ });
2183
+ }
2184
+
2185
+ /******************************************************************************/
2186
+
2187
+ builtinScriptlets.push({
2188
+ name: 'webrtc-if.js',
2189
+ fn: webrtcIf,
2190
+ dependencies: [
2191
+ 'safe-self.fn',
2192
+ ],
2193
+ });
2194
+ function webrtcIf(
2195
+ good = ''
2196
+ ) {
2197
+ if ( typeof good !== 'string' ) { return; }
2198
+ const safe = safeSelf();
2199
+ const reGood = safe.patternToRegex(good);
2200
+ const rtcName = window.RTCPeerConnection
2201
+ ? 'RTCPeerConnection'
2202
+ : (window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : '');
2203
+ if ( rtcName === '' ) { return; }
2204
+ const log = console.log.bind(console);
2205
+ const neuteredPeerConnections = new WeakSet();
2206
+ const isGoodConfig = function(instance, config) {
2207
+ if ( neuteredPeerConnections.has(instance) ) { return false; }
2208
+ if ( config instanceof Object === false ) { return true; }
2209
+ if ( Array.isArray(config.iceServers) === false ) { return true; }
2210
+ for ( const server of config.iceServers ) {
2211
+ const urls = typeof server.urls === 'string'
2212
+ ? [ server.urls ]
2213
+ : server.urls;
2214
+ if ( Array.isArray(urls) ) {
2215
+ for ( const url of urls ) {
2216
+ if ( reGood.test(url) ) { return true; }
2217
+ }
2218
+ }
2219
+ if ( typeof server.username === 'string' ) {
2220
+ if ( reGood.test(server.username) ) { return true; }
2221
+ }
2222
+ if ( typeof server.credential === 'string' ) {
2223
+ if ( reGood.test(server.credential) ) { return true; }
2224
+ }
2225
+ }
2226
+ neuteredPeerConnections.add(instance);
2227
+ return false;
2228
+ };
2229
+ const peerConnectionCtor = window[rtcName];
2230
+ const peerConnectionProto = peerConnectionCtor.prototype;
2231
+ peerConnectionProto.createDataChannel =
2232
+ new Proxy(peerConnectionProto.createDataChannel, {
2233
+ apply: function(target, thisArg, args) {
2234
+ if ( isGoodConfig(target, args[1]) === false ) {
2235
+ log('uBO:', args[1]);
2236
+ return Reflect.apply(target, thisArg, args.slice(0, 1));
2237
+ }
2238
+ return Reflect.apply(target, thisArg, args);
2239
+ },
2240
+ });
2241
+ window[rtcName] =
2242
+ new Proxy(peerConnectionCtor, {
2243
+ construct: function(target, args) {
2244
+ if ( isGoodConfig(target, args[0]) === false ) {
2245
+ log('uBO:', args[0]);
2246
+ return Reflect.construct(target);
2247
+ }
2248
+ return Reflect.construct(target, args);
2249
+ }
2250
+ });
2251
+ }
2252
+
2253
+ /******************************************************************************/
2254
+
2255
+ builtinScriptlets.push({
2256
+ name: 'no-xhr-if.js',
2257
+ aliases: [
2258
+ 'prevent-xhr.js',
2259
+ ],
2260
+ fn: noXhrIf,
2261
+ dependencies: [
2262
+ 'match-object-properties.fn',
2263
+ 'parse-properties-to-match.fn',
2264
+ 'safe-self.fn',
2265
+ ],
2266
+ });
2267
+ function noXhrIf(
2268
+ propsToMatch = '',
2269
+ directive = ''
2270
+ ) {
2271
+ if ( typeof propsToMatch !== 'string' ) { return; }
2272
+ const safe = safeSelf();
2273
+ const xhrInstances = new WeakMap();
2274
+ const propNeedles = parsePropertiesToMatch(propsToMatch, 'url');
2275
+ const log = propNeedles.size === 0 ? console.log.bind(console) : undefined;
2276
+ 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 '';
2306
+ };
2307
+ self.XMLHttpRequest = class extends self.XMLHttpRequest {
2308
+ open(method, url, ...args) {
2309
+ if ( log !== undefined ) {
2310
+ log(`uBO: xhr.open(${method}, ${url}, ${args.join(', ')})`);
2311
+ return super.open(method, url, ...args);
2312
+ }
2313
+ if ( warOrigin !== undefined && url.startsWith(warOrigin) ) {
2314
+ return super.open(method, url, ...args);
2315
+ }
2316
+ const haystack = { method, url };
2317
+ if ( matchObjectProperties(propNeedles, haystack) ) {
2318
+ xhrInstances.set(this, haystack);
2319
+ }
2320
+ return super.open(method, url, ...args);
2321
+ }
2322
+ send(...args) {
2323
+ const haystack = xhrInstances.get(this);
2324
+ if ( haystack === undefined ) {
2325
+ return super.send(...args);
2326
+ }
2327
+ let promise = Promise.resolve({
2328
+ xhr: this,
2329
+ directive,
2330
+ props: {
2331
+ readyState: { value: 4 },
2332
+ response: { value: '' },
2333
+ responseText: { value: '' },
2334
+ responseXML: { value: null },
2335
+ responseURL: { value: haystack.url },
2336
+ status: { value: 200 },
2337
+ statusText: { value: 'OK' },
2338
+ },
2339
+ });
2340
+ 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 = '{}';
2367
+ return details;
2368
+ });
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;
2380
+ }
2381
+ promise.then(details => {
2382
+ Object.defineProperties(details.xhr, details.props);
2383
+ details.xhr.dispatchEvent(new Event('readystatechange'));
2384
+ details.xhr.dispatchEvent(new Event('load'));
2385
+ details.xhr.dispatchEvent(new Event('loadend'));
2386
+ });
2387
+ }
2388
+ };
2389
+ }
2390
+
2391
+ /******************************************************************************/
2392
+
2393
+ builtinScriptlets.push({
2394
+ name: 'no-window-open-if.js',
2395
+ aliases: [
2396
+ 'nowoif.js',
2397
+ 'prevent-window-open.js',
2398
+ 'window.open-defuser.js',
2399
+ ],
2400
+ fn: noWindowOpenIf,
2401
+ dependencies: [
2402
+ 'safe-self.fn',
2403
+ 'should-log.fn',
2404
+ ],
2405
+ });
2406
+ function noWindowOpenIf(
2407
+ pattern = '',
2408
+ delay = '',
2409
+ decoy = ''
2410
+ ) {
2411
+ const safe = safeSelf();
2412
+ const targetMatchResult = pattern.startsWith('!') === false;
2413
+ if ( targetMatchResult === false ) {
2414
+ pattern = pattern.slice(1);
2415
+ }
2416
+ const rePattern = safe.patternToRegex(pattern);
2417
+ let autoRemoveAfter = parseInt(delay);
2418
+ if ( isNaN(autoRemoveAfter) ) {
2419
+ autoRemoveAfter = -1;
2420
+ }
2421
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
2422
+ const logLevel = shouldLog(extraArgs);
2423
+ const createDecoy = function(tag, urlProp, url) {
2424
+ const decoyElem = document.createElement(tag);
2425
+ decoyElem[urlProp] = url;
2426
+ decoyElem.style.setProperty('height','1px', 'important');
2427
+ decoyElem.style.setProperty('position','fixed', 'important');
2428
+ decoyElem.style.setProperty('top','-1px', 'important');
2429
+ decoyElem.style.setProperty('width','1px', 'important');
2430
+ document.body.appendChild(decoyElem);
2431
+ setTimeout(( ) => { decoyElem.remove(); }, autoRemoveAfter * 1000);
2432
+ return decoyElem;
2433
+ };
2434
+ window.open = new Proxy(window.open, {
2435
+ apply: function(target, thisArg, args) {
2436
+ const haystack = args.join(' ');
2437
+ if ( logLevel ) {
2438
+ safe.uboLog('window.open:', haystack);
2439
+ }
2440
+ if ( rePattern.test(haystack) !== targetMatchResult ) {
2441
+ return Reflect.apply(target, thisArg, args);
2442
+ }
2443
+ if ( autoRemoveAfter < 0 ) { return null; }
2444
+ const decoyElem = decoy === 'obj'
2445
+ ? createDecoy('object', 'data', ...args)
2446
+ : createDecoy('iframe', 'src', ...args);
2447
+ let popup = decoyElem.contentWindow;
2448
+ if ( typeof popup === 'object' && popup !== null ) {
2449
+ Object.defineProperty(popup, 'closed', { value: false });
2450
+ } else {
2451
+ const noopFunc = (function(){}).bind(self);
2452
+ popup = new Proxy(self, {
2453
+ get: function(target, prop) {
2454
+ if ( prop === 'closed' ) { return false; }
2455
+ const r = Reflect.get(...arguments);
2456
+ if ( typeof r === 'function' ) { return noopFunc; }
2457
+ return target[prop];
2458
+ },
2459
+ set: function() {
2460
+ return Reflect.set(...arguments);
2461
+ },
2462
+ });
2463
+ }
2464
+ if ( logLevel ) {
2465
+ popup = new Proxy(popup, {
2466
+ get: function(target, prop) {
2467
+ safe.uboLog('window.open / get', prop, '===', target[prop]);
2468
+ return Reflect.get(...arguments);
2469
+ },
2470
+ set: function(target, prop, value) {
2471
+ safe.uboLog('window.open / set', prop, '=', value);
2472
+ return Reflect.set(...arguments);
2473
+ },
2474
+ });
2475
+ }
2476
+ return popup;
2477
+ }
2478
+ });
2479
+ }
2480
+
2481
+ /******************************************************************************/
2482
+
2483
+ builtinScriptlets.push({
2484
+ name: 'close-window.js',
2485
+ aliases: [
2486
+ 'window-close-if.js',
2487
+ ],
2488
+ fn: closeWindow,
2489
+ world: 'ISOLATED',
2490
+ dependencies: [
2491
+ 'safe-self.fn',
2492
+ ],
2493
+ });
2494
+ // https://github.com/uBlockOrigin/uAssets/issues/10323#issuecomment-992312847
2495
+ // https://github.com/AdguardTeam/Scriptlets/issues/158
2496
+ // https://github.com/uBlockOrigin/uBlock-issues/discussions/2270
2497
+ function closeWindow(
2498
+ arg1 = ''
2499
+ ) {
2500
+ if ( typeof arg1 !== 'string' ) { return; }
2501
+ const safe = safeSelf();
2502
+ let subject = '';
2503
+ if ( /^\/.*\/$/.test(arg1) ) {
2504
+ subject = window.location.href;
2505
+ } else if ( arg1 !== '' ) {
2506
+ subject = `${window.location.pathname}${window.location.search}`;
2507
+ }
2508
+ try {
2509
+ const re = safe.patternToRegex(arg1);
2510
+ if ( re.test(subject) ) {
2511
+ window.close();
2512
+ }
2513
+ } catch(ex) {
2514
+ console.log(ex);
2515
+ }
2516
+ }
2517
+
2518
+ /******************************************************************************/
2519
+
2520
+ builtinScriptlets.push({
2521
+ name: 'window.name-defuser.js',
2522
+ fn: windowNameDefuser,
2523
+ });
2524
+ // https://github.com/gorhill/uBlock/issues/1228
2525
+ function windowNameDefuser() {
2526
+ if ( window === window.top ) {
2527
+ window.name = '';
2528
+ }
2529
+ }
2530
+
2531
+ /******************************************************************************/
2532
+
2533
+ builtinScriptlets.push({
2534
+ name: 'overlay-buster.js',
2535
+ fn: overlayBuster,
2536
+ });
2537
+ // Experimental: Generic nuisance overlay buster.
2538
+ // if this works well and proves to be useful, this may end up
2539
+ // as a stock tool in uBO's popup panel.
2540
+ function overlayBuster() {
2541
+ if ( window !== window.top ) { return; }
2542
+ var tstart;
2543
+ var ttl = 30000;
2544
+ var delay = 0;
2545
+ var delayStep = 50;
2546
+ var buster = function() {
2547
+ var docEl = document.documentElement,
2548
+ bodyEl = document.body,
2549
+ vw = Math.min(docEl.clientWidth, window.innerWidth),
2550
+ vh = Math.min(docEl.clientHeight, window.innerHeight),
2551
+ tol = Math.min(vw, vh) * 0.05,
2552
+ el = document.elementFromPoint(vw/2, vh/2),
2553
+ style, rect;
2554
+ for (;;) {
2555
+ if ( el === null || el.parentNode === null || el === bodyEl ) {
2556
+ break;
2557
+ }
2558
+ style = window.getComputedStyle(el);
2559
+ if ( parseInt(style.zIndex, 10) >= 1000 || style.position === 'fixed' ) {
2560
+ rect = el.getBoundingClientRect();
2561
+ if ( rect.left <= tol && rect.top <= tol && (vw - rect.right) <= tol && (vh - rect.bottom) < tol ) {
2562
+ el.parentNode.removeChild(el);
2563
+ tstart = Date.now();
2564
+ el = document.elementFromPoint(vw/2, vh/2);
2565
+ bodyEl.style.setProperty('overflow', 'auto', 'important');
2566
+ docEl.style.setProperty('overflow', 'auto', 'important');
2567
+ continue;
2568
+ }
2569
+ }
2570
+ el = el.parentNode;
2571
+ }
2572
+ if ( (Date.now() - tstart) < ttl ) {
2573
+ delay = Math.min(delay + delayStep, 1000);
2574
+ setTimeout(buster, delay);
2575
+ }
2576
+ };
2577
+ var domReady = function(ev) {
2578
+ if ( ev ) {
2579
+ document.removeEventListener(ev.type, domReady);
2580
+ }
2581
+ tstart = Date.now();
2582
+ setTimeout(buster, delay);
2583
+ };
2584
+ if ( document.readyState === 'loading' ) {
2585
+ document.addEventListener('DOMContentLoaded', domReady);
2586
+ } else {
2587
+ domReady();
2588
+ }
2589
+ }
2590
+
2591
+ /******************************************************************************/
2592
+
2593
+ builtinScriptlets.push({
2594
+ name: 'alert-buster.js',
2595
+ fn: alertBuster,
2596
+ });
2597
+ // https://github.com/uBlockOrigin/uAssets/issues/8
2598
+ function alertBuster() {
2599
+ window.alert = new Proxy(window.alert, {
2600
+ apply: function(a) {
2601
+ console.info(a);
2602
+ },
2603
+ get(target, prop, receiver) {
2604
+ if ( prop === 'toString' ) {
2605
+ return target.toString.bind(target);
2606
+ }
2607
+ return Reflect.get(target, prop, receiver);
2608
+ },
2609
+ });
2610
+ }
2611
+
2612
+ /******************************************************************************/
2613
+
2614
+ builtinScriptlets.push({
2615
+ name: 'nowebrtc.js',
2616
+ fn: noWebrtc,
2617
+ });
2618
+ // Prevent web pages from using RTCPeerConnection(), and report attempts in console.
2619
+ function noWebrtc() {
2620
+ var rtcName = window.RTCPeerConnection ? 'RTCPeerConnection' : (
2621
+ window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : ''
2622
+ );
2623
+ if ( rtcName === '' ) { return; }
2624
+ var log = console.log.bind(console);
2625
+ var pc = function(cfg) {
2626
+ log('Document tried to create an RTCPeerConnection: %o', cfg);
2627
+ };
2628
+ const noop = function() {
2629
+ };
2630
+ pc.prototype = {
2631
+ close: noop,
2632
+ createDataChannel: noop,
2633
+ createOffer: noop,
2634
+ setRemoteDescription: noop,
2635
+ toString: function() {
2636
+ return '[object RTCPeerConnection]';
2637
+ }
2638
+ };
2639
+ var z = window[rtcName];
2640
+ window[rtcName] = pc.bind(window);
2641
+ if ( z.prototype ) {
2642
+ z.prototype.createDataChannel = function() {
2643
+ return {
2644
+ close: function() {},
2645
+ send: function() {}
2646
+ };
2647
+ }.bind(null);
2648
+ }
2649
+ }
2650
+
2651
+ /******************************************************************************/
2652
+
2653
+ builtinScriptlets.push({
2654
+ name: 'golem.de.js',
2655
+ fn: golemDe,
2656
+ });
2657
+ // https://github.com/uBlockOrigin/uAssets/issues/88
2658
+ function golemDe() {
2659
+ const rael = window.addEventListener;
2660
+ window.addEventListener = function(a, b) {
2661
+ rael(...arguments);
2662
+ let haystack;
2663
+ try {
2664
+ haystack = b.toString();
2665
+ } catch(ex) {
2666
+ }
2667
+ if (
2668
+ typeof haystack === 'string' &&
2669
+ /^\s*function\s*\(\)\s*\{\s*window\.clearTimeout\(r\)\s*\}\s*$/.test(haystack)
2670
+ ) {
2671
+ b();
2672
+ }
2673
+ }.bind(window);
2674
+ }
2675
+
2676
+ /******************************************************************************/
2677
+
2678
+ builtinScriptlets.push({
2679
+ name: 'disable-newtab-links.js',
2680
+ fn: disableNewtabLinks,
2681
+ });
2682
+ // https://github.com/uBlockOrigin/uAssets/issues/913
2683
+ function disableNewtabLinks() {
2684
+ document.addEventListener('click', function(ev) {
2685
+ var target = ev.target;
2686
+ while ( target !== null ) {
2687
+ if ( target.localName === 'a' && target.hasAttribute('target') ) {
2688
+ ev.stopPropagation();
2689
+ ev.preventDefault();
2690
+ break;
2691
+ }
2692
+ target = target.parentNode;
2693
+ }
2694
+ });
2695
+ }
2696
+
2697
+ /******************************************************************************/
2698
+
2699
+ builtinScriptlets.push({
2700
+ name: 'remove-cookie.js',
2701
+ aliases: [
2702
+ 'cookie-remover.js',
2703
+ ],
2704
+ fn: cookieRemover,
2705
+ world: 'ISOLATED',
2706
+ dependencies: [
2707
+ 'safe-self.fn',
2708
+ ],
2709
+ });
2710
+ // https://github.com/NanoAdblocker/NanoFilters/issues/149
2711
+ function cookieRemover(
2712
+ needle = ''
2713
+ ) {
2714
+ if ( typeof needle !== 'string' ) { return; }
2715
+ const safe = safeSelf();
2716
+ const reName = safe.patternToRegex(needle);
2717
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 1);
2718
+ const throttle = (fn, ms = 500) => {
2719
+ if ( throttle.timer !== undefined ) { return; }
2720
+ throttle.timer = setTimeout(( ) => {
2721
+ throttle.timer = undefined;
2722
+ fn();
2723
+ }, ms);
2724
+ };
2725
+ const removeCookie = ( ) => {
2726
+ document.cookie.split(';').forEach(cookieStr => {
2727
+ const pos = cookieStr.indexOf('=');
2728
+ if ( pos === -1 ) { return; }
2729
+ const cookieName = cookieStr.slice(0, pos).trim();
2730
+ if ( reName.test(cookieName) === false ) { return; }
2731
+ const part1 = cookieName + '=';
2732
+ const part2a = '; domain=' + document.location.hostname;
2733
+ const part2b = '; domain=.' + document.location.hostname;
2734
+ let part2c, part2d;
2735
+ const domain = document.domain;
2736
+ if ( domain ) {
2737
+ if ( domain !== document.location.hostname ) {
2738
+ part2c = '; domain=.' + domain;
2739
+ }
2740
+ if ( domain.startsWith('www.') ) {
2741
+ part2d = '; domain=' + domain.replace('www', '');
2742
+ }
2743
+ }
2744
+ const part3 = '; path=/';
2745
+ const part4 = '; Max-Age=-1000; expires=Thu, 01 Jan 1970 00:00:00 GMT';
2746
+ document.cookie = part1 + part4;
2747
+ document.cookie = part1 + part2a + part4;
2748
+ document.cookie = part1 + part2b + part4;
2749
+ document.cookie = part1 + part3 + part4;
2750
+ document.cookie = part1 + part2a + part3 + part4;
2751
+ document.cookie = part1 + part2b + part3 + part4;
2752
+ if ( part2c !== undefined ) {
2753
+ document.cookie = part1 + part2c + part3 + part4;
2754
+ }
2755
+ if ( part2d !== undefined ) {
2756
+ document.cookie = part1 + part2d + part3 + part4;
2757
+ }
2758
+ });
2759
+ };
2760
+ removeCookie();
2761
+ window.addEventListener('beforeunload', removeCookie);
2762
+ if ( typeof extraArgs.when !== 'string' ) { return; }
2763
+ const supportedEventTypes = [ 'scroll', 'keydown' ];
2764
+ const eventTypes = extraArgs.when.split(/\s/);
2765
+ for ( const type of eventTypes ) {
2766
+ if ( supportedEventTypes.includes(type) === false ) { continue; }
2767
+ document.addEventListener(type, ( ) => {
2768
+ throttle(removeCookie);
2769
+ }, { passive: true });
2770
+ }
2771
+ }
2772
+
2773
+ /******************************************************************************/
2774
+
2775
+ builtinScriptlets.push({
2776
+ name: 'xml-prune.js',
2777
+ fn: xmlPrune,
2778
+ dependencies: [
2779
+ 'safe-self.fn',
2780
+ 'should-log.fn',
2781
+ ],
2782
+ });
2783
+ function xmlPrune(
2784
+ selector = '',
2785
+ selectorCheck = '',
2786
+ urlPattern = ''
2787
+ ) {
2788
+ if ( typeof selector !== 'string' ) { return; }
2789
+ if ( selector === '' ) { return; }
2790
+ const safe = safeSelf();
2791
+ const reUrl = safe.patternToRegex(urlPattern);
2792
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
2793
+ const log = shouldLog(extraArgs) ? ((...args) => { safe.uboLog(...args); }) : (( ) => { });
2794
+ const queryAll = (xmlDoc, selector) => {
2795
+ const isXpath = /^xpath\(.+\)$/.test(selector);
2796
+ if ( isXpath === false ) {
2797
+ return Array.from(xmlDoc.querySelectorAll(selector));
2798
+ }
2799
+ const xpr = xmlDoc.evaluate(
2800
+ selector.slice(6, -1),
2801
+ xmlDoc,
2802
+ null,
2803
+ XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
2804
+ null
2805
+ );
2806
+ const out = [];
2807
+ for ( let i = 0; i < xpr.snapshotLength; i++ ) {
2808
+ const node = xpr.snapshotItem(i);
2809
+ out.push(node);
2810
+ }
2811
+ return out;
2812
+ };
2813
+ const pruneFromDoc = xmlDoc => {
2814
+ try {
2815
+ if ( selectorCheck !== '' && xmlDoc.querySelector(selectorCheck) === null ) {
2816
+ return xmlDoc;
2817
+ }
2818
+ if ( extraArgs.logdoc ) {
2819
+ const serializer = new XMLSerializer();
2820
+ log(`xmlPrune: document is\n\t${serializer.serializeToString(xmlDoc)}`);
2821
+ }
2822
+ const items = queryAll(xmlDoc, selector);
2823
+ if ( items.length === 0 ) { return xmlDoc; }
2824
+ log(`xmlPrune: removing ${items.length} items`);
2825
+ for ( const item of items ) {
2826
+ if ( item.nodeType === 1 ) {
2827
+ item.remove();
2828
+ } else if ( item.nodeType === 2 ) {
2829
+ item.ownerElement.removeAttribute(item.nodeName);
2830
+ }
2831
+ log(`xmlPrune: ${item.constructor.name}.${item.nodeName} removed`);
2832
+ }
2833
+ } catch(ex) {
2834
+ log(ex);
2835
+ }
2836
+ return xmlDoc;
2837
+ };
2838
+ const pruneFromText = text => {
2839
+ if ( (/^\s*</.test(text) && />\s*$/.test(text)) === false ) {
2840
+ return text;
2841
+ }
2842
+ try {
2843
+ const xmlParser = new DOMParser();
2844
+ const xmlDoc = xmlParser.parseFromString(text, 'text/xml');
2845
+ pruneFromDoc(xmlDoc);
2846
+ const serializer = new XMLSerializer();
2847
+ text = serializer.serializeToString(xmlDoc);
2848
+ } catch(ex) {
2849
+ }
2850
+ return text;
2851
+ };
2852
+ const urlFromArg = arg => {
2853
+ if ( typeof arg === 'string' ) { return arg; }
2854
+ if ( arg instanceof Request ) { return arg.url; }
2855
+ return String(arg);
2856
+ };
2857
+ self.fetch = new Proxy(self.fetch, {
2858
+ apply: function(target, thisArg, args) {
2859
+ const fetchPromise = Reflect.apply(target, thisArg, args);
2860
+ if ( reUrl.test(urlFromArg(args[0])) === false ) {
2861
+ return fetchPromise;
2862
+ }
2863
+ return fetchPromise.then(responseBefore => {
2864
+ const response = responseBefore.clone();
2865
+ return response.text().then(text => {
2866
+ const responseAfter = new Response(pruneFromText(text), {
2867
+ status: responseBefore.status,
2868
+ statusText: responseBefore.statusText,
2869
+ headers: responseBefore.headers,
2870
+ });
2871
+ Object.defineProperties(responseAfter, {
2872
+ ok: { value: responseBefore.ok },
2873
+ redirected: { value: responseBefore.redirected },
2874
+ type: { value: responseBefore.type },
2875
+ url: { value: responseBefore.url },
2876
+ });
2877
+ return responseAfter;
2878
+ }).catch(( ) =>
2879
+ responseBefore
2880
+ );
2881
+ });
2882
+ }
2883
+ });
2884
+ self.XMLHttpRequest.prototype.open = new Proxy(self.XMLHttpRequest.prototype.open, {
2885
+ apply: async (target, thisArg, args) => {
2886
+ if ( reUrl.test(urlFromArg(args[1])) === false ) {
2887
+ return Reflect.apply(target, thisArg, args);
2888
+ }
2889
+ thisArg.addEventListener('readystatechange', function() {
2890
+ if ( thisArg.readyState !== 4 ) { return; }
2891
+ const type = thisArg.responseType;
2892
+ if (
2893
+ type === 'document' ||
2894
+ type === '' && thisArg.responseXML instanceof XMLDocument
2895
+ ) {
2896
+ pruneFromDoc(thisArg.responseXML);
2897
+ return;
2898
+ }
2899
+ if (
2900
+ type === 'text' ||
2901
+ type === '' && typeof thisArg.responseText === 'string'
2902
+ ) {
2903
+ const textin = thisArg.responseText;
2904
+ const textout = pruneFromText(textin);
2905
+ if ( textout === textin ) { return; }
2906
+ Object.defineProperty(thisArg, 'response', { value: textout });
2907
+ Object.defineProperty(thisArg, 'responseText', { value: textout });
2908
+ return;
2909
+ }
2910
+ });
2911
+ return Reflect.apply(target, thisArg, args);
2912
+ }
2913
+ });
2914
+ }
2915
+
2916
+ /******************************************************************************/
2917
+
2918
+ builtinScriptlets.push({
2919
+ name: 'm3u-prune.js',
2920
+ fn: m3uPrune,
2921
+ dependencies: [
2922
+ 'safe-self.fn',
2923
+ 'should-log.fn',
2924
+ ],
2925
+ });
2926
+ // https://en.wikipedia.org/wiki/M3U
2927
+ function m3uPrune(
2928
+ m3uPattern = '',
2929
+ urlPattern = ''
2930
+ ) {
2931
+ if ( typeof m3uPattern !== 'string' ) { return; }
2932
+ const safe = safeSelf();
2933
+ const options = safe.getExtraArgs(Array.from(arguments), 2);
2934
+ const logLevel = shouldLog(options);
2935
+ const uboLog = logLevel ? ((...args) => safe.uboLog(...args)) : (( ) => { });
2936
+ const regexFromArg = arg => {
2937
+ if ( arg === '' ) { return /^/; }
2938
+ const match = /^\/(.+)\/([gms]*)$/.exec(arg);
2939
+ if ( match !== null ) {
2940
+ let flags = match[2] || '';
2941
+ if ( flags.includes('m') ) { flags += 's'; }
2942
+ return new RegExp(match[1], flags);
2943
+ }
2944
+ return new RegExp(
2945
+ arg.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*+/g, '.*?')
2946
+ );
2947
+ };
2948
+ const reM3u = regexFromArg(m3uPattern);
2949
+ const reUrl = regexFromArg(urlPattern);
2950
+ const pruneSpliceoutBlock = (lines, i) => {
2951
+ if ( lines[i].startsWith('#EXT-X-CUE:TYPE="SpliceOut"') === false ) {
2952
+ return false;
2953
+ }
2954
+ uboLog('m3u-prune: discarding', `\n\t${lines[i]}`);
2955
+ lines[i] = undefined; i += 1;
2956
+ if ( lines[i].startsWith('#EXT-X-ASSET:CAID') ) {
2957
+ uboLog(`\t${lines[i]}`);
2958
+ lines[i] = undefined; i += 1;
2959
+ }
2960
+ if ( lines[i].startsWith('#EXT-X-SCTE35:') ) {
2961
+ uboLog(`\t${lines[i]}`);
2962
+ lines[i] = undefined; i += 1;
2963
+ }
2964
+ if ( lines[i].startsWith('#EXT-X-CUE-IN') ) {
2965
+ uboLog(`\t${lines[i]}`);
2966
+ lines[i] = undefined; i += 1;
2967
+ }
2968
+ if ( lines[i].startsWith('#EXT-X-SCTE35:') ) {
2969
+ uboLog(`\t${lines[i]}`);
2970
+ lines[i] = undefined; i += 1;
2971
+ }
2972
+ return true;
2973
+ };
2974
+ const pruneInfBlock = (lines, i) => {
2975
+ if ( lines[i].startsWith('#EXTINF') === false ) { return false; }
2976
+ if ( reM3u.test(lines[i+1]) === false ) { return false; }
2977
+ uboLog('m3u-prune: discarding', `\n\t${lines[i]}, \n\t${lines[i+1]}`);
2978
+ lines[i] = lines[i+1] = undefined; i += 2;
2979
+ if ( lines[i].startsWith('#EXT-X-DISCONTINUITY') ) {
2980
+ uboLog(`\t${lines[i]}`);
2981
+ lines[i] = undefined; i += 1;
2982
+ }
2983
+ return true;
2984
+ };
2985
+ const pruner = text => {
2986
+ if ( (/^\s*#EXTM3U/.test(text)) === false ) { return text; }
2987
+ if ( reM3u.multiline ) {
2988
+ reM3u.lastIndex = 0;
2989
+ for (;;) {
2990
+ const match = reM3u.exec(text);
2991
+ if ( match === null ) { break; }
2992
+ let discard = match[0];
2993
+ let before = text.slice(0, match.index);
2994
+ if (
2995
+ /^[\n\r]+/.test(discard) === false &&
2996
+ /[\n\r]+$/.test(before) === false
2997
+ ) {
2998
+ const startOfLine = /[^\n\r]+$/.exec(before);
2999
+ if ( startOfLine !== null ) {
3000
+ before = before.slice(0, startOfLine.index);
3001
+ discard = startOfLine[0] + discard;
3002
+ }
3003
+ }
3004
+ let after = text.slice(match.index + match[0].length);
3005
+ if (
3006
+ /[\n\r]+$/.test(discard) === false &&
3007
+ /^[\n\r]+/.test(after) === false
3008
+ ) {
3009
+ const endOfLine = /^[^\n\r]+/.exec(after);
3010
+ if ( endOfLine !== null ) {
3011
+ after = after.slice(endOfLine.index);
3012
+ discard += discard + endOfLine[0];
3013
+ }
3014
+ }
3015
+ text = before.trim() + '\n' + after.trim();
3016
+ reM3u.lastIndex = before.length + 1;
3017
+ uboLog('m3u-prune: discarding\n',
3018
+ discard.split(/\n+/).map(s => `\t${s}`).join('\n')
3019
+ );
3020
+ if ( reM3u.global === false ) { break; }
3021
+ }
3022
+ return text;
3023
+ }
3024
+ const lines = text.split(/\n\r|\n|\r/);
3025
+ for ( let i = 0; i < lines.length; i++ ) {
3026
+ if ( lines[i] === undefined ) { continue; }
3027
+ if ( pruneSpliceoutBlock(lines, i) ) { continue; }
3028
+ if ( pruneInfBlock(lines, i) ) { continue; }
3029
+ }
3030
+ return lines.filter(l => l !== undefined).join('\n');
3031
+ };
3032
+ const urlFromArg = arg => {
3033
+ if ( typeof arg === 'string' ) { return arg; }
3034
+ if ( arg instanceof Request ) { return arg.url; }
3035
+ return String(arg);
3036
+ };
3037
+ const realFetch = self.fetch;
3038
+ self.fetch = new Proxy(self.fetch, {
3039
+ apply: function(target, thisArg, args) {
3040
+ if ( reUrl.test(urlFromArg(args[0])) === false ) {
3041
+ return Reflect.apply(target, thisArg, args);
3042
+ }
3043
+ return realFetch(...args).then(realResponse =>
3044
+ realResponse.text().then(text =>
3045
+ new Response(pruner(text), {
3046
+ status: realResponse.status,
3047
+ statusText: realResponse.statusText,
3048
+ headers: realResponse.headers,
3049
+ })
3050
+ )
3051
+ );
3052
+ }
3053
+ });
3054
+ self.XMLHttpRequest.prototype.open = new Proxy(self.XMLHttpRequest.prototype.open, {
3055
+ apply: async (target, thisArg, args) => {
3056
+ if ( reUrl.test(urlFromArg(args[1])) === false ) {
3057
+ return Reflect.apply(target, thisArg, args);
3058
+ }
3059
+ thisArg.addEventListener('readystatechange', function() {
3060
+ if ( thisArg.readyState !== 4 ) { return; }
3061
+ const type = thisArg.responseType;
3062
+ if ( type !== '' && type !== 'text' ) { return; }
3063
+ const textin = thisArg.responseText;
3064
+ const textout = pruner(textin);
3065
+ if ( textout === textin ) { return; }
3066
+ Object.defineProperty(thisArg, 'response', { value: textout });
3067
+ Object.defineProperty(thisArg, 'responseText', { value: textout });
3068
+ });
3069
+ return Reflect.apply(target, thisArg, args);
3070
+ }
3071
+ });
3072
+ }
3073
+
3074
+ /*******************************************************************************
3075
+ *
3076
+ * @scriptlet href-sanitizer
3077
+ *
3078
+ * @description
3079
+ * Set the `href` attribute to a value found in the DOM at, or below the
3080
+ * targeted `a` element.
3081
+ *
3082
+ * ### Syntax
3083
+ *
3084
+ * ```text
3085
+ * example.org##+js(href-sanitizer, selector [, source])
3086
+ * ```
3087
+ *
3088
+ * - `selector`: required, CSS selector, specifies `a` elements for which the
3089
+ * `href` attribute must be overridden.
3090
+ * - `source`: optional, default to `text`, specifies from where to get the
3091
+ * value which will override the `href` attribute.
3092
+ * - `text`: the value will be the first valid URL found in the text
3093
+ * content of the targeted `a` element.
3094
+ * - `[attr]`: the value will be the attribute _attr_ of the targeted `a`
3095
+ * element.
3096
+ * - `?param`: the value will be the query parameter _param_ of the URL
3097
+ * found in the `href` attribute of the targeted `a` element.
3098
+ *
3099
+ * ### Examples
3100
+ *
3101
+ * example.org##+js(href-sanitizer, a)
3102
+ * example.org##+js(href-sanitizer, a[title], [title])
3103
+ * example.org##+js(href-sanitizer, a[href*="/away.php?to="], ?to)
3104
+ *
3105
+ * */
3106
+
3107
+ builtinScriptlets.push({
3108
+ name: 'href-sanitizer.js',
3109
+ fn: hrefSanitizer,
3110
+ world: 'ISOLATED',
3111
+ dependencies: [
3112
+ 'run-at.fn',
3113
+ ],
3114
+ });
3115
+ function hrefSanitizer(
3116
+ selector = '',
3117
+ source = ''
3118
+ ) {
3119
+ if ( typeof selector !== 'string' ) { return; }
3120
+ if ( selector === '' ) { return; }
3121
+ if ( source === '' ) { source = 'text'; }
3122
+ const sanitizeCopycats = (href, text) => {
3123
+ let elems = [];
3124
+ try {
3125
+ elems = document.querySelectorAll(`a[href="${href}"`);
3126
+ }
3127
+ catch(ex) {
3128
+ }
3129
+ for ( const elem of elems ) {
3130
+ elem.setAttribute('href', text);
3131
+ }
3132
+ };
3133
+ const validateURL = text => {
3134
+ if ( text === '' ) { return ''; }
3135
+ if ( /[^\x21-\x7e]/.test(text) ) { return ''; }
3136
+ try {
3137
+ const url = new URL(text, document.location);
3138
+ return url.href;
3139
+ } catch(ex) {
3140
+ }
3141
+ return '';
3142
+ };
3143
+ const extractText = (elem, source) => {
3144
+ if ( /^\[.*\]$/.test(source) ) {
3145
+ return elem.getAttribute(source.slice(1,-1).trim()) || '';
3146
+ }
3147
+ if ( source.startsWith('?') ) {
3148
+ try {
3149
+ const url = new URL(elem.href, document.location);
3150
+ return url.searchParams.get(source.slice(1)) || '';
3151
+ } catch(x) {
3152
+ }
3153
+ return '';
3154
+ }
3155
+ if ( source === 'text' ) {
3156
+ return elem.textContent
3157
+ .replace(/^[^\x21-\x7e]+/, '') // remove leading invalid characters
3158
+ .replace(/[^\x21-\x7e]+$/, '') // remove trailing invalid characters
3159
+ ;
3160
+ }
3161
+ return '';
3162
+ };
3163
+ const sanitize = ( ) => {
3164
+ let elems = [];
3165
+ try {
3166
+ elems = document.querySelectorAll(selector);
3167
+ }
3168
+ catch(ex) {
3169
+ return false;
3170
+ }
3171
+ for ( const elem of elems ) {
3172
+ if ( elem.localName !== 'a' ) { continue; }
3173
+ if ( elem.hasAttribute('href') === false ) { continue; }
3174
+ const href = elem.getAttribute('href');
3175
+ const text = extractText(elem, source);
3176
+ const hrefAfter = validateURL(text);
3177
+ if ( hrefAfter === '' ) { continue; }
3178
+ if ( hrefAfter === href ) { continue; }
3179
+ elem.setAttribute('href', hrefAfter);
3180
+ sanitizeCopycats(href, hrefAfter);
3181
+ }
3182
+ return true;
3183
+ };
3184
+ let observer, timer;
3185
+ const onDomChanged = mutations => {
3186
+ if ( timer !== undefined ) { return; }
3187
+ let shouldSanitize = false;
3188
+ for ( const mutation of mutations ) {
3189
+ if ( mutation.addedNodes.length === 0 ) { continue; }
3190
+ for ( const node of mutation.addedNodes ) {
3191
+ if ( node.nodeType !== 1 ) { continue; }
3192
+ shouldSanitize = true;
3193
+ break;
3194
+ }
3195
+ if ( shouldSanitize ) { break; }
3196
+ }
3197
+ if ( shouldSanitize === false ) { return; }
3198
+ timer = self.requestAnimationFrame(( ) => {
3199
+ timer = undefined;
3200
+ sanitize();
3201
+ });
3202
+ };
3203
+ const start = ( ) => {
3204
+ if ( sanitize() === false ) { return; }
3205
+ observer = new MutationObserver(onDomChanged);
3206
+ observer.observe(document.body, {
3207
+ subtree: true,
3208
+ childList: true,
3209
+ });
3210
+ };
3211
+ runAt(( ) => { start(); }, 'interactive');
3212
+ }
3213
+
3214
+ /*******************************************************************************
3215
+ *
3216
+ * @scriptlet call-nothrow
3217
+ *
3218
+ * @description
3219
+ * Prevent a function call from throwing. The function will be called, however
3220
+ * should it throw, the scriptlet will silently process the exception and
3221
+ * returns as if no exception has occurred.
3222
+ *
3223
+ * ### Syntax
3224
+ *
3225
+ * ```text
3226
+ * example.org##+js(call-nothrow, propertyChain)
3227
+ * ```
3228
+ *
3229
+ * - `propertyChain`: a chain of dot-separated properties which leads to the
3230
+ * function to be trapped.
3231
+ *
3232
+ * ### Examples
3233
+ *
3234
+ * example.org##+js(call-nothrow, Object.defineProperty)
3235
+ *
3236
+ * */
3237
+
3238
+ builtinScriptlets.push({
3239
+ name: 'call-nothrow.js',
3240
+ fn: callNothrow,
3241
+ });
3242
+ function callNothrow(
3243
+ chain = ''
3244
+ ) {
3245
+ if ( typeof chain !== 'string' ) { return; }
3246
+ if ( chain === '' ) { return; }
3247
+ const parts = chain.split('.');
3248
+ let owner = window, prop;
3249
+ for (;;) {
3250
+ prop = parts.shift();
3251
+ if ( parts.length === 0 ) { break; }
3252
+ owner = owner[prop];
3253
+ if ( owner instanceof Object === false ) { return; }
3254
+ }
3255
+ if ( prop === '' ) { return; }
3256
+ const fn = owner[prop];
3257
+ if ( typeof fn !== 'function' ) { return; }
3258
+ owner[prop] = new Proxy(fn, {
3259
+ apply: function(...args) {
3260
+ let r;
3261
+ try {
3262
+ r = Reflect.apply(...args);
3263
+ } catch(ex) {
3264
+ }
3265
+ return r;
3266
+ },
3267
+ });
3268
+ }
3269
+
3270
+
3271
+ /******************************************************************************/
3272
+
3273
+ builtinScriptlets.push({
3274
+ name: 'spoof-css.js',
3275
+ fn: spoofCSS,
3276
+ dependencies: [
3277
+ 'safe-self.fn',
3278
+ ],
3279
+ });
3280
+ function spoofCSS(
3281
+ selector,
3282
+ ...args
3283
+ ) {
3284
+ if ( typeof selector !== 'string' ) { return; }
3285
+ if ( selector === '' ) { return; }
3286
+ const toCamelCase = s => s.replace(/-[a-z]/g, s => s.charAt(1).toUpperCase());
3287
+ const propToValueMap = new Map();
3288
+ for ( let i = 0; i < args.length; i += 2 ) {
3289
+ if ( typeof args[i+0] !== 'string' ) { break; }
3290
+ if ( args[i+0] === '' ) { break; }
3291
+ if ( typeof args[i+1] !== 'string' ) { break; }
3292
+ propToValueMap.set(toCamelCase(args[i+0]), args[i+1]);
3293
+ }
3294
+ const safe = safeSelf();
3295
+ const canDebug = scriptletGlobals.has('canDebug');
3296
+ const shouldDebug = canDebug && propToValueMap.get('debug') || 0;
3297
+ const shouldLog = canDebug && propToValueMap.has('log') || 0;
3298
+ const spoofStyle = (prop, real) => {
3299
+ const normalProp = toCamelCase(prop);
3300
+ const shouldSpoof = propToValueMap.has(normalProp);
3301
+ const value = shouldSpoof ? propToValueMap.get(normalProp) : real;
3302
+ if ( shouldLog === 2 || shouldSpoof && shouldLog === 1 ) {
3303
+ safe.uboLog(prop, value);
3304
+ }
3305
+ return value;
3306
+ };
3307
+ self.getComputedStyle = new Proxy(self.getComputedStyle, {
3308
+ apply: function(target, thisArg, args) {
3309
+ if ( shouldDebug !== 0 ) { debugger; } // jshint ignore: line
3310
+ const style = Reflect.apply(target, thisArg, args);
3311
+ const targetElements = new WeakSet(document.querySelectorAll(selector));
3312
+ if ( targetElements.has(args[0]) === false ) { return style; }
3313
+ const proxiedStyle = new Proxy(style, {
3314
+ get(target, prop, receiver) {
3315
+ if ( typeof target[prop] === 'function' ) {
3316
+ if ( prop === 'getPropertyValue' ) {
3317
+ return (function(prop) {
3318
+ return spoofStyle(prop, target[prop]);
3319
+ }).bind(target);
3320
+ }
3321
+ return target[prop].bind(target);
3322
+ }
3323
+ return spoofStyle(prop, Reflect.get(target, prop, receiver));
3324
+ },
3325
+ getOwnPropertyDescriptor(target, prop) {
3326
+ if ( propToValueMap.has(prop) ) {
3327
+ return {
3328
+ configurable: true,
3329
+ enumerable: true,
3330
+ value: propToValueMap.get(prop),
3331
+ writable: true,
3332
+ };
3333
+ }
3334
+ return Reflect.getOwnPropertyDescriptor(target, prop);
3335
+ },
3336
+ });
3337
+ return proxiedStyle;
3338
+ },
3339
+ get(target, prop, receiver) {
3340
+ if ( prop === 'toString' ) {
3341
+ return target.toString.bind(target);
3342
+ }
3343
+ return Reflect.get(target, prop, receiver);
3344
+ },
3345
+ });
3346
+ Element.prototype.getBoundingClientRect = new Proxy(Element.prototype.getBoundingClientRect, {
3347
+ apply: function(target, thisArg, args) {
3348
+ if ( shouldDebug !== 0 ) { debugger; } // jshint ignore: line
3349
+ const rect = Reflect.apply(target, thisArg, args);
3350
+ const targetElements = new WeakSet(document.querySelectorAll(selector));
3351
+ if ( targetElements.has(thisArg) === false ) { return rect; }
3352
+ let { height, width } = rect;
3353
+ if ( propToValueMap.has('width') ) {
3354
+ width = parseFloat(propToValueMap.get('width'));
3355
+ }
3356
+ if ( propToValueMap.has('height') ) {
3357
+ height = parseFloat(propToValueMap.get('height'));
3358
+ }
3359
+ return new self.DOMRect(rect.x, rect.y, width, height);
3360
+ },
3361
+ get(target, prop, receiver) {
3362
+ if ( prop === 'toString' ) {
3363
+ return target.toString.bind(target);
3364
+ }
3365
+ return Reflect.get(target, prop, receiver);
3366
+ },
3367
+ });
3368
+ }
3369
+
3370
+ /******************************************************************************/
3371
+
3372
+ builtinScriptlets.push({
3373
+ name: 'remove-node-text.js',
3374
+ aliases: [
3375
+ 'rmnt.js',
3376
+ ],
3377
+ fn: removeNodeText,
3378
+ world: 'ISOLATED',
3379
+ dependencies: [
3380
+ 'replace-node-text.fn',
3381
+ ],
3382
+ });
3383
+ function removeNodeText(
3384
+ nodeName,
3385
+ condition,
3386
+ ...extraArgs
3387
+ ) {
3388
+ replaceNodeTextFn(nodeName, '', '', 'condition', condition || '', ...extraArgs);
3389
+ }
3390
+
3391
+ /*******************************************************************************
3392
+ *
3393
+ * set-cookie.js
3394
+ *
3395
+ * Set specified cookie to a specific value.
3396
+ *
3397
+ * Reference:
3398
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-cookie.js
3399
+ *
3400
+ **/
3401
+
3402
+ builtinScriptlets.push({
3403
+ name: 'set-cookie.js',
3404
+ fn: setCookie,
3405
+ world: 'ISOLATED',
3406
+ dependencies: [
3407
+ 'safe-self.fn',
3408
+ 'set-cookie.fn',
3409
+ ],
3410
+ });
3411
+ function setCookie(
3412
+ name = '',
3413
+ value = '',
3414
+ path = ''
3415
+ ) {
3416
+ if ( name === '' ) { return; }
3417
+ name = encodeURIComponent(name);
3418
+
3419
+ const validValues = [
3420
+ 'accept', 'reject',
3421
+ 'accepted', 'rejected', 'notaccepted',
3422
+ 'allow', 'deny',
3423
+ 'allowed', 'disallow',
3424
+ 'enable', 'disable',
3425
+ 'enabled', 'disabled',
3426
+ 'ok',
3427
+ 'on', 'off',
3428
+ 'true', 't', 'false', 'f',
3429
+ 'yes', 'y', 'no', 'n',
3430
+ 'necessary', 'required',
3431
+ ];
3432
+ const normalized = value.toLowerCase();
3433
+ const match = /^("?)(.+)\1$/.exec(normalized);
3434
+ const unquoted = match && match[2] || normalized;
3435
+ if ( validValues.includes(unquoted) === false ) {
3436
+ if ( /^\d+$/.test(unquoted) === false ) { return; }
3437
+ const n = parseInt(value, 10);
3438
+ if ( n > 15 ) { return; }
3439
+ }
3440
+
3441
+ setCookieFn(
3442
+ false,
3443
+ name,
3444
+ value,
3445
+ '',
3446
+ path,
3447
+ safeSelf().getExtraArgs(Array.from(arguments), 3)
3448
+ );
3449
+ }
3450
+
3451
+ // For compatibility with AdGuard
3452
+ builtinScriptlets.push({
3453
+ name: 'set-cookie-reload.js',
3454
+ fn: setCookieReload,
3455
+ world: 'ISOLATED',
3456
+ dependencies: [
3457
+ 'set-cookie.js',
3458
+ ],
3459
+ });
3460
+ function setCookieReload(name, value, path, ...args) {
3461
+ setCookie(name, value, path, 'reload', '1', ...args);
3462
+ }
3463
+
3464
+ /*******************************************************************************
3465
+ *
3466
+ * set-local-storage-item.js
3467
+ * set-session-storage-item.js
3468
+ *
3469
+ * Set a local/session storage entry to a specific, allowed value.
3470
+ *
3471
+ * Reference:
3472
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-local-storage-item.js
3473
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-session-storage-item.js
3474
+ *
3475
+ **/
3476
+
3477
+ builtinScriptlets.push({
3478
+ name: 'set-local-storage-item.js',
3479
+ fn: setLocalStorageItem,
3480
+ world: 'ISOLATED',
3481
+ dependencies: [
3482
+ 'set-local-storage-item.fn',
3483
+ ],
3484
+ });
3485
+ function setLocalStorageItem(key = '', value = '') {
3486
+ setLocalStorageItemFn('local', false, key, value);
3487
+ }
3488
+
3489
+ builtinScriptlets.push({
3490
+ name: 'set-session-storage-item.js',
3491
+ fn: setSessionStorageItem,
3492
+ world: 'ISOLATED',
3493
+ dependencies: [
3494
+ 'set-local-storage-item.fn',
3495
+ ],
3496
+ });
3497
+ function setSessionStorageItem(key = '', value = '') {
3498
+ setLocalStorageItemFn('session', false, key, value);
3499
+ }
3500
+
3501
+ /*******************************************************************************
3502
+ *
3503
+ * @scriptlet set-attr
3504
+ *
3505
+ * @description
3506
+ * Sets the specified attribute on the specified elements. This scriptlet runs
3507
+ * once when the page loads then afterward on DOM mutations.
3508
+
3509
+ * Reference: https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-attr.js
3510
+ *
3511
+ * ### Syntax
3512
+ *
3513
+ * ```text
3514
+ * example.org##+js(set-attr, selector, attr [, value])
3515
+ * ```
3516
+ *
3517
+ * - `selector`: CSS selector of DOM elements for which the attribute `attr`
3518
+ * must be modified.
3519
+ * - `attr`: the name of the attribute to modify
3520
+ * - `value`: the value to assign to the target attribute. Possible values:
3521
+ * - `''`: empty string (default)
3522
+ * - `true`
3523
+ * - `false`
3524
+ * - positive decimal integer 0 <= value < 32768
3525
+ * - `[other]`: copy the value from attribute `other` on the same element
3526
+ * */
3527
+
3528
+ builtinScriptlets.push({
3529
+ name: 'set-attr.js',
3530
+ fn: setAttr,
3531
+ world: 'ISOLATED',
3532
+ dependencies: [
3533
+ 'run-at.fn',
3534
+ ],
3535
+ });
3536
+ function setAttr(
3537
+ selector = '',
3538
+ attr = '',
3539
+ value = ''
3540
+ ) {
3541
+ if ( typeof selector !== 'string' ) { return; }
3542
+ if ( selector === '' ) { return; }
3543
+
3544
+ const validValues = [ '', 'false', 'true' ];
3545
+ let copyFrom = '';
3546
+
3547
+ if ( validValues.includes(value.toLowerCase()) === false ) {
3548
+ if ( /^\d+$/.test(value) ) {
3549
+ const n = parseInt(value, 10);
3550
+ if ( n >= 32768 ) { return; }
3551
+ value = `${n}`;
3552
+ } else if ( /^\[.+\]$/.test(value) ) {
3553
+ copyFrom = value.slice(1, -1);
3554
+ } else {
3555
+ return;
3556
+ }
3557
+ }
3558
+
3559
+ const extractValue = elem => {
3560
+ if ( copyFrom !== '' ) {
3561
+ return elem.getAttribute(copyFrom) || '';
3562
+ }
3563
+ return value;
3564
+ };
3565
+
3566
+ const applySetAttr = ( ) => {
3567
+ const elems = [];
3568
+ try {
3569
+ elems.push(...document.querySelectorAll(selector));
3570
+ }
3571
+ catch(ex) {
3572
+ return false;
3573
+ }
3574
+ for ( const elem of elems ) {
3575
+ const before = elem.getAttribute(attr);
3576
+ const after = extractValue(elem);
3577
+ if ( after === before ) { continue; }
3578
+ elem.setAttribute(attr, after);
3579
+ }
3580
+ return true;
3581
+ };
3582
+ let observer, timer;
3583
+ const onDomChanged = mutations => {
3584
+ if ( timer !== undefined ) { return; }
3585
+ let shouldWork = false;
3586
+ for ( const mutation of mutations ) {
3587
+ if ( mutation.addedNodes.length === 0 ) { continue; }
3588
+ for ( const node of mutation.addedNodes ) {
3589
+ if ( node.nodeType !== 1 ) { continue; }
3590
+ shouldWork = true;
3591
+ break;
3592
+ }
3593
+ if ( shouldWork ) { break; }
3594
+ }
3595
+ if ( shouldWork === false ) { return; }
3596
+ timer = self.requestAnimationFrame(( ) => {
3597
+ timer = undefined;
3598
+ applySetAttr();
3599
+ });
3600
+ };
3601
+ const start = ( ) => {
3602
+ if ( applySetAttr() === false ) { return; }
3603
+ observer = new MutationObserver(onDomChanged);
3604
+ observer.observe(document.body, {
3605
+ subtree: true,
3606
+ childList: true,
3607
+ });
3608
+ };
3609
+ runAt(( ) => { start(); }, 'idle');
3610
+ }
3611
+
3612
+ /*******************************************************************************
3613
+ *
3614
+ * @scriptlet prevent-canvas
3615
+ *
3616
+ * @description
3617
+ * Prevent usage of specific or all (default) canvas APIs.
3618
+ *
3619
+ * ### Syntax
3620
+ *
3621
+ * ```text
3622
+ * example.com##+js(prevent-canvas [, contextType])
3623
+ * ```
3624
+ *
3625
+ * - `contextType`: A specific type of canvas API to prevent (default to all
3626
+ * APIs). Can be a string or regex which will be matched against the type
3627
+ * used in getContext() call. Prepend with `!` to test for no-match.
3628
+ *
3629
+ * ### Examples
3630
+ *
3631
+ * 1. Prevent `example.com` from accessing all canvas APIs
3632
+ *
3633
+ * ```adblock
3634
+ * example.com##+js(prevent-canvas)
3635
+ * ```
3636
+ *
3637
+ * 2. Prevent access to any flavor of WebGL API, everywhere
3638
+ *
3639
+ * ```adblock
3640
+ * *##+js(prevent-canvas, /webgl/)
3641
+ * ```
3642
+ *
3643
+ * 3. Prevent `example.com` from accessing any flavor of canvas API except `2d`
3644
+ *
3645
+ * ```adblock
3646
+ * example.com##+js(prevent-canvas, !2d)
3647
+ * ```
3648
+ *
3649
+ * ### References
3650
+ *
3651
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext
3652
+ *
3653
+ * */
3654
+
3655
+ builtinScriptlets.push({
3656
+ name: 'prevent-canvas.js',
3657
+ fn: preventCanvas,
3658
+ dependencies: [
3659
+ 'safe-self.fn',
3660
+ ],
3661
+ });
3662
+ function preventCanvas(
3663
+ contextType = ''
3664
+ ) {
3665
+ const safe = safeSelf();
3666
+ const pattern = safe.initPattern(contextType, { canNegate: true });
3667
+ const proto = globalThis.HTMLCanvasElement.prototype;
3668
+ proto.getContext = new Proxy(proto.getContext, {
3669
+ apply(target, thisArg, args) {
3670
+ if ( safe.testPattern(pattern, args[0]) ) { return null; }
3671
+ return Reflect.apply(target, thisArg, args);
3672
+ }
3673
+ });
3674
+ }
3675
+
3676
+ /******************************************************************************/
3677
+
3678
+ builtinScriptlets.push({
3679
+ name: 'multiup.js',
3680
+ fn: multiup,
3681
+ world: 'ISOLATED',
3682
+ });
3683
+ function multiup() {
3684
+ const handler = ev => {
3685
+ const target = ev.target;
3686
+ if ( target.matches('button[link]') === false ) { return; }
3687
+ const ancestor = target.closest('form');
3688
+ if ( ancestor === null ) { return; }
3689
+ if ( ancestor !== target.parentElement ) { return; }
3690
+ const link = (target.getAttribute('link') || '').trim();
3691
+ if ( link === '' ) { return; }
3692
+ ev.preventDefault();
3693
+ ev.stopPropagation();
3694
+ document.location.href = link;
3695
+ };
3696
+ document.addEventListener('click', handler, { capture: true });
3697
+ }
3698
+
3699
+
3700
+ /*******************************************************************************
3701
+ *
3702
+ * Scriplets below this section are only available for filter lists from
3703
+ * trusted sources. They all have the property `requiresTrust` set to `true`.
3704
+ *
3705
+ * Trusted sources are:
3706
+ *
3707
+ * - uBO's own filter lists, which name starts with "uBlock filters – ", and
3708
+ * maintained at: https://github.com/uBlockOrigin/uAssets
3709
+ *
3710
+ * - The user's own filters as seen in "My filters" pane in uBO's dashboard.
3711
+ *
3712
+ * The trustworthiness of filters using these privileged scriptlets are
3713
+ * evaluated at filter list compiled time: when a filter using one of the
3714
+ * privileged scriptlet originates from a non-trusted filter list source, it
3715
+ * is discarded at compile time, specifically from within:
3716
+ *
3717
+ * - Source: ./src/js/scriptlet-filtering.js
3718
+ * - Method: scriptletFilteringEngine.compile(), via normalizeRawFilter()
3719
+ *
3720
+ **/
3721
+
3722
+ /*******************************************************************************
3723
+ *
3724
+ * replace-node-text.js
3725
+ *
3726
+ * Replace text instance(s) with another text instance inside specific
3727
+ * DOM nodes. By default, the scriplet stops and quits at the interactive
3728
+ * stage of a document.
3729
+ *
3730
+ * See commit messages for usage:
3731
+ * - https://github.com/gorhill/uBlock/commit/99ce027fd702
3732
+ * - https://github.com/gorhill/uBlock/commit/41876336db48
3733
+ *
3734
+ **/
3735
+
3736
+ builtinScriptlets.push({
3737
+ name: 'trusted-replace-node-text.js',
3738
+ requiresTrust: true,
3739
+ aliases: [
3740
+ 'trusted-rpnt.js',
3741
+ 'replace-node-text.js',
3742
+ 'rpnt.js',
3743
+ ],
3744
+ fn: replaceNodeText,
3745
+ world: 'ISOLATED',
3746
+ dependencies: [
3747
+ 'replace-node-text.fn',
3748
+ ],
3749
+ });
3750
+ function replaceNodeText(
3751
+ nodeName,
3752
+ pattern,
3753
+ replacement,
3754
+ ...extraArgs
3755
+ ) {
3756
+ replaceNodeTextFn(nodeName, pattern, replacement, ...extraArgs);
3757
+ }
3758
+
3759
+ /*******************************************************************************
3760
+ *
3761
+ * trusted-set-constant.js
3762
+ *
3763
+ * Set specified property to any value. This is essentially the same as
3764
+ * set-constant.js, but with no restriction as to which values can be used.
3765
+ *
3766
+ **/
3767
+
3768
+ builtinScriptlets.push({
3769
+ name: 'trusted-set-constant.js',
3770
+ requiresTrust: true,
3771
+ aliases: [
3772
+ 'trusted-set.js',
3773
+ ],
3774
+ fn: trustedSetConstant,
3775
+ dependencies: [
3776
+ 'set-constant-core.fn'
3777
+ ],
3778
+ });
3779
+ function trustedSetConstant(
3780
+ ...args
3781
+ ) {
3782
+ setConstantCore(true, ...args);
3783
+ }
3784
+
3785
+ /*******************************************************************************
3786
+ *
3787
+ * trusted-set-cookie.js
3788
+ *
3789
+ * Set specified cookie to an arbitrary value.
3790
+ *
3791
+ * Reference:
3792
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-set-cookie.js#L23
3793
+ *
3794
+ **/
3795
+
3796
+ builtinScriptlets.push({
3797
+ name: 'trusted-set-cookie.js',
3798
+ requiresTrust: true,
3799
+ fn: trustedSetCookie,
3800
+ world: 'ISOLATED',
3801
+ dependencies: [
3802
+ 'safe-self.fn',
3803
+ 'set-cookie.fn',
3804
+ ],
3805
+ });
3806
+ function trustedSetCookie(
3807
+ name = '',
3808
+ value = '',
3809
+ offsetExpiresSec = '',
3810
+ path = ''
3811
+ ) {
3812
+ if ( name === '' ) { return; }
3813
+
3814
+ const time = new Date();
3815
+
3816
+ if ( value === '$now$' ) {
3817
+ value = Date.now();
3818
+ } else if ( value === '$currentDate$' ) {
3819
+ value = time.toUTCString();
3820
+ }
3821
+
3822
+ let expires = '';
3823
+ if ( offsetExpiresSec !== '' ) {
3824
+ if ( offsetExpiresSec === '1day' ) {
3825
+ time.setDate(time.getDate() + 1);
3826
+ } else if ( offsetExpiresSec === '1year' ) {
3827
+ time.setFullYear(time.getFullYear() + 1);
3828
+ } else {
3829
+ if ( /^\d+$/.test(offsetExpiresSec) === false ) { return; }
3830
+ time.setSeconds(time.getSeconds() + parseInt(offsetExpiresSec, 10));
3831
+ }
3832
+ expires = time.toUTCString();
3833
+ }
3834
+
3835
+ setCookieFn(
3836
+ true,
3837
+ name,
3838
+ value,
3839
+ expires,
3840
+ path,
3841
+ safeSelf().getExtraArgs(Array.from(arguments), 4)
3842
+ );
3843
+ }
3844
+
3845
+ // For compatibility with AdGuard
3846
+ builtinScriptlets.push({
3847
+ name: 'trusted-set-cookie-reload.js',
3848
+ requiresTrust: true,
3849
+ fn: trustedSetCookieReload,
3850
+ world: 'ISOLATED',
3851
+ dependencies: [
3852
+ 'trusted-set-cookie.js',
3853
+ ],
3854
+ });
3855
+ function trustedSetCookieReload(name, value, offsetExpiresSec, path, ...args) {
3856
+ trustedSetCookie(name, value, offsetExpiresSec, path, 'reload', '1', ...args);
3857
+ }
3858
+
3859
+ /*******************************************************************************
3860
+ *
3861
+ * trusted-set-local-storage-item.js
3862
+ *
3863
+ * Set a local storage entry to an arbitrary value.
3864
+ *
3865
+ * Reference:
3866
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-set-local-storage-item.js
3867
+ *
3868
+ **/
3869
+
3870
+ builtinScriptlets.push({
3871
+ name: 'trusted-set-local-storage-item.js',
3872
+ requiresTrust: true,
3873
+ fn: trustedSetLocalStorageItem,
3874
+ world: 'ISOLATED',
3875
+ dependencies: [
3876
+ 'set-local-storage-item.fn',
3877
+ ],
3878
+ });
3879
+ function trustedSetLocalStorageItem(key = '', value = '') {
3880
+ setLocalStorageItemFn('local', true, key, value);
3881
+ }
3882
+
3883
+ builtinScriptlets.push({
3884
+ name: 'trusted-set-session-storage-item.js',
3885
+ requiresTrust: true,
3886
+ fn: trustedSetSessionStorageItem,
3887
+ world: 'ISOLATED',
3888
+ dependencies: [
3889
+ 'set-local-storage-item.fn',
3890
+ ],
3891
+ });
3892
+ function trustedSetSessionStorageItem(key = '', value = '') {
3893
+ setLocalStorageItemFn('session', true, key, value);
3894
+ }
3895
+
3896
+ /*******************************************************************************
3897
+ *
3898
+ * trusted-replace-fetch-response.js
3899
+ *
3900
+ * Replaces response text content of fetch requests if all given parameters
3901
+ * match.
3902
+ *
3903
+ * Reference:
3904
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-replace-fetch-response.js
3905
+ *
3906
+ **/
3907
+
3908
+ builtinScriptlets.push({
3909
+ name: 'trusted-replace-fetch-response.js',
3910
+ requiresTrust: true,
3911
+ fn: trustedReplaceFetchResponse,
3912
+ dependencies: [
3913
+ 'replace-fetch-response.fn',
3914
+ ],
3915
+ });
3916
+ function trustedReplaceFetchResponse(...args) {
3917
+ replaceFetchResponseFn(true, ...args);
3918
+ }
3919
+
3920
+ /******************************************************************************/
3921
+
3922
+ builtinScriptlets.push({
3923
+ name: 'trusted-replace-xhr-response.js',
3924
+ requiresTrust: true,
3925
+ fn: trustedReplaceXhrResponse,
3926
+ dependencies: [
3927
+ 'match-object-properties.fn',
3928
+ 'parse-properties-to-match.fn',
3929
+ 'safe-self.fn',
3930
+ 'should-log.fn',
3931
+ ],
3932
+ });
3933
+ function trustedReplaceXhrResponse(
3934
+ pattern = '',
3935
+ replacement = '',
3936
+ propsToMatch = ''
3937
+ ) {
3938
+ const safe = safeSelf();
3939
+ const xhrInstances = new WeakMap();
3940
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
3941
+ const logLevel = shouldLog({
3942
+ log: pattern === '' && 'all' || extraArgs.log,
3943
+ });
3944
+ const log = logLevel ? ((...args) => { safe.uboLog(...args); }) : (( ) => { });
3945
+ if ( pattern === '*' ) { pattern = '.*'; }
3946
+ const rePattern = safe.patternToRegex(pattern);
3947
+ const propNeedles = parsePropertiesToMatch(propsToMatch, 'url');
3948
+ self.XMLHttpRequest = class extends self.XMLHttpRequest {
3949
+ open(method, url, ...args) {
3950
+ const outerXhr = this;
3951
+ const xhrDetails = { method, url };
3952
+ let outcome = 'match';
3953
+ if ( propNeedles.size !== 0 ) {
3954
+ if ( matchObjectProperties(propNeedles, xhrDetails) === false ) {
3955
+ outcome = 'nomatch';
3956
+ }
3957
+ }
3958
+ if ( outcome === logLevel || outcome === 'all' ) {
3959
+ log(`xhr.open(${method}, ${url}, ${args.join(', ')})`);
3960
+ }
3961
+ if ( outcome === 'match' ) {
3962
+ xhrInstances.set(outerXhr, xhrDetails);
3963
+ }
3964
+ return super.open(method, url, ...args);
3965
+ }
3966
+ get response() {
3967
+ const innerResponse = super.response;
3968
+ const xhrDetails = xhrInstances.get(this);
3969
+ if ( xhrDetails === undefined ) {
3970
+ return innerResponse;
3971
+ }
3972
+ const responseLength = typeof innerResponse === 'string'
3973
+ ? innerResponse.length
3974
+ : undefined;
3975
+ if ( xhrDetails.lastResponseLength !== responseLength ) {
3976
+ xhrDetails.response = undefined;
3977
+ xhrDetails.lastResponseLength = responseLength;
3978
+ }
3979
+ if ( xhrDetails.response !== undefined ) {
3980
+ return xhrDetails.response;
3981
+ }
3982
+ if ( typeof innerResponse !== 'string' ) {
3983
+ return (xhrDetails.response = innerResponse);
3984
+ }
3985
+ const textBefore = innerResponse;
3986
+ const textAfter = textBefore.replace(rePattern, replacement);
3987
+ const outcome = textAfter !== textBefore ? 'match' : 'nomatch';
3988
+ if ( outcome === logLevel || logLevel === 'all' ) {
3989
+ log(
3990
+ `trusted-replace-xhr-response (${outcome})`,
3991
+ `\n\tpattern: ${pattern}`,
3992
+ `\n\treplacement: ${replacement}`,
3993
+ );
3994
+ }
3995
+ return (xhrDetails.response = textAfter);
3996
+ }
3997
+ get responseText() {
3998
+ const response = this.response;
3999
+ if ( typeof response !== 'string' ) {
4000
+ return super.responseText;
4001
+ }
4002
+ return response;
4003
+ }
4004
+ };
4005
+ }
4006
+
4007
+ /*******************************************************************************
4008
+ *
4009
+ * trusted-click-element.js
4010
+ *
4011
+ * Reference API:
4012
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-click-element.js
4013
+ *
4014
+ **/
4015
+
4016
+ builtinScriptlets.push({
4017
+ name: 'trusted-click-element.js',
4018
+ requiresTrust: true,
4019
+ fn: trustedClickElement,
4020
+ world: 'ISOLATED',
4021
+ dependencies: [
4022
+ 'run-at-html-element.fn',
4023
+ 'safe-self.fn',
4024
+ ],
4025
+ });
4026
+ function trustedClickElement(
4027
+ selectors = '',
4028
+ extraMatch = '', // not yet supported
4029
+ delay = ''
4030
+ ) {
4031
+ if ( extraMatch !== '' ) { return; }
4032
+
4033
+ const safe = safeSelf();
4034
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
4035
+ const uboLog = extraArgs.log !== undefined
4036
+ ? ((...args) => { safe.uboLog(...args); })
4037
+ : (( ) => { });
4038
+
4039
+ const selectorList = selectors.split(/\s*,\s*/)
4040
+ .filter(s => {
4041
+ try {
4042
+ void document.querySelector(s);
4043
+ } catch(_) {
4044
+ return false;
4045
+ }
4046
+ return true;
4047
+ });
4048
+ if ( selectorList.length === 0 ) { return; }
4049
+
4050
+ const clickDelay = parseInt(delay, 10) || 1;
4051
+ const t0 = Date.now();
4052
+ const tbye = t0 + 10000;
4053
+ let tnext = selectorList.length !== 1 ? t0 : t0 + clickDelay;
4054
+
4055
+ const terminate = ( ) => {
4056
+ selectorList.length = 0;
4057
+ next.stop();
4058
+ observe.stop();
4059
+ };
4060
+
4061
+ const next = notFound => {
4062
+ if ( selectorList.length === 0 ) {
4063
+ uboLog(`trusted-click-element: Completed`);
4064
+ return terminate();
4065
+ }
4066
+ const tnow = Date.now();
4067
+ if ( tnow >= tbye ) {
4068
+ uboLog(`trusted-click-element: Timed out`);
4069
+ return terminate();
4070
+ }
4071
+ if ( notFound ) { observe(); }
4072
+ const delay = Math.max(notFound ? tbye - tnow : tnext - tnow, 1);
4073
+ next.timer = setTimeout(( ) => {
4074
+ next.timer = undefined;
4075
+ process();
4076
+ }, delay);
4077
+ uboLog(`trusted-click-element: Waiting for ${selectorList[0]}...`);
4078
+ };
4079
+ next.stop = ( ) => {
4080
+ if ( next.timer === undefined ) { return; }
4081
+ clearTimeout(next.timer);
4082
+ next.timer = undefined;
4083
+ };
4084
+
4085
+ const observe = ( ) => {
4086
+ if ( observe.observer !== undefined ) { return; }
4087
+ observe.observer = new MutationObserver(( ) => {
4088
+ if ( observe.timer !== undefined ) { return; }
4089
+ observe.timer = setTimeout(( ) => {
4090
+ observe.timer = undefined;
4091
+ process();
4092
+ }, 20);
4093
+ });
4094
+ observe.observer.observe(document, {
4095
+ attributes: true,
4096
+ childList: true,
4097
+ subtree: true,
4098
+ });
4099
+ };
4100
+ observe.stop = ( ) => {
4101
+ if ( observe.timer !== undefined ) {
4102
+ clearTimeout(observe.timer);
4103
+ observe.timer = undefined;
4104
+ }
4105
+ if ( observe.observer ) {
4106
+ observe.observer.disconnect();
4107
+ observe.observer = undefined;
4108
+ }
4109
+ };
4110
+
4111
+ const process = ( ) => {
4112
+ next.stop();
4113
+ if ( Date.now() < tnext ) { return next(); }
4114
+ const selector = selectorList.shift();
4115
+ if ( selector === undefined ) { return terminate(); }
4116
+ const elem = document.querySelector(selector);
4117
+ if ( elem === null ) {
4118
+ selectorList.unshift(selector);
4119
+ return next(true);
4120
+ }
4121
+ uboLog(`trusted-click-element: Clicked ${selector}`);
4122
+ elem.click();
4123
+ tnext += clickDelay;
4124
+ next();
4125
+ };
4126
+
4127
+ runAtHtmlElementFn(process);
4128
+ }
4129
+
4130
+ /******************************************************************************/
4131
+
4132
+ builtinScriptlets.push({
4133
+ name: 'trusted-prune-inbound-object.js',
4134
+ requiresTrust: true,
4135
+ fn: trustedPruneInboundObject,
4136
+ dependencies: [
4137
+ 'object-find-owner.fn',
4138
+ 'object-prune.fn',
4139
+ 'safe-self.fn',
4140
+ ],
4141
+ });
4142
+ function trustedPruneInboundObject(
4143
+ entryPoint = '',
4144
+ argPos = '',
4145
+ rawPrunePaths = '',
4146
+ rawNeedlePaths = ''
4147
+ ) {
4148
+ if ( entryPoint === '' ) { return; }
4149
+ let context = globalThis;
4150
+ let prop = entryPoint;
4151
+ for (;;) {
4152
+ const pos = prop.indexOf('.');
4153
+ if ( pos === -1 ) { break; }
4154
+ context = context[prop.slice(0, pos)];
4155
+ if ( context instanceof Object === false ) { return; }
4156
+ prop = prop.slice(pos+1);
4157
+ }
4158
+ if ( typeof context[prop] !== 'function' ) { return; }
4159
+ const argIndex = parseInt(argPos);
4160
+ if ( isNaN(argIndex) ) { return; }
4161
+ if ( argIndex < 1 ) { return; }
4162
+ const safe = safeSelf();
4163
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 4);
4164
+ const needlePaths = [];
4165
+ if ( rawPrunePaths !== '' ) {
4166
+ needlePaths.push(...rawPrunePaths.split(/ +/));
4167
+ }
4168
+ if ( rawNeedlePaths !== '' ) {
4169
+ needlePaths.push(...rawNeedlePaths.split(/ +/));
4170
+ }
4171
+ const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true });
4172
+ const mustProcess = root => {
4173
+ for ( const needlePath of needlePaths ) {
4174
+ if ( objectFindOwnerFn(root, needlePath) === false ) {
4175
+ return false;
4176
+ }
4177
+ }
4178
+ return true;
4179
+ };
4180
+ context[prop] = new Proxy(context[prop], {
4181
+ apply: function(target, thisArg, args) {
4182
+ const targetArg = argIndex <= args.length
4183
+ ? args[argIndex-1]
4184
+ : undefined;
4185
+ if ( targetArg instanceof Object && mustProcess(targetArg) ) {
4186
+ let objBefore = targetArg;
4187
+ if ( extraArgs.dontOverwrite ) {
4188
+ try {
4189
+ objBefore = safe.JSON_parse(safe.JSON_stringify(targetArg));
4190
+ } catch(_) {
4191
+ objBefore = undefined;
4192
+ }
4193
+ }
4194
+ if ( objBefore !== undefined ) {
4195
+ const objAfter = objectPruneFn(
4196
+ objBefore,
4197
+ rawPrunePaths,
4198
+ rawNeedlePaths,
4199
+ stackNeedle,
4200
+ extraArgs
4201
+ );
4202
+ args[argIndex-1] = objAfter || objBefore;
4203
+ }
4204
+ }
4205
+ return Reflect.apply(target, thisArg, args);
4206
+ },
4207
+ });
4208
+ }
4209
+
4210
+ /******************************************************************************/
4211
+
4212
+ builtinScriptlets.push({
4213
+ name: 'trusted-prune-outbound-object.js',
4214
+ requiresTrust: true,
4215
+ fn: trustedPruneOutboundObject,
4216
+ dependencies: [
4217
+ 'object-prune.fn',
4218
+ 'safe-self.fn',
4219
+ ],
4220
+ });
4221
+ function trustedPruneOutboundObject(
4222
+ entryPoint = '',
4223
+ rawPrunePaths = '',
4224
+ rawNeedlePaths = ''
4225
+ ) {
4226
+ if ( entryPoint === '' ) { return; }
4227
+ let context = globalThis;
4228
+ let prop = entryPoint;
4229
+ for (;;) {
4230
+ const pos = prop.indexOf('.');
4231
+ if ( pos === -1 ) { break; }
4232
+ context = context[prop.slice(0, pos)];
4233
+ if ( context instanceof Object === false ) { return; }
4234
+ prop = prop.slice(pos+1);
4235
+ }
4236
+ if ( typeof context[prop] !== 'function' ) { return; }
4237
+ const safe = safeSelf();
4238
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
4239
+ context[prop] = new Proxy(context[prop], {
4240
+ apply: function(target, thisArg, args) {
4241
+ const objBefore = Reflect.apply(target, thisArg, args);
4242
+ if ( objBefore instanceof Object === false ) { return objBefore; }
4243
+ const objAfter = objectPruneFn(
4244
+ objBefore,
4245
+ rawPrunePaths,
4246
+ rawNeedlePaths,
4247
+ { matchAll: true },
4248
+ extraArgs
4249
+ );
4250
+ return objAfter || objBefore;
4251
+ },
4252
+ });
4253
+ }
4254
+
4255
+ /******************************************************************************/