1

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"
    }
}

Dev Topia
  • 23
  • 4
  • Including the relevant code would be helpful here, especially the code that shows how you are manipulating the background image. The error you are seeing is due to the website's [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). With strict CSPs you can't arbitrarily inject resources or execute code. You can work around this in a few different ways, but without seeing your code, it'll be hard to say which is best. I'd look at [web accessible resources](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/web_accessible_resources). – justinw Sep 02 '22 at 19:36
  • @justinw Thanks, just updated the question to include the relevant code. – Dev Topia Sep 02 '22 at 20:30
  • Is that javascript coming from a content script? background page? The problem you are seeing is due to a Content Security Policy on the website where you are executing the code. Content Security Policies can get updated and change whenever the website admin decide, this is why it might have not been a problem originally. You'd want to circumvent the Content Security Policy to avoid this issue. You can do this by rewriting headers (not advisable) or rebuilding your extension to use a web accessible resource (link in prev comment) - it won't be a quick fix – justinw Sep 02 '22 at 22:25
  • @justinw It's from the background.js. Is there a way I can have the user upload from a file system and save the image locally, would that also work? – Dev Topia Sep 02 '22 at 22:55
  • I am honestly not sure if that would work or not, but it seems like it would be worth a try. You could try fetching the image, converting it to data and loading it that as well. Since the CSP allows for `self`, that could possibly work. -[reference](https://stackoverflow.com/questions/38810956/set-background-image-to-a-blob-uri) / [reference](https://stackoverflow.com/questions/42471755/convert-image-into-blob-using-javascript) – justinw Sep 03 '22 at 01:24

1 Answers1

1

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:;
Rahul Sharma
  • 5,562
  • 4
  • 24
  • 48
  • After trying that method I'm getting the following, " 'content_security_policy.extension_pages': CSP directive 'script-src' must be specified (either explicitly, or implicitly via 'default-src') and must allowlist only secure resources." Any help appreciated. – Dev Topia Sep 08 '22 at 18:46
  • Could you please show your `manifest.json` file? – Rahul Sharma Sep 08 '22 at 18:59
  • Just updated to OP to include the manifest – Dev Topia Sep 08 '22 at 19:46
  • @DevTopia It was with the assumption that you already had a content security policy in place. I've updated the the answer with a policy that should work for you. You should read more about CSP and what purpose does it serve. For starters you could go here: https://content-security-policy.com/ – Rahul Sharma Sep 09 '22 at 06:18