How to add variable to xhr.open outta Chrome extension? - javascript

I'm writing a Chrome extension, which should on loading of every new domain in browser get special remote url, add to it the current domain (like with window.location.hostname), get special metric from the target page, produced on this way, (with XMLHttpRequest and XPath), and show this metric as BadgeText.
I've got nearly all working, but only with static url. If instead of "+window.location.hostname+" i hardcode any domain name, everything works like expected - i get the number as BadgeText. But how can i get this work with domain currently loaded in browser?
This is my background.js:
chrome.tabs.onUpdated.addListener(function (tabid, changeInfo, tab) {
chrome.tabs.query({ 'active': true, 'currentWindow': true }, function (tabs) {
let newUrl = new URL(tabs[0].url);
currentDomain = newUrl.hostname;
console.log(currentDomain);
});
});
var xhr = new XMLHttpRequest();
xhr.open("GET", "url part 1" + window.location.hostname + "url part 2", true);
xhr.responseType = 'document';
xhr.send();
xhr.onreadystatechange = function () {
console.log("XHR callback readyState = " + this.readyState);
if (this.readyState == 4) {
function getElementByXpath(path) {
return xhr.response.evaluate(path, xhr.response, null, XPathResult.STRING_TYPE, null).stringValue;
}
console.log(getElementByXpath("//div[#class='data-mini']/span/span[#class='value']/text()"));
var badgeText = getElementByXpath("//div[#class='data-mini']/span/span[#class='value']/text()");
console.log(badgeText);
chrome.browserAction.setBadgeText({ text: String(badgeText) });
console.log(String(badgeText));
}
}
With the first part i get clean domain of the currently loaded tab into console. The second part should do the rest job.
What remains, is to get
currentDomain
into
xhr.open("GET", "https://app.sistrix.com/app_visindex/__loadModule/lang/de/domain/"+currentDomain+"/source/de/ref/app_controller_efcdc3b3cab713326d8830ac95b499e454ae4e46053a5cc6/_action/_result/_cache//_loadbox/empty/_ajax/1/_module-expire/217287/_controller", true);
The main goal:
on visiting of every other domain the url in xhr.open is modified with the current domain,
XHRHttpRequest gets new number from HTML element defined with XPath,
the number is shown as BadgeText.

If I understood well your question, you want to get page information + it's current hostname when switching tabs.
So { pageInfo, currentHost }.
This information you want to pass to the background and do an XHR with the right host...
Here is how would I solve this:
In your content.js:
// Gets needed data from the content when the tab changes (i.e on window focus).
// For example I will take the content of first paragraph and the hostname:
window.onfocus = function () {
const firstParagraphText = document.getElementsByTagName('p')[0].innerText;
const hostName = window.location.host;
this.sendDataToBackground({ paragraph: firstParagraphText, host: hostName });
}
function sendDataToBackground(data) {
chrome.runtime.sendMessage(chrome.runtime.id, data);
}
Then in your background.js you have to retrieve the info sent by content:
chrome.runtime.onMessage.addListener(function (request, sender) {
console.log('First paragraph = ', request.paragraph);
console.log('Host = ', request.host);
// DO XHR WITH NEW HOST...
});
This works for me, if you wish I can create a public repo with one working example...

The correct and working code is:
chrome.tabs.onUpdated.addListener(function(tabid, changeInfo, tab){
chrome.tabs.query({'active' : true, 'currentWindow': true}, function(tabs){
let newUrl = new URL(tabs[0].url);
var currentDomain = newUrl.hostname;
var xhr = new XMLHttpRequest();
xhr.open("GET", "url part 1"+currentDomain+"url part 2", true);
xhr.responseType='document';
xhr.send();
xhr.onreadystatechange = function() {
if (this.readyState == 4) {
function getElementByXpath(path) {
return xhr.response.evaluate(path, xhr.response, null, XPathResult.STRING_TYPE, null).stringValue;
}
var badgeText = getElementByXpath("//div[#class='data-mini']/span/span[#class='value']/text()");
chrome.browserAction.setBadgeText({text: String(badgeText)});
chrome.browserAction.setBadgeBackgroundColor({ color: '#1d2554' });
}
}
});
});

Related

Chrome Extension: WebQL database is not appearing in Inspector

I am trying to create database and tables in background.js file of Chrome but somehow it's not being created. When I see in Chrome Inspector > Resources > WebSQL, I find nothing. Code is given below:
function fetchData(){
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost/php/fetch.php", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// JSON.parse does not evaluate the attacker's scripts.
var resp = xhr.responseText;
if(resp != null) {
var json = JSON.parse(resp)
console.log(resp);
var data = json['data'];
if(data != null) {
openDatabase('documents', '1.0', 'my storage', 5*1024*1024, function (db) {
alert('Called'); //This is not being called.
});
//var dbConnection = openDbConnect();
//createTable(dbConnection);
//Code below is called
for(var a=0;a <= data.length;a++) {
alert(data[a].title);
}
}
}
}
}
xhr.send();
}
Update
I guess it's being created: My Extension ID is bkjajbjnoadlhnhmfekipifehbhgidpg
In ~/Library/Application Support/Google/Chrome/Default/databases I find:
chrome-extension_bkjajbjnoadlhnhmfekipifehbhgidpg_0
But it's weird I can't see it in Inspector.
Update #2
Turns out that like pages, WebSQL is not visible across Chrome. It shows Db to the page which is visited. Now I am getting no idea how to excess chrome related Db in Viewer.
To access the inspector for the background page of your app, go to Menu>Settings>Extensions and make sure it's in Developer Mode. It should have a link to inspect the background page of your app in there. It will open up in a new window.

Chrome extension: XHR request to website, get html content by class name

I am creating a chrome extension that will go to a specified website, and get parts of the site's HTML from the source code.
I want to get the html content contained within a div with class name 'span1 rating-num-span'.
I tried using .getElementsByClassName but it returned undefined, however when I use .getElementsByTagName on ('h2') it worked.
Here is the javascript function to make the request from my main.js
function getFlowSite(){
var request = new XMLHttpRequest();
request.onreadystatechange = function(){
if (request.readyState == 4){
if (request.status == 200){
var temp = document.createElement('div');
temp.innerHTML = request.responseText;
alert(temp.getElementsByTagName('h2')[0].innerText);
alert(temp.getElementsByClassName('span1 rating-num-span')[0].innerText);
}
else{
console.log("Messed up!!!");
}
}
};
request.open("GET", "http://uwflow.com/course/" + courseName, true);
request.send(null);
}
stumped...
Thanks for reading!
--------------------Update------------------------
Turns out the class isn't present initially on the page, and is loaded in dynamically with a script. How can I get the source code of the page after everything is loaded in?
That element is added by the page script dynamically.
It's not present initially on the page. You can check this by examining the first server response from the site when loading it with devtools Network panel open. Or, if you use the great uBlock (origin) extension, simply disable all javascript on the site temporarily and reload the page.
You have two options:
find out how that webpage's code fetches the data from the server/elsewhere and do it yourself, there's usually some kind of JSON API. For example in this case there's a huge config object right in the page:
<script>
window.pageData.courseObj = {"ratings": [{"count": 375, "rating": .............
Simply use XMLHttpRequest with .responseType = "document" mode and get that element, then use JSON.parse on it.
Or, actually, in this case a simple regexp + JSON.parse will do:
var match = request.responseText
.match(/window\.pageData\.courseObj\s*=\s*(\{.+?\});\s*[\r\n]/);
var config = JSON.parse(match[1]);
config.ratings.forEach(function(r) { console.log(r) });
Object {count: 375, rating: 0.6986666666666667, name: "usefulness"}
Object {count: 494, rating: 0.7449392712550608, name: "easiness"}
Object {count: 555, rating: 0.5621621621621622, name: "interest"}
The above code wasn't tested live and doesn't contain any error checks which must be implemented in the real code.
load the page as a normal browser tab without activating it, inject a content script, wait for the element to appear, extract the data, close the tab.
manifest.json:
"permissions": ["http://uwflow.com/*"] - permissions for executeScript on non-active tab
popup.js:
var globalTabId = 0;
function openTab(url) {
chrome.tabs.create({url: url, active: false}, function(tab) {
globalTabId = tab.id;
chrome.tabs.executeScript(tab.id, {file: "getData.js", runAt: "document_end"});
});
}
chrome.runtime.onMessage.addListener(function(msg, sender, response) {
if (msg.action == "data" && sender.tab && sender.tab.id == globalTabId) {
chrome.tabs.remove(globalTabId);
processData(msg.data);
}
});
getData.js, this is a content script but it doesn't need to be declared in manifest.json.
var interval = setInterval(function() {
var ratings = document.querySelector(".span1.rating-num-span");
if (!ratings) {
return;
}
clearInterval(interval);
chrome.runtime.sendMessage({action: "data", data: {ratings: ratings.textContent}});
}, 100);

How to get the URL of a <img> that has been redirected? [duplicate]

If there is an img tag in a page whose final image it displays comes after a 302 redirect, is there a way with javascript to obtain what that final URL is after the redirect? Using javascript on img.src just gets the first URL (what's in the page), not what it was redirected to.
Here's a jsfiddle illustration: http://jsfiddle.net/jfriend00/Zp4zG/
No, this is not possible. src is an attribute and it does not change.
I know this question is old, and was already marked answered, but another question that I was trying to answer was marked as a duplicate of this, and I don't see any indication in any of the existing answers that you can get the true URL via the HTTP header. A simple example (assuming a single image tag on your page) would be something like this...
var req = new XMLHttpRequest();
req.onreadystatechange=function() {
if (req.readyState===4) {// && req.status===200) {
alert("actual url: " + req.responseURL);
}
}
req.open('GET', $('img').prop('src'), true);
req.send();
If you are open to using third party proxy this can be done. Obviously not a javascript solution This one uses the proxy service from cors-anywhere.herokuapp.com. Just adding this solution for people who are open to proxies and reluctant to implement this in backend.
Here is a fork of the original fiddle
$.ajaxPrefilter( function (options) {
if (options.crossDomain && jQuery.support.cors) {
var http = (window.location.protocol === 'http:' ? 'http:' : 'https:');
options.url = http + '//cors-anywhere.herokuapp.com/' + options.url;
//options.url = "http://cors.corsproxy.io/url=" + options.url;
}
});
$.ajax({
type: 'HEAD', //'GET'
url:document.getElementById("testImage").src,
success: function(data, textStatus, request){
alert(request.getResponseHeader('X-Final-Url'));
},
error: function (request, textStatus, errorThrown) {
alert(request.getResponseHeader('X-Final-Url'));
}
});
based on http://jsfiddle.net/jfriend00/Zp4zG, this snippets works in Firefox 17.0:
alert(document.getElementById("testImage").baseURI)
It doesn't work in Chrome. Not tested anything else-
Here is a workaround that I found out. But it works only if the image on the same domain otherwise you will get an empty string:
var img = document.getElementById("img");
getSrc(img.getAttribute("src"), function (realSrc) {
alert("Real src is: " + realSrc);
});
function getSrc(src, cb) {
var iframe = document.createElement("iframe"),
b = document.getElementsByTagName("body")[0];
iframe.src = src;
iframe.className = "hidden";
iframe.onload = function () {
var val;
try {
val = this.contentWindow.location.href;
} catch (e) {
val = "";
}
if (cb) {
cb(val);
}
b.removeChild(this);
};
b.appendChild(iframe);
}
http://jsfiddle.net/infous/53Layyhg/1/

Page doesn't respond to HREF until AJAX completes asynchronous fetch

I have an ajax request executing through the XMLHttpRequest() object
My AJAX method is called in this format:
var xmlhttp = new XMLHttpRequest();
$(document).ready(function () { LoadData(); });
function LoadData()
{
var parameters = "DisplayData=true";
var url = "default.aspx";
Send(url, parameters, "DisplayData");
CheckForAbort();
}
function Send(url, parameters, QueryType)
{
...
xmlhttp.open("POST", url, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-lencoded");
xmlhttp.send(parameters);
xmlhttp.onreadystatechange = function (){...}
}
There is also a timer on the page which refreshes the data by making a new request through the Send(...) method in intervals of 15 seconds. Every .3 seconds and it calls an Elipsis() method that displays and "blinks" the "loading message" (if appropriate to be displayed) and checks for the abort.
var Color = "red";
function Elipsis() {
if (ResponseMessage != "")
{
if (Color == "darkred") { Color = 'red'; } else { Color = 'darkred'; }
$("#StatusResponse").css("display", "block");
$("#StatusResponse").css("color", Color);
CheckForAbort();
}
}
function CheckForAbort()
{
console.log("MenuActivted: " + MenuActivted);
if (MenuActivted)
{
xmlhttp.abort();
ResponseMessage = "Aborting Request";
MenuActivted = false;
}
}
But when the user clicks the menu bar which is an anchor tag with the HREF set to another page. The browser doesn't respond until the ajax request has completed it's fetch.
The HTML HREF is called the following way on an ASPX page:
<%#Eval("Text")%>
the Ajax Abort sets the flag that is checked in the CheckForAbort() method:
var MenuActivted = false;
function AbortAjax()
{
MenuActivted = true;
return false;
}
I am running IE 11 on Win 7. I have called an abort() method in another section of the code. which executes the xmlhttp.abort(). The response status and ready state respond (console output below) but the page still waits to respond to the HREF
Console output:
HTML1300: Navigation occurred.
File: ChangePassword.aspx
MenuActivted: true
ReadyState: 4
Status: 0
Does anyone have a solution to this problem?
[Updated **********]
I thought I had the solution but I didn't.
I commented out the set header but although it allowed my HREF to execute it was because the xhr was throwing an error and the fetch was terminating.
xmlhttp.open("POST", url, true);
//xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.send(parameters);
Please read the entire post before responding.

create plugins to detect suspicious ajax

I want to make browser extension for Firefox that detect the ajax code of of website that load the hidden page and redirect to new page ,like if user visit index.php where ajax load the two pages one is hiddenpage.php and redirect to new.php . Is there any other solution to detect this ajax at client side.
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
//document.getElementById("myDiv").innerHTML="";
}
}
xmlhttp.open("GET","hidden.php",true);
xmlhttp.send();
}
HTML
click here
document.addEventListener('DOMContentLoaded', function() {
getCurrentTabUrl(function(url) {
fetchData(url);
});
});
function fetchData(url)
{
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange=function()
{
if (xhr.readyState==4 && xhr.status==200)
{
var data = xhr.responseText;
var index = data.indexOf('XMLHttpRequest');
if(index != -1){
document.getElementById("status").innerHTML = "The page contains AJAX requests";
}else{
document.getElementById("status").innerHTML = "Page doesn't contains AJAX";
}
//document.getElementById("status").innerHTML = data;
}
}
//xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
//xhr.setRequestHeader("Access-Control-Request-Method", "POST");
xhr.send();
}
function getCurrentTabUrl(callback) {
var queryInfo = {
active: true,
currentWindow: true
};
chrome.tabs.query(queryInfo, function(tabs) {
var tab = tabs[0];
var url = tab.url;
console.assert(typeof url == 'string', 'tab.url should be a string');
callback(url);
});
}
just go through this code you will get the better help
You can modify XMLHttpRequest's prototype in an userscript.
/* Save the old method somewhere, it may be useful if you want to allow some AJAX */
XMLHttpRequest.prototype._send = XMLHttpRequest.prototype.send;
/* Override the previous method to define yours */
XMLHttpRequest.prototype.send = function () {
/* Do stuff here */
alert(1);
/* Use this line if you want to continue the AJAX request */
XMLHttpRequest.prototype._send.apply(this, arguments);
}

Categories