I am learning to make a chrome extension and deveoped one with a popup browser action and have the following js file (called in popup.html via )
chrome.tabs.executeScript({
code:
"var frameworks = [];" +
"if(!!window.Vue) frameworks.push('Vue.js');" +
"if(!!window.jQuery) frameworks.push('jQuery.js');" +
"frameworks;"
}, (frameworks) => {
document.body.innerHTML = frameworks[0].length
})
But when I am testing it on my website made using both vue and jquery it returns 0, I also checked it on other websites but all behaved same.
What am I doing wrong here?
Related
I'm making an extension for chrome where the user can input a script, then press "run" to inject it into the current tab. I am using MV3 (manifest v3). Are there any ways to do this?
My code:
HTML:
<div class="scriptrunner">
<h1>Script Runner</h1>
<textarea placeholder="Enter script here" id="script"></textarea>
<button id="run">Run Script</button>
</div>
Javascript:
let button = document.getElementById("run");
button.addEventListener("click", async () => {
let input = document.getElementById("script");
let script = input.value;
// this is where the script would be ran
});
I've tried the following:
Using chrome.scripting.executeScript()
Using eval()
Using chrome.scripting.executeScript() to insert a script tag with a function, then running the function
I just started working on chrome extensions, so maybe I missed something, or this is just impossible.
Executing arbitrary user code (userscripts) isn't yet implemented in ManifestV3 and is still forbidden by the policies of Chrome's Web store for extensions.
The personal workaround (e.g. in an unpacked extension) is to run such code in the page context i.e. not as a content script:
async function execInPage(code) {
const [tab] = await chrome.tabs.query({currentWindow: true, active: true});
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: code => {
const el = document.createElement('script');
el.textContent = code;
document.documentElement.appendChild(el);
el.remove();
},
args: [code],
world: 'MAIN',
//injectImmediately: true, // Chrome 102+
});
}
execInPage('console.log(123)');
Warning! This may be blocked by the site if it has a strict Content-Security-Policy, in which case you can remove this header via declarativeNetRequest API.
I'm developing a react app based chrome extension which uses Google's material design and has a couple of pages with navigation.
I want to inject the extension inside the browser tab when the extension is launched from the browser address toolbar. I've seen multiple extensions do so by injecting a div(inside the body of webpage) containing an iframe with src equal to the extension's pop-up HTML page.
I execute the following function when the extension is launched. Which basically injects the extension into the target webpage body but it appears multiple times inside the target web page.
function main() {
const extensionOrigin = "chrome-extension://" + chrome.runtime.id;
if (!location.ancestorOrigins.contains(extensionOrigin)) {
// Fetch the local React index.html page
fetch(chrome.runtime.getURL("index.html") /*, options */)
.then((response) => response.text())
.then((html) => {
const styleStashHTML = html.replace(
/\/static\//g,
`${extensionOrigin}/static/`
);
const body = document.getElementsByTagName("body")[0];
$(styleStashHTML).appendTo(body);
})
.catch((error) => {
console.warn(error);
});
}
}
See Image of Incorrect Injection
Any help or guidance would be very appreciated. Thanks!
I have a Chrome extension (https://chrome.google.com/webstore/detail/apsic-xbench-extension-fo/nhadbgflnognogbicnbeepnbpehlocgc) that suddenly stopped working right after the Chrome 73 update.
The symptom is that if I go to the page where the extension is designed to work (https://translate.google.com/toolkit) and I click on the extension icon, instead of running the background page code, the pop-up menu for the extension appears (as if I had right-clicked the icon).
However, if I load the exact same code locally (not from the store), the Chrome extension runs fine.
The background page console for the extension loaded from the store does not seem to issue any error. If I place a breakpoint for the first line in the onClicked listener for the page action, it does not stop there for the Chrome store extension (and the breakpoint works fine for the extension loaded locally).
Why do I get different behaviors if I load the extension from the Chrome store or I load it locally?
In Chrome 72, the extension worked fine.
Answering own question: I tracked down the issue. It turned out that if the Chrome extension was installed from the Chrome store using Chrome 72, then it did not work right after the update to Chrome 73.
However, if after Chrome 73 is updated, you remove the extension and add it again from the Chrome store, then the Chrome extension works again. Strange but true.
Chrome 73 inject some new security. Just try to move your xHTTP requests to your background script with chrome.runtime.sendMessage and get response with SendResponse callback.
In content or popup script replace ajax with :
chrome.runtime.sendMessage(
{ action: "check", data: {/* params for url */}},
// callback with url response
function(response) {
if( response.success ) {
var myDataFromUrl = response.data;
...
} else {
console.log('Error with `check`,', response.data);
}
}
);
From background script:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
var url = 'https://mysyte.com/';
if(request.action === 'check' ) {
url = url + 'check'
ajax( url, request.data,
success: function( d ) {
sendResponse({success: true, data: d});
},
error : function( d ) {
sendResponse({success: false, data: d});
}
);
}
});
function ajax( url, params, cbSuccess, cbError ) { ... }
I know that there's a bunch of questions about the "not allowed by Access-Control-Allow-Origin." error.
But I've tried some of them without success. :(
Some appointments:
I'm trying to build a dev-tools-tab extension
I can touch flickr API like the example shows
I can't reach localhost
Already tried several permission wildcards
http://localhost/
http://*/
*://*/
Already tried pack'd and unpack'd extensions
currently, manifest.json has
"version": "0.0.1",
"manifest_version": 2,
"devtools_page": "components/devtools.html",
"permissions": [
"http://*/"
]
devtools.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script src="../js/devtools.js"></script>
</body>
</html>
and, devtools.js
(function (window) {
"use strict";
var xhr1, xhr2, url;
xhr1 = new window.XMLHttpRequest();
xhr2 = new window.XMLHttpRequest();
xhr1.onreadystatechange = function () {
if (this.readyState === 4) {
console.log('flickr ok');
}
};
xhr2.onreadystatechange = function () {
console.log(this.readyState);
if (this.readyState === 4) {
console.log(this.responseText);
}
};
url = 'https://secure.flickr.com/services/rest/?' +
'method=flickr.photos.search&' +
'api_key=90485e931f687a9b9c2a66bf58a3861a&' +
'text=' + encodeURIComponent('cats') + '&' +
'safe_search=1&' +
'content_type=1&' +
'sort=interestingness-desc&' +
'per_page=20';
xhr1.open('get', url, true);
xhr1.send();
url = 'http://apache.local';
xhr2.open('get', url, true);
xhr2.setRequestHeader('Origin', url);
xhr2.send();
Chrome console output:
1 devtools.js:12
Refused to set unsafe header "Origin" devtools.html:1
XMLHttpRequest cannot load http://apache.local/. Origin chrome-extension://nafbpegjhkifjgmlkjpaaglhdpjchlhk is not allowed by Access-Control-Allow-Origin. devtools.html:1
4 devtools.js:12
flickr ok devtools.js:8
Chrome version:
28.0.1500.20 dev
Thanks in any advice.
I've got it!
Actually, the problem is that I'm trying to perform XHR requests on devtools page and it seems to have no permissions to bypass cross-origin-access policies like a popup page do.
Devtools tab tries are also unsuccessful.
edit
Is an stage-permission related. Not wildcard-permission. As I've said, I've managed to perform queries on some domains, yet not having they explicitly on my permissions array.
The problem really lies on the type of script running.
The same script, if used as a popup, work'd fine. So, I've tried as an background-script with success too! I was facing the problem that devtools_page and related doesn't have such permissions...
The APIs available to extension pages within the Developer Tools window include all devtools modules listed above and chrome.extension API. Other extension APIs are not available to the Developer Tools pages, but you may invoke them by sending a request to the background page of your extension, similarly to how it's done in the content scripts.
http://developer.chrome.com/extensions/devtools.html
That level of script denies non explicit cross xhrs.
Solved the problem putting the requests in a background script and using messages api.
Thank you!
I've read all the cross domain iframe posts here (my thanks to all of you!) and elsewhere.
The postMessage script at cross-domain iframe resizer? works beautifully in Firefox 5 and up. It resizes the iframe every time a page is clicked within the iframe perfectly.
But it doesn't resize at all in IE (7 8 or 9) on my computer. I checked the security settings and the one in IE for access across domains was checked to enable.
Does postMessage not work in IE? - Or is there something else that needs to be added? thanks
It's a great script from thomax - it also works on so you can use iframes on mobile - iphones and android
For IE7 and IE8, you have to use window.attachEvent instead of window.addEventListener
It should also be onmessage instead of message (see below) ps you also need to do the same on the server with the content posting its size
<script type="text/javascript">
if (window.addEventListener)
{
function resizeCrossDomainIframe(id) {
var iframe = document.getElementById(id);
window.addEventListener('message', function(event) {
var height = parseInt(event.data) + 32;
iframe.height = height + "px";
}, false);
}
}
else if (window.attachEvent)
{
function resizeCrossDomainIframe(id) {
var iframe = document.getElementById(id);
window.attachEvent('onmessage', function(event) {
var height = parseInt(event.data) + 32;
iframe.height = height + "px";
}, false);
}
}
</script>
Using Peter's code and some ideas from here, you could separate out the compatibility from the executable code, and add some cross-site validation.
<script type="text/javascript">
// Create browser compatible event handler.
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen for a message from the iframe.
eventer(messageEvent, function(e) {
if (e.origin !== 'http://yourdomain.com' || isNaN(e.data)) return;
document.getElementById('iframe_id_goes_here').style.height = e.data + 'px';
}, false);
</script>
Also, for completeness, you could use the following code within the iframe whenever you want to trigger the resize.
parent.postMessage(document.body.offsetHeight, '*');
You can use the implementation of Ben Alman. Here is an example of cross-domain communication, including an example of iframe resize.
http://benalman.com/code/projects/jquery-postmessage/examples/iframe/
According to the documentation, it works on Internet Explorer 6-8, Firefox 3, Safari 3-4, Chrome, Opera 9.
Having looked a lots of different solutions to this I ended up writing a simple jQuery plugin to take a account of a number of different use cases. As I needed a solution that supported multiple user generated iFrames on a portal page, supported browser resizes and could cope with the host page JavaScript loading after the iFrame. I also added support for sizing to width and a callback function and allow the override of the body.margin, as you will likely want to have this set to zero.
https://github.com/davidjbradshaw/iframe-resizer
The host page users jQuery, the iframe code is just a little self-contained JavaScript, so that it's a good guest on other people pages.
The jQuery is then initialised on the host page and has the following available options. More details on what these do on the GitHub page.
$('iframe').iFrameSizer({
log: false,
contentWindowBodyMargin:8,
doHeight:true,
doWidth:false,
enablePublicMethods:false,
interval:33,
autoResize: true,
callback:function(messageData){
$('p#callback').html('<b>Frame ID:</b> ' + messageData.iframe.id +
' <b>Height:</b> ' + messageData.height +
' <b>Width:</b> ' + messageData.width +
' <b>Event type:</b> ' + messageData.type);
}
});
If you set enablePublicMethods, it gives you access in the iframe to manually set the iFrame size and even remove the iframe from the host page.