Chrome Extension imports/exports - javascript

I'm failing hard in trying to import/export functions from one file to another with a Chrome Extension. My problem is the following:
I have one script that's loaded as a content script from the manifest.js file. That script's name is script.js. In that script, I have a code like this to detect the URL of the webpage I've opened (in order to start my extension):
chrome.runtime.sendMessage({ command: 'currentTab' }, (tab) => { console.log('We're in.') });
Also, in the same script I have a function to attach two other scripts that I will use them as modules since they have export/import functions. These are: core.js and utils.js. The function is:
injectScript('extension.../modules/core.js');
injectScript('extension.../modules/utils.js');
function injectScript(scriptURL) {
const script = document.createElement('script');
script.setAttribute('type', 'module');
script.setAttribute('src', scriptURL);
const head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
head.insertBefore(script, head.lastChild);
}
So, this first script.js sends a message to the background.js script in order to check for the tab URL and if everything's correct, I'll insert as modules my two other scripts.
Now, when I detect the URL of the website as OK, I would like to execute a function start() (which is in core.js) from this main script.js in order to execute everything from core.js that uses imported functions from utils.js.
I've also detected that if I inject my utils.js with the script.js it also injects it through the manifest.json. I'm really stuck in here guys. Could you give me a hand with this spaghetti mess?
Thank you!

Related

Chrome edit 3rd party script [duplicate]

I would like to override a javascript file with my own version of the similar javascript file in chrome.
Let me explain:
Lets say a site 'http://example.com' calls 'http://example.com/script/somescript.js'.
What I would like to do is override the file 'http://example.com/script/somescript.js' with my own version located at 'http://localhost/script/somescript.js'.
I need to effectively modify a function in the original Javascript file.
With Chrome 65 this has become trivial.
Using local overrides – Chrome 65
What is it?
It is a new feature that allows us to override a websites code/css with a local copy that is persisted across sessions. Once you override a file it shall remain until you remove the override.
How to set it up?
Open the Sources panel.
Open the Overrides tab.
Open overrides tab
Click Setup Overrides.
Select which directory you want to save your changes to.
At the top of your viewport, click Allow to give DevTools read and write access to the directory.
Make your changes.
After you add a folder you can switch to the network tab and right click on any file and select “Save for overrides”. I have already overridden scripts.js so it shows with a “blue dot”.
There are plugins and tools in Chrome for these purposes:
Chrome's DevTools, tab Local Overrides (supported from Chrome 65)
Requestly
Resource Override
You might also want to use Tamper, which is a mitmproxy based devtools extension that lets you edit remote files locally and serve them directly to Chrome. (but it's more headache to install and use it)
Choose the one which is easier to use for you.
You can create a chrome extension yourself. It is surprisingly easy and takes only a few minutes if you use a tool like yeoman chrome extension. Create a new directory and run the generator
yo chrome-extension
Enter a name for your extension and a short description. Select Page Action and that you want to use Content Scripts. You can ignore other options - follow this excellent guide if you come in doubt, but it is really straight forward.
? What would you like to call this extension? insert-script
? How would you like to describe this extension? replace a function with another function
? Would you like to use UI Action? Page Action
? Would you like more UI Features? Content Scripts
? Would you like to set permissions?
..etc. Now you have a directory structure like this
app
bower_components
images
_locales
scripts.babel
background.js
chromereload.js
contentscript.js
You cannot replace an existing loaded remote script with another script, since the script already is loaded into the DOM. But you can insert a new script at the end of body which overrides the function you want to replace. Functions is variables, if you add a new function to the document with the same name as an existing function, the new function will be executed instead of the old, exactly as if you declared a new variable with the same name as an existing variable. Now open and edit contentscript.js :
'use strict';
console.log('\'Allo \'Allo! Content script');
The code could look like this
'use strict';
var code = `
function foo() {
alert('foo');
}
`;
var script = document.createElement('script');
script.textContent = code;
document.body.appendChild(script);
Notice the template literal. We need to insert the code as a string, but with backticks it is more readable. Replace foo() with the function you want to override.
There is no need for deployment or bundling. You can install your extension right away from the path where you runned the generator
go to chrome://extensions
check developer mode
click upload unpacked extension
select manifest.json from your path
after that you just have to hit reload on the extensions page when you have made changes to contentscript.js.
you can load your file into the page by adding (or executing in the console) this script.
window.onload = function () {
var script = document.createElement('script');
script.src = '//localhost/your/script';
script.onload = function() {
console.log('your script have been loaded');
}
document.body.appendChild(script);
}
If the file that you want to override contains global functions/variables will be override with the new version in your file or if the elements that you want to override are namespaced just follow the path (e.g My.namespace.method = myNewMethod)
According to dharam's answer above,Resource Override works.
For people who doesn't have access to Chrome store,you can download the source here:
https://github.com/kylepaulsen/ResourceOverride
in Chrome,get into chrome://extensions/ ,enable developer mode,then load the extracted source root directory(which contains the file manifest.json) into Chrome.
tested for Chrome 73.0.3683.86 on Windows 10 .I can't post anything on StackOverflow before because https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js is blocked.Then in the settings of ResourceOverride,I map it to https://localhost/jquery-1.12.4.min.js and it finally works.
I run an ASP.NET Core 2.1 project with SSL enabled and localhost certificate enabled to serve jquery-1.12.4.min.js from local disk.
In the launchSettings.json,there is
"applicationUrl": "https://localhost:443;http://localhost:80",
in the Kestral profile(not IIS profile).

Injecting Google recaptcha's JS file in a chrome extension's content.js

New to chrome extensions and have the following issue:
I am trying to display recaptcha in my content script. As you know, it needs to include this <script src="https://www.google.com/recaptcha/api.js" async defer></script> tag, and since content scripts run in an isolated environment, I cannot just add it via
const script = document.createElement('script');
script.src = 'https://...';
// ...and so on
This accepted answer, however, illustrates a great way of script injection into a content script, but only for local files. So is there any way to include a script from a CDN?
Try doing it this way:
var apiScript = document.createElement('script');
apiScript.setAttribute('src','insert source here');
document.head.appendChild(apiScript);

JS function works on chrome console but not when load from plugin

So I have a webpage with a function applaud. When I call it from the console, I get the normal return:
applaud(3004,1935);
undefined
However, if I use CTG plugins (simple plugin to run a js script), with that code
applaud(3004,1935);
I get the following error in console:
3VM5444:1 Uncaught ReferenceError: applaud is not defined
at <anonymous>:1:1
(anonymous) # VM5444:1
and function isn't working.
Do you know how I can use it?
Thanks.
I know this is a bit outdated, but I can answer this. (I made the extension in question.)
Chrome Extensions by default insert scripts into a webpage in a different context than the rest of the page. This is for security reasons. If you'd like to run code in the context of the webpage, you'd need to use a little workaround.
In the script that the Chrome Extension injects, have that inject a <script> tag into the body of the page. Then that script will be loaded and be able to execute the functions like you can in the console.
Here's a demo of code that can do what I'm talking about:
//Create a new script element.
var script = document.createElement("script");
//Get the function you want to inject as a string and add it to the script.
script.innerHTML = injection.toString();
//Add a call to that injection function so it'll automatically execute once it's injected.
script.innerHTML += "injection();";
//Inject that newly created script into the body of the page.
document.body.appendChild(script);
//The contents of this script will be run inside the same context as the webpage.
function injection(){
applaud(3004, 1935);
}

Why can't my content script use already injected script?

For my Chrome extension, I inject a Javascript file and a CSS file that are needed for the modal to load up by using content.js. Injection is successful and I see those two files in the DOM.
And then I send a message to the background.js to do some stuff and this works too because I receive the message back from there. But my modal fails to load because it seems that it cannot use the injected Javascript file.
Let's say I have a function that inject the files into DOM. Let's call it inject(). I call this function at the start of the content.js file and they are injected successfully. But when I get back message from background.js and try to load the modal, it fails.
If I again try to call inject() function inside chrome.runtime.sendMessage function, the modal successful loads up.
In content.js I have the following code. I send a message to the background script whenever user click a link on the current page.
chrome.runtime.sendMessage(link,function(response){
inject(); //Now the modal loads. But if I remove this, the modal fails to load.
loadModalFunction(response);
});
My question then is if I had already injected modal.js and modal.css as soon as the page has loaded, why do I need to inject the files again to load the modal? My extension loads the modal whenever a user click a link on a page. So my concern is that if I have to inject the two files into the DOM whenever a user clicks something, it would make the page slow.
Update with more code:
In content.js:
function injectStuffs(){
var jquery = chrome.extension.getURL("jquery-1.11.3.min.js");
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = jquery;
$("head").append(script);
var modaljs = chrome.extension.getURL("modal.js");
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = modaljs;
$("head").append(script);
var link = document.createElement("link");
link.href = chrome.extension.getURL("modal.css");
link.type = "text/css";
link.rel = "stylesheet";
$("head").append(link);
}
injectStuffs() //Inject the scripts into ```DOM```
$(document).on('click', '.readmore a', function(event) {
event.preventDefault();
var link = $(this).attr('href');
chrome.runtime.sendMessage(link,function(response){
injectStuffs() //I need to inject here again to load the modal up. Why?
loadModal(response);
});
});
I'm actually surprised that calling injectStuffs() a second time works! I believe the problem is caused by the "isolated world" that your content script is running in:
Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. [reference]
When you list JavaScript files in the js property of a content script in your manifest, all those files are considered to be part of the content script, so each of the files can see the functions/variables defined in the others (but not in the page).
In contrast, when you inject JavaScript files by writing <script> elements to the DOM, those files are considered to be part of the page, so your content script can't see the functions/variables defined in them.
So in your situation, content.js is in your content script, but jquery-1.11.3.min.js and modal.js are in the page. That's why content.js can't call loadModal().
You probably want to add jquery-1.11.3.min.js and modal.js to your content script in the manifest. But if you really need to decide at runtime whether to load the JavaScript files, then see the docs for programmatic injection.

How to use javascript functions, defined in some external *.js file in browser's javascript console?

I would like to know is it possible to save some, for example,simplemath.js file with
function ADD(a, b)
{
return a + b;
}
simple function, run opera's or some other browser's javascript console, include somehow this (simplemath.js) file, call ADD(2, 5), and get a result in console or execute javascript code on current web page and manipulate with it's content. How can I do that? How can I use javascript functions from external files in web-browser's javascript console?
// EDITS
simplemath.js is just local file, somewhere on hard drive (c:\temp\simplemath.js), no localhost web servers running. I want to run scripts from it on any web page and get result similar to typing javascript: function ADD(a, b){return a+b;} alert(ADD(1, 41);) in browsers address bar, but via console, and load ADD function from external file.
You have at least two ways too load the script in the header from the console:
document.head.innerHTML+="<script src='simplemath.js'></script>";
or using appendChild():
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'simplemath.js';
document.head.appendChild(script);
if the ADD function is defined in the global space you can call ADD(2, 5) directly in the console.
Also you can load jQuery using the above ways first and then load the scripts with:
$.getScript('simplemath.js');
And most importantly so you don't have any problem with security or paths and be allowed to load those javascript files you should have all those scripts in one folder in the same folder an empty html and open the console in the same window that empty html is ran.
Else you will have problems with domains and paths.
You can include your simplemath.js file as a userscript into Opera:
If enabled, User JavaScript will be loaded on most pages that you
visit, including pages in any frames and inline frames. Any global
functions and variables created in the User JavaScript will be
available, and can be read by any scripts on these pages. For this
reason, to protect your privacy and security, we recommend that you do
not include any sensitive information in your User JavaScript
You can enable it globally or on specific pages only. Opera does also support greasemonkey scripts, a Firefox addon. Yet (at least in FF) they usually run in a sandbox, so they will not leak global variables into the webpage where it would be accessible from the console (unless you explicitly state so).

Categories