Chrome Extension Content Policy Directive Error - google-chrome-extension

I published a Chrome extension that lets the user change the background image on a certain website using the image's url which worked fine, however, recently it stopped work with the following error. It was working even after months in the store.
*Refused to load the image 'https://preview.redd.it/5qz0nzspaq481.png?auto=webp&s=767213b884285c0caba56175ac4a231d2764871b' because it violates the following Content Security Policy directive: "img-src 'self' data: *.cloudfront.net *.google-analytics.com .kaptcha.com
background.js
var inputParent = document.getElementsByClassName(
"nav rbx-navbar hidden-xs hidden-sm col-md-5 col-lg-4"
)[0];
// Dropdown button
var dropdownContainer = document.createElement("div");
var dropdownBtn = document.createElement("a");
var dropdownChild = document.createElement("div");
// Dp Container
dropdownContainer.id = "dropdown";
dropdownContainer.className = "cursor-pointer";
// Dp Button
dropdownBtn.id = "dropbtn";
dropdownBtn.className = "font-header-2 nav-menu-title text-header";
dropdownBtn.innerText = "Theme";
// Menu
dropdownChild.id = "myDropdown";
dropdownChild.className = "dropdown-content";
var newDiv = document.createElement("div");
newDiv.className = "font-header-2 nav-menu-title text-header";
newDiv.innerText = "Theme";
// Appends
inputParent.appendChild(dropdownContainer);
inputParent.appendChild(dropdownBtn);
inputParent.appendChild(dropdownChild);
// Input
var input = document.createElement("input");
input.id = "theme-url-input";
input.type = "text";
input.placeholder = "Paste image URL here...";
//input.value = "Image URL...";
// Save
var save = document.createElement("button");
save.id = "save-url";
save.innerText = "Save";
// Update
var update = document.createElement("button");
update.id = "submit-url";
update.innerText = "Update";
dropdownChild.appendChild(input);
dropdownChild.appendChild(save);
dropdownChild.appendChild(update);
document.getElementById("dropbtn").onclick = function () {
document.getElementById("myDropdown").classList.toggle("show");
};
// Close the dropdown menu if the user clicks outside of it
window.onclick = function (e) {
if (
!e.target.matches("#dropbtn") &&
!e.target.matches("#myDropdown") &&
!e.target.matches("#theme-url-input") &&
!e.target.matches("#submit-url") &&
!e.target.matches("#save-url")
) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains("show")) {
openDropdown.classList.remove("show");
}
}
}
};
// Change background and Save
document.getElementById("save-url").onclick = function () {
var value = input.value;
var background = document.getElementsByClassName("container-main")[0];
// Set background URL
chrome.storage.sync.set({ url: value }, function () {
if (value == "") {
background.style.backgroundImage =
"linear-gradient(transparent 40%, #20283c 90%),url(" + url + ")";
}
console.log(url);
});
};
var background = document.getElementsByClassName("container-main")[0];
// Get background URL
chrome.storage.sync.get("url", function (data) {
background.style.backgroundImage =
"linear-gradient(transparent 40%, #20283c 90%),url(" + data.url + ")";
});
document.getElementById("submit-url").onclick = function () {
if (input.value !== "") {
location.reload();
return false;
}
};
Manifest
// Manifest
{
"manifest_version": 3,
"name": "extension name
",
"description": "some desc.",
"version": "1.2.1",
"icons": {"128": "icon_128.png"},
"permissions": [
"storage"
],
"content_security_policy": {
"extension_pages": "img-src 'self' data: *.cloudfront.net *.google-analytics.com .kaptcha.com *.redd.it"
},
"content_scripts": [{
"css": ["style.css","style.scss"],
"js": ["content.js","background.js"],
"matches": ["https://www.website.com/*"]
}],
"action": {
"default_icon": "icon_128.png",
"default_title" : "Extension",
"default_popup" : "popup.html"
}
}

This is because of CSP in your manifest file. Check your manifest.json file and look for the key content_security_policy. If you're on manifest V2, your manifest.json should look like this:
{
"name": "<your_extension_name>",
"description": "<your_extension_description>",
"version": "1.0",
"manifest_version": 2,
...
...
"content_security_policy": "<your CSP policy>" <--- you need to edit this
...
}
While if you're on manifest V3, manifest.json would look like this for you:
{
"name": "<your_extension_name>",
"description": "<your_extension_description>",
"version": "1.0",
"manifest_version": 3,
...
...
"content_security_policy": {
"extension_pages": "<your CSP policy>" <--- you need to edit this
}
...
}
You're trying to load an image which is from this origin: https://preview.redd.it which is a violation of your existing CSP. Edit the line highlighted in above example files to include src from *.redd.it.
So the new policy for img-src should be:
"img-src 'self' data: *.cloudfront.net *.google-analytics.com .kaptcha.com *.redd.it
Edit: Assuming your extension loads only images from different origins. Updated policy that should work:
default-src 'self'; connect-src * data: blob: filesystem:; style-src 'self' data: 'unsafe-inline'; img-src 'self' data: *.cloudfront.net *.google-analytics.com .kaptcha.com *.redd.it; frame-src 'self' data:; font-src 'self' data:; media-src * data: blob: filesystem:;

Related

Chrome extension cant run a fetch request because it violets CSP

I am working on a chrome extension and it does work locally but it gives the following error when launched as a chrome extension:
Refused to execute inline event handler because it violates the following Content Security Policy directive: "script-src 'self' https://apis.google.com". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
my manifest file is:
{
"manifest_version": 2,
"name": "Fake News Launcher",
"description": "Check the integrity of news!",
"version": "1.1.0",
"icons": {
"128": "icon_128.png"
},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "index.html"
},
"permissions": [
"activeTab"
]
}
I tried adding "content_security_policy":"script-src 'self' https://apis.google.com; object-src 'self'" but that did not fix the issue
the function that causes the error is
async function onTestChange() {
let key = window.event.keyCode;
let string = $(".fact-input").val();
//! If the user has pressed enter
if (key === 13) {
try {
const res = await fetch("http://127.0.0.1:5000/create/", {
method: "POST",
body: JSON.stringify({
string,
}),
headers: {
"Content-Type": "application/json",
},
});
const data = await res.json();
loadingbar(parseInput(data));
} catch (err) {
console.log(err);
}
}
}
Refused to execute inline event handler because...
it means you use inline event handlers in the tags like: <tag onclick='some_js_code'>, <select onchange='js_funct()', <body onload='some_handler()'> etc.
All these requires 'unsafe-inline' in script-src (there is not any workaround using 'unsafe-hashes' and 'hash-value' tokens with cross browser support for now).
Best way to avoid this error and not to use 'unsafe-inline' is to hang event handlers via addEventListener().
Since you do use jQuery it's very easy.
PS: You did not shown full CSP, but the fetch("http://127.0.0.1:5000/create/" requires connect-src 'self' http://127.0.0.1:5000 in Dev and connect-src 'self' in Prod.

Load an Iframe with cross origin domain with google chrome extensions

I'm developing a chrome extension for gmail application and i want to load our web application content through iframe. But i'm getting blocked frame even though, we add content secuirity policy tag in manifest.json. What is the right way to implement loading of cross origin domain content with iframe in gmail chrome extension?
Here is the error that i'm getting.
Refused to frame 'example.com/' because it violates the following Content Security Policy directive: "frame-src 'self' https://clients4.google.com/insights/consumersurveys/ https://calendar.google.com/accounts/ https://ogs.google.com https://onegoogle............etc.
Manifest File:
{
"name": "gmailext12",
"version": "1.0.0",
"manifest_version": 2,
"description": "gmailext12",
"icons": {
"16": "images/16.png",
"128": "images/128.png"
},
"background" : {
"scripts" : ["scripts/background.js"]
},
"browser_action": {
"default_icon": "images/16.png"
},
"content_security_policy": "script-src 'self' 'shakey' https://example.com; frame-src 'self' 'shakey' https://example.com; object-src 'self'",
"permissions": [
"activeTab",
"tabs"
]
}
Content.js
var iframe = document.createElement('iframe');
// Must be declared at web_accessible_resources in manifest.json
iframe.id = 'gmail-pega123';
// iframe.src = chrome.runtime.getURL('iframe.html');
iframe.src = 'https://example.com';
// Some styles for a fancy sidebar
iframe.style.cssText = '`enter code here`';
document.body.appendChild(iframe);

how to make gtag to work in chrome extension?

I've added gtag.js to my chrome extension but I don't see anything on the nework, please tell me what I did wrong.
This is my CSP in manifest.json
{
"content_security_policy": "script-src 'self' https://www.googletagmanager.com https://ssl.google-analytics.com https://www.google-analytics.com https://mustsee-earth.firebaseio.com; object-src 'self'"
}
This is my index.html used by my extension (which replaces the user's default tab)
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>mustsee.earth</title>
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X"></script>
</head>
Here's how I trigger views and events
gtag('config', GATID, {
page_title: place.name,
page_path: path
})
gtag('event', binding_value.action, {
event_category: binding_value.category,
event_label: binding_value.label,
value: binding_value.value
})
Although I followed every step, here's what I have on the network : nothing.
Here's the dataLayer var which proves my events are added to the queue but not triggered
[
{
"0": "js",
"1": "2018-04-24T21:02:54.881Z"
},
{
"0": "config",
"1": "UA-XXXXXXXXX-X",
"2": {
"checkProtocolTask": null,
"custom_map": {
"dimension5": "under 1.5 or failed"
}
}
},
{
"0": "config",
"1": "UA-XXXXXXXXX-X",
"2": {
"page_title": "Mesquite Flat Sand Dunes",
"page_path": "/mesquite-flat-oleksandr-mokrohuz-small.jpg"
}
},
{
"0": "event",
"1": "click on reload",
"2": {
"event_category": "Image View"
}
}
]
What can the issue be here ?
Adding gtm in the Chrome Extension is a bit tricky job. I had faced the same issues you are facing now. However, this is possible to implement gtm in CE.
Your manifest looks fine. You need to do some configuration changes in https://tagmanager.google.com/
You must add checkProtocolTask : false to each gtm tag in order to track them from Google Chrome Extension.
Add checkProtocolTask : false to Fields to Set
Scroll down to Fields to Set, and add a new field:
Field Name: checkProtocolTask
Value: false
See this SO post for more details.
gtag('config', GATID, {
page_title: place.name,
page_path: path
})
gtag = (function (old_gtag) {
var inited = false;
return function gtag() {
if (!inited && window.ga && window.ga.getAll) {
window.ga.getAll().forEach(function (tracker) {
tracker.set("checkProtocolTask", null);
inited = true;
});
}
if (inited) return old_gtag.apply(this, arguments);
var args = arguments;
setTimeout(function () {
gtag.apply(this, args);
}, 300);
};
})(gtag);
gtag('event', binding_value.action, {
event_category: binding_value.category,
event_label: binding_value.label,
value: binding_value.value
})

Change user-agent headers only in incognito mode with a Chrome extension

I'm trying to have my extension only work while in incognito mode. I can't seem to get it to work by adding "incognito": "split" to my manifest.json, and adding an if statement in the background.js looking for chrome.extension.inIncognitoContext.
Edit:
Okay, so what I'm trying to do is change my user-agent headers while only in incognito. I'm doing this based off this: http://elaineou.com/2016/02/19/how-to-use-chrome-extensions-to-bypass-paywalls/
It works for the said link above, but I can't seem to get it to work for all website while in incognito mode. This also won't be released, and I do have the allowed in incognito button checked.
manifest.json
{
"name": "Incognito Chrome Extension",
"version": "0.1",
"description": "This is an incognito chrome extension.",
"incognito": "split",
"permissions": ["webRequest", "webRequestBlocking",
"http://localhost:3000/",
"http://*/*",
"https://*/*"
],
"background": {
"scripts": ["background.js"]
},
"manifest_version": 2
}
Background.js
var ALLOW_COOKIES = [""];
if(chrome.extension.inIncognitoContext){
function changeRefer(details) {
foundReferer = false;
foundUA = false;
var reqHeaders = details.requestHeaders.filter(function(header) {
// block cookies by default
if (header.name !== "Cookie") {
return header;
}
allowHeader = ALLOW_COOKIES.map(function(url) {
if (details.url.includes(url)) {
return true;
}
return false;
});
if (allowHeader.reduce(function(a, b) { return a || b}, false)) { return header; }
}).map(function(header) {
if (header.name === "Referer") {
header.value = "https://www.google.com/";
foundReferer = true;
}
if (header.name === "User-Agent") {
header.value = "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
foundUA = true;
}
return header;
});
// append referer
if (!foundReferer) {
reqHeaders.push({
"name": "Referer",
"value": "https://www.google.com/"
});
}
if (!foundUA) {
reqHeaders.push({
"name": "User-Agent",
"value": "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
});
}
console.log(reqHeaders);
return {requestHeaders: reqHeaders};
}
function blockCookies(details) {
for (var i = 0; i < details.responseHeaders.length; ++i) {
if (details.responseHeaders[i].name === "Set-Cookie") {
details.responseHeaders.splice(i, 1);
}
}
return {responseHeaders: details.responseHeaders};
}
chrome.webRequest.onBeforeSendHeaders.addListener(changeRefer, {
urls: ["<all_urls>"],
types: ["main_frame"],
}, ["requestHeaders", "blocking"]);
chrome.webRequest.onHeadersReceived.addListener(blockCookies, {
urls: ["<all_urls>"],
types: ["main_frame"],
}, ["responseHeaders", "blocking"]);
}
I guess that your concern is the extra redundant background page process?
Add "incognito": "split" in the manifest file and close the extension's background page in non-incognito mode:
// background page or event page:
if (!chrome.extension.inIncognitoContext) {
window.close();
}
Content scripts will still be run in non-incognito pages. To counter that, just exit your code after checking whether your extension is running in incognito mode (similar to the above check).
Note: If the extension is going to be published and only useful in incognito mode, consider checking whether incognito mode is enabled and offer instructions if it's disabled. See e.g. How can I enable my chrome extension in incognito mode?

Chrome Extension not working (Error with permissions?)

Thanks for taking the time to read this.
Here is the directory of my extension folder.
And here is the manifest code :
{
"manifest_version": 2,
"name": "Technobuffalo Stories",
"description": "Your Description about Extension goes here",
"version": "1.0",
"content_scripts": [ {
"js": [ "popup.js" ],
"matches": [ "http://feeds.feedburner.com/*" ]
} ],
"permissions": [ "http://feeds.feedburner.com/*" ],
"browser_action": {
"default_icon": "icon_16.jpeg",
"default_popup": "popup.html"
}
}
Here is popup.html :
<html>
<head>
<title>Technobuffalo Stories
</title>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script src="popup.js"></script>
</head>
<body>
<div id="feed" style="background-color:orange;height:500px;width:500px;" ></div>
</body>
</html>
and last of all here is popup.js :
google.load("feeds", "1");
function initialize() {
var feed = new google.feeds.Feed("http://feeds.feedburner.com/technobuffalo/rss?format=xml");
feed.load(function(result) {
if (!result.error) {
var container = document.getElementById("feed");
for (var i = 0; i < result.feed.entries.length; i++) {
var entry = result.feed.entries[i];
var div = document.createElement("div");
div.appendChild(document.createTextNode(entry.title));
container.appendChild(div);
}
}
});
}
google.setOnLoadCallback(initialize);
When I open the popup.html file as it is, the required result is displayed but when I load the Chrome extension, only the background color of the div can be seen. Is there any problem with the permissions that I have set or is it something else?
Thanks,
Yash.
You have to add the following line to manifest.json to be able to use resources from www.google.com:
"content_security_policy": "script-src 'self' https://www.google.com; object-src 'self'"
As Rob W already pointed out this is a security feature that has been introduced with manifest version 2.

Resources