Block URL with a specific word somewhere in the subdomain - javascript

I am trying to make a Chrome extension that blocks URLs with a specific word in the subdomain, but not other URLs in that domain. For example, let's say I want to block all tumblr blogs with the word "cola" in the subdomain.
It should be able to block this page: http://coca-cola.tumblr.com/.
I have tried to use this url match: urls:["*://*cola*.tumblr.com/*"], but it is not working. And I cannot think of any other combinations that might work. Can somebody point me in the right direction?
This is my full background.js:
chrome.webRequest.onBeforeRequest.addListener(
function() {
return {cancel: true };
},
{
urls:["*://*cola*.tumblr.com/*"] // This is the part I'm messing up.
},
["blocking"]
);

Your code fails because *://*cola*.tumblr.com/* is not a valid match pattern. Wildcards can only be used in the path component of an URL, or at the start of a host name.
If you want to block an URL whose subdomain contains some keyword, you need to match the whole domain, and use JavaScript to check whether the subdomain contains the profane word.
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
var hostname = details.url.split('/', 3)[2];
return {
cancel: hostname.indexOf('cola') >= 0
};
},
{
urls:["*://*.tumblr.com/*"]
},
["blocking"]
);
Or using the chrome.declarativeWebRequest API (omitted chrome.runtime.onInstalled event for brevity):
chrome.declarativeWebRequest.onRequest.addRules({
id: 'some rule id',
conditions: [
new chrome.declarativeWebRequest.RequestMatcher({
url: {
hostContains: 'cola',
hostSuffix: '.tumblr.com'
}
})
],
actions: [
new chrome.declarativeWebRequest.CancelRequest()
]
});

Related

How to handle onBeforeSendHeaders in Chrome v3

I have some published Chrome Extension. I am trying to move it from mv2 to mv3 format. Inside background.js , I am intercepting the header with below code.
chrome.webRequest.onBeforeSendHeaders.addListener(
onBeforeSendHeadersHandler, {
urls: <url list obtained using websocket from machine>,
types: ['main_frame']
},
['blocking', 'requestHeaders']
);
var onBeforeSendHeadersHandler = function(details) {
if (details.requestHeaders[idx].name === 'Purpose' &&details.requestHeaders[idx].name === 'prefetch') {
return {};
}
var condition = <some code>;
chrome.tabs.update(params);
return {cancel: condition ? true : false };
}
Based upon the input in "details" onBeforeSendHeadersHandler will run some logic and return true or false. Which will decide whether Extension will handle the url or not.
With v3 how can I intercept the header at runtime and return some values.
I tried "declarative_net_request" in manifest.json and tried updateDynamicRules , it's not working. But even though I can fix the issue, my query is how can I define some finction() to be executed inside onBeforeSendHeadersHandler() , as I can not write all the conditions inside rules.json file or update it dynamically.
V3 has depricated "blocking" call , which is a must for my requirement. Is there any alternative for this ?
you can use declarativeNetRequest permission to block request
chrome.declarativeNetRequest.updateDynamicRules({
addRules:[{
"id":1,
"action": { "type": "block" },
"condition": {
"urlFilter": 'url-part',
"resourceTypes": [
"main_frame",
"sub_frame"
]
}
}],
removeRuleIds: [1]
});

Chrome page action not open popup on click

I have this code to activate an extension only if a certain website is visited. I've noticed that the extension icon will be always clickable and will be not grey if the url isn't mathcing with the condition setted and when the desired website is visited and the url match, if the user click on the extension icon, the popup will not be opened. How I can fix?
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostEquals: 'www.example.com/video/*', schemes: ["https"] },
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
});
});
chrome.pageAction.onClicked.addListener( () => {
chrome.windows.create({
url: chrome.runtime.getURL('popup.html'),
width: 500,
height: 295,
type: 'popup'
});
});
Your rule for hostEquals will never match anything because per the documentation it's compared against the host part of a URL e.g. simply www.example.com so it can't have / or *. Note that chrome.declarativeContent uses its own filtering system, it does not support any of the usual matching patterns used by content_scripts or webRequest.
Solution 1:
{ hostEquals: 'www.example.com', pathPrefix: '/video/', schemes: ['https'] }
Solution 2:
{ urlPrefix: 'https://www.example.com/video/' }

opening tabs/windows without displaying them [duplicate]

I'm the author of Intab, a Chrome extension that lets you view a link inline as opposed to a new tab. There's not much fancy stuff going on behind the scenes, it's just an iframe that loads the URL the user clicked on.
It works great except for sites that set the X-Frame-Options header to DENY or SAMEORIGIN. Some really big sites like Google and Facebook both use it which makes for a slightly janky experience.
Is there any way to get around this? Since I'm using a Chrome extension, is there any browser level stuff I can access that might help? Looking for any ideas or help!
Chrome offers the webRequest API to intercept and modify HTTP requests. You can remove the X-Frame-Options header to allow inlining pages within an iframe.
chrome.webRequest.onHeadersReceived.addListener(
function(info) {
var headers = info.responseHeaders;
for (var i=headers.length-1; i>=0; --i) {
var header = headers[i].name.toLowerCase();
if (header == 'x-frame-options' || header == 'frame-options') {
headers.splice(i, 1); // Remove header
}
}
return {responseHeaders: headers};
}, {
urls: [
'*://*/*', // Pattern to match all http(s) pages
// '*://*.example.org/*', // Pattern to match one http(s) site
],
types: [ 'sub_frame' ]
}, [
'blocking',
'responseHeaders',
// Modern Chrome needs 'extraHeaders' to see and change this header,
// so the following code evaluates to 'extraHeaders' only in modern Chrome.
chrome.webRequest.OnHeadersReceivedOptions.EXTRA_HEADERS,
].filter(Boolean)
);
In the manifest, you need to specify the webRequest and webRequestBlocking permissions, plus the URLs patterns you're intending to intercept i.e. "*://*/*" or "*://www.example.org/*" for the example above.
ManifestV3 example using declarativeNetRequest
See also the warning at the end of this answer!
manifest.json for Chrome 96 and newer,
doesn't show a separate permission for "Block page content" during installation
"minimum_chrome_version": "96",
"permissions": ["declarativeNetRequestWithHostAccess"],
"host_permissions": ["*://*.example.com/"],
"background": {"service_worker": "bg.js"},
bg.js for Chrome 101 and newer using initiatorDomains and requestDomains
(don't forget to add "minimum_chrome_version": "101" in manifest.json)
const iframeHosts = [
'example.com',
];
chrome.runtime.onInstalled.addListener(() => {
const RULE = {
id: 1,
condition: {
initiatorDomains: [chrome.runtime.id],
requestDomains: iframeHosts,
resourceTypes: ['sub_frame'],
},
action: {
type: 'modifyHeaders',
responseHeaders: [
{header: 'X-Frame-Options', operation: 'remove'},
{header: 'Frame-Options', operation: 'remove'},
],
},
};
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: [RULE.id],
addRules: [RULE],
});
});
Old Chrome 84-100
Use the following instead, if your extension should be compatible with these old versions.
manifest.json for Chrome 84 and newer,
shows a separate permission for "Block page content" during installation
"permissions": ["declarativeNetRequest"],
"host_permissions": ["*://*.example.com/"],
"background": {"service_worker": "bg.js"},
bg.js for Chrome 84 and newer using the now deprecated domains
const iframeHosts = [
'example.com',
];
chrome.runtime.onInstalled.addListener(() => {
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: iframeHosts.map((h, i) => i + 1),
addRules: iframeHosts.map((h, i) => ({
id: i + 1,
condition: {
domains: [chrome.runtime.id],
urlFilter: `||${h}/`,
resourceTypes: ['sub_frame'],
},
action: {
type: 'modifyHeaders',
responseHeaders: [
{header: 'X-Frame-Options', operation: 'remove'},
{header: 'Frame-Options', operation: 'remove'},
],
},
})),
});
});
Warning: beware of site's service worker
You may have to remove the service worker of the site(s) and clear its cache before adding the iframe or before opening the extension page because many modern sites use the service worker to create the page without making a network request thus ignoring our header-stripping rule.
Add "browsingData" to "permissions" in manifest.json
Clear the SW:
function removeSW(url) {
return chrome.browsingData.remove({
origins: [new URL(url).origin],
}, {
cacheStorage: true,
serviceWorkers: true,
});
}
// If you add an iframe element in DOM:
async function addIframe(url, parent = document.body) {
await removeSW(url);
const el = document.createElement('iframe');
parent.appendChild(el);
el.src = url;
return el;
}
// If you open an extension page with an <iframe> element in its HTML:
async function openPage(url) {
await removeSW('https://example.com/');
return chrome.tabs.create({url});
}
You can try the Frame extension that lets the user drop X-Frame-Options and Content-Security-Policy HTTP response headers, allowing pages to be iframed.
The code is available on github
It's based on ManifestV3 and working perfectly with Google & Facebook.

How do you redirect a custom generated URL in javascript?

I'm trying to write an extension for personal use. Background.js file where I want to take a url - detect an integer from within it - redirect it to a new URL with the string concatenated in between. But it doesn't seem to work (I'm new). This is a very specific case for personal use. Here is my example code so far (of course the URLs are sample):
const abc = "https://www.google.com/anc/wddsd/";
const xyz = "/tracking/file/subsystem";
var res = url.split('/')[4]; //can I even access the URL before the function begins?
Say there is a Numeric Digit that occurs just after /wddsd/ and I want to extract it from the original URL and place it in the redirected URL.
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
return {
redirectUrl:
abc + res + xyz
};
},
{
urls: [
"*//www.google.com/*"
],
types: [
"main_frame",
"sub_frame",
"stylesheet",
"script",
"image",
"object",
"xmlhttprequest",
"other"
]
},
["blocking"]
);
update: The permissions of my manifest.json are:
"permissions": ["webRequest", "webRequestBlocking", "*://google.com/*"]
Hey to anyone stumbling upon this in the future, I fixed it myself by essentially replacing
var res = url.split('/')[4];
with
var res = details.url.split('/')[4];
and putting it inside the function. Hooray.

What is the proper way to change http headers in a chrome extension? [duplicate]

I'm the author of Intab, a Chrome extension that lets you view a link inline as opposed to a new tab. There's not much fancy stuff going on behind the scenes, it's just an iframe that loads the URL the user clicked on.
It works great except for sites that set the X-Frame-Options header to DENY or SAMEORIGIN. Some really big sites like Google and Facebook both use it which makes for a slightly janky experience.
Is there any way to get around this? Since I'm using a Chrome extension, is there any browser level stuff I can access that might help? Looking for any ideas or help!
Chrome offers the webRequest API to intercept and modify HTTP requests. You can remove the X-Frame-Options header to allow inlining pages within an iframe.
chrome.webRequest.onHeadersReceived.addListener(
function(info) {
var headers = info.responseHeaders;
for (var i=headers.length-1; i>=0; --i) {
var header = headers[i].name.toLowerCase();
if (header == 'x-frame-options' || header == 'frame-options') {
headers.splice(i, 1); // Remove header
}
}
return {responseHeaders: headers};
}, {
urls: [
'*://*/*', // Pattern to match all http(s) pages
// '*://*.example.org/*', // Pattern to match one http(s) site
],
types: [ 'sub_frame' ]
}, [
'blocking',
'responseHeaders',
// Modern Chrome needs 'extraHeaders' to see and change this header,
// so the following code evaluates to 'extraHeaders' only in modern Chrome.
chrome.webRequest.OnHeadersReceivedOptions.EXTRA_HEADERS,
].filter(Boolean)
);
In the manifest, you need to specify the webRequest and webRequestBlocking permissions, plus the URLs patterns you're intending to intercept i.e. "*://*/*" or "*://www.example.org/*" for the example above.
ManifestV3 example using declarativeNetRequest
See also the warning at the end of this answer!
manifest.json for Chrome 96 and newer,
doesn't show a separate permission for "Block page content" during installation
"minimum_chrome_version": "96",
"permissions": ["declarativeNetRequestWithHostAccess"],
"host_permissions": ["*://*.example.com/"],
"background": {"service_worker": "bg.js"},
bg.js for Chrome 101 and newer using initiatorDomains and requestDomains
(don't forget to add "minimum_chrome_version": "101" in manifest.json)
const iframeHosts = [
'example.com',
];
chrome.runtime.onInstalled.addListener(() => {
const RULE = {
id: 1,
condition: {
initiatorDomains: [chrome.runtime.id],
requestDomains: iframeHosts,
resourceTypes: ['sub_frame'],
},
action: {
type: 'modifyHeaders',
responseHeaders: [
{header: 'X-Frame-Options', operation: 'remove'},
{header: 'Frame-Options', operation: 'remove'},
],
},
};
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: [RULE.id],
addRules: [RULE],
});
});
Old Chrome 84-100
Use the following instead, if your extension should be compatible with these old versions.
manifest.json for Chrome 84 and newer,
shows a separate permission for "Block page content" during installation
"permissions": ["declarativeNetRequest"],
"host_permissions": ["*://*.example.com/"],
"background": {"service_worker": "bg.js"},
bg.js for Chrome 84 and newer using the now deprecated domains
const iframeHosts = [
'example.com',
];
chrome.runtime.onInstalled.addListener(() => {
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: iframeHosts.map((h, i) => i + 1),
addRules: iframeHosts.map((h, i) => ({
id: i + 1,
condition: {
domains: [chrome.runtime.id],
urlFilter: `||${h}/`,
resourceTypes: ['sub_frame'],
},
action: {
type: 'modifyHeaders',
responseHeaders: [
{header: 'X-Frame-Options', operation: 'remove'},
{header: 'Frame-Options', operation: 'remove'},
],
},
})),
});
});
Warning: beware of site's service worker
You may have to remove the service worker of the site(s) and clear its cache before adding the iframe or before opening the extension page because many modern sites use the service worker to create the page without making a network request thus ignoring our header-stripping rule.
Add "browsingData" to "permissions" in manifest.json
Clear the SW:
function removeSW(url) {
return chrome.browsingData.remove({
origins: [new URL(url).origin],
}, {
cacheStorage: true,
serviceWorkers: true,
});
}
// If you add an iframe element in DOM:
async function addIframe(url, parent = document.body) {
await removeSW(url);
const el = document.createElement('iframe');
parent.appendChild(el);
el.src = url;
return el;
}
// If you open an extension page with an <iframe> element in its HTML:
async function openPage(url) {
await removeSW('https://example.com/');
return chrome.tabs.create({url});
}
You can try the Frame extension that lets the user drop X-Frame-Options and Content-Security-Policy HTTP response headers, allowing pages to be iframed.
The code is available on github
It's based on ManifestV3 and working perfectly with Google & Facebook.

Categories

Resources