Sending data from Chrome extension to local python file - javascript

I'm trying to send some data from a Chrome extension content script to a background script to my local python file. It goes from the content script to the background script fine, but when I try to send it to the python file, I just get "POST http://localhost:5000/bootstrap 400 (BAD REQUEST)." Can't figure out what's going on. I'm new to this. Many thanks!
background.js
// Sending messages from background / event page
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
chrome.tabs.query({ active: true }, function(tabs) {
const msg = "Hello from background 🔥";
chrome.tabs.sendMessage(tabs[0].id, { "message": msg });
})
}
});
// Listening to messages page
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request);
var articleData = request
// Callback for that request
$.ajax({
type: 'POST',
url: 'http://localhost:5000/bootstrap',
data: articleData,
success: function (newArticle){
alert('success');
}
})
sendResponse({ message: "Background has received that message 🔥" });
});
relevant part of fakenews.py
#app.route('/bootstrap', methods=['GET', 'POST'])
def bootstrap():
posted = 1
print ("bootstrap")
global article
if request.method == 'POST':
if not request.form['title'] or not request.form['url'] or not request.form['image_url'] or not request.form['snippet']:
flash('Please enter all the fields', 'error')
else:
article = Article(request.form['title'], request.form['url'], request.form['image_url'],
request.form['snippet'])
db.session.add(article)
try:
db.session.commit()
except exc.SQLAlchemyError:
flash('Article url already exists, failed to post new article')
posted = 0
#return render_template('/error.html', article_url=article.url)
article_list = Article.query.filter_by(url=article.url)
if posted == 1:
flash('Record was successfully added')
else:
db.session.rollback()
article_list = Article.query.filter_by(url=article.url)
article=article_list[0]
print ("article.id=" + str(article.id))
vote_choices = VoteChoice.getVoteChoiceList()
return render_template('/votefor.html', article_id=article.id,
article_title=article.title,
article_url=article.url, vote_choices=vote_choices
)
relevant part of content.js
chrome.runtime.sendMessage({ message: [title, image, url] }, function(response) {
console.log(response);
});
// Listening to messages in Context Script
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request);
// Callback
sendResponse({ message: 'Content script has received that message âš¡' })
})
});
manifest.json
{
"manifest_version": 2,
"name": "OrangeBox",
"version": "1.0",
"permissions": ["http://localhost/" ,"tabs"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["contentScript.js"]
}
],
"background": { "scripts": ["jquery-3.4.1.js", "background.js"], "persistent": false },
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["jquery-3.4.1.js", "waitForKeyElements.js", "content.js"]
}
]
}

Problem
In content.js you're sending
message: [title, image, url]
The background.js is just passing this on to fakenews.py, and this is where things break...
fakenews.py is expecting a request object that looks like
{
title: <some time>,
url: <some url>,
image_url: <...>,
snippet: <...>
}
but what it's getting looks like
{
message: [
<some title>,
<some image>,
<some url>
]
}
Fix
The quick fix is changing the content.js line to be
chrome.runtime.sendMessage({"title": title, "image_url": image, "url": url, "snippet": "test"}, function(response) {
Note I'm putting a placeholder for snippet because the backend is expecting a value for it

Related

Chrome extension messages not getting through

manifest.json:
{
"manifest_version": 2,
"name": "chrome-extension-bar",
"description": "Chrome Extension Bar",
"version": "1.0",
"browser_action": {
"default_title": "Chrome Extension Bar",
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"permissions": [
"<all_urls>",
"tabs"
],
"content_security_policy": "script-src 'self' https://ajax.googleapis.com/ https://maxcdn.bootstrapcdn.com ; object-src 'self'"
}
background.js:
console.log("In background.js")
chrome.runtime.onMessage.addListener (
function (request, sender, sendResponse) {
console.log("In listener");
// to send back your response to the current tab
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {fileData: response}, function(response) {
sendResponse({farewell: "goodbye"});
});
});
return true;
}
);
content_script.js:
var current_title_bar = document.getElementById("global-nav");
console.log("Title bar:" + current_title_bar);
current_title_bar.appendChild(extension_bar); // <= GODD, getting here
document.getElementById("idStartButton").addEventListener('click', function () {
console.log('Sending start button message: ' + document.getElementById("idNumSecondsPerPage").value);
chrome.runtime.sendMessage({numSecondsPerPage : document.getElementById("idNumSecondsPerPage").value}, function(response) {
console.log('Got response: ' + response.farewell);
});
});
document.getElementById("idStopButton").addEventListener('click', function () {
console.log('Sending stop button message: ' + document.getElementById("idNumPages").value);
chrome.runtime.sendMessage({numPages : document.getElementById("idNumPages").value}, function(response) {
console.log('Got response: ' + response.farewell);
});
});
The messages seem to be getting sent, but there's I'm not getting anything back from the receiver.
Console log on the page into which the form was injected:
Entering content_script.js
content_script.js:156 Title bar:[object HTMLElement]
content_script:161 Sending start button message: 67
content_script:168 Sending stop button message: 76
Why aren't the messages sent by background.js received by content_script.js? Are they even sent?
If you want to send a message from the background.js script to the content_script.js then you need to set an onMessage listener on the content script.
What you might do in this case is, after receiving the event on the background script, just call the callback function, instead you're sending a new event with a callback function than when it is executed, calls the callback function of the first event.
Instead of doing this:
console.log("In listener");
// to send back your response to the current tab
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {fileData: response}, function(response) {
sendResponse({farewell: "goodbye"});
});
});
just do this
console.log("In listener");
// send back your response
sendResponse({farewell: "goodbye"});

Cannot send post data via chrome extension

I have an API endpoint that exists, and I know it works correctly (I test frequently, successfully using PostMan). The problem is that when I am posting to it via my chrome extension, I am able to connect, however, no data values are being sent.
Here's my chrome manifest:
{
"background": {
"scripts": ["eventPage.js","jquery-3.3.1.min.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["https://*.amazon.com/*"],
"js": ["content.js", "jquery-3.3.1.min.js", "inject.js"],
"css": ["content.css"]
}
],
"permissions": [
"tabs",
"storage",
"https://*.amazon.com/*",
"https://*.cloudfunctions.net/*"
] }
Here is the event page that makes the call:
// listen to all messages at runtime
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
if (request.todo == 'sendLoad') {
console.log("MADE IT! Request Data", request.data)
// FYI the request.data output is correct; everything is there
// AJAX
$.ajax({
url: "https://prefix.cloudfunctions.net/endpoint",
type: "post",
data: {productName: encodeURIComponent(jQuery.trim(request.data.productName)), productImg: encodeURIComponent(request.data.productImg), productUrl: encodeURIComponent(request.data.productUrl), price: request.data.price, byLineValue: request.data.byLineValue, byLineUrl: encodeURIComponent(request.data.byLineUrl), amazonPath: encodeURIComponent(request.data.amazonPath[2]), uid: request.data.uid, tid: "1"} ,
success: function (response) {
console.log("Send complete: ", response);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
}
});
};
});
(FYI, I also just tried to send request.data alone and was unsuccessful.)
I also tried to make the call using an xmlhttp request:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","https://prefix.cloudfunctions.net/endpoint",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(request.data);
And I also tried using a jQuery post:
$.post("https://prefix.cloudfunctions.net/endpoint",{{productName: encodeURIComponent(jQuery.trim(request.data.productName)), productImg: encodeURIComponent(request.data.productImg), productUrl: encodeURIComponent(request.data.productUrl), price: request.data.price, byLineValue: request.data.byLineValue, byLineUrl: encodeURIComponent(request.data.byLineUrl), amazonPath: encodeURIComponent(request.data.amazonPath[2]), uid: request.data.uid, tid: "1"})
.done(function (data) {
console.log("Send complete: " + data);
})
.fail(function() {
console.log("Error sending data")
})
.always(function() {
console.log("jQuery Post complete")
})
For each of these my API is returning a message that the values do not exist:
Error: Value for argument "data" is not a valid Firestore document. Cannot use "undefined" as a Firestore value (found in field productImg).
at Object.validateUserInput (/srv/node_modules/#google-cloud/firestore/build/src/serializer.js:273:15)
at Object.validateDocumentData (/srv/node_modules/#google-cloud/firestore/build/src/write-batch.js:622:26)
at CollectionReference.add (/srv/node_modules/#google-cloud/firestore/build/src/reference.js:1743:23)
at exports.addToTrunk.functions.https.onRequest (/srv/lib/index.js:27:14)
at cloudFunction (/srv/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /worker/worker.js:783:7
at /worker/worker.js:766:11
at _combinedTickCallback (internal/process/next_tick.js:132:7)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)
As I mentioned earlier, the endpoint works successfully but is not finding the data values that are sent.
UPDATE:
It's looking like the firebase "add" function that's not working correctly. Here is the code in the firebase function:
newTrunk.add({
created_at: created_at,
uid: "CG8B0mdqzMed3PPCiwsKkBtXmiA2", //request.body.uid, //TODO: pull in uid from localstorage
tid: '1', //TODO: provide list of trunks for person to select from when adding via extension
productImg: JSON.stringify(request.body.productImg),
price: JSON.stringify(request.body.price),
productUrl: JSON.stringify(request.body.productUrl),
byLineValue: JSON.stringify(request.body.byLineValue),
byLineUrl: JSON.stringify(request.body.byLineUrl),
amazonPath: JSON.stringify(request.body.amazonPath),
source: JSON.stringify(request.body.source),
productName: JSON.stringify(request.body.productName)
// Tried to stringify and see if it would help ... it didn't
// productImg: request.body.productImg,
// price: request.body.price,
// productUrl: request.body.productUrl,
// byLineValue: request.body.byLineValue,
// byLineUrl: request.body.byLineUrl,
// amazonPath: request.body.amazonPath,
// source: request.body.source,
// productName: request.body.productName
})
.then(function(docRef) {
// console.log("TCL: docRef", docRef)
console.log("New item in trunk added with ID: ", docRef.id)
response.status(200).send("Successful")
})
.catch(function(error) {
console.error("Error adding newTrunk: ", error)
response.status(500).send(error)
});

Send and receive parameters with Ajax GET

I'm having some issues trying to send and receive parameters in javascript and Ajax. I´m sending to /api/getHighScores and that function requires a timestamp for input and the output is a json-file with user information and a value, the highscore. When I receive the response, I want it to print in my Chrome plugin as well.
This is the code right now.
data = {
"startTime": JSON.stringify(1490208166633),
}
function getHighscores() {
$("#knapp2").click(function() {
$.ajax({
type:"GET",
url: "/api/getHighscores",
data:[startTime=1490208166633],
success: function (response){}
});
});
}
{
"manifest_version": 2,
"version": "1.1",
"browser_action": {
"default_icon": "resources/img/clock-icon-png-10763.png",
"default_popup": "popup/popup.html"
},
"background": {
"scripts": ["background/background.js"],
"persistent": false
},
"permissions": [
"activeTab",
"https://ajax.googleapis.com/"
]
}
I've made a few assumptions here about your API structure but this is what I would expect to be.
Typically the
api/getHighScores
endpoint would get all the high scores independent of the time stamp variable.
var data = { startTime: 1490208166633 };
var userInfomation;
$("#knapp2").click(function() {
$.ajax({
type:"GET",
url: "/api/getHighscores/" + data.startTime,
success: function (userInfo)
{
userInfomation = userInfo;
}
error: function (response)
{
// you should deal with the error case as well
// it could give you more information about whats going wrong.
}
});
});
function getHighscores() {
$("#knapp2").trigger("click");
}
If you are actually sending data under a GET method.
var data = { startTime: 1490208166633 };
var userInfomation;
$("#knapp2").click(function() {
$.ajax({
type:"GET",
url: "/api/getHighscores",
data: JSON.stringify(data);
success: function (userInfo)
{
userInfomation = userInfo;
}
});
});

Chrome extension, how to send message from panel to content script

My contentScript sends a message to backgroundScript which opens a popup/panel/window. This panel loads an external web page.
I'm injecting some javascript in the panel to interact with it.
What I'm trying do achieve now is to send data from the panel to the 'main page' (contentScript).
I have successfully managed to send messages from the panel to the backgroundScript.
What I don't understand/know is how to pass the data from the backgoundScript to the contentScript.
Updated script from #Haibara Ai's comment
manifest.js
{
"name": "My extension",
"version": "0.1",
"manifest_version": 2,
"description": "description",
"permissions": ["activeTab", "tabs","http://*/*","https://*/*"],
"content_scripts": [
{
// Change 'matches' attribute to load content
// script only in pages you want to.
"matches": ["SomeUrl"],
"js": ["jquery.min.js", "contentscript.js", "notifier.js"]
}
],
"background": {
"scripts": ["eventPage.js"],
"persistent": false
}
}
contentscript.js
$(document).ready(function() {
var link = document.getElementById('inputLink');
// onClick's logic below:
link.addEventListener('click', function() {
chrome.runtime.sendMessage({
action: 'createWindow',
url: $('input[name=link]').val()
}, function(message) {
console.log(message);
})
});
});
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
alert('a');
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
eventPage.js
chrome.runtime.onMessage.addListener(function(request) {
if (request && request.action === 'createWindow' && request.url) {
chrome.windows.create(
{
url: request.url,
focused: true,
incognito: true,
type: "panel"
}, function (newWindow) {
chrome.tabs.executeScript(newWindow.tabs[0].id, {
file: "jquery.min.js"
}, function() {
chrome.tabs.executeScript(newWindow.tabs[0].id, {
file: "htmlselection.js"
});
});
chrome.tabs.insertCSS(newWindow.tabs[0].id, {file: "htmlselection.css"});
});
} else {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
console.log(chrome.tabs);
chrome.tabs.sendMessage(tabs[0].id, {action: "SendIt"}, function(response) {});
});
}
});
htmlselection.js (injected in the popup/panel/window)
[...]
//After a click within the popup/panel/window
chrome.runtime.sendMessage({ text: 'test' });
[...]
Thank you for your help.
Updated
If you want to send message inside chrome.runtime.onMessage, just use the callback sendResponse or use sender.tab.id as tabId to send back the message.
And there are other problems with your code:
Since you are use Programming injection to inject script, you should declare them in "web_accessible_resources" in manifest.json
"web_accessible_resources": [
"htmlselection.js",
"jquery.min.js",
"htmlselection.css"
]
In your contentscript.js, just remove message part, since you didn't receive anything in this script.
For eventpage.js, use sendResponse instead of tab.query.
else {
console.log("2");
sendResponse({ action: "SendIt" });
}
Previous
Take a look at Message Passing, you could send a message from background page using the following code snippets:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
Fixed version of the snippet:
chrome.tabs.query({active: true, currentWindow: false}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
Set the currentWindow:false and it worked.

Chrome Extension post request not sending data

First time using the site to ask a question. I'm new to Chrome Extensions so I'm sure I'm making some stupid mistake. I apologize in advance.
I'm trying to grab the current tab's url and POST it to a URL that will then recieve it and push it into a database. Like my own personal bookmarking service. I've debuged as much as I can, the data is making it all the way to where i'm sending my XHR request.. but the data doesn't come out when I echo it on my server side script. I'm confirming that it's hitting my URL because i'm console logging the output... but again no data is being passed.
BACKGROUND.JS
chrome.runtime.onMessage.addListener(function(request, sender, callback) {
if (request.action == "xhttp") {
var xhttp = new XMLHttpRequest();
var method = request.method ? request.method.toUpperCase() : 'GET';
xhttp.open(method, request.url, true);
xhttp.send(request.data);
xhttp.onload = function() {
callback(xhttp.responseText);
};
return true
}
});
MANIFEST.json
{
"name": "bookmarker",
"version": "0.0.1",
"manifest_version": 2,
"description": "POSTIN BOOKMARKS!",
"homepage_url": "URL",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"permissions": [
"contentSettings",
"cookies",
"tabs",
"geolocation",
"http://*/*"
],
"content_scripts": [
{
"js": ["contentscript.js"],
"matches": ["http://*/*"]
}
],
"browser_action": {
"default_icon": "icons/icon16.png",
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
MAIN.JS
jQuery(function() {
jQuery('.reminded').on('click', function(e){
e.preventDefault();
chrome.tabs.query({currentWindow: true, active: true}, function(tabs){
var url = tabs[0].url,
date = 1391048414,
clientId = 1234
chrome.runtime.sendMessage({
method: "POST",
action: "xhttp",
url: "http://www.API.com/endpoint",
data: {url: url, date: date, clientId: clientId}
}, function(responseText) {
console.log(responseText);
});
});
});
});
Thank you very much in advance for any light anyone can share.
You didn't mention where "main.js" was used, but I guess that it's used in the popup page, right? The popup page can also make cross-domain requests in a Chrome extension when you've declared the permissions in the manifest file. So, just use jQuery.ajax directly to make the cross-domain request:
jQuery.ajax({
type: "POST",
url: "http://www.API.com/endpoint",
data: {url: url, date: date, clientId: clientId},
success: function(data) {
console.log(data);
}
});
For the record, the code in your question is failing because you're trying to submit a JavaScript Object ({url: url, date: date, clientId: clientId} via the .send method of a XMLHttpRequest. This makes no sense, and your server would receive the string [object Object] because of the default serialization of objects.
To get your original code to work, you should use jQuery.param to serialize the form data and xhttp.setRequestHeader("Content-Type", "application/x-www-form-url-encoded");.

Categories

Resources