Search code examples
javascriptjsongoogle-chromegoogle-chrome-extensiongoogle-chrome-app

Chrome Extension: insert a user input string into multiple declarativeNetRequest regexSubstitution rules


I have an extension that replaces the UTM parameter in URLs with the string WTTDOTM. It works by having a number of rulesets, each with an individual regexSubstitution rule. I did it this way because if I have multiple rules trying to do a regex substitution in the same ruleset, only one seems to execute (this will be relevant in a bit).

Here is one of the rules. I am wondering if there is a way to collect a user input and have the json reference that input, so that instead of "regexSubstitution": "\\1WTTDOTM\\2" the rule is changed to "regexSubstitution": "\\1[USER_INPUT]\\2".

utmsource.json

[
{
    "id": 1,
    "priority": 1,
    "action": {
      "type": "redirect",
      "redirect": { "regexSubstitution": "\\1WTTDOTM\\2" }
    },
    "condition": {
      "regexFilter": "(.*?utm_source=).+?($|\\&.*)",
      "resourceTypes": ["main_frame"]
    }
  }
]

manifest.json (simplified w/o extra rules, they all follow the format of the above just with utm_medium/campaign/term/content substituted for utm_source:

{
    "manifest_version": 3,
    "name": "CustomUTM",
    "version": "1.0",
    "description": "Custom UTM Extension",
    "declarative_net_request": {
    "rule_resources": [
      {
        "id": "ruleset_1",
        "enabled": true,
        "path": "utmsource.json"
      }
    ]
  },
  "host_permissions": ["*://*/*"],
  "permissions": ["declarativeNetRequest", "declarativeNetRequestFeedback"],
    "icons": {
          "128": "icon128.png" }
}

I know I can create dynamic rules with updateDynamicRules, but it seems as though all dynamic rules exist in the same ruleset which is where the multiple regexSubstitution conflict from earlier becomes relevant, because unless there is a way to make multiple different dynamic rulesets, only one substitution will actually execute.

Any help would be greatly appreciated!

EDIT ----

Below is an example of one json ruleset containing multiple regexSubstitution rules:

For the example input https://about.fb.com/regulations/?utm_source=programmatic&utm_medium=paid-offplatform&utm_term=fillerterm&utm_content=fillercontent

The actual output is https://about.fb.com/regulations/?utm_source=programmatic&utm_medium=paid-offplatform&utm_term=fillerterm&utm_content=WTTDOTM

While the desired output is https://about.fb.com/regulations/?utm_source=WTTDOTM&utm_medium=paid-WTTDOTM&utm_term=WTTDOTM&utm_content=WTTDOTM

It will always complete only the rule with the largest priority #. That is why I am concerned about updateDynamicRules, unless there is some weird regex formula I can use to condense these 4 rules into 1 for this substitution.

condensedruleset.json

[
{
    "id": 1,
    "priority": 1,
    "action": {
      "type": "redirect",
      "redirect": { "regexSubstitution": "\\1WTTDOTM\\2" }
    },
    "condition": {
      "regexFilter": "(.*?utm_source=).+?($|\\&.*)",
      "resourceTypes": ["main_frame"]
    }
  },
{
    "id": 2,
    "priority": 2,
    "action": {
      "type": "redirect",
      "redirect": { "regexSubstitution": "\\1WTTDOTM\\2" }
    },
    "condition": {
      "regexFilter": "(.*?utm_medium=).+?($|\\&.*)",
      "resourceTypes": ["main_frame"]
    }
  },
  {
    "id": 3,
    "priority": 3,
    "action": {
      "type": "redirect",
      "redirect": { "regexSubstitution": "\\1WTTDOTM\\2" }
    },
    "condition": {
      "regexFilter": "(.*?utm_term=).+?($|\\&.*)",
      "resourceTypes": ["main_frame"]
    }
  },
  {
    "id": 4,
    "priority": 4,
    "action": {
      "type": "redirect",
      "redirect": { "regexSubstitution": "\\1WTTDOTM\\2" }
    },
    "condition": {
      "regexFilter": "(.*?utm_content=).+?($|\\&.*)",
      "resourceTypes": ["main_frame"]
    }
  }
]

whereas if I do multiple rulesets like this, I get the desired output:

utmsource.json

[
{
    "id": 1,
    "priority": 1,
    "action": {
      "type": "redirect",
      "redirect": { "regexSubstitution": "\\1Fuck%20Off%20My%20Data\\2" }
    },
    "condition": {
      "regexFilter": "(.*?utm_source=).+?($|\\&.*)",
      "resourceTypes": ["main_frame"]
    }
  }
]

utmmedium.json

[
  {
    "id": 1,
    "priority": 1,
    "action": {
      "type": "redirect",
      "redirect": { "regexSubstitution": "\\1Fuck%20Off%20My%20Data\\2" }
    },
    "condition": {
      "regexFilter": "(.*?utm_medium=).+?($|\\&.*)",
      "resourceTypes": ["main_frame"]
    }
  }
]

and so on. The manifest for this looks like this:

manifest.json

{
    "manifest_version": 3,
    "name": "CustomUTM",
    "version": "1.3",
    "description": "Custom UTM Extension",
    "declarative_net_request": {
    "rule_resources": [
      {
        "id": "ruleset_1",
        "enabled": true,
        "path": "utmsource.json"
      },
      {
        "id": "ruleset_2",
        "enabled": true,
        "path": "utmmedium.json"
      },
      {
        "id": "ruleset_3",
        "enabled": true,
        "path": "utmcontent.json"
      },
      {
        "id": "ruleset_4",
        "enabled": true,
        "path": "utmcampaign.json"
      },
      {
        "id": "ruleset_5",
        "enabled": true,
        "path": "utmterm.json"
      }
    ]
  },
  "host_permissions": ["*://*/*"],
  "permissions": ["declarativeNetRequest", "declarativeNetRequestFeedback"],
    "icons": {
          "128": "icon128.png" }
}

Solution

  • Use a transform action for the query part, not regexSubstitution, and a condition that matches all the parameters.

    "condition": {
      "regexFilter": "[?&]utm_(source|medium|term|content)=[^&]+",
      "resourceTypes": ["main_frame"]
    },
    "action": {
      "type": "redirect",
      "redirect": {
        "transform": {
          "queryTransform": {
            "addOrReplaceParams": [
              {"key": "utm_source", "value": "foo"},
              {"key": "utm_medium", "value": "foo"},
              {"key": "utm_term", "value": "foo"},
              {"key": "utm_content", "value": "foo"}
            ]
          }
        }
      }
    }