@browserless.io/browserless 2.24.0 → 2.24.2

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 (81) hide show
  1. package/CHANGELOG.md +16 -3
  2. package/build/browsers/index.js +1 -1
  3. package/build/routes/chrome/http/content.post.body.json +8 -8
  4. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  5. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  6. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  7. package/build/routes/chromium/http/content.post.body.json +8 -8
  8. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  9. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  10. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  11. package/build/routes/management/http/meta.get.js +3 -1
  12. package/build/shared/utils/performance/main.js +2 -1
  13. package/extensions/ublock/_locales/ar/messages.json +3 -3
  14. package/extensions/ublock/_locales/bg/messages.json +1 -1
  15. package/extensions/ublock/_locales/br_FR/messages.json +2 -2
  16. package/extensions/ublock/_locales/cy/messages.json +11 -11
  17. package/extensions/ublock/_locales/el/messages.json +2 -2
  18. package/extensions/ublock/_locales/hu/messages.json +1 -1
  19. package/extensions/ublock/_locales/id/messages.json +1 -1
  20. package/extensions/ublock/_locales/lv/messages.json +4 -4
  21. package/extensions/ublock/_locales/mk/messages.json +130 -130
  22. package/extensions/ublock/_locales/oc/messages.json +1 -1
  23. package/extensions/ublock/_locales/pt_BR/messages.json +1 -1
  24. package/extensions/ublock/_locales/pt_PT/messages.json +2 -2
  25. package/extensions/ublock/_locales/si/messages.json +100 -100
  26. package/extensions/ublock/_locales/sr/messages.json +4 -4
  27. package/extensions/ublock/_locales/vi/messages.json +19 -19
  28. package/extensions/ublock/_locales/zh_TW/messages.json +28 -28
  29. package/extensions/ublock/assets/assets.json +33 -29
  30. package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +2984 -3287
  31. package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +150 -171
  32. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +37 -27
  33. package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +802 -888
  34. package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +2355 -2071
  35. package/extensions/ublock/assets/ublock/badlists.txt +9 -1
  36. package/extensions/ublock/assets/ublock/badware.min.txt +354 -243
  37. package/extensions/ublock/assets/ublock/filters.min.txt +5837 -5737
  38. package/extensions/ublock/assets/ublock/privacy.min.txt +151 -38
  39. package/extensions/ublock/assets/ublock/quick-fixes.min.txt +83 -127
  40. package/extensions/ublock/assets/ublock/unbreak.min.txt +66 -50
  41. package/extensions/ublock/css/codemirror.css +4 -0
  42. package/extensions/ublock/document-blocked.html +3 -1
  43. package/extensions/ublock/js/arglist-parser.js +116 -0
  44. package/extensions/ublock/js/background.js +1 -1
  45. package/extensions/ublock/js/logger-ui.js +1 -1
  46. package/extensions/ublock/js/messaging.js +9 -2
  47. package/extensions/ublock/js/pagestore.js +3 -1
  48. package/extensions/ublock/js/redirect-engine.js +3 -1
  49. package/extensions/ublock/{assets/resources/set-attr.js → js/resources/attribute.js} +115 -11
  50. package/extensions/ublock/js/resources/base.js +38 -0
  51. package/extensions/ublock/js/resources/cookie.js +419 -0
  52. package/extensions/ublock/js/resources/href-sanitizer.js +188 -0
  53. package/extensions/ublock/js/resources/localstorage.js +235 -0
  54. package/extensions/ublock/js/resources/parse-replace.js +54 -0
  55. package/extensions/ublock/js/resources/prevent-settimeout.js +236 -0
  56. package/extensions/ublock/js/resources/proxy-apply.js +109 -0
  57. package/extensions/ublock/js/resources/replace-argument.js +120 -0
  58. package/extensions/ublock/{assets → js}/resources/run-at.js +20 -4
  59. package/extensions/ublock/{assets → js}/resources/safe-self.js +5 -4
  60. package/extensions/ublock/{assets → js}/resources/scriptlets.js +90 -1589
  61. package/extensions/ublock/js/resources/set-constant.js +287 -0
  62. package/extensions/ublock/js/resources/shared.js +44 -0
  63. package/extensions/ublock/js/resources/spoof-css.js +163 -0
  64. package/extensions/ublock/js/s14e-serializer.js +2 -1
  65. package/extensions/ublock/js/scriptlet-filtering-core.js +1 -1
  66. package/extensions/ublock/js/scriptlet-filtering.js +1 -31
  67. package/extensions/ublock/js/static-dnr-filtering.js +143 -129
  68. package/extensions/ublock/js/static-filtering-parser.js +27 -117
  69. package/extensions/ublock/js/static-net-filtering.js +53 -141
  70. package/extensions/ublock/js/traffic.js +1 -1
  71. package/extensions/ublock/js/urlskip.js +166 -0
  72. package/extensions/ublock/js/vapi-background-ext.js +38 -14
  73. package/extensions/ublock/manifest.json +1 -1
  74. package/package.json +11 -11
  75. package/src/browsers/index.ts +1 -1
  76. package/src/routes/management/http/meta.get.ts +6 -1
  77. package/src/shared/utils/performance/main.ts +2 -8
  78. package/static/docs/swagger.json +10 -10
  79. package/static/docs/swagger.min.json +9 -9
  80. package/static/function/client.js +119 -18
  81. package/static/function/index.html +119 -18
@@ -18,16 +18,16 @@
18
18
 
19
19
  Home: https://github.com/gorhill/uBlock
20
20
 
21
- The scriptlets below are meant to be injected only into a
22
- web page context.
23
21
  */
24
22
 
23
+ import { registerScriptlet } from './base.js';
25
24
  import { runAt } from './run-at.js';
26
25
  import { safeSelf } from './safe-self.js';
27
26
 
28
27
  /******************************************************************************/
29
28
 
30
29
  export function setAttrFn(
30
+ trusted = false,
31
31
  logPrefix,
32
32
  selector = '',
33
33
  attr = '',
@@ -37,7 +37,7 @@ export function setAttrFn(
37
37
  if ( attr === '' ) { return; }
38
38
 
39
39
  const safe = safeSelf();
40
- const copyFrom = /^\[.+\]$/.test(value)
40
+ const copyFrom = trusted === false && /^\[.+\]$/.test(value)
41
41
  ? value.slice(1, -1)
42
42
  : '';
43
43
 
@@ -95,13 +95,13 @@ export function setAttrFn(
95
95
  };
96
96
  runAt(( ) => { start(); }, 'idle');
97
97
  }
98
- setAttrFn.details = {
98
+ registerScriptlet(setAttrFn, {
99
99
  name: 'set-attr.fn',
100
100
  dependencies: [
101
101
  runAt,
102
102
  safeSelf,
103
103
  ],
104
- };
104
+ });
105
105
 
106
106
  /**
107
107
  * @scriptlet set-attr
@@ -147,16 +147,16 @@ export function setAttr(
147
147
  }
148
148
  }
149
149
 
150
- setAttrFn(logPrefix, selector, attr, value);
150
+ setAttrFn(false, logPrefix, selector, attr, value);
151
151
  }
152
- setAttr.details = {
152
+ registerScriptlet(setAttr, {
153
153
  name: 'set-attr.js',
154
154
  dependencies: [
155
155
  safeSelf,
156
156
  setAttrFn,
157
157
  ],
158
158
  world: 'ISOLATED',
159
- };
159
+ });
160
160
 
161
161
  /**
162
162
  * @trustedScriptlet trusted-set-attr
@@ -186,9 +186,9 @@ export function trustedSetAttr(
186
186
  ) {
187
187
  const safe = safeSelf();
188
188
  const logPrefix = safe.makeLogPrefix('trusted-set-attr', selector, attr, value);
189
- setAttrFn(logPrefix, selector, attr, value);
189
+ setAttrFn(true, logPrefix, selector, attr, value);
190
190
  }
191
- trustedSetAttr.details = {
191
+ registerScriptlet(trustedSetAttr, {
192
192
  name: 'trusted-set-attr.js',
193
193
  requiresTrust: true,
194
194
  dependencies: [
@@ -196,6 +196,110 @@ trustedSetAttr.details = {
196
196
  setAttrFn,
197
197
  ],
198
198
  world: 'ISOLATED',
199
- };
199
+ });
200
+
201
+ /**
202
+ * @scriptlet remove-attr
203
+ *
204
+ * @description
205
+ * Remove one or more attributes from a set of elements.
206
+ *
207
+ * @param attribute
208
+ * The name of the attribute(s) to remove. This can be a list of space-
209
+ * separated attribute names.
210
+ *
211
+ * @param [selector]
212
+ * Optional. A CSS selector for the elements to target. Default to
213
+ * `[attribute]`, or `[attribute1],[attribute2],...` if more than one
214
+ * attribute name is specified.
215
+ *
216
+ * @param [behavior]
217
+ * Optional. Space-separated tokens which modify the default behavior.
218
+ * - `asap`: Try to remove the attribute as soon as possible. Default behavior
219
+ * is to remove the attribute(s) asynchronously.
220
+ * - `stay`: Keep trying to remove the specified attribute(s) on DOM mutations.
221
+ * */
222
+
223
+ export function removeAttr(
224
+ rawToken = '',
225
+ rawSelector = '',
226
+ behavior = ''
227
+ ) {
228
+ if ( typeof rawToken !== 'string' ) { return; }
229
+ if ( rawToken === '' ) { return; }
230
+ const safe = safeSelf();
231
+ const logPrefix = safe.makeLogPrefix('remove-attr', rawToken, rawSelector, behavior);
232
+ const tokens = safe.String_split.call(rawToken, /\s*\|\s*/);
233
+ const selector = tokens
234
+ .map(a => `${rawSelector}[${CSS.escape(a)}]`)
235
+ .join(',');
236
+ if ( safe.logLevel > 1 ) {
237
+ safe.uboLog(logPrefix, `Target selector:\n\t${selector}`);
238
+ }
239
+ const asap = /\basap\b/.test(behavior);
240
+ let timerId;
241
+ const rmattrAsync = ( ) => {
242
+ if ( timerId !== undefined ) { return; }
243
+ timerId = safe.onIdle(( ) => {
244
+ timerId = undefined;
245
+ rmattr();
246
+ }, { timeout: 17 });
247
+ };
248
+ const rmattr = ( ) => {
249
+ if ( timerId !== undefined ) {
250
+ safe.offIdle(timerId);
251
+ timerId = undefined;
252
+ }
253
+ try {
254
+ const nodes = document.querySelectorAll(selector);
255
+ for ( const node of nodes ) {
256
+ for ( const attr of tokens ) {
257
+ if ( node.hasAttribute(attr) === false ) { continue; }
258
+ node.removeAttribute(attr);
259
+ safe.uboLog(logPrefix, `Removed attribute '${attr}'`);
260
+ }
261
+ }
262
+ } catch(ex) {
263
+ }
264
+ };
265
+ const mutationHandler = mutations => {
266
+ if ( timerId !== undefined ) { return; }
267
+ let skip = true;
268
+ for ( let i = 0; i < mutations.length && skip; i++ ) {
269
+ const { type, addedNodes, removedNodes } = mutations[i];
270
+ if ( type === 'attributes' ) { skip = false; }
271
+ for ( let j = 0; j < addedNodes.length && skip; j++ ) {
272
+ if ( addedNodes[j].nodeType === 1 ) { skip = false; break; }
273
+ }
274
+ for ( let j = 0; j < removedNodes.length && skip; j++ ) {
275
+ if ( removedNodes[j].nodeType === 1 ) { skip = false; break; }
276
+ }
277
+ }
278
+ if ( skip ) { return; }
279
+ asap ? rmattr() : rmattrAsync();
280
+ };
281
+ const start = ( ) => {
282
+ rmattr();
283
+ if ( /\bstay\b/.test(behavior) === false ) { return; }
284
+ const observer = new MutationObserver(mutationHandler);
285
+ observer.observe(document, {
286
+ attributes: true,
287
+ attributeFilter: tokens,
288
+ childList: true,
289
+ subtree: true,
290
+ });
291
+ };
292
+ runAt(( ) => { start(); }, safe.String_split.call(behavior, /\s+/));
293
+ }
294
+ registerScriptlet(removeAttr, {
295
+ name: 'remove-attr.js',
296
+ aliases: [
297
+ 'ra.js',
298
+ ],
299
+ dependencies: [
300
+ runAt,
301
+ safeSelf,
302
+ ],
303
+ });
200
304
 
201
305
  /******************************************************************************/
@@ -0,0 +1,38 @@
1
+ /*******************************************************************************
2
+
3
+ uBlock Origin - a comprehensive, efficient content blocker
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
+ */
22
+
23
+ export const registeredScriptlets = [];
24
+
25
+ export const registerScriptlet = (fn, details) => {
26
+ if ( typeof details !== 'object' ) {
27
+ throw new ReferenceError('Missing scriptlet details');
28
+ }
29
+ details.fn = fn;
30
+ fn.details = details;
31
+ if ( Array.isArray(details.dependencies) ) {
32
+ details.dependencies.forEach((fn, i, array) => {
33
+ if ( typeof fn !== 'function' ) { return; }
34
+ array[i] = fn.details.name;
35
+ });
36
+ }
37
+ registeredScriptlets.push(details);
38
+ };
@@ -0,0 +1,419 @@
1
+ /*******************************************************************************
2
+
3
+ uBlock Origin - a comprehensive, efficient content blocker
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
+ */
22
+
23
+ import { registerScriptlet } from './base.js';
24
+ import { safeSelf } from './safe-self.js';
25
+
26
+ /******************************************************************************/
27
+
28
+ export function getSafeCookieValuesFn() {
29
+ return [
30
+ 'accept', 'reject',
31
+ 'accepted', 'rejected', 'notaccepted',
32
+ 'allow', 'disallow', 'deny',
33
+ 'allowed', 'denied',
34
+ 'approved', 'disapproved',
35
+ 'checked', 'unchecked',
36
+ 'dismiss', 'dismissed',
37
+ 'enable', 'disable',
38
+ 'enabled', 'disabled',
39
+ 'essential', 'nonessential',
40
+ 'forbidden', 'forever',
41
+ 'hide', 'hidden',
42
+ 'necessary', 'required',
43
+ 'ok',
44
+ 'on', 'off',
45
+ 'true', 't', 'false', 'f',
46
+ 'yes', 'y', 'no', 'n',
47
+ 'all', 'none', 'functional',
48
+ 'granted', 'done',
49
+ ];
50
+ }
51
+ registerScriptlet(getSafeCookieValuesFn, {
52
+ name: 'get-safe-cookie-values.fn',
53
+ });
54
+
55
+ /******************************************************************************/
56
+
57
+ export function getAllCookiesFn() {
58
+ const safe = safeSelf();
59
+ return safe.String_split.call(document.cookie, /\s*;\s*/).map(s => {
60
+ const pos = s.indexOf('=');
61
+ if ( pos === 0 ) { return; }
62
+ if ( pos === -1 ) { return `${s.trim()}=`; }
63
+ const key = s.slice(0, pos).trim();
64
+ const value = s.slice(pos+1).trim();
65
+ return { key, value };
66
+ }).filter(s => s !== undefined);
67
+ }
68
+ registerScriptlet(getAllCookiesFn, {
69
+ name: 'get-all-cookies.fn',
70
+ dependencies: [
71
+ safeSelf,
72
+ ],
73
+ });
74
+
75
+ /******************************************************************************/
76
+
77
+ export function getCookieFn(
78
+ name = ''
79
+ ) {
80
+ const safe = safeSelf();
81
+ for ( const s of safe.String_split.call(document.cookie, /\s*;\s*/) ) {
82
+ const pos = s.indexOf('=');
83
+ if ( pos === -1 ) { continue; }
84
+ if ( s.slice(0, pos) !== name ) { continue; }
85
+ return s.slice(pos+1).trim();
86
+ }
87
+ }
88
+ registerScriptlet(getCookieFn, {
89
+ name: 'get-cookie.fn',
90
+ dependencies: [
91
+ safeSelf,
92
+ ],
93
+ });
94
+
95
+ /******************************************************************************/
96
+
97
+ export function setCookieFn(
98
+ trusted = false,
99
+ name = '',
100
+ value = '',
101
+ expires = '',
102
+ path = '',
103
+ options = {},
104
+ ) {
105
+ // https://datatracker.ietf.org/doc/html/rfc2616#section-2.2
106
+ // https://github.com/uBlockOrigin/uBlock-issues/issues/2777
107
+ if ( trusted === false && /[^!#$%&'*+\-.0-9A-Z[\]^_`a-z|~]/.test(name) ) {
108
+ name = encodeURIComponent(name);
109
+ }
110
+ // https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1
111
+ // The characters [",] are given a pass from the RFC requirements because
112
+ // apparently browsers do not follow the RFC to the letter.
113
+ if ( /[^ -:<-[\]-~]/.test(value) ) {
114
+ value = encodeURIComponent(value);
115
+ }
116
+
117
+ const cookieBefore = getCookieFn(name);
118
+ if ( cookieBefore !== undefined && options.dontOverwrite ) { return; }
119
+ if ( cookieBefore === value && options.reload ) { return; }
120
+
121
+ const cookieParts = [ name, '=', value ];
122
+ if ( expires !== '' ) {
123
+ cookieParts.push('; expires=', expires);
124
+ }
125
+
126
+ if ( path === '' ) { path = '/'; }
127
+ else if ( path === 'none' ) { path = ''; }
128
+ if ( path !== '' && path !== '/' ) { return; }
129
+ if ( path === '/' ) {
130
+ cookieParts.push('; path=/');
131
+ }
132
+
133
+ if ( trusted ) {
134
+ if ( options.domain ) {
135
+ cookieParts.push(`; domain=${options.domain}`);
136
+ }
137
+ cookieParts.push('; Secure');
138
+ } else if ( /^__(Host|Secure)-/.test(name) ) {
139
+ cookieParts.push('; Secure');
140
+ }
141
+
142
+ try {
143
+ document.cookie = cookieParts.join('');
144
+ } catch(_) {
145
+ }
146
+
147
+ const done = getCookieFn(name) === value;
148
+ if ( done && options.reload ) {
149
+ window.location.reload();
150
+ }
151
+
152
+ return done;
153
+ }
154
+ registerScriptlet(setCookieFn, {
155
+ name: 'set-cookie.fn',
156
+ dependencies: [
157
+ getCookieFn,
158
+ ],
159
+ });
160
+
161
+ /**
162
+ * @scriptlet set-cookie
163
+ *
164
+ * @description
165
+ * Set a cookie to a safe value.
166
+ *
167
+ * @param name
168
+ * The name of the cookie to set.
169
+ *
170
+ * @param value
171
+ * The value of the cookie to set. Must be a safe value. Unsafe values will be
172
+ * ignored and no cookie will be set. See getSafeCookieValuesFn() helper above.
173
+ *
174
+ * @param [path]
175
+ * Optional. The path of the cookie to set. Default to `/`.
176
+ *
177
+ * Reference:
178
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-cookie.js
179
+ * */
180
+
181
+ export function setCookie(
182
+ name = '',
183
+ value = '',
184
+ path = ''
185
+ ) {
186
+ if ( name === '' ) { return; }
187
+ const safe = safeSelf();
188
+ const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path);
189
+ const normalized = value.toLowerCase();
190
+ const match = /^("?)(.+)\1$/.exec(normalized);
191
+ const unquoted = match && match[2] || normalized;
192
+ const validValues = getSafeCookieValuesFn();
193
+ if ( validValues.includes(unquoted) === false ) {
194
+ if ( /^-?\d+$/.test(unquoted) === false ) { return; }
195
+ const n = parseInt(value, 10) || 0;
196
+ if ( n < -32767 || n > 32767 ) { return; }
197
+ }
198
+
199
+ const done = setCookieFn(
200
+ false,
201
+ name,
202
+ value,
203
+ '',
204
+ path,
205
+ safe.getExtraArgs(Array.from(arguments), 3)
206
+ );
207
+
208
+ if ( done ) {
209
+ safe.uboLog(logPrefix, 'Done');
210
+ }
211
+ }
212
+ registerScriptlet(setCookie, {
213
+ name: 'set-cookie.js',
214
+ world: 'ISOLATED',
215
+ dependencies: [
216
+ getSafeCookieValuesFn,
217
+ safeSelf,
218
+ setCookieFn,
219
+ ],
220
+ });
221
+
222
+ // For compatibility with AdGuard
223
+ export function setCookieReload(name, value, path, ...args) {
224
+ setCookie(name, value, path, 'reload', '1', ...args);
225
+ }
226
+ registerScriptlet(setCookieReload, {
227
+ name: 'set-cookie-reload.js',
228
+ world: 'ISOLATED',
229
+ dependencies: [
230
+ setCookie,
231
+ ],
232
+ });
233
+
234
+ /**
235
+ * @trustedScriptlet trusted-set-cookie
236
+ *
237
+ * @description
238
+ * Set a cookie to any value. This scriptlet can be used only from a trusted
239
+ * source.
240
+ *
241
+ * @param name
242
+ * The name of the cookie to set.
243
+ *
244
+ * @param value
245
+ * The value of the cookie to set. Must be a safe value. Unsafe values will be
246
+ * ignored and no cookie will be set. See getSafeCookieValuesFn() helper above.
247
+ *
248
+ * @param [offsetExpiresSec]
249
+ * Optional. The path of the cookie to set. Default to `/`.
250
+ *
251
+ * @param [path]
252
+ * Optional. The path of the cookie to set. Default to `/`.
253
+ *
254
+ * Reference:
255
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-cookie.js
256
+ * */
257
+
258
+ export function trustedSetCookie(
259
+ name = '',
260
+ value = '',
261
+ offsetExpiresSec = '',
262
+ path = ''
263
+ ) {
264
+ if ( name === '' ) { return; }
265
+
266
+ const safe = safeSelf();
267
+ const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path);
268
+ const time = new Date();
269
+
270
+ if ( value.includes('$now$') ) {
271
+ value = value.replaceAll('$now$', time.getTime());
272
+ }
273
+ if ( value.includes('$currentDate$') ) {
274
+ value = value.replaceAll('$currentDate$', time.toUTCString());
275
+ }
276
+ if ( value.includes('$currentISODate$') ) {
277
+ value = value.replaceAll('$currentISODate$', time.toISOString());
278
+ }
279
+
280
+ let expires = '';
281
+ if ( offsetExpiresSec !== '' ) {
282
+ if ( offsetExpiresSec === '1day' ) {
283
+ time.setDate(time.getDate() + 1);
284
+ } else if ( offsetExpiresSec === '1year' ) {
285
+ time.setFullYear(time.getFullYear() + 1);
286
+ } else {
287
+ if ( /^\d+$/.test(offsetExpiresSec) === false ) { return; }
288
+ time.setSeconds(time.getSeconds() + parseInt(offsetExpiresSec, 10));
289
+ }
290
+ expires = time.toUTCString();
291
+ }
292
+
293
+ const done = setCookieFn(
294
+ true,
295
+ name,
296
+ value,
297
+ expires,
298
+ path,
299
+ safeSelf().getExtraArgs(Array.from(arguments), 4)
300
+ );
301
+
302
+ if ( done ) {
303
+ safe.uboLog(logPrefix, 'Done');
304
+ }
305
+ }
306
+ registerScriptlet(trustedSetCookie, {
307
+ name: 'trusted-set-cookie.js',
308
+ requiresTrust: true,
309
+ world: 'ISOLATED',
310
+ dependencies: [
311
+ safeSelf,
312
+ setCookieFn,
313
+ ],
314
+ });
315
+
316
+ // For compatibility with AdGuard
317
+ export function trustedSetCookieReload(name, value, offsetExpiresSec, path, ...args) {
318
+ trustedSetCookie(name, value, offsetExpiresSec, path, 'reload', '1', ...args);
319
+ }
320
+ registerScriptlet(trustedSetCookieReload, {
321
+ name: 'trusted-set-cookie-reload.js',
322
+ requiresTrust: true,
323
+ world: 'ISOLATED',
324
+ dependencies: [
325
+ trustedSetCookie,
326
+ ],
327
+ });
328
+
329
+ /**
330
+ * @scriptlet remove-cookie
331
+ *
332
+ * @description
333
+ * Removes current site cookies specified by name. The removal operation occurs
334
+ * immediately when the scriptlet is injected, then when the page is unloaded.
335
+ *
336
+ * @param needle
337
+ * A string or a regex matching the name of the cookie(s) to remove.
338
+ *
339
+ * @param ['when', token]
340
+ * Vararg, optional. The parameter following 'when' tells when extra removal
341
+ * operations should take place.
342
+ * - `scroll`: when the page is scrolled
343
+ * - `keydown`: when a keyboard touch is pressed
344
+ *
345
+ * */
346
+
347
+ export function removeCookie(
348
+ needle = ''
349
+ ) {
350
+ if ( typeof needle !== 'string' ) { return; }
351
+ const safe = safeSelf();
352
+ const reName = safe.patternToRegex(needle);
353
+ const extraArgs = safe.getExtraArgs(Array.from(arguments), 1);
354
+ const throttle = (fn, ms = 500) => {
355
+ if ( throttle.timer !== undefined ) { return; }
356
+ throttle.timer = setTimeout(( ) => {
357
+ throttle.timer = undefined;
358
+ fn();
359
+ }, ms);
360
+ };
361
+ const remove = ( ) => {
362
+ safe.String_split.call(document.cookie, ';').forEach(cookieStr => {
363
+ const pos = cookieStr.indexOf('=');
364
+ if ( pos === -1 ) { return; }
365
+ const cookieName = cookieStr.slice(0, pos).trim();
366
+ if ( reName.test(cookieName) === false ) { return; }
367
+ const part1 = cookieName + '=';
368
+ const part2a = '; domain=' + document.location.hostname;
369
+ const part2b = '; domain=.' + document.location.hostname;
370
+ let part2c, part2d;
371
+ const domain = document.domain;
372
+ if ( domain ) {
373
+ if ( domain !== document.location.hostname ) {
374
+ part2c = '; domain=.' + domain;
375
+ }
376
+ if ( domain.startsWith('www.') ) {
377
+ part2d = '; domain=' + domain.replace('www', '');
378
+ }
379
+ }
380
+ const part3 = '; path=/';
381
+ const part4 = '; Max-Age=-1000; expires=Thu, 01 Jan 1970 00:00:00 GMT';
382
+ document.cookie = part1 + part4;
383
+ document.cookie = part1 + part2a + part4;
384
+ document.cookie = part1 + part2b + part4;
385
+ document.cookie = part1 + part3 + part4;
386
+ document.cookie = part1 + part2a + part3 + part4;
387
+ document.cookie = part1 + part2b + part3 + part4;
388
+ if ( part2c !== undefined ) {
389
+ document.cookie = part1 + part2c + part3 + part4;
390
+ }
391
+ if ( part2d !== undefined ) {
392
+ document.cookie = part1 + part2d + part3 + part4;
393
+ }
394
+ });
395
+ };
396
+ remove();
397
+ window.addEventListener('beforeunload', remove);
398
+ if ( typeof extraArgs.when !== 'string' ) { return; }
399
+ const supportedEventTypes = [ 'scroll', 'keydown' ];
400
+ const eventTypes = safe.String_split.call(extraArgs.when, /\s/);
401
+ for ( const type of eventTypes ) {
402
+ if ( supportedEventTypes.includes(type) === false ) { continue; }
403
+ document.addEventListener(type, ( ) => {
404
+ throttle(remove);
405
+ }, { passive: true });
406
+ }
407
+ }
408
+ registerScriptlet(removeCookie, {
409
+ name: 'remove-cookie.js',
410
+ aliases: [
411
+ 'cookie-remover.js',
412
+ ],
413
+ world: 'ISOLATED',
414
+ dependencies: [
415
+ safeSelf,
416
+ ],
417
+ });
418
+
419
+ /******************************************************************************/