@adguard/agtree 1.1.4 → 1.1.5

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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- * AGTree v1.1.4 (build date: Wed, 30 Aug 2023 10:02:46 GMT)
2
+ * AGTree v1.1.5 (build date: Tue, 05 Sep 2023 15:10:53 GMT)
3
3
  * (c) 2023 AdGuard Software Ltd.
4
4
  * Released under the MIT license
5
5
  * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
@@ -13,7 +13,7 @@ export { ecssTree as ECSSTree };
13
13
  import cloneDeep from 'clone-deep';
14
14
  import XRegExp from 'xregexp';
15
15
  import { parse as parse$1 } from 'tldts';
16
- import { redirects } from '@adguard/scriptlets';
16
+ import scriptlets from '@adguard/scriptlets';
17
17
 
18
18
  /**
19
19
  * @file Possible adblock syntaxes are listed here.
@@ -69,6 +69,9 @@ var AdblockSyntax;
69
69
  * @file Constant values used by all parts of the library
70
70
  */
71
71
  // General
72
+ /**
73
+ * Empty string.
74
+ */
72
75
  const EMPTY = '';
73
76
  const SPACE = ' ';
74
77
  const TAB = '\t';
@@ -6125,7 +6128,7 @@ var data$N = { adg_os_any:{ name:"csp",
6125
6128
  assignable:true,
6126
6129
  negatable:false,
6127
6130
  value_optional:true,
6128
- value_format:"(?xi)\n ^(\n base-uri|\n child-src|\n connect-src|\n default-src|\n font-src|\n form-action|\n frame-ancestors|\n frame-src|\n img-src|\n manifest-src|\n media-src|\n navigate-to|\n object-src|\n plugin-types|\n prefetch-src|\n report-to|\n report-uri|\n sandbox|\n script-src|\n style-src|\n upgrade-insecure-requests|\n worker-src|\n )\n \\s+\n \\S{1,}" },
6131
+ value_format:"csp_value" },
6129
6132
  adg_ext_any:{ name:"csp",
6130
6133
  description:"This modifier completely changes the rule behavior.\nIf it is applied to a rule, it will not block the matching request.\nThe response headers are going to be modified instead.",
6131
6134
  docs:"https://adguard.app/kb/general/ad-filtering/create-own-filters/#csp-modifier",
@@ -6137,7 +6140,7 @@ var data$N = { adg_os_any:{ name:"csp",
6137
6140
  assignable:true,
6138
6141
  negatable:false,
6139
6142
  value_optional:true,
6140
- value_format:"(?xi)\n ^(\n base-uri|\n child-src|\n connect-src|\n default-src|\n font-src|\n form-action|\n frame-ancestors|\n frame-src|\n img-src|\n manifest-src|\n media-src|\n navigate-to|\n object-src|\n plugin-types|\n prefetch-src|\n report-to|\n report-uri|\n sandbox|\n script-src|\n style-src|\n upgrade-insecure-requests|\n worker-src|\n )\n \\s+\n \\S{1,}" },
6143
+ value_format:"csp_value" },
6141
6144
  abp_ext_any:{ name:"csp",
6142
6145
  description:"This modifier completely changes the rule behavior.\nIf it is applied to a rule, it will not block the matching request.\nThe response headers are going to be modified instead.",
6143
6146
  docs:"https://help.adblockplus.org/hc/en-us/articles/360062733293-How-to-write-filters#content-security-policies",
@@ -6147,7 +6150,7 @@ var data$N = { adg_os_any:{ name:"csp",
6147
6150
  assignable:true,
6148
6151
  negatable:false,
6149
6152
  value_optional:true,
6150
- value_format:"(?xi)\n ^(\n base-uri|\n child-src|\n connect-src|\n default-src|\n font-src|\n form-action|\n frame-ancestors|\n frame-src|\n img-src|\n manifest-src|\n media-src|\n navigate-to|\n object-src|\n plugin-types|\n prefetch-src|\n report-to|\n report-uri|\n sandbox|\n script-src|\n style-src|\n upgrade-insecure-requests|\n worker-src|\n )\n \\s+\n \\S{1,}" },
6153
+ value_format:"csp_value" },
6151
6154
  ubo_ext_any:{ name:"csp",
6152
6155
  description:"This modifier completely changes the rule behavior.\nIf it is applied to a rule, it will not block the matching request.\nThe response headers are going to be modified instead.",
6153
6156
  docs:"https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#csp",
@@ -6159,7 +6162,7 @@ var data$N = { adg_os_any:{ name:"csp",
6159
6162
  assignable:true,
6160
6163
  negatable:false,
6161
6164
  value_optional:true,
6162
- value_format:"(?xi)\n ^(\n base-uri|\n child-src|\n connect-src|\n default-src|\n font-src|\n form-action|\n frame-ancestors|\n frame-src|\n img-src|\n manifest-src|\n media-src|\n navigate-to|\n object-src|\n plugin-types|\n prefetch-src|\n report-to|\n report-uri|\n sandbox|\n script-src|\n style-src|\n upgrade-insecure-requests|\n worker-src|\n )\n \\s+\n \\S{1,}" } };
6165
+ value_format:"csp_value" } };
6163
6166
 
6164
6167
  var data$M = { adg_os_any:{ name:"denyallow",
6165
6168
  description:"The `$denyallow` modifier allows to avoid creating additional rules\nwhen it is needed to disable a certain rule for specific domains.\n`$denyallow` matches only target domains and not referrer domains.",
@@ -6666,7 +6669,8 @@ var data$l = { adg_os_any:{ name:"permissions",
6666
6669
  inverse_conflicts:true,
6667
6670
  assignable:true,
6668
6671
  negatable:false,
6669
- value_format:"(?x)\n ^\n (\n ?:(\n accelerometer|\n ambient-light-sensor|\n autoplay|\n battery|\n camera|\n display-capture|\n document-domain|\n encrypted-media|\n execution-while-not-rendered|\n execution-while-out-of-viewport|\n fullscreen|\n gamepad|\n geolocation|\n gyroscope|\n hid|\n identity-credentials-get|\n idle-detection|\n local-fonts|\n magnetometer|\n microphone|\n midi|\n payment|\n picture-in-picture|\n publickey-credentials-create|\n publickey-credentials-get|\n screen-wake-lock|\n serial|\n speaker-selection|\n storage-access|\n usb|\n web-share|\n xr-spatial-tracking\n )\n =\\(\\)\n # optional escaped comma for multiple permissions\n (\\\\,(\\s+)?)?\n )+\n $" } };
6672
+ value_optional:true,
6673
+ value_format:"permissions_value" } };
6670
6674
 
6671
6675
  var data$k = { adg_any:{ name:"ping",
6672
6676
  description:"The rule corresponds to requests caused by either navigator.sendBeacon() or the ping attribute on links.",
@@ -7327,15 +7331,104 @@ const ALLOWED_STEALTH_OPTIONS = new Set([
7327
7331
  'xclientdata',
7328
7332
  'dpi',
7329
7333
  ]);
7334
+ /**
7335
+ * Allowed CSP directives for $csp modifier.
7336
+ *
7337
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#directives}
7338
+ */
7339
+ const ALLOWED_CSP_DIRECTIVES = new Set([
7340
+ 'base-uri',
7341
+ 'child-src',
7342
+ 'connect-src',
7343
+ 'default-src',
7344
+ 'font-src',
7345
+ 'form-action',
7346
+ 'frame-ancestors',
7347
+ 'frame-src',
7348
+ 'img-src',
7349
+ 'manifest-src',
7350
+ 'media-src',
7351
+ 'navigate-to',
7352
+ 'object-src',
7353
+ 'plugin-types',
7354
+ 'prefetch-src',
7355
+ 'report-to',
7356
+ 'report-uri',
7357
+ 'sandbox',
7358
+ 'script-src',
7359
+ 'style-src',
7360
+ 'upgrade-insecure-requests',
7361
+ 'worker-src',
7362
+ ]);
7363
+ /**
7364
+ * Allowed stealth options for $permissions modifier.
7365
+ *
7366
+ * @see {@link https://adguard.app/kb/general/ad-filtering/create-own-filters/#permissions-modifier}
7367
+ */
7368
+ const ALLOWED_PERMISSION_DIRECTIVES = new Set([
7369
+ 'accelerometer',
7370
+ 'ambient-light-sensor',
7371
+ 'autoplay',
7372
+ 'battery',
7373
+ 'camera',
7374
+ 'display-capture',
7375
+ 'document-domain',
7376
+ 'encrypted-media',
7377
+ 'execution-while-not-rendered',
7378
+ 'execution-while-out-of-viewport',
7379
+ 'fullscreen',
7380
+ 'gamepad',
7381
+ 'geolocation',
7382
+ 'gyroscope',
7383
+ 'hid',
7384
+ 'identity-credentials-get',
7385
+ 'idle-detection',
7386
+ 'local-fonts',
7387
+ 'magnetometer',
7388
+ 'microphone',
7389
+ 'midi',
7390
+ 'payment',
7391
+ 'picture-in-picture',
7392
+ 'publickey-credentials-create',
7393
+ 'publickey-credentials-get',
7394
+ 'screen-wake-lock',
7395
+ 'serial',
7396
+ 'speaker-selection',
7397
+ 'storage-access',
7398
+ 'usb',
7399
+ 'web-share',
7400
+ 'xr-spatial-tracking',
7401
+ ]);
7402
+ /**
7403
+ * One of available tokens for $permission modifier value.
7404
+ *
7405
+ * @see {@link https://w3c.github.io/webappsec-permissions-policy/#structured-header-serialization}
7406
+ */
7407
+ const PERMISSIONS_TOKEN_SELF = 'self';
7408
+ /**
7409
+ * One of allowlist values for $permissions modifier.
7410
+ *
7411
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Permissions_Policy#allowlists}
7412
+ */
7413
+ const EMPTY_PERMISSIONS_ALLOWLIST = `${OPEN_PARENTHESIS}${CLOSE_PARENTHESIS}`;
7330
7414
  /**
7331
7415
  * Prefixes for error messages used in modifier validation.
7332
7416
  */
7333
7417
  const VALIDATION_ERROR_PREFIX = {
7334
7418
  BLOCK_ONLY: 'Only blocking rules may contain the modifier',
7335
7419
  EXCEPTION_ONLY: 'Only exception rules may contain the modifier',
7420
+ INVALID_CSP_DIRECTIVES: 'Invalid CSP directives for the modifier',
7336
7421
  INVALID_LIST_VALUES: 'Invalid values for the modifier',
7337
7422
  INVALID_NOOP: 'Invalid noop modifier',
7423
+ INVALID_PERMISSION_DIRECTIVE: 'Invalid Permissions-Policy directive for the modifier',
7424
+ INVALID_PERMISSION_ORIGINS: 'Origins in the value is invalid for the modifier and the directive',
7425
+ INVALID_PERMISSION_ORIGIN_QUOTES: 'Double quotes should be used for origins in the value of the modifier',
7338
7426
  MIXED_NEGATIONS: 'Simultaneous usage of negated and not negated values is forbidden for the modifier',
7427
+ NO_CSP_VALUE: 'No CSP value for the modifier and the directive',
7428
+ NO_CSP_DIRECTIVE_QUOTE: 'CSP directives should no be quoted for the modifier',
7429
+ NO_UNESCAPED_PERMISSION_COMMA: 'Unescaped comma in the value is not allowed for the modifier',
7430
+ // TODO: implement later for $scp and $permissions
7431
+ // NO_VALUE_ONLY_FOR_EXCEPTION: 'Modifier without value can be used only in exception rules',
7339
7432
  NOT_EXISTENT: 'Non-existent modifier',
7340
7433
  NOT_NEGATABLE_MODIFIER: 'Non-negatable modifier',
7341
7434
  NOT_NEGATABLE_VALUE: 'Values cannot be negated for the modifier',
@@ -7647,10 +7740,12 @@ class QuoteUtils {
7647
7740
  var CustomValueFormatValidatorName;
7648
7741
  (function (CustomValueFormatValidatorName) {
7649
7742
  CustomValueFormatValidatorName["App"] = "pipe_separated_apps";
7743
+ CustomValueFormatValidatorName["Csp"] = "csp_value";
7650
7744
  // there are some differences between $domain and $denyallow
7651
7745
  CustomValueFormatValidatorName["DenyAllow"] = "pipe_separated_denyallow_domains";
7652
7746
  CustomValueFormatValidatorName["Domain"] = "pipe_separated_domains";
7653
7747
  CustomValueFormatValidatorName["Method"] = "pipe_separated_methods";
7748
+ CustomValueFormatValidatorName["Permissions"] = "permissions_value";
7654
7749
  CustomValueFormatValidatorName["StealthOption"] = "pipe_separated_stealth_options";
7655
7750
  })(CustomValueFormatValidatorName || (CustomValueFormatValidatorName = {}));
7656
7751
  /**
@@ -7711,6 +7806,32 @@ const isValidMethodModifierValue = (value) => {
7711
7806
  const isValidStealthModifierValue = (value) => {
7712
7807
  return ALLOWED_STEALTH_OPTIONS.has(value);
7713
7808
  };
7809
+ /**
7810
+ * Checks whether the given `rawOrigin` is valid as Permissions Allowlist origin.
7811
+ *
7812
+ * @see {@link https://w3c.github.io/webappsec-permissions-policy/#allowlists}
7813
+ *
7814
+ * @param rawOrigin The raw origin.
7815
+ *
7816
+ * @returns True if the origin is valid, false otherwise.
7817
+ */
7818
+ const isValidPermissionsOrigin = (rawOrigin) => {
7819
+ // origins should be quoted by double quote
7820
+ const actualQuoteType = QuoteUtils.getStringQuoteType(rawOrigin);
7821
+ if (actualQuoteType !== QuoteType.Double) {
7822
+ return false;
7823
+ }
7824
+ const origin = QuoteUtils.removeQuotes(rawOrigin);
7825
+ try {
7826
+ // validate the origin by URL constructor
7827
+ // https://w3c.github.io/webappsec-permissions-policy/#algo-parse-policy-directive
7828
+ new URL(origin);
7829
+ }
7830
+ catch (e) {
7831
+ return false;
7832
+ }
7833
+ return true;
7834
+ };
7714
7835
  /**
7715
7836
  * Checks whether the given `value` is valid domain as $denyallow modifier value.
7716
7837
  * Important: wildcard tld are not supported, compared to $domain.
@@ -7901,14 +8022,196 @@ const validatePipeSeparatedMethods = (modifier) => {
7901
8022
  const validatePipeSeparatedStealthOptions = (modifier) => {
7902
8023
  return validateListItemsModifier(modifier, (raw) => StealthOptionListParser.parse(raw), isValidStealthModifierValue, customNoNegatedListItemsValidator);
7903
8024
  };
8025
+ /**
8026
+ * Validates `csp_value` custom value format.
8027
+ * Used for $csp modifier.
8028
+ *
8029
+ * @param modifier Modifier AST node.
8030
+ *
8031
+ * @returns Validation result.
8032
+ */
8033
+ const validateCspValue = (modifier) => {
8034
+ const modifierName = modifier.modifier.value;
8035
+ if (!modifier.value?.value) {
8036
+ return getValueRequiredValidationResult(modifierName);
8037
+ }
8038
+ // $csp modifier value may contain multiple directives
8039
+ // e.g. "csp=child-src 'none'; frame-src 'self' *; worker-src 'none'"
8040
+ const policyDirectives = modifier.value.value
8041
+ .split(SEMICOLON)
8042
+ // rule with $csp modifier may end with semicolon
8043
+ // e.g. "$csp=sandbox allow-same-origin;"
8044
+ // TODO: add predicate helper for `(i) => !!i`
8045
+ .filter((i) => !!i);
8046
+ const invalidValueValidationResult = getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.VALUE_INVALID}: '${modifierName}': "${modifier.value.value}"`);
8047
+ if (policyDirectives.length === 0) {
8048
+ return invalidValueValidationResult;
8049
+ }
8050
+ const invalidDirectives = [];
8051
+ for (let i = 0; i < policyDirectives.length; i += 1) {
8052
+ const policyDirective = policyDirectives[i].trim();
8053
+ if (!policyDirective) {
8054
+ return invalidValueValidationResult;
8055
+ }
8056
+ const chunks = policyDirective.split(SPACE);
8057
+ const [directive, ...valueChunks] = chunks;
8058
+ // e.g. "csp=child-src 'none'; ; worker-src 'none'"
8059
+ // validator it here ↑
8060
+ if (!directive) {
8061
+ return invalidValueValidationResult;
8062
+ }
8063
+ if (!ALLOWED_CSP_DIRECTIVES.has(directive)) {
8064
+ // e.g. "csp='child-src' 'none'"
8065
+ if (ALLOWED_CSP_DIRECTIVES.has(QuoteUtils.removeQuotes(directive))) {
8066
+ return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.NO_CSP_DIRECTIVE_QUOTE}: '${modifierName}': ${directive}`);
8067
+ }
8068
+ invalidDirectives.push(directive);
8069
+ continue;
8070
+ }
8071
+ if (valueChunks.length === 0) {
8072
+ return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.NO_CSP_VALUE}: '${modifierName}': '${directive}'`);
8073
+ }
8074
+ }
8075
+ if (invalidDirectives.length > 0) {
8076
+ const directivesToStr = QuoteUtils.quoteAndJoinStrings(invalidDirectives, QuoteType.Double);
8077
+ return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.INVALID_CSP_DIRECTIVES}: '${modifierName}': ${directivesToStr}`);
8078
+ }
8079
+ return { valid: true };
8080
+ };
8081
+ /**
8082
+ * Validates permission allowlist origins in the value of $permissions modifier.
8083
+ *
8084
+ * @see {@link https://w3c.github.io/webappsec-permissions-policy/#allowlists}
8085
+ *
8086
+ * @param allowlistChunks Array of allowlist chunks.
8087
+ * @param directive Permission directive name.
8088
+ * @param modifierName Modifier name.
8089
+ *
8090
+ * @returns Validation result.
8091
+ */
8092
+ const validatePermissionAllowlistOrigins = (allowlistChunks, directive, modifierName) => {
8093
+ const invalidOrigins = [];
8094
+ for (let i = 0; i < allowlistChunks.length; i += 1) {
8095
+ const chunk = allowlistChunks[i].trim();
8096
+ // skip few spaces between origins (they were splitted by space)
8097
+ // e.g. 'geolocation=("https://example.com" "https://*.example.com")'
8098
+ if (chunk.length === 0) {
8099
+ continue;
8100
+ }
8101
+ /**
8102
+ * 'self' should be checked case-insensitively
8103
+ *
8104
+ * @see {@link https://w3c.github.io/webappsec-permissions-policy/#algo-parse-policy-directive}
8105
+ *
8106
+ * @example 'geolocation=(self)'
8107
+ */
8108
+ if (chunk.toLowerCase() === PERMISSIONS_TOKEN_SELF) {
8109
+ continue;
8110
+ }
8111
+ if (QuoteUtils.getStringQuoteType(chunk) !== QuoteType.Double) {
8112
+ return getInvalidValidationResult(
8113
+ // eslint-disable-next-line max-len
8114
+ `${VALIDATION_ERROR_PREFIX.INVALID_PERMISSION_ORIGIN_QUOTES}: '${modifierName}': '${directive}': '${QuoteUtils.removeQuotes(chunk)}'`);
8115
+ }
8116
+ if (!isValidPermissionsOrigin(chunk)) {
8117
+ invalidOrigins.push(chunk);
8118
+ }
8119
+ }
8120
+ if (invalidOrigins.length > 0) {
8121
+ const originsToStr = QuoteUtils.quoteAndJoinStrings(invalidOrigins);
8122
+ return getInvalidValidationResult(
8123
+ // eslint-disable-next-line max-len
8124
+ `${VALIDATION_ERROR_PREFIX.INVALID_PERMISSION_ORIGINS}: '${modifierName}': '${directive}': ${originsToStr}`);
8125
+ }
8126
+ return { valid: true };
8127
+ };
8128
+ /**
8129
+ * Validates permission allowlist in the modifier value.
8130
+ *
8131
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Permissions_Policy#allowlists}
8132
+ * @see {@link https://w3c.github.io/webappsec-permissions-policy/#allowlists}
8133
+ *
8134
+ * @param allowlist Allowlist value.
8135
+ * @param directive Permission directive name.
8136
+ * @param modifierName Modifier name.
8137
+ *
8138
+ * @returns Validation result.
8139
+ */
8140
+ const validatePermissionAllowlist = (allowlist, directive, modifierName) => {
8141
+ // `*` is one of available permissions tokens
8142
+ // e.g. 'fullscreen=*'
8143
+ // https://w3c.github.io/webappsec-permissions-policy/#structured-header-serialization
8144
+ if (allowlist === WILDCARD$1
8145
+ // e.g. 'autoplay=()'
8146
+ || allowlist === EMPTY_PERMISSIONS_ALLOWLIST) {
8147
+ return { valid: true };
8148
+ }
8149
+ if (!(allowlist.startsWith(OPEN_PARENTHESIS) && allowlist.endsWith(CLOSE_PARENTHESIS))) {
8150
+ return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.VALUE_INVALID}: '${modifierName}'`);
8151
+ }
8152
+ const allowlistChunks = allowlist.slice(1, -1).split(SPACE);
8153
+ return validatePermissionAllowlistOrigins(allowlistChunks, directive, modifierName);
8154
+ };
8155
+ /**
8156
+ * Validates single permission in the modifier value.
8157
+ *
8158
+ * @param permission Single permission value.
8159
+ * @param modifierName Modifier name.
8160
+ * @param modifierValue Modifier value.
8161
+ *
8162
+ * @returns Validation result.
8163
+ */
8164
+ const validateSinglePermission = (permission, modifierName, modifierValue) => {
8165
+ // empty permission in the rule
8166
+ // e.g. 'permissions=storage-access=()\\, \\, camera=()'
8167
+ // the validator is here ↑
8168
+ if (!permission) {
8169
+ return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.VALUE_INVALID}: '${modifierName}'`);
8170
+ }
8171
+ if (permission.includes(COMMA)) {
8172
+ return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.NO_UNESCAPED_PERMISSION_COMMA}: '${modifierName}': '${modifierValue}'`);
8173
+ }
8174
+ const [directive, allowlist] = permission.split(EQUALS);
8175
+ if (!ALLOWED_PERMISSION_DIRECTIVES.has(directive)) {
8176
+ return getInvalidValidationResult(`${VALIDATION_ERROR_PREFIX.INVALID_PERMISSION_DIRECTIVE}: '${modifierName}': '${directive}'`);
8177
+ }
8178
+ return validatePermissionAllowlist(allowlist, directive, modifierName);
8179
+ };
8180
+ /**
8181
+ * Validates `permissions_value` custom value format.
8182
+ * Used for $permissions modifier.
8183
+ *
8184
+ * @param modifier Modifier AST node.
8185
+ *
8186
+ * @returns Validation result.
8187
+ */
8188
+ const validatePermissions = (modifier) => {
8189
+ if (!modifier.value?.value) {
8190
+ return getValueRequiredValidationResult(modifier.modifier.value);
8191
+ }
8192
+ const modifierName = modifier.modifier.value;
8193
+ const modifierValue = modifier.value.value;
8194
+ // multiple permissions may be separated by escaped commas
8195
+ const permissions = modifier.value.value.split(`${BACKSLASH}${COMMA}`);
8196
+ for (let i = 0; i < permissions.length; i += 1) {
8197
+ const permission = permissions[i].trim();
8198
+ const singlePermissionValidationResult = validateSinglePermission(permission, modifierName, modifierValue);
8199
+ if (!singlePermissionValidationResult.valid) {
8200
+ return singlePermissionValidationResult;
8201
+ }
8202
+ }
8203
+ return { valid: true };
8204
+ };
7904
8205
  /**
7905
8206
  * Map of all available pre-defined validators for modifiers with custom `value_format`.
7906
8207
  */
7907
8208
  const CUSTOM_VALUE_FORMAT_MAP = {
7908
8209
  [CustomValueFormatValidatorName.App]: validatePipeSeparatedApps,
8210
+ [CustomValueFormatValidatorName.Csp]: validateCspValue,
7909
8211
  [CustomValueFormatValidatorName.DenyAllow]: validatePipeSeparatedDenyAllowDomains,
7910
8212
  [CustomValueFormatValidatorName.Domain]: validatePipeSeparatedDomains,
7911
8213
  [CustomValueFormatValidatorName.Method]: validatePipeSeparatedMethods,
8214
+ [CustomValueFormatValidatorName.Permissions]: validatePermissions,
7912
8215
  [CustomValueFormatValidatorName.StealthOption]: validatePipeSeparatedStealthOptions,
7913
8216
  };
7914
8217
  /**
@@ -8011,6 +8314,10 @@ const validateForSpecificSyntax = (modifiersData, syntax, modifier, isException)
8011
8314
  // e.g. 'domain'
8012
8315
  if (specificBlockerData[SpecificKey.Assignable]) {
8013
8316
  if (!modifier.value) {
8317
+ // TODO: ditch value_optional after custom validators are implemented for value_format for all modifiers.
8318
+ // This checking should be done in each separate custom validator,
8319
+ // because $csp and $permissions without value can be used only in extension rules,
8320
+ // but $cookie with no value can be used in both blocking and exception rules.
8014
8321
  /**
8015
8322
  * Some assignable modifiers can be used without a value,
8016
8323
  * e.g. '@@||example.com^$cookie'.
@@ -9260,6 +9567,11 @@ class CosmeticRuleConverter extends RuleConverterBase {
9260
9567
  /**
9261
9568
  * @file Network rule modifier list converter.
9262
9569
  */
9570
+ // Since scriptlets library doesn't have ESM exports, we should import
9571
+ // the whole module and then extract the required functions from it here.
9572
+ // Otherwise importing AGTree will cause an error in ESM environment,
9573
+ // because scriptlets library doesn't support named exports.
9574
+ const { redirects } = scriptlets;
9263
9575
  /**
9264
9576
  * @see {@link https://adguard.com/kb/general/ad-filtering/create-own-filters/#csp-modifier}
9265
9577
  */
@@ -9596,7 +9908,7 @@ class LogicalExpressionUtils {
9596
9908
  }
9597
9909
  }
9598
9910
 
9599
- const version$1 = "1.1.4";
9911
+ const version$1 = "1.1.5";
9600
9912
 
9601
9913
  /**
9602
9914
  * @file AGTree version