Access open shadow-root from browser extension content script (Chrome / Firefox) - google-chrome-extension

Within the elements tab of the browser development tools, the shadow root appears as #shadow-root (open) and it is accessible from the development console via document.getElementById('parent').shadowRoot, where the element with id of parent contains the shadow root. However, from the content script of a Chrome browser extension the same code results in null (while document.getElementById('parent') of course works as expected). Is it possible to access shadow-root from a browser extension?
TL;DR. Tried to access the shadow-root element from a browser extension in the same way that it is accessible from the developer's console. Expected it to work in a browser extension in the same way that it works in the developer's console.
manifest.json
{
"content_scripts": [ {
"exclude_globs": [ ],
"exclude_matches": [ ],
"include_globs": [
"https://*.test.com/*"
],
"js": [
"script.js",
],
"matches": ["http://*/*","https://*/*"],
"run_at": "document_idle",
//"run_at": "document_end",
"all_frames": true
} ],
"permissions": [
"cookies",
"storage",
"http://*/",
"https://*/",
"tabs",
"contextMenus",
"management",
"clipboardWrite",
],
"converted_from_user_script": false,
"description": "test",
"key": "--",
"name": "test",
"version": "1.0",
"manifest_version": 2
}
script.js
if (document.readyState == "complete" || document.readyState == "interactive") {
console.log(document.getElementById('parent').shadowRoot);
} else {
document.onreadystatechange = function () {
if (document.readyState == "complete" || document.readyState == "interactive")
{
console.log(document.getElementById('parent').shadowRoot);
}
}
}

Related

Linking to local files within css file

I'm attempting to completely overhaul a websites css and possibly html and just trying to find a way that works for me.
The problem is that within an extension local css file I'm also trying to define a font url via extension local files.
manifest.json:
{
"name": "Test theme",
"description": "Custom theme for Darkmass.gg.",
"version": "0.0.1",
"manifest_version": 3,
"content_scripts": [
{
"matches": [
"https://*.example.com/*"
],
"css": [
"./css/main.css"
],
"js": [
"./js/app.js"
],
"run_at": "document_end"
}
],
"web_accessible_resources": [
{
"resources": [ "./media/*" ],
"matches": [ "https://*.example.com/*" ]
}
]
}
main.css:
#font-face {
font-family: NFLDolph;
src: url('chrome-extension://ipbedjgbhlnngdddbaojpnaicdpifmgd//media/fonts/NFLDOLPH.TTF');
}
The problem clearly lies with the source url for the NFLDolph font-face, if I just leave it as ./media/fonts/NFLDOLPH.ttf than it just tries to load the font from example.com instead of locally.
And here is the error I get:
Denying load of chrome-extension://ipbedjgbhlnngdddbaojpnaicdpifmgd//media/fonts/NFLDOLPH.TTF. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.
I made a sample.
manifest.json
{
"name": "NFLDolph",
"version": "1.0",
"manifest_version": 3,
"content_scripts": [
{
"css": [
"main.css"
],
"matches": [
"<all_urls>"
]
}
],
"web_accessible_resources": [
{
"resources": [
"font/*.TTF"
],
"matches": [
"<all_urls>"
]
}
]
}
main.css
#font-face {
font-family: NFLDolph;
src: url("chrome-extension://__MSG_##extension_id__/font/NFLDOLPH.TTF");
}
* { font-family: NFLDolph, serif }

Injected script was not load

manifest.json
{
"manifest_version": 3,
"name": "Inject Scripts",
"version": "1.0",
"content_scripts": [{
"matches": [
"*://*/*"
],
"run_at": "document_end",
"js": [
"content.js"
]
}],
"web_accessible_resources": [{
"resources": [
"every site .js"
],
"matches": []
}]
}
content.js
document.head.insertAdjacentHTML('beforeend', ˋ<script src="${chrome.runtime.getURL('every site .js')}"></script>ˋ)
every site .js
console.log('injected')
<script> was inserted to <head> successful with the src="chrome-extension://<extension ID>/every site .js" attribute but there is neither console.log output nor Error message.
I installed my extension locally by enabling "Developer mode" and "Load unpacked" in "chrome://extensions/".
Do I need to specify "permissions" in manifest.json?

Script injection on mail.google.com using chrome extension

I am working on a chrome extension in which I am replacing the chrome's web API function navigator.credentials.create with a custom handler. navigator.credentials.create is called when a user initiates a 2FA registration for a security key.
The custom handler is working on facebook.com but, it doesn't work on mail.google.com.
I have attached the minimal code for the extension I'm working on. This script is injected on every page and can be confirmed through console "injected script". In my sample app, I printed a console statement "In extension's create" in the custom handler of navigator.credentials.create. This should be printed whenever a user initiates the 2FA registration process. It is working for facebook but doesn't work on https://myaccount.google.com/. I have verified that the script is inserted in all iframes available on the website. I also confirmed that mail.google.com is not using service workers to call navigator.credentials.create API.
content_script.js
const webauthnInject = document.createElement('script');
webauthnInject.type = 'text/javascript';
webauthnInject.src = 'chrome-extension://' + chrome.runtime.id + '/inject_webauthn.js';
document.documentElement.appendChild(webauthnInject);
inject_webauthn.js
(() => {
console.log("injected script");
const real_create = navigator.credentials.create;
navigator.credentials.create = async function() {
console.log("In extension's create");
let res = await real_create.bind(navigator.credentials)(arguments[0]);
return res;
};
})();
manifest.json
{
"manifest_version": 2,
"name": "sample app",
"description": "A Sample app",
"version": "1.0.2",
"minimum_chrome_version": "36.0.1985.18",
"content_scripts": [
{
"all_frames": true,
"match_about_blank": true,
"matches": [
"https://*/*",
"http://*/*"
],
"exclude_matches": [
"https://*/*.xml"
],
"run_at": "document_start",
"js": [
"content_script.js"
]
}
],
"background": {
"persistent": false,
"scripts": [
"background.js"
]
},
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"permissions": [
"tabs",
"storage",
"https://*/*",
"http://*/*"
],
"web_accessible_resources": [
"inject_webauthn.js"
]
}

Running jquery script triggered by context menu in chrome extension

I am new to chrome extension development. The sample code I have is not running properly.
Requirement: Executing any jquery script(say $("body").hide();) on click of context menu button.
From the code, only jquery part is not working.
I have following files:
manifest.json
{
"manifest_version": 2,
"name": "jQuery DOM",
"version": "1",
"permissions": [
"contextMenus","tabs","activeTab"
],
"background": {
"scripts": ["jquery.min.js","sample.js"]
},
"description": "Manipulate the DOM when the page is done loading",
"browser_action": {
"name": "Manipulate DOM",
"icons": ["icon.png"],
"default_icon": "icon.png"
},
"content_scripts": [ {
"js": [ "jquery.min.js", "background.js" ],
"matches": [ "http://*/*", "https://*/*"],
"run_at": "document_end"
}]
}
background.js
$("body").append('Test');
I have icon.png in folder, and it gets loaded well.
jquery.min.js in same folder
sample.js
alert("Extension loaded");
function genericOnClick(info, tab) {
alert("Tab "+tab.id);
chrome.tabs.executeScript(tab.id, {
file: "jquery.min.js",
allFrames: true
},function(){
alert("callback");
$("body").hide();
});
alert("Completed");
$("body").hide();
}
var contexts = ["page"];
for (var i = 0; i < contexts.length; i++) {
var context = contexts[i];
var title = "Test Page menu item";
var id = chrome.contextMenus.create({"title": title, "contexts":[context],
"onclick": genericOnClick});
console.log("'" + context + "' item:" + id);
}
background.js works!
All the alerts work file, but .hide function from genericOnClick doesn't work.
Even if I move the code from sample.js to backgroud.js, it won't work.
Can you please tell me where did i go wrong ?
As I mentioned, a background script isn't allowed to interact with the DOM, (while a content script isn't allowed to use chrome.contextMenus). You need to combine both, and use message passing to tell the content script when to execute. Some other adjustments I made:
I renamed background.js and content.js so that their names now
reflect what they do, and made background.js into an event page.
I removed the browser action (the
extension would need browserAction.html or background.js would
need chrome.browserAction.onClicked.addListener to do anything
other than show the icon).
Programmatically injecting jquery means that always loading it as a
content script is unnecessary (although skipping programmatic injection allows you to omit the last three permissions).
background.js doesn't need jquery
anymore, so it isn't loaded there either.
The default executeScript
tab is the active tab, so we don't need it's id.
Here's the finished product:
manifest.json
{
"manifest_version": 2,
"name": "jQuery DOM",
"version": "1",
"permissions": [
"contextMenus", "activeTab", "tabs", "http://*/", "https://*/"
],
"background": {
"scripts": [ "background.js" ],
"persistent": false
},
"content_scripts": [ {
"js": [ "content.js" ],
"matches": [ "<all_urls>" ]
}],
"description": "Manipulate the DOM when the page is done loading"
}
background.js
function genericOnClick(info, tab) {
chrome.tabs.executeScript(null,
{"file": "jquery.min.js"},
function() {
chrome.tabs.sendMessage(tab.id,{"message":"hide"});
});
}
chrome.contextMenus.create({"title": "Test Page menu item",
"contexts":["page"],
"id":"contextId"});
chrome.contextMenus.onClicked.addListener(genericOnClick);
content.js
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg.message == 'hide') {
$("body").hide();
}
sendResponse();
});
Your content.js is probably much larger than it is here (+1 for the SSCCE). But if it is small, another option would be to omit the content script entirely, and replace the sendMessage with chrome.tabs.executeScript(null,{code:"$('body').hide();"});.

Content Security Policy doesn't allow mixed content

I am trying to access an internal machine of my network via chrome extensions. I am calling a php file from my chrome extension. I am using manifest file as follows:
{
"content_scripts": [ {
"js": [ "lib/jquery.js", "lib/jquery-ui.js", "lib/util.js" ],
"matches": [ "*://plus.example.com/*", "*://tools.example.com/*" ]
}, {
"js": [ "tools/g_tool.js" ],
"matches": [ "*://plus.example.com/*" ]
}, {
"js": [ "tools/b_tool.js" ],
"matches": [ "*://tools.google.com/*" ]
} ],
"icons": {
"128": "images/icon_128.png",
"16": "images/icon_16.png",
"48": "images/icon_48.png"
},
"manifest_version": 2,
"name": "Tool",
"permissions": [ "*://plus.example.com/*", "*://tools.example.com/*", "http://myusername-example.com/*"],
"version": "0.7",
"web_accessible_resources": [ "images/loading.gif" ]
}
The internal machine which I am using can be used only via http. So, I am looking around for a way to use it in my chrome extension.

Resources