Dynamic Insert into iFrame w/ ActiveTab permission -- Denied?

255 views
Skip to first unread message

John Gordon

unread,
Jun 19, 2024, 9:40:06 AMJun 19
to Chromium Extensions
I'm getting this error when attempting to dynamically inject a script into an iFrame of the active tab:

Error encountered: Error: error injecting script into tab '1071087490' and frame '350': Error: Cannot access contents of the page. Extension manifest must request permission to access the respective host.

Here's my code:

chrome.scripting.executeScript({
target: {
tabId: tab.id!,
frameIds: [frameId],
},
files: [contentScript],
}),

And my manifest permissions:
permissions: [
"storage",
"contextMenus",
"activeTab",
"scripting",
"webNavigation",
],

The injection process is started when the user selects a context menu item, which I believe gives me host_permissions to go HOG WILD! on the active tab, including the iFrames within it, but I'm being denied!

ideas:

Maiybe there's something with the iFrames url that makes it a cross-origin issue, and I'm denied for that reason. Here are the urls of the tab and the iFrame:

Tab:
https://www.thewebsite.app.thewebsiteinc.com/profound

iFrame:
https://dms08a.thewebsite.app.thewebsiteinc.com/dtdms?suffixid=1&token=%22eyJraWQiOiJRUHhzQ0lKY0VfenJrS2VCTWtkN2JKdkRMUWpBR1ZqY2VVQzRKMnpZRVg0IiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULkgtc0VKcWRnc2tHU3JfU3NCb0xlWGtscDRabTdJVGlDblFXTXpLYWNjVzQiLCJpc3MiOiJodHRwczovL2F1dGhvcml6ZS5jb3hhdXRvaW5jLmNvbS9vYXV0aDIvYXVzMTMyc3Y3OUpwQVlpbkUzNTciLCJhdWQiOiJwcm9kdWN0aW9uLXJlc291cmNlcyIsImlhdCI6MTcxODcxNjM5NCwiZXhwIjoxNzE4NzE3Mjk0LCJjaWQiOiIwb2ExdWMzanR0RGEzeWVlbjM1NyIsInVpZCI6IjAwdWR2bXphMHZXOGI3VjBDMzU3Iiwic2NwIjpbImRtcy5kZWFsZXJncm91cC1kZWFsZXJzaGlwLnJlYWQiLCJvcGVuaWQiLCJwcm9maWxlIiwiZG1zLmdsb2JhbC11c2VyLnJlYWQiXSwiYXV0aF90aW1lIjoxNzE4NzE2MzkyLCJzdWIiOiIwZDgwMzBjYS0yYjUyLTQ0N2UtYmYwOS0wNjZlZDgxMzZhYjQiLCJjbHMiOiJ1c2VyIn0.X_HIBKQtHLzT6HG5JjEAj3rz4M-yACPXGrodZxNcW-jOJlHSLO9Zw_wyT1L_IlxFJ2MpmAdIw3-kBFvl0vbaqtNuGoVpUhSuPOY_WrclRWWIfFJoEGO91gEbYNpEJw8GWnWCpVDdskQpqW-W3pW1-hlqwaS1VH7JpKPHfdKdfy9_xQ_EpNzm2Dq6tT_scG1025Xt_JcQfEEpOVC73KJo10bCOH8-JhGf_0Hz08X7EG9Ujxjz8THwGoImP_C56aIw0g3h3ccV3IygAccOTUQNoq1yOQSYjYoO1KWWibq8jivHy9CShQKxPh7U6EqrsZycwivlKe2gvM-BEY3IMN84AQ%22&FusionDealershipID=410019579&Skin=content-only&cdccw=true"

I think that the domains should work okay, though.

Idea 2:

My god-like host_permissions for the active tab are lost somewhere as I'm calling my code. Somehow the magic powers granted to me with the activeTab permission when the user invokes the context menu are lost by the time I go to insert the page.

My code flow:

background.ts:  registers an asynchronous event handler for the chrome.contextMenus.OnClicked event. The handler code is in another typescript module.

handleMenuitemClick.ts: attempts to inject the script first. It calls a function in another typescript module in my extension code to do this.

Last thoughts:

When inserting into the tab itself, frameId = 0, all is well. But I get the failure when attempting to insert into that iFrame.

This isn't an issue when I use chrome.scripting.executeScript() with allFrames: true. I do see my content script inserted when I inspect the source files of the page in chrome's developer tools, but I don't know if the script was just inserted into the tab, and not the iFrame (anyone know how to check if the content script was inserted into an iFrame of the tab?).

Thanks for reading all this and your help!





woxxom

unread,
Jun 19, 2024, 10:22:17 AMJun 19
to Chromium Extensions, John Gordon
activeTab grants access only to the tab, see https://crbug.com/41379298.


> anyone know how to check if the content script was inserted into an iFrame of the tab?

You can add to your code something like console.log(window==top ? 'main doc' : 'iframe', document)

You can also expand the context selector in console toolbar. The name of the extension will be listed under the top document or frame. This works only for content scripts in an isolated world, not in the main world. Note that it doesn't show the name of the content script, it just shows that the extension has an isolated world there.

John Gordon

unread,
Jun 19, 2024, 10:55:48 AMJun 19
to Chromium Extensions, woxxom, John Gordon
Thanks for the link. Very helpful. I was able to solve my problem by adding "*://*.thewebsite.app.thewebsiteinc.com/profound/*" to my host_permissions in the manifest file. It's a bummer that I have a security notice in my extension's details -- I would've loved just rolling with activeTab and scripting -- but it doesn't seem possible.

You're a great help, woxxom. Don't ever quit your day job ;-).

Rahul Bansal

unread,
Oct 6, 2024, 12:35:50 PMOct 6
to Chromium Extensions, John Gordon, woxxom
so this is still a problem?
The way to make it work is by adding a host permission.

John Gordon

unread,
Oct 7, 2024, 9:40:39 AMOct 7
to Rahul Bansal, Chromium Extensions, woxxom

Yep, this was addressed, but by using optional_host_permissions instead of host_permissions. This makes it so the extension doesn't have scary privacy warnings for users:

optional_host_permissions: ["*://*/*"],

The gist is that you can detect if the extension has host permissions for the current tab or embedded cross-domain iframe. If it doesn't, it can request them at runtime. When requested, a dialog is displayed to the user. The benefit here is that you don't have to hard-code all of your hosts you want access to, and that the extension isn't disabled if you had to add a new host permissions entry.

Code to implement in a context menu handler:

chrome.contextMenus.onClicked.addListener((onClickData, tab) => {
if (!tab || !isMyMenuItem(onClickData)) return;

const hostName = extractHostName(onClickData, tab);

const handlePermissionGranted = () =>
handleMenuItemClick(tab, onClickData.frameId)();

const handlePermissionDenied = () => {
console.log(`User denied host_permission for "${hostName}"`);
};

const handlePermissionRequest = (hasPermission: boolean) => {
if (hasPermission) {
handlePermissionGranted();
} else {
chrome.permissions.request(
{ origins: [`*://${hostName}/*`] },
(permissionGranted) => {
permissionGranted
? handlePermissionGranted()
: handlePermissionDenied();
},
);
}
};
 
  //this is the meat of the handler here
try {
if (isIframe(onClickData)) {
checkPermissionsAndRequestIfNeeded(hostName, handlePermissionRequest);
} else {
handlePermissionGranted();
}
} catch (e) {
catchExceptionForSentry(e);
}
});
Reply all
Reply to author
Forward
0 new messages