Reputation: 51
I'm trying to make a web filtering chrome extension that will block certain sites and replace their html with a block page included in the extension.
let bans = ["*://*.amazon.com/*", "*://*.youtube.com/*", "*://*.netflix.com/*","*://*.facebook.com/*", "*://*.twitter.com/*"];
chrome.webRequest.onBeforeRequest.addListener(
function(details){
try{
chrome.tabs.executeScript(null, {file: "content.js"});
}
catch(error){
console.error(error);
}
return {cancel: true};
},
{urls: bans},
["blocking"]
);
This should mean that if I try to visit any site on that banned list the content script should replace the page with my own block page. However for some reason some sites never load the block page, other sites don't get blocked at all and some sites seem to work perfectly. Even stranger the listener seems to be triggered on sites not listed in the bans array at all. I can't figure out any sort of pattern between these behaviors.
I don't believe they are the source of the problem but here are the permissions in my manifest (manifest v2)
"web_accessible_resources": [
"certBlockPage.html",
"blockPageLight.html"
],
"incognito": "split",
"permissions": [
"webNavigation",
"webRequest",
"webRequestBlocking",
"tabs",
"windows",
"identity",
"http://*/*",
"https://*/*",
"<all_urls>"
]
and here is the content.js file
window.onload = function(){
fetch(chrome.runtime.getURL('certBlockPage.html'))
.then(r => r.text())
.then(html => {
document.open();
document.write(html);
document.close;
});
}
Upvotes: 2
Views: 2311
Reputation: 73616
There are several problems.
runAt: 'document_start'
in executeScript's options so it will wait in case you navigated to a banned site while the old page in this tab was still loading.load
event was already fired in the tab so your window.onload will never run. Don't use onload, just run the code immediately.details.tabId
and details.frameId
.{cancel: true}
, but then executeScript will fail because the newtab page, which is currently shown in this tab, can't run content scripts. Same for any other chrome:// or chrome-extension:// tab or when a network error is displayed inside the tab.background script:
updateListener(['amazon.com', 'youtube.com', 'netflix.com']);
function updateListener(hosts) {
chrome.webRequest.onBeforeRequest.removeListener(onBeforeRequest);
chrome.webRequest.onBeforeRequest.addListener(
onBeforeRequest, {
types: ['main_frame', 'sub_frame'],
urls: hosts.map(h => `*://*.${h}/*`),
}, [
'blocking',
]);
}
function onBeforeRequest(details) {
const {tabId, frameId} = details;
chrome.tabs.executeScript(tabId, {
file: 'content.js',
runAt: 'document_start',
matchAboutBlank: true,
frameId,
}, () => chrome.runtime.lastError && redirectTab(tabId));
// Cancel the navigation without showing that it was canceled
return {redirectUrl: 'javascript:void 0'};
}
function redirectTab(tabId) {
chrome.tabs.update(tabId, {url: 'certBlockPage.html'});
}
content.js:
fetch(chrome.runtime.getURL('certBlockPage.html'))
.then(r => r.text())
.then(html => {
try {
document.open();
document.write(html);
document.close();
} catch (e) {
location.href = chrome.runtime.getURL('certBlockPage.html');
}
});
No need for content scripts.
const bannedHosts = ['amazon.com', 'youtube.com', 'netflix.com'];
chrome.webRequest.onBeforeRequest.addListener(
details => ({
redirectUrl: chrome.runtime.getURL('certBlockPage.html'),
}), {
types: ['main_frame', 'sub_frame'],
urls: bannedHosts.map(h => `*://*.${h}/*`),
}, [
'blocking',
]);
This is the fastest method but it's limited to a very simple predefined set of actions. See the documentation and don't forget to add "declarativeNetRequest"
to "permissions"
in manifest.json, and "<all_urls>"
to host_permissions
(ManifestV3 still doesn't support optional permissions).
const bannedHosts = ['amazon.com', 'youtube.com', 'netflix.com'];
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: bannedHosts.map((h, i) => i + 1),
addRules: bannedHosts.map((h, i) => ({
id: i + 1,
action: {type: 'redirect', redirect: {extensionPath: '/certBlockPage.html'}},
condition: {urlFilter: `||${h}/`, resourceTypes: ['main_frame', 'sub_frame']},
})),
});
Upvotes: 4