Skip to content

Commit

Permalink
[ENGG-1696] MV3: support for rq_request_initiator_origin() predefined…
Browse files Browse the repository at this point in the history
… function (#1677)

* MV3: Expose onBeforeAjaxRequest hook for service worker to register new DNR rules

* added request processor

* fix: tabService cleanup

* fix: cache the rules

* added todo comment

* update timeout

* cleanup AJAX interception

* cleanup request processor

* remove logs

* fix: excluded

* fix: excluded domains

* added comment

* moved to psmh

* refactor: methods

* remove session rules on extension status toggle

* do no create dnr for predefined function

* added predefined function session rule

* fix:type

* null safe

* refactor: request processor

* fix: headers match

* added filters check

* fix: request type

* fix: regex substitution

* fix: moved to file

* fix: initiator domain function

* fix: parseHeaders rule

* fix: matchedRule info

* fixed match rule getter

* fix: destructure

* fix: matched rule

* fix: import changes

* remove log

* fix: functions

---------

Co-authored-by: Vaibhav Nigam <[email protected]>
  • Loading branch information
nafees87n and lazyvab committed May 13, 2024
1 parent 15da788 commit 819e1aa
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 32 deletions.
72 changes: 42 additions & 30 deletions app/src/modules/extension/ruleParser/parseHeadersRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,53 @@ import { ExtensionRule, ExtensionRuleAction, HeadersRuleOperation, ModifyHeaderI
import { parseConditionFromSource } from "./utils";

const parseHeaders = (headers: HeadersRuleModificationData[]): ModifyHeaderInfo[] => {
return headers.map((header) => {
if (header.type === HeaderRuleActionType.REMOVE) {
return {
header: header.header,
operation: "remove" as HeadersRuleOperation,
};
} else {
return {
header: header.header,
value: header.value,
operation: "set" as HeadersRuleOperation,
};
}
});
return headers
.map((header) => {
if (header.value === "rq_request_initiator_origin()") {
return null;
}

if (header.type === HeaderRuleActionType.REMOVE) {
return {
header: header.header,
operation: "remove" as HeadersRuleOperation,
};
} else {
return {
header: header.header,
value: header.value,
operation: "set" as HeadersRuleOperation,
};
}
})
.filter(Boolean);
};

const parseHeadersRule = (rule: HeadersRule): ExtensionRule[] => {
return rule.pairs.map(
(rulePair): ExtensionRule => {
const condition = parseConditionFromSource(rulePair.source);
const action: ExtensionRuleAction = {
type: RuleActionType.MODIFY_HEADERS,
};

if (rulePair.modifications?.Request?.length) {
action.requestHeaders = parseHeaders(rulePair.modifications?.Request);
}
return rule.pairs
.map(
(rulePair): ExtensionRule => {
const condition = parseConditionFromSource(rulePair.source);
const action: ExtensionRuleAction = {
type: RuleActionType.MODIFY_HEADERS,
};

if (rulePair.modifications?.Response?.length) {
action.responseHeaders = parseHeaders(rulePair.modifications?.Response);
}
if (rulePair.modifications?.Request?.length) {
action.requestHeaders = parseHeaders(rulePair.modifications?.Request);
}

if (rulePair.modifications?.Response?.length) {
action.responseHeaders = parseHeaders(rulePair.modifications?.Response);
}

return { action, condition };
}
);
if (!(action.requestHeaders?.length || action.responseHeaders?.length)) {
return null;
}

return { action, condition };
}
)
.filter(Boolean);
};

export default parseHeadersRule;
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Rule } from "common/types";
import { findMatchingRule } from "../ruleMatcher";
import { updateRequestSpecificRules } from "../rulesManager";
import { AJAXRequestDetails, SessionRuleType } from "./types";

const INITIATOR_DOMAIN_FUNCTION = "rq_request_initiator_origin()";

export const handleInitiatorDomainFunction = async (
tabId: number,
requestDetails: AJAXRequestDetails,
rules: Rule[]
) => {
const { isApplied, matchedPair } = findMatchingRule(rules, requestDetails) ?? {};

if (!isApplied) {
return;
}

const headerKeyValueMap: Record<"Response" | "Request", Record<string, string>> = {
Request: {},
Response: {},
};

if (matchedPair.modifications?.Request?.length) {
matchedPair.modifications.Request.forEach((header: { header: string; type: string; value: string }) => {
if (header.value === INITIATOR_DOMAIN_FUNCTION) {
headerKeyValueMap.Request[header.header] = requestDetails.initiatorDomain;
}
});
}

if (matchedPair.modifications?.Response?.length) {
matchedPair.modifications.Response.forEach((header: { header: string; type: string; value: string }) => {
if (header.value === INITIATOR_DOMAIN_FUNCTION) {
headerKeyValueMap.Response[header.header] = requestDetails.initiatorDomain;
}
});
}

const ruleAction: {
requestHeaders?: chrome.declarativeNetRequest.RuleAction["requestHeaders"];
responseHeaders?: chrome.declarativeNetRequest.RuleAction["responseHeaders"];
} = {};

if (Object.keys(headerKeyValueMap.Request).length) {
ruleAction.requestHeaders = Object.entries(headerKeyValueMap.Request).map(([header, value]) => ({
header,
value,
operation: chrome.declarativeNetRequest.HeaderOperation.SET,
}));
}

if (Object.keys(headerKeyValueMap.Response).length) {
ruleAction.responseHeaders = Object.entries(headerKeyValueMap.Response).map(([header, value]) => ({
header,
value,
operation: chrome.declarativeNetRequest.HeaderOperation.SET,
}));
}

if (!Object.keys(ruleAction).length) {
return;
}

await updateRequestSpecificRules(
tabId,
requestDetails.url,
{
action: {
...ruleAction,
type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS,
},
condition: {
urlFilter: `|${requestDetails.url}|`,
resourceTypes: [chrome.declarativeNetRequest.ResourceType.XMLHTTPREQUEST],
tabIds: [tabId],
requestMethods: [requestDetails.method.toLowerCase() as chrome.declarativeNetRequest.RequestMethod],
excludedInitiatorDomains: ["requestly.io", "requestly.com"],
},
},
SessionRuleType.INITIATOR_DOMAIN
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import { getEnabledRules, onRuleOrGroupChange } from "common/rulesStore";
import { Rule, RuleType } from "common/types";
import { AJAXRequestDetails } from "./types";
import { forwardHeadersOnRedirect } from "./handleHeadersOnRedirect";
import { handleInitiatorDomainFunction } from "./handleInitiatorDomainFunction";

class RequestProcessor {
cachedRules: Record<string, Rule[]> = {
redirectRules: [],
replaceRules: [],
headerRules: [],
};

private updateCachedRules = async () => {
this.cachedRules.redirectRules = await getEnabledRules(RuleType.REDIRECT);
this.cachedRules.replaceRules = await getEnabledRules(RuleType.REPLACE);
this.cachedRules.headerRules = await getEnabledRules(RuleType.HEADERS);
};

constructor() {
Expand All @@ -28,6 +31,8 @@ class RequestProcessor {
...requestProcessor.cachedRules.redirectRules,
...requestProcessor.cachedRules.replaceRules,
]);

await handleInitiatorDomainFunction(tabId, requestDetails, requestProcessor.cachedRules.headerRules);
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export interface AJAXRequestDetails {

export enum SessionRuleType {
FORWARD_IGNORED_HEADERS = "forwardIgnoredHeaders",
INITIATOR_DOMAIN = "initiatorDomain",
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ export const matchRuleWithRequest = function (rule: Rule, requestDetails: AJAXRe
);

if (!matchedPair) {
return {};
return {
isApplied: false,
};
}

const destinationUrl = populateRedirectedUrl(matchedPair, rule.ruleType, requestDetails);
Expand Down Expand Up @@ -217,7 +219,7 @@ export const populateRedirectedUrl = (rulePair: RulePair, ruleType: RuleType, re
export const findMatchingRule = (rules: Rule[], requestDetails: AJAXRequestDetails) => {
for (const rule of rules) {
const matchedRule = matchRuleWithRequest(rule, requestDetails);
if (matchedRule) {
if (matchedRule.isApplied) {
return matchedRule;
}
}
Expand Down

0 comments on commit 819e1aa

Please sign in to comment.