1

I need to get the url of a chrome tab when it's navigated but before the user is redirected from a rule that is set using declarativeNetRequest.

At the moment the user can add a rule using context menu, it will be redirected to an internal extension page when try to visit the filtered host.


chrome.contextMenus.onClicked.addListener( ( clickData) => {
    switch (clickData.menuItemId) {
        case 'blockHost':
            blockHost(clickData)
            console.log('Added host')
            break;
        case 'unblockHost':
            unblockHost(clickData)
            chrome.declarativeNetRequest.getDynamicRules( rules => console.log(rules) )
            console.log('Removed host')           
            break;
    }
})

const blockHost = async (clickData) => {
    let hostname = new URL(clickData.pageUrl).hostname
    console.log(hostname)
    let rules = await chrome.declarativeNetRequest.getDynamicRules()    
    console.log(rules.length, rules)
    let newRule = await chrome.declarativeNetRequest.updateDynamicRules({
                addRules: [{
                    id: rules.length + 1,
                    action: {type: 'redirect', redirect: {extensionPath: '/forbidden.html'}},
                    condition: {urlFilter: `${hostname}/`, resourceTypes: ['main_frame', 'sub_frame']}
                }]
            });
    console.log(newRule)
    let updatedRules = await chrome.declarativeNetRequest.getDynamicRules()
    console.log('blockedhost executed', updatedRules)
}

since the user is redirected, it's impossible for me at the moment to remove a certain url. My idea is to get the url before the redirection is occur, but how I can do this?

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
newbiedev
  • 2,607
  • 3
  • 17
  • 65

1 Answers1

3

Use regexFilter + substitution to append the original URL to extension page URL:

const EXT_PAGE = chrome.runtime.getURL('/forbidden.html');
const RULES = [{
  id: 1,
  action: {
    type: 'redirect',
    redirect: { regexSubstitution: EXT_PAGE + '#\\0' },
  },
  condition: {
    requestDomains: ['example.com'], // remove this line to match all sites
    regexFilter: '^.+$',
    resourceTypes: ['main_frame', 'sub_frame'],
  },
}];
chrome.declarativeNetRequest.updateDynamicRules({
  removeRuleIds: RULES.map(r => r.id),
  addRules: RULES,
});

Now your extension page (forbidden.html) can read this URL:

const origUrl = location.hash.slice(1);

You can also hide the original URL from the address bar:

history.replaceState(document.title, null, location.href.split('#')[0]);

Hopefully there'll be a better solution if https://crbug.com/1241397 is implemented.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • I'm testing the code where I've implemented the suggested solution with regex, at the moment I'm able to add new rules, but the problem is to remove them since I'm not able to use the this line of code anymore `removeRuleIds: rules.map( (h, i) => hostname+'/' === h.condition.urlFilter ? h.id : null ).filter( el => el !== null )` – newbiedev Aug 18 '22 at 12:44
  • Extract a function that takes hostname and produces the string for regexFilter, then use it both to create and find the rule. – wOxxOm Aug 18 '22 at 14:38
  • not sure to understand, my idea is to clear the `condition.regexFilter` string to have only the host but not sure how to proceed – newbiedev Aug 18 '22 at 14:49
  • 1
    ```function makeRe(h) { return `^https?://([^/]*?[.@])?${h.replace(/\\./g, '\\.')}(:\\d+)?/.*$` }``` then use it in `regexFilter: makeRe(hostname)` and to find: `const re = makeRe(hostname); const ids = rules.map(r => r.condition.regexFilter === re && r.id).filter(Boolean)` – wOxxOm Aug 18 '22 at 14:54
  • ok, more clera now.The function will just append the regex to the desired host. nice solution – newbiedev Aug 18 '22 at 15:00
  • the function is working fine, I'm able to refersh the page after a rule is added and removing a rule if needed. My last problem now is to get a list of the blocked hosts without storing them into localstorage but by taking them from rules, is possible to manipulate the string from the function to remove only the regex? – newbiedev Aug 18 '22 at 15:54
  • 1
    Yes, it's a simple `slice` and `replace`. – wOxxOm Aug 18 '22 at 18:29
  • I think I will try to get the length of the url that will be part of the pattern, and the length of the pattern itself that will include the url, then pass the start until the url inside the pattern and the end of it that can be obtained by adding the url string length to the initial length of the regex pattern?Something like `let regex = '^https?://([^/]*?[.@])?$'+h.replace(/\\./g, '\\.')+'(:\\d+)?/.*$' console.log(h.length, regex.length) console.log(regex.slice(23, 39))` – newbiedev Aug 18 '22 at 21:11