@browserless.io/browserless 2.5.0-beta-4 → 2.6.0

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 (191) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/README.md +65 -34
  3. package/build/config.d.ts +2 -2
  4. package/build/config.js +3 -3
  5. package/build/data/classes.json +1 -1
  6. package/build/data/selectors.json +1 -1
  7. package/build/http.d.ts +1 -0
  8. package/build/http.js +1 -0
  9. package/build/routes/chrome/http/content.post.body.json +8 -8
  10. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  11. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  12. package/build/routes/chrome/http/screenshot.post.body.json +9 -9
  13. package/build/routes/chromium/http/content.post.body.json +8 -8
  14. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  15. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  16. package/build/routes/chromium/http/screenshot.post.body.json +9 -9
  17. package/build/routes/management/http/active.get.d.ts +16 -0
  18. package/build/routes/management/http/active.get.js +17 -0
  19. package/build/routes/management/tests/management.spec.js +7 -0
  20. package/build/server.js +1 -1
  21. package/build/types.d.ts +6 -4
  22. package/build/types.js +1 -0
  23. package/build/utils.d.ts +1 -1
  24. package/docker/base/Dockerfile +1 -1
  25. package/extensions/ublock/1p-filters.html +4 -3
  26. package/extensions/ublock/3p-filters.html +3 -3
  27. package/extensions/ublock/_locales/ar/messages.json +16 -4
  28. package/extensions/ublock/_locales/az/messages.json +16 -4
  29. package/extensions/ublock/_locales/be/messages.json +19 -7
  30. package/extensions/ublock/_locales/bg/messages.json +16 -4
  31. package/extensions/ublock/_locales/bn/messages.json +33 -21
  32. package/extensions/ublock/_locales/br_FR/messages.json +33 -21
  33. package/extensions/ublock/_locales/bs/messages.json +16 -4
  34. package/extensions/ublock/_locales/ca/messages.json +16 -4
  35. package/extensions/ublock/_locales/cs/messages.json +16 -4
  36. package/extensions/ublock/_locales/cv/messages.json +16 -4
  37. package/extensions/ublock/_locales/cy/messages.json +16 -4
  38. package/extensions/ublock/_locales/da/messages.json +21 -9
  39. package/extensions/ublock/_locales/de/messages.json +17 -5
  40. package/extensions/ublock/_locales/el/messages.json +16 -4
  41. package/extensions/ublock/_locales/en/messages.json +16 -4
  42. package/extensions/ublock/_locales/en_GB/messages.json +16 -4
  43. package/extensions/ublock/_locales/eo/messages.json +17 -5
  44. package/extensions/ublock/_locales/es/messages.json +16 -4
  45. package/extensions/ublock/_locales/et/messages.json +16 -4
  46. package/extensions/ublock/_locales/eu/messages.json +16 -4
  47. package/extensions/ublock/_locales/fa/messages.json +24 -12
  48. package/extensions/ublock/_locales/fi/messages.json +16 -4
  49. package/extensions/ublock/_locales/fil/messages.json +16 -4
  50. package/extensions/ublock/_locales/fr/messages.json +16 -4
  51. package/extensions/ublock/_locales/fy/messages.json +16 -4
  52. package/extensions/ublock/_locales/gl/messages.json +16 -4
  53. package/extensions/ublock/_locales/gu/messages.json +16 -4
  54. package/extensions/ublock/_locales/he/messages.json +25 -13
  55. package/extensions/ublock/_locales/hi/messages.json +31 -19
  56. package/extensions/ublock/_locales/hr/messages.json +16 -4
  57. package/extensions/ublock/_locales/hu/messages.json +16 -4
  58. package/extensions/ublock/_locales/hy/messages.json +17 -5
  59. package/extensions/ublock/_locales/id/messages.json +16 -4
  60. package/extensions/ublock/_locales/it/messages.json +17 -5
  61. package/extensions/ublock/_locales/ja/messages.json +16 -4
  62. package/extensions/ublock/_locales/ka/messages.json +16 -4
  63. package/extensions/ublock/_locales/kk/messages.json +16 -4
  64. package/extensions/ublock/_locales/kn/messages.json +74 -62
  65. package/extensions/ublock/_locales/ko/messages.json +16 -4
  66. package/extensions/ublock/_locales/lt/messages.json +23 -11
  67. package/extensions/ublock/_locales/lv/messages.json +16 -4
  68. package/extensions/ublock/_locales/mk/messages.json +16 -4
  69. package/extensions/ublock/_locales/ml/messages.json +19 -7
  70. package/extensions/ublock/_locales/mr/messages.json +16 -4
  71. package/extensions/ublock/_locales/ms/messages.json +16 -4
  72. package/extensions/ublock/_locales/nb/messages.json +16 -4
  73. package/extensions/ublock/_locales/nl/messages.json +16 -4
  74. package/extensions/ublock/_locales/no/messages.json +16 -4
  75. package/extensions/ublock/_locales/oc/messages.json +16 -4
  76. package/extensions/ublock/_locales/pa/messages.json +16 -4
  77. package/extensions/ublock/_locales/pl/messages.json +17 -5
  78. package/extensions/ublock/_locales/pt_BR/messages.json +16 -4
  79. package/extensions/ublock/_locales/pt_PT/messages.json +16 -4
  80. package/extensions/ublock/_locales/ro/messages.json +17 -5
  81. package/extensions/ublock/_locales/ru/messages.json +16 -4
  82. package/extensions/ublock/_locales/si/messages.json +16 -4
  83. package/extensions/ublock/_locales/sk/messages.json +16 -4
  84. package/extensions/ublock/_locales/sl/messages.json +16 -4
  85. package/extensions/ublock/_locales/so/messages.json +16 -4
  86. package/extensions/ublock/_locales/sq/messages.json +16 -4
  87. package/extensions/ublock/_locales/sr/messages.json +16 -4
  88. package/extensions/ublock/_locales/sv/messages.json +20 -8
  89. package/extensions/ublock/_locales/sw/messages.json +16 -4
  90. package/extensions/ublock/_locales/ta/messages.json +16 -4
  91. package/extensions/ublock/_locales/te/messages.json +16 -4
  92. package/extensions/ublock/_locales/th/messages.json +42 -30
  93. package/extensions/ublock/_locales/tr/messages.json +19 -7
  94. package/extensions/ublock/_locales/uk/messages.json +16 -4
  95. package/extensions/ublock/_locales/ur/messages.json +16 -4
  96. package/extensions/ublock/_locales/vi/messages.json +16 -4
  97. package/extensions/ublock/_locales/zh_CN/messages.json +16 -4
  98. package/extensions/ublock/_locales/zh_TW/messages.json +42 -30
  99. package/extensions/ublock/assets/assets.json +95 -78
  100. package/extensions/ublock/assets/resources/scriptlets.js +70 -24
  101. package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +6258 -3453
  102. package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +277 -40
  103. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +8 -32
  104. package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +107 -12
  105. package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +1160 -954
  106. package/extensions/ublock/assets/ublock/badlists.txt +1 -2
  107. package/extensions/ublock/assets/ublock/badware.min.txt +395 -270
  108. package/extensions/ublock/assets/ublock/filters.min.txt +1176 -1238
  109. package/extensions/ublock/assets/ublock/privacy.min.txt +32 -31
  110. package/extensions/ublock/assets/ublock/quick-fixes.min.txt +120 -110
  111. package/extensions/ublock/assets/ublock/unbreak.min.txt +75 -36
  112. package/extensions/ublock/css/1p-filters.css +2 -1
  113. package/extensions/ublock/css/3p-filters.css +1 -16
  114. package/extensions/ublock/css/advanced-settings.css +1 -0
  115. package/extensions/ublock/css/asset-viewer.css +1 -0
  116. package/extensions/ublock/css/code-viewer.css +1 -0
  117. package/extensions/ublock/css/codemirror.css +37 -10
  118. package/extensions/ublock/css/common.css +36 -2
  119. package/extensions/ublock/css/dashboard.css +9 -3
  120. package/extensions/ublock/css/devtools.css +1 -0
  121. package/extensions/ublock/css/document-blocked.css +3 -3
  122. package/extensions/ublock/css/dom-inspector.css +1 -0
  123. package/extensions/ublock/css/dyna-rules.css +1 -0
  124. package/extensions/ublock/css/epicker-ui.css +76 -66
  125. package/extensions/ublock/css/fa-icons.css +1 -0
  126. package/extensions/ublock/css/logger-ui.css +2 -0
  127. package/extensions/ublock/css/popup-fenix.css +1 -0
  128. package/extensions/ublock/css/whitelist.css +1 -0
  129. package/extensions/ublock/dashboard.html +20 -13
  130. package/extensions/ublock/devtools.html +2 -0
  131. package/extensions/ublock/dyna-rules.html +2 -2
  132. package/extensions/ublock/img/flags-of-the-world/np.png +0 -0
  133. package/extensions/ublock/img/fontawesome/fontawesome-defs.svg +1 -0
  134. package/extensions/ublock/js/1p-filters.js +72 -23
  135. package/extensions/ublock/js/3p-filters.js +71 -25
  136. package/extensions/ublock/js/asset-viewer.js +1 -0
  137. package/extensions/ublock/js/assets.js +83 -89
  138. package/extensions/ublock/js/background.js +20 -27
  139. package/extensions/ublock/js/base64-custom.js +1 -102
  140. package/extensions/ublock/js/benchmarks.js +36 -21
  141. package/extensions/ublock/js/biditrie.js +8 -23
  142. package/extensions/ublock/js/broadcast.js +2 -4
  143. package/extensions/ublock/js/cachestorage.js +594 -396
  144. package/extensions/ublock/js/codemirror/search.js +49 -37
  145. package/extensions/ublock/js/codemirror/ubo-static-filtering.js +233 -215
  146. package/extensions/ublock/js/contentscript-extra.js +31 -1
  147. package/extensions/ublock/js/cosmetic-filtering.js +35 -33
  148. package/extensions/ublock/js/dashboard.js +11 -7
  149. package/extensions/ublock/js/devtools.js +22 -0
  150. package/extensions/ublock/js/dom.js +2 -2
  151. package/extensions/ublock/js/dyna-rules.js +17 -16
  152. package/extensions/ublock/js/epicker-ui.js +41 -16
  153. package/extensions/ublock/js/fa-icons.js +1 -0
  154. package/extensions/ublock/js/hntrie.js +10 -25
  155. package/extensions/ublock/js/i18n.js +15 -15
  156. package/extensions/ublock/js/logger-ui.js +9 -6
  157. package/extensions/ublock/js/messaging.js +51 -26
  158. package/extensions/ublock/js/pagestore.js +21 -23
  159. package/extensions/ublock/js/popup-fenix.js +35 -22
  160. package/extensions/ublock/js/redirect-engine.js +15 -30
  161. package/extensions/ublock/js/reverselookup.js +1 -1
  162. package/extensions/ublock/js/s14e-serializer.js +1405 -0
  163. package/extensions/ublock/js/scriptlet-filtering-core.js +1 -1
  164. package/extensions/ublock/js/scriptlets/epicker.js +27 -18
  165. package/extensions/ublock/js/settings.js +32 -21
  166. package/extensions/ublock/js/start.js +121 -62
  167. package/extensions/ublock/js/static-ext-filtering-db.js +6 -6
  168. package/extensions/ublock/js/static-ext-filtering.js +17 -28
  169. package/extensions/ublock/js/static-filtering-parser.js +26 -4
  170. package/extensions/ublock/js/static-net-filtering.js +69 -168
  171. package/extensions/ublock/js/storage.js +178 -155
  172. package/extensions/ublock/js/traffic.js +11 -7
  173. package/extensions/ublock/js/vapi-background.js +49 -62
  174. package/extensions/ublock/js/vapi-client.js +13 -16
  175. package/extensions/ublock/js/webext.js +10 -2
  176. package/extensions/ublock/js/whitelist.js +27 -25
  177. package/extensions/ublock/lib/publicsuffixlist/publicsuffixlist.js +3 -7
  178. package/extensions/ublock/manifest.json +2 -1
  179. package/extensions/ublock/web_accessible_resources/epicker-ui.html +5 -8
  180. package/extensions/ublock/whitelist.html +3 -4
  181. package/package.json +13 -13
  182. package/src/config.ts +3 -4
  183. package/src/http.ts +1 -0
  184. package/src/routes/management/http/active.get.ts +30 -0
  185. package/src/routes/management/tests/management.spec.ts +13 -0
  186. package/src/server.ts +1 -1
  187. package/src/types.ts +2 -1
  188. package/static/docs/swagger.json +57 -11
  189. package/static/docs/swagger.min.json +56 -10
  190. package/static/function/client.js +4155 -3350
  191. package/extensions/ublock/_locales/ku/messages.json +0 -1294
@@ -19,44 +19,39 @@
19
19
  Home: https://github.com/gorhill/uBlock
20
20
  */
21
21
 
22
- 'use strict';
23
-
24
22
  /******************************************************************************/
25
23
 
26
- import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js';
27
- import punycode from '../lib/punycode.js';
24
+ import * as sfp from './static-filtering-parser.js';
28
25
 
29
- import io from './assets.js';
26
+ import { CompiledListReader, CompiledListWriter } from './static-filtering-io.js';
27
+ import { LineIterator, orphanizeString } from './text-utils.js';
30
28
  import { broadcast, filteringBehaviorChanged, onBroadcast } from './broadcast.js';
29
+ import { i18n, i18n$ } from './i18n.js';
30
+ import {
31
+ permanentFirewall,
32
+ permanentSwitches,
33
+ permanentURLFiltering,
34
+ } from './filtering-engines.js';
35
+ import { ubolog, ubologSet } from './console.js';
36
+
31
37
  import cosmeticFilteringEngine from './cosmetic-filtering.js';
38
+ import { hostnameFromURI } from './uri-utils.js';
39
+ import io from './assets.js';
32
40
  import logger from './logger.js';
33
41
  import lz4Codec from './lz4.js';
42
+ import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js';
43
+ import punycode from '../lib/punycode.js';
44
+ import { redirectEngine } from './redirect-engine.js';
34
45
  import staticExtFilteringEngine from './static-ext-filtering.js';
35
46
  import staticFilteringReverseLookup from './reverselookup.js';
36
47
  import staticNetFilteringEngine from './static-net-filtering.js';
37
48
  import µb from './background.js';
38
- import { hostnameFromURI } from './uri-utils.js';
39
- import { i18n, i18n$ } from './i18n.js';
40
- import { redirectEngine } from './redirect-engine.js';
41
- import { sparseBase64 } from './base64-custom.js';
42
- import { ubolog, ubologSet } from './console.js';
43
- import * as sfp from './static-filtering-parser.js';
44
-
45
- import {
46
- permanentFirewall,
47
- permanentSwitches,
48
- permanentURLFiltering,
49
- } from './filtering-engines.js';
50
49
 
51
- import {
52
- CompiledListReader,
53
- CompiledListWriter,
54
- } from './static-filtering-io.js';
50
+ /******************************************************************************/
55
51
 
56
- import {
57
- LineIterator,
58
- orphanizeString,
59
- } from './text-utils.js';
52
+ // https://eslint.org/docs/latest/rules/no-prototype-builtins
53
+ const hasOwnProperty = (o, p) =>
54
+ Object.prototype.hasOwnProperty.call(o, p);
60
55
 
61
56
  /******************************************************************************/
62
57
 
@@ -98,24 +93,80 @@ import {
98
93
  /******************************************************************************/
99
94
 
100
95
  {
101
- let localSettingsLastSaved = Date.now();
96
+ const requestStats = µb.requestStats;
97
+ let requestStatsDisabled = false;
98
+
99
+ µb.loadLocalSettings = async ( ) => {
100
+ requestStatsDisabled = µb.hiddenSettings.requestStatsDisabled;
101
+ if ( requestStatsDisabled ) { return; }
102
+ return Promise.all([
103
+ vAPI.sessionStorage.get('requestStats'),
104
+ vAPI.storage.get('requestStats'),
105
+ vAPI.storage.get([ 'blockedRequestCount', 'allowedRequestCount' ]),
106
+ ]).then(([ a, b, c ]) => {
107
+ if ( a instanceof Object && a.requestStats ) { return a.requestStats; }
108
+ if ( b instanceof Object && b.requestStats ) { return b.requestStats; }
109
+ if ( c instanceof Object && Object.keys(c).length === 2 ) {
110
+ return {
111
+ blockedCount: c.blockedRequestCount,
112
+ allowedCount: c.allowedRequestCount,
113
+ };
114
+ }
115
+ return { blockedCount: 0, allowedCount: 0 };
116
+ }).then(({ blockedCount, allowedCount }) => {
117
+ requestStats.blockedCount += blockedCount;
118
+ requestStats.allowedCount += allowedCount;
119
+ });
120
+ };
102
121
 
103
- const shouldSave = ( ) => {
104
- if ( µb.localSettingsLastModified > localSettingsLastSaved ) {
105
- µb.saveLocalSettings();
106
- }
107
- saveTimer.on(saveDelay);
122
+ const SAVE_DELAY_IN_MINUTES = 3.6;
123
+ const QUICK_SAVE_DELAY_IN_SECONDS = 23;
124
+
125
+ const stopTimers = ( ) => {
126
+ vAPI.alarms.clear('saveLocalSettings');
127
+ quickSaveTimer.off();
128
+ saveTimer.off();
108
129
  };
109
130
 
110
- const saveTimer = vAPI.defer.create(shouldSave);
111
- const saveDelay = { sec: 23 };
131
+ const saveTimer = vAPI.defer.create(( ) => {
132
+ µb.saveLocalSettings();
133
+ });
134
+
135
+ const quickSaveTimer = vAPI.defer.create(( ) => {
136
+ if ( vAPI.sessionStorage.unavailable !== true ) {
137
+ vAPI.sessionStorage.set({ requestStats: requestStats });
138
+ }
139
+ if ( requestStatsDisabled ) { return; }
140
+ saveTimer.on({ min: SAVE_DELAY_IN_MINUTES });
141
+ vAPI.alarms.createIfNotPresent('saveLocalSettings', {
142
+ delayInMinutes: SAVE_DELAY_IN_MINUTES + 0.5
143
+ });
144
+ });
112
145
 
113
- saveTimer.onidle(saveDelay);
146
+ µb.incrementRequestStats = (blocked, allowed) => {
147
+ requestStats.blockedCount += blocked;
148
+ requestStats.allowedCount += allowed;
149
+ quickSaveTimer.on({ sec: QUICK_SAVE_DELAY_IN_SECONDS });
150
+ };
114
151
 
115
- µb.saveLocalSettings = function() {
116
- localSettingsLastSaved = Date.now();
117
- return vAPI.storage.set(this.localSettings);
152
+ µb.saveLocalSettings = ( ) => {
153
+ stopTimers();
154
+ if ( requestStatsDisabled ) { return; }
155
+ return vAPI.storage.set({ requestStats: µb.requestStats });
118
156
  };
157
+
158
+ onBroadcast(msg => {
159
+ if ( msg.what !== 'hiddenSettingsChanged' ) { return; }
160
+ const newState = µb.hiddenSettings.requestStatsDisabled;
161
+ if ( requestStatsDisabled === newState ) { return; }
162
+ requestStatsDisabled = newState;
163
+ if ( newState ) {
164
+ stopTimers();
165
+ µb.requestStats.blockedCount = µb.requestStats.allowedCount = 0;
166
+ } else {
167
+ µb.loadLocalSettings();
168
+ }
169
+ });
119
170
  }
120
171
 
121
172
  /******************************************************************************/
@@ -136,7 +187,7 @@ import {
136
187
  for ( const entry of adminSettings ) {
137
188
  if ( entry.length < 1 ) { continue; }
138
189
  const name = entry[0];
139
- if ( usDefault.hasOwnProperty(name) === false ) { continue; }
190
+ if ( hasOwnProperty(usDefault, name) === false ) { continue; }
140
191
  const value = entry.length < 2
141
192
  ? usDefault[name]
142
193
  : this.settingValueFromString(usDefault, name, entry[1]);
@@ -165,8 +216,8 @@ import {
165
216
 
166
217
  const toRemove = [];
167
218
  for ( const key in this.userSettings ) {
168
- if ( this.userSettings.hasOwnProperty(key) === false ) { continue; }
169
- if ( toSave.hasOwnProperty(key) ) { continue; }
219
+ if ( hasOwnProperty(this.userSettings, key) === false ) { continue; }
220
+ if ( hasOwnProperty(toSave, key) ) { continue; }
170
221
  toRemove.push(key);
171
222
  }
172
223
  if ( toRemove.length !== 0 ) {
@@ -203,7 +254,7 @@ import {
203
254
  for ( const entry of advancedSettings ) {
204
255
  if ( entry.length < 1 ) { continue; }
205
256
  const name = entry[0];
206
- if ( hsDefault.hasOwnProperty(name) === false ) { continue; }
257
+ if ( hasOwnProperty(hsDefault, name) === false ) { continue; }
207
258
  const value = entry.length < 2
208
259
  ? hsDefault[name]
209
260
  : this.hiddenSettingValueFromString(name, entry[1]);
@@ -237,8 +288,8 @@ import {
237
288
  }
238
289
 
239
290
  for ( const key in hsDefault ) {
240
- if ( hsDefault.hasOwnProperty(key) === false ) { continue; }
241
- if ( hsAdmin.hasOwnProperty(name) ) { continue; }
291
+ if ( hasOwnProperty(hsDefault, key) === false ) { continue; }
292
+ if ( hasOwnProperty(hsAdmin, name) ) { continue; }
242
293
  if ( typeof hs[key] !== typeof hsDefault[key] ) { continue; }
243
294
  this.hiddenSettings[key] = hs[key];
244
295
  }
@@ -283,8 +334,8 @@ onBroadcast(msg => {
283
334
  const matches = /^\s*(\S+)\s+(.+)$/.exec(line);
284
335
  if ( matches === null || matches.length !== 3 ) { continue; }
285
336
  const name = matches[1];
286
- if ( out.hasOwnProperty(name) === false ) { continue; }
287
- if ( this.hiddenSettingsAdmin.hasOwnProperty(name) ) { continue; }
337
+ if ( hasOwnProperty(out, name) === false ) { continue; }
338
+ if ( hasOwnProperty(this.hiddenSettingsAdmin, name) ) { continue; }
288
339
  const value = this.hiddenSettingValueFromString(name, matches[2]);
289
340
  if ( value !== undefined ) {
290
341
  out[name] = value;
@@ -296,7 +347,7 @@ onBroadcast(msg => {
296
347
  µb.hiddenSettingValueFromString = function(name, value) {
297
348
  if ( typeof name !== 'string' || typeof value !== 'string' ) { return; }
298
349
  const hsDefault = this.hiddenSettingsDefault;
299
- if ( hsDefault.hasOwnProperty(name) === false ) { return; }
350
+ if ( hasOwnProperty(hsDefault, name) === false ) { return; }
300
351
  let r;
301
352
  switch ( typeof hsDefault[name] ) {
302
353
  case 'boolean':
@@ -369,6 +420,9 @@ onBroadcast(msg => {
369
420
  /******************************************************************************/
370
421
 
371
422
  µb.isTrustedList = function(assetKey) {
423
+ if ( assetKey === this.userFiltersPath ) {
424
+ if ( this.userSettings.userFiltersTrusted ) { return true; }
425
+ }
372
426
  if ( this.parsedTrustedListPrefixes.length === 0 ) {
373
427
  this.parsedTrustedListPrefixes =
374
428
  µb.hiddenSettings.trustedListPrefixes.split(/ +/).map(prefix => {
@@ -530,7 +584,6 @@ onBroadcast(msg => {
530
584
  // https://github.com/gorhill/uBlock/issues/1022
531
585
  // Be sure to end with an empty line.
532
586
  content = content.trim();
533
- if ( content !== '' ) { content += '\n'; }
534
587
  this.removeCompiledFilterList(this.userFiltersPath);
535
588
  return io.put(this.userFiltersPath, content);
536
589
  };
@@ -626,6 +679,7 @@ onBroadcast(msg => {
626
679
  cosmeticFilteringEngine.removeFromSelectorCache(
627
680
  hostnameFromURI(details.docURL)
628
681
  );
682
+ staticFilteringReverseLookup.resetLists();
629
683
  };
630
684
 
631
685
  µb.userFiltersAreEnabled = function() {
@@ -637,7 +691,7 @@ onBroadcast(msg => {
637
691
  µb.autoSelectRegionalFilterLists = function(lists) {
638
692
  const selectedListKeys = [ this.userFiltersPath ];
639
693
  for ( const key in lists ) {
640
- if ( lists.hasOwnProperty(key) === false ) { continue; }
694
+ if ( hasOwnProperty(lists, key) === false ) { continue; }
641
695
  const list = lists[key];
642
696
  if ( list.content !== 'filters' ) { continue; }
643
697
  if ( list.off !== true ) {
@@ -891,7 +945,7 @@ onBroadcast(msg => {
891
945
  let acceptedCount = snfe.acceptedCount + sxfe.acceptedCount;
892
946
  let discardedCount = snfe.discardedCount + sxfe.discardedCount;
893
947
  µb.applyCompiledFilters(compiled, assetKey === µb.userFiltersPath);
894
- if ( µb.availableFilterLists.hasOwnProperty(assetKey) ) {
948
+ if ( hasOwnProperty(µb.availableFilterLists, assetKey) ) {
895
949
  const entry = µb.availableFilterLists[assetKey];
896
950
  entry.entryCount = snfe.acceptedCount + sxfe.acceptedCount -
897
951
  acceptedCount;
@@ -927,7 +981,7 @@ onBroadcast(msg => {
927
981
  // content.
928
982
  const toLoad = [];
929
983
  for ( const assetKey in lists ) {
930
- if ( lists.hasOwnProperty(assetKey) === false ) { continue; }
984
+ if ( hasOwnProperty(lists, assetKey) === false ) { continue; }
931
985
  if ( lists[assetKey].off ) { continue; }
932
986
  toLoad.push(
933
987
  µb.getCompiledFilterList(assetKey).then(details => {
@@ -974,7 +1028,7 @@ onBroadcast(msg => {
974
1028
  /******************************************************************************/
975
1029
 
976
1030
  µb.getCompiledFilterList = async function(assetKey) {
977
- const compiledPath = 'compiled/' + assetKey;
1031
+ const compiledPath = `compiled/${assetKey}`;
978
1032
 
979
1033
  // https://github.com/uBlockOrigin/uBlock-issues/issues/1365
980
1034
  // Verify that the list version matches that of the current compiled
@@ -983,11 +1037,10 @@ onBroadcast(msg => {
983
1037
  this.compiledFormatChanged === false &&
984
1038
  this.badLists.has(assetKey) === false
985
1039
  ) {
986
- const compiledDetails = await io.get(compiledPath);
1040
+ const content = await io.fromCache(compiledPath);
987
1041
  const compilerVersion = `${this.systemSettings.compiledMagic}\n`;
988
- if ( compiledDetails.content.startsWith(compilerVersion) ) {
989
- compiledDetails.assetKey = assetKey;
990
- return compiledDetails;
1042
+ if ( content.startsWith(compilerVersion) ) {
1043
+ return { assetKey, content };
991
1044
  }
992
1045
  }
993
1046
 
@@ -1017,7 +1070,7 @@ onBroadcast(msg => {
1017
1070
  assetKey,
1018
1071
  trustedSource: this.isTrustedList(assetKey),
1019
1072
  });
1020
- io.put(compiledPath, compiledContent);
1073
+ io.toCache(compiledPath, compiledContent);
1021
1074
 
1022
1075
  return { assetKey, content: compiledContent };
1023
1076
  };
@@ -1046,7 +1099,7 @@ onBroadcast(msg => {
1046
1099
  /******************************************************************************/
1047
1100
 
1048
1101
  µb.removeCompiledFilterList = function(assetKey) {
1049
- io.remove('compiled/' + assetKey);
1102
+ io.remove(`compiled/${assetKey}`);
1050
1103
  };
1051
1104
 
1052
1105
  µb.removeFilterList = function(assetKey) {
@@ -1149,7 +1202,10 @@ onBroadcast(msg => {
1149
1202
  µb.loadRedirectResources = async function() {
1150
1203
  try {
1151
1204
  const success = await redirectEngine.resourcesFromSelfie(io);
1152
- if ( success === true ) { return true; }
1205
+ if ( success === true ) {
1206
+ ubolog('Loaded redirect/scriptlets resources from selfie');
1207
+ return true;
1208
+ }
1153
1209
 
1154
1210
  const fetcher = (path, options = undefined) => {
1155
1211
  if ( path.startsWith('/web_accessible_resources/') ) {
@@ -1173,20 +1229,17 @@ onBroadcast(msg => {
1173
1229
  const results = await Promise.all(fetchPromises);
1174
1230
  if ( Array.isArray(results) === false ) { return results; }
1175
1231
 
1176
- let content = '';
1232
+ const content = [];
1177
1233
  for ( let i = 1; i < results.length; i++ ) {
1178
1234
  const result = results[i];
1179
- if (
1180
- result instanceof Object === false ||
1181
- typeof result.content !== 'string' ||
1182
- result.content === ''
1183
- ) {
1184
- continue;
1185
- }
1186
- content += '\n\n' + result.content;
1235
+ if ( result instanceof Object === false ) { continue; }
1236
+ if ( typeof result.content !== 'string' ) { continue; }
1237
+ if ( result.content === '' ) { continue; }
1238
+ content.push(result.content);
1239
+ }
1240
+ if ( content.length !== 0 ) {
1241
+ redirectEngine.resourcesFromString(content.join('\n\n'));
1187
1242
  }
1188
-
1189
- redirectEngine.resourcesFromString(content);
1190
1243
  redirectEngine.selfieFromResources(io);
1191
1244
  } catch(ex) {
1192
1245
  ubolog(ex);
@@ -1225,8 +1278,11 @@ onBroadcast(msg => {
1225
1278
  }
1226
1279
 
1227
1280
  try {
1228
- const result = await io.get(`compiled/${this.pslAssetKey}`);
1229
- if ( psl.fromSelfie(result.content, sparseBase64) ) { return; }
1281
+ const selfie = await io.fromCache(`selfie/${this.pslAssetKey}`);
1282
+ if ( psl.fromSelfie(selfie) ) {
1283
+ ubolog('Loaded PSL from selfie');
1284
+ return;
1285
+ }
1230
1286
  } catch (reason) {
1231
1287
  ubolog(reason);
1232
1288
  }
@@ -1240,7 +1296,8 @@ onBroadcast(msg => {
1240
1296
  µb.compilePublicSuffixList = function(content) {
1241
1297
  const psl = publicSuffixList;
1242
1298
  psl.parse(content, punycode.toASCII);
1243
- io.put(`compiled/${this.pslAssetKey}`, psl.toSelfie(sparseBase64));
1299
+ ubolog(`Loaded PSL from ${this.pslAssetKey}`);
1300
+ return io.toCache(`selfie/${this.pslAssetKey}`, psl.toSelfie());
1244
1301
  };
1245
1302
 
1246
1303
  /******************************************************************************/
@@ -1260,39 +1317,24 @@ onBroadcast(msg => {
1260
1317
  if ( µb.inMemoryFilters.length !== 0 ) { return; }
1261
1318
  if ( Object.keys(µb.availableFilterLists).length === 0 ) { return; }
1262
1319
  await Promise.all([
1263
- io.put(
1264
- 'selfie/main',
1265
- JSON.stringify({
1266
- magic: µb.systemSettings.selfieMagic,
1267
- availableFilterLists: µb.availableFilterLists,
1268
- })
1269
- ),
1270
- redirectEngine.toSelfie('selfie/redirectEngine'),
1271
- staticExtFilteringEngine.toSelfie(
1272
- 'selfie/staticExtFilteringEngine'
1320
+ io.toCache('selfie/staticMain', {
1321
+ magic: µb.systemSettings.selfieMagic,
1322
+ availableFilterLists: µb.availableFilterLists,
1323
+ }),
1324
+ io.toCache('selfie/staticExtFilteringEngine',
1325
+ staticExtFilteringEngine.toSelfie()
1273
1326
  ),
1274
- staticNetFilteringEngine.toSelfie(io,
1275
- 'selfie/staticNetFilteringEngine'
1327
+ io.toCache('selfie/staticNetFilteringEngine',
1328
+ staticNetFilteringEngine.toSelfie()
1276
1329
  ),
1277
1330
  ]);
1278
1331
  lz4Codec.relinquish();
1279
1332
  µb.selfieIsInvalid = false;
1333
+ ubolog('Filtering engine selfie created');
1280
1334
  };
1281
1335
 
1282
1336
  const loadMain = async function() {
1283
- const details = await io.get('selfie/main');
1284
- if (
1285
- details instanceof Object === false ||
1286
- typeof details.content !== 'string' ||
1287
- details.content === ''
1288
- ) {
1289
- return false;
1290
- }
1291
- let selfie;
1292
- try {
1293
- selfie = JSON.parse(details.content);
1294
- } catch(ex) {
1295
- }
1337
+ const selfie = await io.fromCache('selfie/staticMain');
1296
1338
  if ( selfie instanceof Object === false ) { return false; }
1297
1339
  if ( selfie.magic !== µb.systemSettings.selfieMagic ) { return false; }
1298
1340
  if ( selfie.availableFilterLists instanceof Object === false ) { return false; }
@@ -1306,12 +1348,11 @@ onBroadcast(msg => {
1306
1348
  try {
1307
1349
  const results = await Promise.all([
1308
1350
  loadMain(),
1309
- redirectEngine.fromSelfie('selfie/redirectEngine'),
1310
- staticExtFilteringEngine.fromSelfie(
1311
- 'selfie/staticExtFilteringEngine'
1351
+ io.fromCache('selfie/staticExtFilteringEngine').then(selfie =>
1352
+ staticExtFilteringEngine.fromSelfie(selfie)
1312
1353
  ),
1313
- staticNetFilteringEngine.fromSelfie(io,
1314
- 'selfie/staticNetFilteringEngine'
1354
+ io.fromCache('selfie/staticNetFilteringEngine').then(selfie =>
1355
+ staticNetFilteringEngine.fromSelfie(selfie)
1315
1356
  ),
1316
1357
  ]);
1317
1358
  if ( results.every(v => v) ) {
@@ -1321,33 +1362,26 @@ onBroadcast(msg => {
1321
1362
  catch (reason) {
1322
1363
  ubolog(reason);
1323
1364
  }
1365
+ ubolog('Filtering engine selfie not available');
1324
1366
  destroy();
1325
1367
  return false;
1326
1368
  };
1327
1369
 
1328
- const destroy = function() {
1370
+ const destroy = function(options = {}) {
1329
1371
  if ( µb.selfieIsInvalid === false ) {
1330
- io.remove(/^selfie\//);
1372
+ io.remove(/^selfie\/static/, options);
1331
1373
  µb.selfieIsInvalid = true;
1332
- }
1333
- if ( µb.wakeupReason === 'createSelfie' ) {
1334
- µb.wakeupReason = '';
1335
- return createTimer.offon({ sec: 27 });
1374
+ ubolog('Filtering engine selfie marked for invalidation');
1336
1375
  }
1337
1376
  vAPI.alarms.create('createSelfie', {
1338
- delayInMinutes: µb.hiddenSettings.selfieAfter
1377
+ delayInMinutes: (µb.hiddenSettings.selfieDelayInSeconds + 17) / 60,
1339
1378
  });
1340
- createTimer.offon({ min: µb.hiddenSettings.selfieAfter });
1379
+ createTimer.offon({ sec: µb.hiddenSettings.selfieDelayInSeconds });
1341
1380
  };
1342
1381
 
1343
1382
  const createTimer = vAPI.defer.create(create);
1344
1383
 
1345
- vAPI.alarms.onAlarm.addListener(alarm => {
1346
- if ( alarm.name !== 'createSelfie') { return; }
1347
- µb.wakeupReason = 'createSelfie';
1348
- });
1349
-
1350
- µb.selfieManager = { load, destroy };
1384
+ µb.selfieManager = { load, create, destroy };
1351
1385
  }
1352
1386
 
1353
1387
  /******************************************************************************/
@@ -1399,8 +1433,8 @@ onBroadcast(msg => {
1399
1433
  const µbus = this.userSettings;
1400
1434
  const adminus = data.userSettings;
1401
1435
  for ( const name in µbus ) {
1402
- if ( µbus.hasOwnProperty(name) === false ) { continue; }
1403
- if ( adminus.hasOwnProperty(name) === false ) { continue; }
1436
+ if ( hasOwnProperty(µbus, name) === false ) { continue; }
1437
+ if ( hasOwnProperty(adminus, name) === false ) { continue; }
1404
1438
  bin[name] = adminus[name];
1405
1439
  binNotEmpty = true;
1406
1440
  }
@@ -1463,13 +1497,21 @@ onBroadcast(msg => {
1463
1497
  vAPI.storage.set(bin);
1464
1498
  }
1465
1499
 
1466
- if (
1467
- Array.isArray(toOverwrite.filters) &&
1468
- toOverwrite.filters.length !== 0
1469
- ) {
1470
- this.saveUserFilters(toOverwrite.filters.join('\n'));
1500
+ let userFiltersAfter;
1501
+ if ( Array.isArray(toOverwrite.filters) ) {
1502
+ userFiltersAfter = toOverwrite.filters.join('\n').trim();
1471
1503
  } else if ( typeof data.userFilters === 'string' ) {
1472
- this.saveUserFilters(data.userFilters);
1504
+ userFiltersAfter = data.userFilters.trim();
1505
+ }
1506
+ if ( typeof userFiltersAfter === 'string' ) {
1507
+ const bin = await vAPI.storage.get(this.userFiltersPath);
1508
+ const userFiltersBefore = bin && bin[this.userFiltersPath] || '';
1509
+ if ( userFiltersAfter !== userFiltersBefore ) {
1510
+ await Promise.all([
1511
+ this.saveUserFilters(userFiltersAfter),
1512
+ this.selfieManager.destroy(),
1513
+ ]);
1514
+ }
1473
1515
  }
1474
1516
  };
1475
1517
 
@@ -1507,7 +1549,6 @@ onBroadcast(msg => {
1507
1549
 
1508
1550
  {
1509
1551
  let next = 0;
1510
- let lastEmergencyUpdate = 0;
1511
1552
 
1512
1553
  const launchTimer = vAPI.defer.create(fetchDelay => {
1513
1554
  next = 0;
@@ -1516,6 +1557,7 @@ onBroadcast(msg => {
1516
1557
 
1517
1558
  µb.scheduleAssetUpdater = async function(details = {}) {
1518
1559
  launchTimer.off();
1560
+ vAPI.alarms.clear('assetUpdater');
1519
1561
 
1520
1562
  if ( details.now ) {
1521
1563
  next = 0;
@@ -1534,40 +1576,23 @@ onBroadcast(msg => {
1534
1576
  this.hiddenSettings.autoUpdatePeriod * 3600000;
1535
1577
 
1536
1578
  const now = Date.now();
1537
- let needEmergencyUpdate = false;
1538
-
1539
- // Respect cooldown period before launching an emergency update.
1540
- const timeSinceLastEmergencyUpdate = (now - lastEmergencyUpdate) / 3600000;
1541
- if ( timeSinceLastEmergencyUpdate > 1 ) {
1542
- const entries = await io.getUpdateAges({
1543
- filters: µb.selectedFilterLists,
1544
- internal: [ '*' ],
1545
- });
1546
- for ( const entry of entries ) {
1547
- if ( entry.ageNormalized < 2 ) { continue; }
1548
- needEmergencyUpdate = true;
1549
- lastEmergencyUpdate = now;
1550
- break;
1551
- }
1552
- }
1553
1579
 
1554
1580
  // Use the new schedule if and only if it is earlier than the previous
1555
1581
  // one.
1556
1582
  if ( next !== 0 ) {
1557
- updateDelay = Math.min(updateDelay, Math.max(next - now, 0));
1558
- }
1559
-
1560
- if ( needEmergencyUpdate ) {
1561
- updateDelay = Math.min(updateDelay, 15000);
1583
+ updateDelay = Math.min(updateDelay, Math.max(next - now, 1));
1562
1584
  }
1563
1585
 
1564
1586
  next = now + updateDelay;
1565
1587
 
1566
- const fetchDelay = needEmergencyUpdate
1567
- ? 2000
1568
- : this.hiddenSettings.autoUpdateAssetFetchPeriod * 1000 || 60000;
1588
+ const fetchDelay = details.fetchDelay ||
1589
+ this.hiddenSettings.autoUpdateAssetFetchPeriod * 1000 ||
1590
+ 60000;
1569
1591
 
1570
1592
  launchTimer.on(updateDelay, fetchDelay);
1593
+ vAPI.alarms.create('assetUpdater', {
1594
+ delayInMinutes: Math.ceil(updateDelay / 60000) + 0.25
1595
+ });
1571
1596
  };
1572
1597
  }
1573
1598
 
@@ -1580,7 +1605,7 @@ onBroadcast(msg => {
1580
1605
  if ( topic === 'before-asset-updated' ) {
1581
1606
  if ( details.type === 'filters' ) {
1582
1607
  if (
1583
- this.availableFilterLists.hasOwnProperty(details.assetKey) === false ||
1608
+ hasOwnProperty(this.availableFilterLists, details.assetKey) === false ||
1584
1609
  this.selectedFilterLists.indexOf(details.assetKey) === -1 ||
1585
1610
  this.badLists.get(details.assetKey)
1586
1611
  ) {
@@ -1594,9 +1619,8 @@ onBroadcast(msg => {
1594
1619
  if ( topic === 'after-asset-updated' ) {
1595
1620
  // Skip selfie-related content.
1596
1621
  if ( details.assetKey.startsWith('selfie/') ) { return; }
1597
- const cached = typeof details.content === 'string' &&
1598
- details.content !== '';
1599
- if ( this.availableFilterLists.hasOwnProperty(details.assetKey) ) {
1622
+ const cached = typeof details.content === 'string' && details.content !== '';
1623
+ if ( hasOwnProperty(this.availableFilterLists, details.assetKey) ) {
1600
1624
  if ( cached ) {
1601
1625
  if ( this.selectedFilterLists.indexOf(details.assetKey) !== -1 ) {
1602
1626
  this.extractFilterListMetadata(
@@ -1604,8 +1628,7 @@ onBroadcast(msg => {
1604
1628
  details.content
1605
1629
  );
1606
1630
  if ( this.badLists.has(details.assetKey) === false ) {
1607
- io.put(
1608
- 'compiled/' + details.assetKey,
1631
+ io.toCache(`compiled/${details.assetKey}`,
1609
1632
  this.compileFilters(details.content, {
1610
1633
  assetKey: details.assetKey,
1611
1634
  trustedSource: this.isTrustedList(details.assetKey),
@@ -590,7 +590,7 @@ const onHeadersReceived = function(details) {
590
590
  }
591
591
  };
592
592
 
593
- const reMediaContentTypes = /^(?:audio|image|video)\//;
593
+ const reMediaContentTypes = /^(?:audio|image|video)\/|(?:\/ogg)$/;
594
594
 
595
595
  /******************************************************************************/
596
596
 
@@ -749,7 +749,7 @@ const bodyFilterer = (( ) => {
749
749
  /* t */ if ( bytes[i+6] !== 0x74 ) { continue; }
750
750
  break;
751
751
  }
752
- if ( (i - 40) >= 65536 ) { return; }
752
+ if ( (i + 40) >= 65536 ) { return; }
753
753
  i += 8;
754
754
  // find first alpha character
755
755
  let j = -1;
@@ -827,13 +827,17 @@ const bodyFilterer = (( ) => {
827
827
  }
828
828
  if ( this.status !== 'finishedtransferringdata' ) { return; }
829
829
 
830
- // If encoding is still unknown, try to extract from stream data
830
+ // If encoding is still unknown, try to extract from stream data.
831
+ // Just assume utf-8 if ultimately no encoding can be looked up.
831
832
  if ( session.charset === undefined ) {
832
833
  const charsetFound = charsetFromStream(session.buffer);
833
- if ( charsetFound === undefined ) { return streamClose(session); }
834
- const charsetUsed = textEncode.normalizeCharset(charsetFound);
835
- if ( charsetUsed === undefined ) { return streamClose(session); }
836
- session.charset = charsetUsed;
834
+ if ( charsetFound !== undefined ) {
835
+ const charsetUsed = textEncode.normalizeCharset(charsetFound);
836
+ if ( charsetUsed === undefined ) { return streamClose(session); }
837
+ session.charset = charsetUsed;
838
+ } else {
839
+ session.charset = 'utf-8';
840
+ }
837
841
  }
838
842
 
839
843
  while ( session.jobs.length !== 0 ) {