here is my manifest.json file
{
"name": "myweb",
"version": "1.1",
"manifest_version": 3,
"description": "Injects Web3 library into web pages",
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"web3-inject.js"
]
}
],
"permissions": [
"scripting",
"webRequest",
"tabs",
"activeTab",
"management",
"webNavigation",
"notifications",
"storage"
],
"host_permissions": [
"<all_urls>"
],
"action": {
"default_popup": "./popup.html"
}
}
popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Web3 Extension</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<h1>Send ETH</h1>
<form>
<label for="to">To address:</label>
<input type="text" id="to" name="to" required><br>
<label for="amount">Amount:</label>
<input type="number" id="amount" name="amount" min="0" step="0.0001" required><br>
<button type="submit">Send</button>
</form>
<div id="status"></div>
<script src="popup.js"></script>
</body>
</html>
popup.js file
// Wait for the page to load
document.addEventListener('DOMContentLoaded', function() {
// Add a listener for the form submit event
document.querySelector('form').addEventListener('submit', function(event) {
// Prevent the default form submission behavior
event.preventDefault();
// Get the form data
const to = document.getElementById('to').value;
const amount = document.getElementById('amount').value;
// Check if a web3 provider is available
if (typeof window.ethereum !== 'undefined') {
// Use web3 to interact with the Ethereum blockchain
const web3 = new Web3(window.ethereum);
console.log('Web3 provider detected');
// Get the current account
web3.eth.getAccounts().then(accounts => {
const account = accounts[0];
console.log('Current account:', account);
// Send the transaction
web3.eth.sendTransaction({
from: account,
to: to,
value: web3.utils.toWei(amount, 'ether')
}).then(result => {
console.log('Transaction sent:', result);
// Show a success message to the user
document.getElementById('status').textContent = 'Transaction sent';
}).catch(error => {
console.error('Transaction failed:', error);
// Show an error message to the user
document.getElementById('status').textContent = 'Transaction failed';
});
}).catch(error => {
console.error('Could not get current account:', error);
// Show an error message to the user
document.getElementById('status').textContent = 'Could not get current account';
});
} else {
console.error('No web3 provider detected');
// Show an error message to the user
document.getElementById('status').textContent = 'No web3 provider detected';
}
});
});
web3-inject.js file
var web3js;
// Wait for the page to load
window.addEventListener('load', function() {
// Check if web3 is already injected
if (typeof web3 !== 'undefined') {
web3js = new Web3(web3.currentProvider);
console.log("Injected web3 detected.");
} else {
// If web3 is not already injected, inject it
var script = document.createElement('script');
script.src = 'web3.min.js';
document.head.appendChild(script);
console.log("Injected web3 not detected, injecting now.");
// Wait for web3 to load
script.addEventListener('load', function() {
web3js = new Web3(web3.currentProvider);
});
}
// Now you can use web3js to interact with the Ethereum blockchain
console.log(web3js.eth.accounts);
});
every time i will get this error and also try using cdn but in manifest version 3 cdn is disabled so how to inject web3
lib and i try many way but always getting this errror so please tell me how to do it.
and how metamask chrome extension inject web3 in every page i want to know.
Note: web3.min.js file is there in root directory.
Related
With manifest V3, the background's Service Worker will unload (being inactive) after idling for 30 seconds. When I send a runtime message from popup to background without any further actions, after 30 seconds, the background's Service Worker is unloaded like usual. But when I send a runtime message from background to popup, it is not unloaded when idling anymore until it is forcefully unloaded by 5 minutes.
After it is forcefully unloaded by 5 minutes cap, when the popup is triggered again, message is not successfully passed anymore.
Here are the test codes (no special permissions):
manifest.json
{
"manifest_version": 3,
"name": "Test sw-pp msg",
"version": "1.0.0",
"action": {
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"permissions": [
"activeTab"
],
"host_permissions": [
"http://*/*",
"https://*/*"
]
}
popup.js
const lblStatus = document.getElementById('lblStatus');
// send test message from popup to background -> OK
chrome.runtime.sendMessage('to-background', (res) => {
if (chrome.runtime.lastError) {
lblStatus.textContent = 'Error';
} else {
lblStatus.textContent = 'OK';
}
});
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg == 'to-popup') {
lblStatus.textContent = 'Message from background to popup';
sendResponse(1);
}
});
popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="lblStatus" style="padding: 2em; font-size: 2em;"></div>
<script src="popup.js"></script>
</body>
</html>
background.js
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg == 'to-background') {
console.log('Message from popup to background');
sendResponse(1);
/* Test sending message from background to popup
- The first time the message is sent, the background's service worker may still be unloaded like usual
- The second,... time the message is sent, the background's service worker is not unloaded anymore.
- Without below code, the background's service worker is unloaded like usual
*/
setTimeout(() => {
chrome.runtime.sendMessage('to-popup', (res) => {
if (chrome.runtime.lastError) {
console.log('ERR');
} else {
console.log('OK');
}
});
}, 2000);
}
});
So I wonder what is the correct way to send message from background to popup (or options,...) in Manifest V3 extension?
I'm trying to create tiny chrome extension.
This one has one input that contains login that user can typea dn a button. Once clicked, script is injected to current page and I'm trying to pass data (the login entered in extension html) but it looks it isn't running and I don't know how to test it more in order to find the reason why it isn't running.
At this point, the alert("inject is running"); is runing but not the alert("csEvent fired"); when I press the button and ther eis no error message in the extension manager.
Here is the code:
Manifest
{
"name" :"Quick Pass",
"version" :"1.0",
"manifest_version": 2,
"description" :"Password for quick access",
"browser_action" :
{
"default_icon" : "icone.png",
"default_popup": "popup.html"
},
"web_accessible_resources": ["inject.js"],
"permissions": [
"https://*/*",
"http://*/*",
"tabs",
"activeTab"
]
}
buttonScript.js
document.getElementById("myButton").addEventListener("click", myFunction);
// When user clicks on the submit button of the extension, load the script on current tab
function myFunction() {
chrome.tabs.getSelected(null, function(tab){
chrome.tabs.executeScript({
file: 'inject.js'
});
});
// data you want to sent
let data = {
login: document.getElementById("loginPopup").value,
pwd: "Password"
};
// send data through a DOM event
document.dispatchEvent(new CustomEvent('csEvent', {detail: data}));
}
inject.js
// Injected from Chrome "APPI Pass" extension
(function() {
alert("inject is running");
document.addEventListener('csEvent', function (event) {
alert("csEvent fired");
console.log(event.detail.login+event.detail.pwd);
document.getElementById("Email").value = event.detail.login;
document.getElementById("Password").value = event.detail.pwd
document.getElementByTagName("form").submit();
});
})();
And the popup.html:
<DOCTYPE html>
<head>
</head>
<body>
<h2>Appi Magic</h2>
<h3>Enter Login:</h3>
<input type="text" id="loginPopup">
<button id="myButton">Let go</button>
<script src="buttonScript.js"></script>
</body>
</html>
Thanks
I'm trying to use a web worker in my webextension to make things run faster, but I can't seem to get even the demo webworker example that MDN provides to work. This is my manifest:
{
"manifest_version": 2,
"name": "test",
"version": "1.0.0",
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"sharedTest.js"
]
}
]
}
This is sharedTest.js:
console.log("js loaded");
if (window.Worker) { // Check if Browser supports the Worker api.
// Requires script name as input
var myWorker = new Worker(browser.runtime.getURL('testWorker.js'));
myWorker.onmessage = function(e) {
console.log('Message received from worker');
console.log(e.data);
};
myWorker.postMessage([42, 23]); // Sending message as an array to the worker
console.log('Message posted to worker');
}
and this is testWorker.js:
onmessage = function(e) {
console.log('Message received from main script');
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
console.log('Posting message back to main script');
postMessage(workerResult);
}
If anyone can tell me what I'm doing wrong or if there is anything missing in my manifest, that'd be great.
So it turns out, due to the same-origin policy, you can't use normal web workers in webextensions. However, you can get around this by wrapping your worker in a blob like so:
var blob = new Blob([
`onmessage = function(e) {
console.log('Message received from main script');
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
console.log('Posting message back to main script');
postMessage(workerResult);
}`]);
// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);
var worker = new Worker(blobURL);
worker.onmessage = function(e) {
console.log('Message received from worker');
console.log(e.data);
};
worker.postMessage([42, 23]); // Sending message as an array to the worker
console.log('Message posted to worker');
And that will work. The above example was based on this article, and that does work in webextensions (for theoretically everything but Internet Explorer). However, that blob worker is not within the same origin as the rest of your extension anymore, so due to the same-origin policy, the global importScripts() will not work to import any files in your extension. This means that you have to include all necessary methods and logic within the Blob, which is less than ideal.
Alternatively, I realized that this is kind of what background scripts are for, or for my case, event pages.
It may be an old question, but in case anyone is looking for a solution other than using blobs or background scripts, this might be it - without caveats.
If you attempt to load your WebWorker with your current manifest.js, you will get an error. However, you can add your worker.js file as an additional resource, so that your browser can access it. You can do this by adding web_accessible_resource key to your manifest.json. NB: the path specified as value to the key will be relative to the manifest file.
{
"manifest_version": 2,
"name": "MyExtension",
"version": "1.0",
"content_scripts": [
{
"all_frames": true,
"matches": [ "<all_urls>" ],
"js": [ "js/content.js", "js/import.js" ],
"run_at": "document_end",
"css": ["css/style.css"]
}
],
"web_accessible_resources": [ "js/worker.js", "pictures/cat.svg" ]
}
You can then obtain the runtime url of your worker from your content.js to create the worker:
const worker = new Worker(browser.runtime.getURL('js/worker.js'));
worker.onmessage = (e) => {window.console.log(e);
To import a script to your worker, you first need to specify it as a content script in your manifest (path relative to manifest). Then in your worker you can import it as:
self.importScripts('import.js');
self.onmessage = (e) => importStuff.doWork(e);
The path to your import script here is relative to the worker file itself.
That's it - enjoy threading in extensions.
It appears to be possible to create Workers from the background page! While the original question looked like they were trying to use a content script that feature does not seem to be available.
Here's a dumb unimaginative example for spawning a web worker on the background page:
manifest.json:
{
"manifest_version": 2,
"name": "",
"description": "",
"version": "0.0.1",
"background": { "page": "background.html" }
}
background.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="background.js"></script>
</head>
</html>
background.js:
if(window.Worker)
{
const myWorker = new Worker(browser.runtime.getURL('worker.js'));
myWorker.onmessage = function(msg) {
console.log("Main Script: Message received", msg.data);
}
let i = 0;
setInterval(() => {myWorker.postMessage({num: i++});}, 500);
}
else
{
console.log("Worker's not supported :(")
}
worker.js:
onmessage = function(msg)
{
postMessage({timestamp: Date.now(), passedData: msg.data});
}
If you need to use a content script then you can use ports to send messages from the script to the background page and back again.
I am trying to build a chrome extension for bulk tagging functionality by using gmail API.
I am using inboxsdk API for button creation in gmail inbox.
The button which I am using will be displayed in the gmail tool-bar next to delete button in existing gmail scenario.
Also for bulk tagging functionality to work on button click I am using gmail API.
In the sense when we click the button the selected mails should get tagged with the "general" label in gmail inbox.
I am facing the issue when I am trying to execute the chrome extension
at button click means
After the mails got selected for tagging.
When I click on the 'General' button for the mails to get tagged with general label.
At that time the mails are not getting tagged and the error message is
getting displayed.
The UI of my present functionality
The error which I am facing on button click is
Error logged: ReferenceError: GmailApp is not defined
at tagLabel (chrome-extension://comojhnglmoikgmlgajalpkdmhkkhdao/contentScript/tag.js:6:13)
at e.i.onClick [as _activateFunction] (https://www.inboxsdk.com/build/platform-implementation.js:96:9933)
at e.r.value (https://www.inboxsdk.com/build/platform-implementation.js:97:9380)
at eval (https://www.inboxsdk.com/build/platform-implementation.js:97:9085)
at eval (https://www.inboxsdk.com/build/platform-implementation.js:9:21971)
at eval (https://www.inboxsdk.com/build/platform-implementation.js:9:14725)
at Object.n.UpdateBarrier.c [as inTransaction] (https://www.inboxsdk.com/build/platform-implementation.js:9:14490)
at e.push (https://www.inboxsdk.com/build/platform-implementation.js:9:24310)
at e.handleEvent (https://www.inboxsdk.com/build/platform-implementation.js:9:25004)
at eval (https://www.inboxsdk.com/build/platform-implementation.js:9:10944)
at HTMLDivElement.eval (https://www.inboxsdk.com/build/platform-implementation.js:9:31344)
at HTMLDivElement.eval (https://www.inboxsdk.com/build/platform-implementation.js:95:8103)
Original error stack:
ReferenceError: GmailApp is not defined
at tagLabel (chrome-extension://comojhnglmoikgmlgajalpkdmhkkhdao/contentScript/tag.js:6:13)
at e.i.onClick [as _activateFunction] (https://www.inboxsdk.com/build/platform-implementation.js:96:9933)
at e.r.value (https://www.inboxsdk.com/build/platform-implementation.js:97:9380)
at eval (https://www.inboxsdk.com/build/platform-implementation.js:97:9085)
at eval (https://www.inboxsdk.com/build/platform-implementation.js:9:21971)
at eval (https://www.inboxsdk.com/build/platform-implementation.js:9:14725)
at Object.n.UpdateBarrier.c [as inTransaction] (https://www.inboxsdk.com/build/platform-implementation.js:9:14490)
at e.push (https://www.inboxsdk.com/build/platform-implementation.js:9:24310)
at e.handleEvent (https://www.inboxsdk.com/build/platform-implementation.js:9:25004)
at eval (https://www.inboxsdk.com/build/platform-implementation.js:9:10944)
at HTMLDivElement.eval (https://www.inboxsdk.com/build/platform-implementation.js:9:31344)
at HTMLDivElement.eval (https://www.inboxsdk.com/build/platform-implementation.js:95:8103)
Error logged from:
at Object.i [as default] (https://www.inboxsdk.com/build/platform-implementation.js:74:26373)
at a (https://www.inboxsdk.com/build/platform-implementation.js:95:7900)
at Function.f.value (https://www.inboxsdk.com/build/platform-implementation.js:95:11263)
at HTMLDivElement.eval (https://www.inboxsdk.com/build/platform-implementation.js:95:8142)
Error details: Uncaught error in event listener
Extension App Ids: [
{
"appId": "sdk_mailtag_fd47af3e65"
}
]
Sent by App: false
Session Id: 1448273876180-0.754944005748257
Extension Id: chrome-extension://comojhnglmoikgmlgajalpkdmhkkhdao/
InboxSDK Loader Version: 0.7.9-802f1aa6afeaeaff
InboxSDK Implementation Version: 0.7.13-1448069038650-cd7978078f7ce7a6
Uncaught ReferenceError: GmailApp is not defined
The code of the functionality:
manifest.json:
{
"name": "Gmail Extension",
"description": "Extension for tagging",
"version": "0.1",
"manifest_version": 2,
"minimum_chrome_version": "29",
"background": {
"page": "/background/index.html"
},
"content_scripts": [
{
"matches": [
"https://mail.google.com/*",
"https://inbox.google.com/*"],
"js": ["/libs/inboxsdk.js", "/libs/alertify/alertify.min.js", "/contentScript/tag.js"],
"css": ["/libs/alertify/alertify.default.css", "/libs/alertify/alertify.core.css"],
"run_at": "document_end"
}],
"web_accessible_resources": ["/icons/tag.png", "*"],
"permissions": ["identity", "<all_urls>", "tabs", "webRequest", "webRequestBlocking", "https://accounts.google.com/*", "https://www.googleapis.com/*", "https://mail.google.com/",
"https://inbox.google.com/"],
"content_security_policy": "script-src 'self' 'sha256-Y+2PBkTuXdKc9Mz9jB6CV7zSLRMuViwjLM28phOgupM=' https://apis.google.com; object-src 'self'",
"oauth2": {
"client_id": "763145023672-gblto66pc638n485lu08visrvpocfqbs.apps.googleusercontent.com",
"scopes": ["https://mail.google.com/",
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/gmail.labels",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"]
}
}
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Extension for tagging</title>
<meta charset='utf-8' />
<script src = "auth.js" </script>
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=checkAuth"></script>
<script src = "/libs/inboxsdk.js" </script>
<script src = "/contentScript/tag.js" </script>
</head>
<body>
<div id="authorize-div" style="display: none">
<span>Authorize access to Gmail API</span>
<!--Button for the user to click to initiate auth sequence -->
<button id="authorize-button" onclick="handleAuthClick(event)">
Authorize
</button>
</div>
</body>
</html>
auth.js:
var CLIENT_ID = '763145023672-gblto66pc638n485lu08visrvpocfqbs.apps.googleusercontent.com';
var SCOPES = [
'https://mail.google.com/',
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/gmail.labels',
'https://www.googleapis.com/auth/gmail.send'
];
function checkAuth() {
gapi.auth.authorize({
'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': true
},
handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeDiv = document.getElementById('authorize-div');
if (authResult && !authResult.error) {
// Hide auth UI, then load client library.
authorizeDiv.style.display = 'none';
loadGmailApi();
} else {
// Show auth UI, allowing the user to initiate authorization by
// clicking authorize button.
authorizeDiv.style.display = 'inline';
}
}
function handleAuthClick(event) {
gapi.auth.authorize({
'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': false
},
handleAuthResult);
return false;
}
function loadGmailApi() {
gapi.client.load('gmail', 'v1', updateLabel);
}
function updateLabel(){
var request = gapi.client.gmail.users.labels.update({
'userId': 'me'
});
request.execute(function(resp) {
tagLabel()
});
}
tag.js:
function whenNoneSelected(route) {
return false;
}
function register(sdk) {
function tagLabel() {
var label = GmailApp.getUserLabelByName("General");
var threads = label.getThreads(); // var threads = GmailApp.getThreads();
for (var i=0; i<threads.length; i++) {
//add label "General" for selected threads
threads[i].addLabel(label);
}
alertify.success('Threads marked as General');
}
sdk.Toolbars.registerToolbarButtonForList({
title: 'General',
section: sdk.Toolbars.SectionNames.INBOX_STATE,
iconUrl: chrome.extension.getURL('/icons/tag.png'),
onClick: tagLabel,
hasDropdown: false,
hideFor: whenNoneSelected,
keyboardShortcutHandle: null
});
}
InboxSDK.load('1', 'sdk_mailtag_fd47af3e65').then(register);
Anyone with relevant solution will be greatly appreciated.
I can't get a response from my content script to show up in my popup.html. When this code runs and the find button is clicked, "Hello from response!" prints, but the variable response is printed as undefined. The ultimate goal is to get the current tab's DOM into my script file so that I can parse through it. I'm using a single time message to a content script to get the DOM, but it's not being returned and is showing up as undefined. I'm looking for any help possible. Thanks.
popup.html:
<!DOCTYPE html>
<html>
<body>
<head>
<script src="script.js"></script>
</head>
<form >
Find: <input id="find" type="text"> </input>
</form>
<button id="find_button"> Find </button>
</body>
</html>
manifest.json:
{
"name": "Enhanced Find",
"version": "1.0",
"manifest_version": 2,
"description": "Ctrl+F, but better",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs",
"*://*/*"
],
"background":{
"scripts": ["script.js"],
"persistent": true
},
"content_scripts":[
{
"matches": ["http://*/*", "https://*/*"],
"js": ["content_script.js"],
"run_at": "document_end"
}
]
}
script.js:
var bkg = chrome.extension.getBackgroundPage();
function eventHandler(){
var input = document.getElementById("find");
var text = input.value;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
var tab = tabs[0];
var url = tab.url;
chrome.tabs.sendMessage(tab.id, {method: "getDocuments"}, function(response){
bkg.console.log("Hello from response!");
bkg.console.log(response);
});
});
}
content_script.js:
var bkg = chrome.extension.getBackgroundPage();
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
if(request.method == "getDOM"){
sendResponse({data : bkg.document});
}else{
sendResponse({});
}
});
There are quite a few issues with your code (see my comment above).
Some suggestions/considerations first:
Do not inject your content script into all webpages. Inject programmatically and only when the user wants to search.
It might be a better idea to do the "searching" right in the content script, where you have direct access to the DOM and can manipulate it (e.g. highlight search results etc). You might need to adjust your permissions if you go for this approach, but always try to keep them to a minimum (e.g. don't use tabs where activeTab would suffice, etc).
Keep in mind that, once the popup is closed/hidden (e.g. a tab receives focus), all JS executing in the context of the popup is aborted.
If you want some sort of persistence (even temporary), e.g. remembering the recent results or last search term, you can use something like chrome.storage or localStorage.
Finally, sample code from my demo version of your extension:
Extension files organization:
extension-root-directory/
|
|_____fg/
| |_____content.js
|
|_____popup/
| |_____popup.html
| |_____popup.js
|
|_____manifest.json
manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"offline_enabled": true,
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": ["fg/content.js"],
"run_at": "document_end",
}
],
"browser_action": {
"default_title": "Test Extension",
"default_popup": "popup/popup.html"
}
}
content.js:
// Listen for message...
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
// If the request asks for the DOM content...
if (request.method && (request.method === "getDOM")) {
// ...send back the content of the <html> element
// (Note: You can't send back the current '#document',
// because it is recognised as a circular object and
// cannot be converted to a JSON string.)
var html = document.all[0];
sendResponse({ "htmlContent": html.innerHTML });
}
});
popup.html:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="popup.js"></script>
</head>
<body>
Search:
<input type="text" id="search" />
<input type="button" id="searchBtn" value=" Find "
style="width:100%;" />
</body>
</html>
popup.js:
window.addEventListener("DOMContentLoaded", function() {
var inp = document.getElementById("search");
var btn = document.getElementById("searchBtn");
btn.addEventListener("click", function() {
var searchTerm = inp.value;
if (!inp.value) {
alert("Please, enter a term to search for !");
} else {
// Get the active tab
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
// If there is an active tab...
if (tabs.length > 0) {
// ...send a message requesting the DOM...
chrome.tabs.sendMessage(tabs[0].id, {
method: "getDOM"
}, function(response) {
if (chrome.runtime.lastError) {
// An error occurred :(
console.log("ERROR: ", chrome.runtime.lastError);
} else {
// Do something useful with the HTML content
console.log([
"<html>",
response.htmlContent,
"</html>"
].join("\n"));
}
});
}
});
}
});
});