| import * as _DEFAULT_RULES from '../data/rules.json'; |
| |
| export const DEFAULT_RULES: Rule[] = _DEFAULT_RULES as Rule[]; |
| |
| // Returns the content of the file `data/rules.json` as an object. |
| export function getDefaultRules() { |
| return [...DEFAULT_RULES]; |
| } |
| |
| export function isValidRule(rule: Rule) { |
| return ( |
| Object.values(Operator).includes(rule.operator) && |
| ((rule.operator === Operator.BLOCK && rule.target) || |
| (rule.operator === Operator.REDIRECT && |
| rule.target && |
| rule.destination) || |
| !!rule.destination) |
| ); |
| } |
| |
| export function isInjectRule(rule: Rule) { |
| return [ |
| Operator.INJECT_JS_MODULE_PLUGIN, |
| Operator.INJECT_JS_PLUGIN, |
| Operator.INJECT_HTML_CODE, |
| Operator.INJECT_EXP, |
| ].some(op => op === rule.operator); |
| } |
| |
| export function getStaticRules( |
| tabIds: number[] |
| ): chrome.declarativeNetRequest.Rule[] { |
| if (tabIds.length === 0) return []; |
| return [ |
| { |
| action: { |
| requestHeaders: [ |
| { |
| header: 'cache-control', |
| value: 'max-age=0, no-cache, no-store, must-revalidate', |
| operation: chrome.declarativeNetRequest.HeaderOperation.SET, |
| }, |
| { |
| header: 'x-google-cache-control', |
| value: 'max-age=0, no-cache, no-store, must-revalidate', |
| operation: chrome.declarativeNetRequest.HeaderOperation.SET, |
| }, |
| ], |
| type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS, |
| }, |
| condition: { |
| urlFilter: '*', |
| tabIds, |
| }, |
| // We just don't want to conflict with dynamic rule ids. They start counting from 1. |
| id: 314159, |
| }, |
| ]; |
| } |
| |
| export function toChromeRule( |
| rule: Rule, |
| tabIds: number[], |
| ruleId: number |
| ): chrome.declarativeNetRequest.Rule | undefined { |
| if (rule.disabled) return undefined; |
| if (tabIds.length === 0) return undefined; |
| |
| const action = convertRuleToAction(rule); |
| if (!action) return undefined; |
| return { |
| action, |
| condition: { |
| regexFilter: rule.target, |
| tabIds, |
| }, |
| id: ruleId, |
| }; |
| } |
| |
| function convertRuleToAction( |
| rule: Rule |
| ): chrome.declarativeNetRequest.RuleAction | undefined { |
| switch (rule.operator) { |
| case Operator.BLOCK: |
| return { |
| type: chrome.declarativeNetRequest.RuleActionType.BLOCK, |
| }; |
| case Operator.ADD_RESPONSE_HEADER: |
| case Operator.REMOVE_RESPONSE_HEADER: |
| return { |
| responseHeaders: headerInfos(rule), |
| type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS, |
| }; |
| case Operator.ADD_REQUEST_HEADER: |
| return { |
| requestHeaders: headerInfos(rule), |
| type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS, |
| }; |
| case Operator.REDIRECT: |
| return { |
| type: chrome.declarativeNetRequest.RuleActionType.REDIRECT, |
| redirect: {regexSubstitution: rule.destination}, |
| }; |
| default: |
| return undefined; |
| } |
| } |
| |
| function headerInfos( |
| rule: Rule |
| ): chrome.declarativeNetRequest.ModifyHeaderInfo[] | undefined { |
| const operation = |
| rule.operator === Operator.REMOVE_RESPONSE_HEADER |
| ? chrome.declarativeNetRequest.HeaderOperation.REMOVE |
| : chrome.declarativeNetRequest.HeaderOperation.SET; |
| |
| const headerInfos: chrome.declarativeNetRequest.ModifyHeaderInfo[] = []; |
| const ruleHeaders = rule.destination.split('|'); |
| for (const header of ruleHeaders) { |
| const partial = header.split('='); |
| headerInfos.push({ |
| header: partial[0], |
| operation, |
| value: partial[1], |
| }); |
| } |
| return headerInfos; |
| } |
| |
| /** |
| * Supported operators. |
| */ |
| export enum Operator { |
| BLOCK = 'block', |
| REDIRECT = 'redirect', |
| INJECT_HTML_CODE = 'injectHtmlCode', |
| INJECT_JS_PLUGIN = 'injectJSPlugin', |
| INJECT_JS_MODULE_PLUGIN = 'injectJSModule', |
| REMOVE_RESPONSE_HEADER = 'rRespHeader', |
| ADD_RESPONSE_HEADER = 'addRespHeader', |
| ADD_REQUEST_HEADER = 'addReqHeader', |
| INJECT_EXP = 'injectExp', |
| } |
| |
| /** |
| * Rule type. |
| */ |
| export interface Rule { |
| disabled: boolean; |
| target: string; |
| operator: Operator; |
| destination: string; |
| } |
| |
| /** |
| * Util to get url parameters |
| */ |
| export function getUrlParameter(param: string) { |
| const qs = window.location.search.substring(1); |
| const partials = qs.split('&'); |
| const res = []; |
| for (let i = 0; i < partials.length; i++) { |
| const name = partials[i].split('='); |
| if (name[0] == param) { |
| res.push(name[1]); |
| } |
| } |
| return res; |
| } |
| |
| // Note that this does not work from a content script. It does not have access |
| // to the `chrome.tabs` API. |
| export async function getActiveTab(): Promise<chrome.tabs.Tab | undefined> { |
| const activeTabs = await chrome.tabs.query({ |
| active: true, |
| currentWindow: true, |
| }); |
| const activeTab = activeTabs[0]; |
| if (!activeTab?.id || !activeTab?.url) return undefined; |
| return activeTab; |
| } |