is it possible to share data of localstorage between tabs? - google-chrome-extension

I have two domains and I need to pass localstorage data from domain A to domain B when execute a botton of the extension that i'm creating?

The easiest way is to use chrome.storage.local. Content scripts in all tabs can access chrome.storage.local.
So, content script in Domain A tab:
chrome.storage.local.set({
fromDomainA: window.localStorage.getItem('fromDomainA')
});
In contentScript on Domain B tab:
const fromDomainA = await chrome.storage.local.get('fromDomainA');
console.log(fromDomainA);

this is my example. First i created a button in popup.html that execute a message to content-script.
document.getElementById("syncronize").onclick = function () {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, { greeting: "hello" }, () => {});
});
};
then i need to get the value of localstorage from domain A to send to the domain B. i send other message to background
console.log("localstorage", localStorage);
console.log("sessionStorage", sessionStorage);
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.greeting == "hello") {
console.log(request, sender, "from the extension");
chrome.runtime.sendMessage(
{ method: "send", value: localStorage.getItem("token") },
(response) => {
console.log("messasage contentScript", response);
}
);
}
sendResponse({ farewell: "goodbye" });
return true;
});
final in the background file i listen the message and assign the value to the global var but i don't sure if the context of the background file is only to the domain A.
Can i get that value to domain B?
i need to pass that token from domain A to the domain B

Related

How to set input on chrome extension to text from dom?

I am trying to get text from the web page on click into the input on my chrome extension.
Content script
document.addEventListener('click', function (e) {
let target = e.target
let text = target.textContent || target.innerText;
chrome.runtime.sendMessage({ text }, function (response) {
console.log(response.farewell);
});
}, false);
and background script
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
document.getElementById("userinput").value = "My value";
sendResponse({ farewell: request.text });
}
);
My popup.html just has id of 'userinput' and i am getting unchecked runtime.lastError: The message port closed before a response was received. Error

Chrome Extension - Monitoring network traffic with body data in background [duplicate]

It seems to be difficult problem (or impossible??).
I want to get and read HTTP Response, caused by HTTP Request in browser, under watching Chrome Extension background script.
We can get HTTP Request Body in this way
chrome.webRequest.onBeforeRequest.addListener(function(data){
// data contains request_body
},{'urls':[]},['requestBody']);
I also checked these stackoverflows
Chrome extensions - Other ways to read response bodies than chrome.devtools.network?
Chrome extension to read HTTP response
Is there any clever way to get HTTP Response Body in Chrome Extension?
I can't find better way then this anwser.
Chrome extension to read HTTP response
The answer told how to get response headers and display in another page.But there is no body info in the response obj(see event-responseReceived). If you want to get response body without another page, try this.
var currentTab;
var version = "1.0";
chrome.tabs.query( //get current Tab
{
currentWindow: true,
active: true
},
function(tabArray) {
currentTab = tabArray[0];
chrome.debugger.attach({ //debug at current tab
tabId: currentTab.id
}, version, onAttach.bind(null, currentTab.id));
}
)
function onAttach(tabId) {
chrome.debugger.sendCommand({ //first enable the Network
tabId: tabId
}, "Network.enable");
chrome.debugger.onEvent.addListener(allEventHandler);
}
function allEventHandler(debuggeeId, message, params) {
if (currentTab.id != debuggeeId.tabId) {
return;
}
if (message == "Network.responseReceived") { //response return
chrome.debugger.sendCommand({
tabId: debuggeeId.tabId
}, "Network.getResponseBody", {
"requestId": params.requestId
}, function(response) {
// you get the response body here!
// you can close the debugger tips by:
chrome.debugger.detach(debuggeeId);
});
}
}
I think it's useful enough for me and you can use chrome.debugger.detach(debuggeeId)to close the ugly tip.
sorry, mabye not helpful... ^ ^
There is now a way in a Chrome Developer Tools extension, and sample code can be seen here: blog post.
In short, here is an adaptation of his sample code:
chrome.devtools.network.onRequestFinished.addListener(request => {
request.getContent((body) => {
if (request.request && request.request.url) {
if (request.request.url.includes('facebook.com')) {
//continue with custom code
var bodyObj = JSON.parse(body);//etc.
}
}
});
});
This is definitely something that is not provided out of the box by the Chrome Extension ecosystem. But, I could find a couple of ways to get around this but both come with their own set of drawbacks.
The first way is:
Use a content script to inject our own custom script.
Use the custom script to extend XHR's native methods to read the response.
Add the response to the web page's DOM inside a hidden (not display: none) element.
Use the content script to read the hidden response.
The second way is to create a DevTools extension which is the only extension that provides an API to read each request.
I have penned down both the methods in a detailed manner in a blog post here.
Let me know if you face any issues! :)
To get a XHR response body you can follow the instructions in this answer.
To get a FETCH response body you can check Solution 3 in this article and also this answer. Both get the response body without using chrome.debugger.
In a nutshell, you need to inject the following function into the page from the content script using the same method used for the XHR requests.
const constantMock = window.fetch;
window.fetch = function() {
return new Promise((resolve, reject) => {
constantMock.apply(this, arguments)
.then((response) => {
if (response) {
response.clone().json() //the response body is a readablestream, which can only be read once. That's why we make a clone here and work with the clone
.then( (json) => {
console.log(json);
//Do whatever you want with the json
resolve(response);
})
.catch((error) => {
console.log(error);
reject(response);
})
}
else {
console.log(arguments);
console.log('Undefined Response!');
reject(response);
}
})
.catch((error) => {
console.log(error);
reject(response);
})
})
}
If response.clone().json() does not work, you can try response.clone().text()
I show my completed code if it can be some help. I added the underscore to get the request url, thanks
//background.js
import _, { map } from 'underscore';
var currentTab;
var version = "1.0";
chrome.tabs.onActivated.addListener(activeTab => {
currentTab&&chrome.debugger.detach({tabId:currentTab.tabId});
currentTab = activeTab;
chrome.debugger.attach({ //debug at current tab
tabId: currentTab.tabId
}, version, onAttach.bind(null, currentTab.tabId));
});
function onAttach(tabId) {
chrome.debugger.sendCommand({ //first enable the Network
tabId: tabId
}, "Network.enable");
chrome.debugger.onEvent.addListener(allEventHandler);
}
function allEventHandler(debuggeeId, message, params) {
if (currentTab.tabId !== debuggeeId.tabId) {
return;
}
if (message === "Network.responseReceived") { //response return
chrome.debugger.sendCommand({
tabId: debuggeeId.tabId
}, "Network.getResponseBody", {
"requestId": params.requestId
//use underscore to add callback a more argument, passing params down to callback
}, _.partial(function(response,params) {
// you get the response body here!
console.log(response.body,params.response.url);
// you can close the debugger tips by:
// chrome.debugger.detach(debuggeeId);
},_,params));
}
}
I also find there is a bug in chrome.debugger.sendCommand. If I have two requests with same URI but different arguments. such as:
requests 1:https://www.example.com/orders-api/search?limit=15&offer=0
requests 2:https://www.example.com/orders-api/search?limit=85&offer=15
The second one will not get the corrected responseBody, it will show:
Chrome Extension: "Unchecked runtime.lastError: {"code":-32000,"message":"No resource with given identifier found"}
But I debugger directly in background devtools, it get the second one right body.
chrome.debugger.sendCommand({tabId:2},"Network.getResponseBody",{requestId:"6932.574"},function(response){console.log(response.body)})
So there is no problem with tabId and requestId.
Then I wrap the chrome.debugger.sendCommand with setTimeout, it will get the first and second responseBody correctly.
if (message === "Network.responseReceived") { //response return
console.log(params.response.url,debuggeeId.tabId,params.requestId)
setTimeout(()=>{
chrome.debugger.sendCommand({
tabId: debuggeeId.tabId
}, "Network.getResponseBody", {
"requestId": params.requestId
//use underscore to add callback a more argument, passing params down to callback
}, _.partial(function(response,params,debuggeeId) {
// you get the response body here!
console.log(response.body,params.response.url);
// you can close the debugger tips by:
// chrome.debugger.detach(debuggeeId);
},_,params,debuggeeId));
},800)
}
I think the setTimeout is not the perfect solution, can some one give help?
thanks.

Initiating an outbound call using Twilio Function

twiml.dial(dialNode => {
dialNode.conference('Test conference', {
startConferenceOnEnter: true,
endConferenceOnExit: false,
from: context.CALLER_ID,
to: event.TO
})
I have tried this on Twilio Functions but this returns an error on the client side.
There are quite a few Twilio Function examples, one of which is making an outbound call. You can view the examples here (under Function Examples) on the left side of the screen.
Make a Call
// Description
// Make a call
exports.handler = function (context, event, callback) {
// Make sure under Functions Settings tab:
// "Add my Twilio Credentials (ACCOUNT_SID) and (AUTH_TOKEN) to ENV" is CHECKED
const twilioClient = context.getTwilioClient();
// Pass in From, To, and Url as query parameters
// Example: https://x.x.x.x/<path>?From=%2b15108675310&To=%2b15108675310&Url=http%3A%2F%2Fdemo.twilio.com%2Fdocs%2Fvoice.xml
// Note URL encoding above
let from = event.From || '+15095550100';
// If passing in To, make sure to validate, to avoid placing calls to unexpected locations
let to = event.To || '+15105550100';
let url = event.Url || 'http://demo.twilio.com/docs/voice.xml';
twilioClient.calls
.create({
url: url,
from: from,
to: to,
})
.then((result) => {
console.log('Call successfully placed');
console.log(result.sid);
return callback(null, 'success');
})
.catch((error) => {
console.log(error);
return callback(error);
});
};

How to pass message from site to host and get response in google-chrome-extension

There is a plugin written for google-chrome that connects messages from the site to the user's computer. A mandatory requirement is that the plug-in through the background.js script keeps a constant connection, in fact, it keeps it through the port, but I cannot send the response received from the host to the site in any way.
That is, I send a message from the site to the plugin like this:
// script on the site
chrome.runtime.sendMessage(extensionId, {type: "SEND_FROM_WEB_SITE"}, function(response){
console.log(response)
})
Here I establish a permanent connection to the user's computer through the port, receive a message from the website, and try to send the response back to the site.
// script background.js
// establishing a connection
connect()
function onNativeMessage(message){
if(message.type == 'GET_FROM_HOST') {
// HERE I RECEIVE AN ANSWER FROM THE USER'S COMPUTER WHICH SHOULD BE TRANSFERRED TO THE SITE? QUESTION HOW
console.log(message);
}
}
function connect(){
port = chrome.runtime.connectNative(hostName);
port.onMessage.addListener(onNativeMessage);
}
function sendNativeMessage(message) {
port.postMessage(message);
}
// listening to the message from the website
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
if (request.type == "GET_FROM_WEB_SITE"){
// WE RECEIVE A MESSAGE FROM THE WEE SITE AND SEND IT TO THE USER'S COMPUTER, HOW DO I TRANSFER THROUGH "sendResponse" THE RESPONSE TO THE SITE
sendNativeMessage(request);
}
});
Just in case, the manifest file with permissions // manifest.json
{
"name": "app plugin",
"short_name": "app",
"description": "app",
"manifest_version": 2,
"permissions": ["nativeMessaging", "activeTab", "tabs", "storage"],
"background": {
"scripts": ["background.js"],
"persistent": false
},
}
All you need is to remember sendResponse until the response from the native host is received and use return true to keep onMessageExternal channel open:
let savedSendResponse;
let port = chrome.runtime.connectNative(hostName);
port.onMessage.addListener(message => {
if (savedSendResponse) {
savedSendResponse(message);
savedSendResponse = null;
}
});
chrome.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {
port.postMessage(request);
savedSendResponse = sendResponse;
return true; // keep the channel open until savedSendResponse is called
});
However, a complication will arise if a) your host app processes messages asynchronously and b) several tabs with the same site may be opened and each could send a message. In this case we need to separately remember each sendResponse. We can do it by assigning a temporary internal id to the messages between the host and the extension. Host app should read this id from the messages and write the same id in its responses.
let sendMap = new Map();
let port = chrome.runtime.connectNative(hostName);
port.onMessage.addListener(message => {
const send = sendMap.get(message.id);
if (send) {
sendMap.delete(message.id);
send(message);
}
});
chrome.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {
request.id = performance.now();
sendMap.set(request.id, sendResponse);
port.postMessage(request);
return true; // keep the channel open until sendResponse is called
});

How to send responses from onMessageExternal Listener?

I am sending a message from a content script to my extension using chrome.runtime.sendMessage.
Content Script:
chrome.runtime.sendMessage(extensionId, {
"some" : "request"
}
},
function(response) {
alert("got response");
}
);
The receiving part in the background script looks like that:
Background Script A
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
This works well: send response is logged to the console of the background page and I receive the alert got response from the content script.
I then introduced some asynchronous JavaScript to the listener:
Background Script B
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
window.crypto.subtle.generateKey({
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: {
name: "SHA-256"
}
}, false, ["sign"]).then(function(keyPair) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
});
here the callback is called regularly (meaning, send response is logged to the console of the background page after completion. The content script however never receives the response (i.e. there is no got response alert).
What am I doing wrong here? Why is the responseCallback called in A but not in B? That's exactly what the callback chain is made for or isn't it?
This seems to be a bug/feature in chrome. Apparently you need to return true, otherwise the message channel will be closed:
https://developer.chrome.com/extensions/runtime.html#event-onMessageExternal
This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called).
Adding return true; to the background script like this solves the issue:
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
window.crypto.subtle.generateKey({
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: {
name: "SHA-256"
}
}, false, ["sign"]).then(function(keyPair) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
return true;
});

Resources