Skip to content

Commit

Permalink
AG-24592: support for $method in mv3 converter
Browse files Browse the repository at this point in the history
Merge in ADGUARD-FILTERS/tsurlfilter from feature/AG-24592 to master

Squashed commit of the following:

commit 1ab1e88
Merge: 9db8fbd fd2c7fa
Author: Dmitriy Seregin <[email protected]>
Date:   Wed Aug 9 18:36:41 2023 +0400

    Merge branch 'master' into feature/AG-24592

commit 9db8fbd
Author: Dmitriy Seregin <[email protected]>
Date:   Wed Aug 9 18:29:11 2023 +0400

    fix

commit a6bd4a1
Author: Dmitriy Seregin <[email protected]>
Date:   Tue Aug 8 15:38:33 2023 +0400

    AG-24592: support for $method in mv3 converter
  • Loading branch information
105th committed Aug 9, 2023
1 parent fd2c7fa commit fd3ec59
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 15 deletions.
2 changes: 2 additions & 0 deletions packages/tsurlfilter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- Support for `$to` modifier in the MV3 converter.
- Support for `$method` modifier in the MV3 converter.


## [2.1.6] - 2023-08-04

Expand Down
130 changes: 124 additions & 6 deletions packages/tsurlfilter/src/rules/declarative-converter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ the blocking rule will not be applied despite it has the `$important` modifier
```
<a name="basic_modifiers__$method"></a>
## $method
<b>Status</b>: not implemented yet
<b>Status</b>: supported
<br/>
<b>Examples:</b>
<br/>
Expand All @@ -897,7 +897,37 @@ example 1
↓↓↓↓ converted to ↓↓↓↓

```json
[]
[
{
"id": 1,
"action": {
"type": "block"
},
"condition": {
"urlFilter": "||evil.com^",
"requestMethods": [
"get",
"head"
],
"isUrlFilterCaseSensitive": false,
"resourceTypes": [
"main_frame",
"sub_frame",
"stylesheet",
"script",
"image",
"font",
"object",
"xmlhttprequest",
"ping",
"media",
"websocket",
"other"
]
},
"priority": 76
}
]

```
example 2
Expand All @@ -909,7 +939,37 @@ example 2
↓↓↓↓ converted to ↓↓↓↓

```json
[]
[
{
"id": 1,
"action": {
"type": "block"
},
"condition": {
"urlFilter": "||evil.com^",
"excludedRequestMethods": [
"post",
"put"
],
"isUrlFilterCaseSensitive": false,
"resourceTypes": [
"main_frame",
"sub_frame",
"stylesheet",
"script",
"image",
"font",
"object",
"xmlhttprequest",
"ping",
"media",
"websocket",
"other"
]
},
"priority": 2
}
]

```
example 3
Expand All @@ -921,7 +981,36 @@ example 3
↓↓↓↓ converted to ↓↓↓↓

```json
[]
[
{
"id": 1,
"action": {
"type": "allow"
},
"condition": {
"urlFilter": "||evil.com",
"requestMethods": [
"get"
],
"isUrlFilterCaseSensitive": false,
"resourceTypes": [
"main_frame",
"sub_frame",
"stylesheet",
"script",
"image",
"font",
"object",
"xmlhttprequest",
"ping",
"media",
"websocket",
"other"
]
},
"priority": 100101
}
]

```
example 4
Expand All @@ -933,7 +1022,36 @@ example 4
↓↓↓↓ converted to ↓↓↓↓

```json
[]
[
{
"id": 1,
"action": {
"type": "allow"
},
"condition": {
"urlFilter": "||evil.com",
"excludedRequestMethods": [
"post"
],
"isUrlFilterCaseSensitive": false,
"resourceTypes": [
"main_frame",
"sub_frame",
"stylesheet",
"script",
"image",
"font",
"object",
"xmlhttprequest",
"ping",
"media",
"websocket",
"other"
]
},
"priority": 100002
}
]

```
<a name="basic_modifiers__$popup"></a>
Expand Down Expand Up @@ -3663,4 +3781,4 @@ example 1.
<a name="not_supported_in_extension__$app_(not_supported_in_extension)"></a>
## $app (not supported in extension)
<a name="not_supported_in_extension__$extension_(not_supported_in_extension)"></a>
## $extension (not supported in extension)
## $extension (not supported in extension)
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { z as zod } from 'zod';

import { RequestType } from '../../request-type';
import { HTTPMethod } from '../../modifiers/method-modifier';

/**
* https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-DomainType
Expand Down Expand Up @@ -150,6 +151,26 @@ export enum RequestMethod {
Put = 'put',
}

/**
* tsurlfilter {@link HTTPMethod} without {@link HTTPMethod.TRACE}
* because it is not supported by {@link RequestMethod}.
*/
export type SupportedHttpMethod = Exclude<HTTPMethod, HTTPMethod.TRACE>;

/**
* Map {@link HTTPMethod} to declarative {@link RequestMethod}.
*/
export const DECLARATIVE_REQUEST_METHOD_MAP: Record<SupportedHttpMethod, RequestMethod> = {
[HTTPMethod.GET]: RequestMethod.Get,
[HTTPMethod.POST]: RequestMethod.Post,
[HTTPMethod.PUT]: RequestMethod.Put,
[HTTPMethod.DELETE]: RequestMethod.Delete,
[HTTPMethod.PATCH]: RequestMethod.Patch,
[HTTPMethod.HEAD]: RequestMethod.Head,
[HTTPMethod.OPTIONS]: RequestMethod.Options,
[HTTPMethod.CONNECT]: RequestMethod.Connect,
};

/**
* https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-RuleCondition
*/
Expand All @@ -165,7 +186,7 @@ const RuleConditionValidator = zod.strictObject({
isUrlFilterCaseSensitive: zod.boolean().optional(),
regexFilter: zod.string().optional(),
requestDomains: zod.string().array().optional(),
requestMethods: zod.string().array().optional(),
requestMethods: zod.nativeEnum(RequestMethod).array().optional(),
/**
* If none of the `excludedResourceTypes` and `resourceTypes` are specified,
* all resource types except "main_frame" will be matched.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ import {
RuleActionHeaders,
ModifyHeaderInfo,
DECLARATIVE_RESOURCE_TYPES_MAP,
DECLARATIVE_REQUEST_METHOD_MAP,
SupportedHttpMethod,
RequestMethod,
} from '../declarative-rule';
import {
TooComplexRegexpError,
Expand All @@ -127,6 +130,7 @@ import { ResourcesPathError } from '../errors/converter-options-errors';
import { RedirectModifier } from '../../../modifiers/redirect-modifier';
import { RemoveHeaderModifier } from '../../../modifiers/remove-header-modifier';
import { CSP_HEADER_NAME } from '../../../modifiers/csp-modifier';
import { HTTPMethod } from '../../../modifiers/method-modifier';

/**
* Contains the generic logic for converting a {@link NetworkRule}
Expand Down Expand Up @@ -170,6 +174,22 @@ export abstract class DeclarativeRuleConverter {
.map(([resourceTypeKey]) => resourceTypeKey) as ResourceType[];
}

/**
* Converts list of tsurlfilter {@link HTTPMethod|methods} to declarative
* supported http {@link RequestMethod|methods} via excluding 'trace' method.
*
* @param methods List of {@link HTTPMethod|methods}.
*
* @returns List of {@link RequestMethod|methods}.
*/
private static mapHttpMethodToDeclarativeHttpMethod(methods: HTTPMethod[]): RequestMethod[] {
return methods
// Filters unsupported `trace` method
.filter((m): m is SupportedHttpMethod => m !== HTTPMethod.TRACE)
// Map tsurlfilter http method to supported declarative http method
.map((m) => DECLARATIVE_REQUEST_METHOD_MAP[m]);
}

/**
* Checks if the string contains only ASCII characters.
*
Expand Down Expand Up @@ -428,13 +448,13 @@ export abstract class DeclarativeRuleConverter {

// set initiatorDomains
const permittedDomains = rule.getPermittedDomains();
if (permittedDomains && permittedDomains.length > 0) {
if (permittedDomains && permittedDomains.length !== 0) {
condition.initiatorDomains = this.toASCII(permittedDomains);
}

// set excludedInitiatorDomains
const excludedDomains = rule.getRestrictedDomains();
if (excludedDomains && excludedDomains.length > 0) {
if (excludedDomains && excludedDomains.length !== 0) {
condition.excludedInitiatorDomains = this.toASCII(excludedDomains);
}

Expand All @@ -446,9 +466,9 @@ export abstract class DeclarativeRuleConverter {
// Can be specified $to or $denyallow, but not together.
const denyAllowDomains = rule.getDenyAllowDomains();
const restrictedToDomains = rule.getRestrictedToDomains();
if (denyAllowDomains && denyAllowDomains.length > 0) {
if (denyAllowDomains && denyAllowDomains.length !== 0) {
condition.excludedRequestDomains = this.toASCII(denyAllowDomains);
} else if (restrictedToDomains && restrictedToDomains.length > 0) {
} else if (restrictedToDomains && restrictedToDomains.length !== 0) {
condition.excludedRequestDomains = this.toASCII(restrictedToDomains);
}

Expand All @@ -465,6 +485,16 @@ export abstract class DeclarativeRuleConverter {
condition.resourceTypes = this.getResourceTypes(permittedRequestTypes);
}

const permittedMethods = rule.getPermittedMethods();
if (permittedMethods && permittedMethods.length !== 0) {
condition.requestMethods = this.mapHttpMethodToDeclarativeHttpMethod(permittedMethods);
}

const restrictedMethods = rule.getRestrictedMethods();
if (restrictedMethods && restrictedMethods.length !== 0) {
condition.excludedRequestMethods = this.mapHttpMethodToDeclarativeHttpMethod(restrictedMethods);
}

// set isUrlFilterCaseSensitive
condition.isUrlFilterCaseSensitive = rule.isOptionEnabled(NetworkRuleOption.MatchCase);

Expand All @@ -478,9 +508,10 @@ export abstract class DeclarativeRuleConverter {
*/
const shouldMatchAllResourcesTypes = rule.isOptionEnabled(NetworkRuleOption.RemoveHeader)
|| rule.isOptionEnabled(NetworkRuleOption.Csp)
|| rule.isOptionEnabled(NetworkRuleOption.To);
|| rule.isOptionEnabled(NetworkRuleOption.To)
|| rule.isOptionEnabled(NetworkRuleOption.Method);
const emptyResourceTypes = !condition.resourceTypes && !condition.excludedResourceTypes;
if (shouldMatchAllResourcesTypes && emptyResourceTypes && !rule.isAllowlist()) {
if (shouldMatchAllResourcesTypes && emptyResourceTypes) {
condition.resourceTypes = [
ResourceType.MainFrame,
ResourceType.SubFrame,
Expand Down Expand Up @@ -588,6 +619,7 @@ export abstract class DeclarativeRuleConverter {
* $removeheader - if it contains a title from a prohibited list
* (see {@link RemoveHeaderModifier.FORBIDDEN_HEADERS});
* $jsonprune;
* $method - if the modifier contains 'trace' method,
* $hls.
*
* @param rule - Network rule.
Expand Down Expand Up @@ -680,6 +712,33 @@ export abstract class DeclarativeRuleConverter {
return null;
};

/**
* Checks if the $method values in the provided network rule
* are supported for conversion to MV3.
*
* @param r Network rule.
* @param name Modifier's name.
*
* @returns Error {@link UnsupportedModifierError} or null if rule is supported.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const checkMethodModifierFn = (r: NetworkRule, name: string): UnsupportedModifierError | null => {
const permittedMethods = r.getPermittedMethods();
const restrictedMethods = r.getRestrictedMethods();
if (
permittedMethods?.some((method) => method === HTTPMethod.TRACE)
|| restrictedMethods?.some((method) => method === HTTPMethod.TRACE)
) {
return new UnsupportedModifierError(
// eslint-disable-next-line max-len
`Network rule with $method modifier containing 'trace' method is not supported: "${r.getText()}"`,
r,
);
}

return null;
};

const unsupportedOptions = [
/* Specific exceptions */
{ option: NetworkRuleOption.Elemhide, name: '$elemhide', skipConversion: true },
Expand All @@ -692,7 +751,6 @@ export abstract class DeclarativeRuleConverter {
{ option: NetworkRuleOption.Extension, name: '$extension' },
{ option: NetworkRuleOption.Stealth, name: '$stealth' },
/* Specific exceptions */
{ option: NetworkRuleOption.Method, name: '$method' },
{
option: NetworkRuleOption.Popup,
name: '$popup',
Expand Down Expand Up @@ -720,6 +778,11 @@ export abstract class DeclarativeRuleConverter {
name: '$removeheader',
customChecks: [checkAllowRulesFn, checkRemoveHeaderModifierFn],
},
{
option: NetworkRuleOption.Method,
name: '$method',
customChecks: [checkMethodModifierFn],
},
{ option: NetworkRuleOption.JsonPrune, name: '$jsonprune' },
{ option: NetworkRuleOption.Hls, name: '$hls' },
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ page$domain=targetdomain.com|~example.org
*/BannerAd.gif$match-case

! ## $method
! <b>Status</b>: not implemented yet
! <b>Status</b>: supported
! <br/>
! <b>Examples:</b>
! <br/>
Expand Down
Loading

0 comments on commit fd3ec59

Please sign in to comment.