javascriptvue.jschrome-extension-manifest-v3chrome-declarativenetrequest

Get original URL when redirecting via declarativeNetRequest + extensionPath


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?


Solution

  • 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.