we are looking to read/save a POST REQUEST's body/payload through chrome extension.
Scenario: a target webpage will submit a post request to server once in a while.
Requirement: chrome extension's popup.html has a button with id='startIntercept' and upon clicked we need to save the next firing post request's all details(headers, payload) to a session variable.
we only need to save what post request is been sent from current tab. we are not bothered what response we received for the post request.
through a source we came to know a way to achieve it by "Overwriting window.XMLHttpRequest.prototype.open method" by saving old open method to a variable and create a new open method to intercept any request and save it then pass parameters to old open method to get usual expected page functionality.
code used:
//popup.js
let startIntercept = document.getElementById("startIntercept");
startIntercept.addEventListener("click", async () => {
let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["startWork.js"],
});
});
//startWork.js
let oldXHROpen = window.XMLHttpRequest.prototype.open;
console.log('script injected');
window.XMLHttpRequest.prototype.open = function() {
this.addEventListener("load", function() {
const responseBody = this.responseText;
sessionStorage.setItem('payload', responseBody );
});
return oldXHROpen.apply(this, arguments);
};
//manifest.json
"name": "extTracker",
"description": "want to save post request details",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"host_permissions": ["<all_urls>"],
"permissions": ["storage", "activeTab", "scripting"],
"web_accessible_resources": [{
"resources": ["/assets/media/blinkSd.mp3"],
"matches": ["<all_urls>"],
"use_dynamic_url": true
}],
"action": {
"default_popup": "popup.html",
},
*once we have a working model we will enhance manifest file/filter requests to intercept accordingly
the above code fails to save/intercept any request made from current tab even through script 'startWork.js' is successfully injected.
why it fails?? any better approach to achieve this functionality?
Your Expertise and Time are very much appreciated. Thank You
Related
Problem
My chrome extension needs to inject the content script into all tabs when switched on and then when any new tabs are loaded etc.
By adding the content script to the manifest file I can satisfy the second requirement of having it loaded in newly loaded tabs.
To make it also inject the content script into tabs as soon as the extension is loaded or refreshed (there is no popup), I am using chrome.scripting.executeScript.
Problem is each time the extension is turned off/on or refreshed, the content script is loaded in again and any DOM manipulation from content script occurs multiple times.
So from reading another post, I liked the idea of sending a message to the content script, if I don't get a response (undefined) then I inject the script into this tab, if I do get a response then do nothing.
In my background logs I get this error Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist. which is what I would expect if the content script did not exist, but even when the content script is clearly being loaded, I still get the same error.
Any help greatly appreciated. And maybe this is not even the best approach for this, I am not sure. Ideally I would also want the extension to immediately stop working when it's turned off, but I haven't got around to this problem yet.
Manifest
{
"name": "Text highlighter",
"description": "Text highlighter",
"version": "1.0.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"options_ui": {
"page": "options.html",
"open_in_tab": false
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": [ "styles.css" ]
}
],
"permissions": ["storage", "activeTab", "scripting", "tabs"],
"host_permissions": ["<all_urls>"]
}
self.oninstall = () => {
chrome.tabs.query({}, function(tabs) {
tabs.forEach((tab) => {
chrome.tabs.sendMessage(tab.id, true, (response) => {
console.log('response', response);
if(!response) {
chrome.scripting.executeScript({
target: {tabId: tab.id},
files: ['content.js']
});
chrome.scripting.insertCSS({
target: { tabId: tab.id },
files: ['styles.css']
});
}
});
});
});
};
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('request', request);
sendResponse(true);
return true;
});
I've been trying to work with chrome extensions lately and right now I'm just trying to get familiar with the chrome apis.
Specifically, I'm testing out chrome.tabs.query to create an alert with the URL of the currently active tab, but the event doesn't trigger. Here is the code for my background.js file.
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
var activeTab = tabs[0];
var activeTabUrl = activeTab.url;
alert(activeTabUrl);
});
And here is my manifest.json. I'm pretty sure all the permissions are correct.
{
"manifest_version": 2,
"name": "Time Tracker",
"description": "Track how much time spent on ...",
"version": "1.0",
"permissions": ["history", "bookmarks", "activeTab", "tabs"],
"background":{
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["http://*.www.youtube.com/*"],
"js": ["content.js"]
}
],
"browser_action": {
"default_popup": "popup.html",
"default_icon": "/images/clock.png"
}
}
I've also tried out other chrome apis such as chrome.history.onVisited to try and add an eventListener but nothing seems to be working.
I've added a link to the full repo here.
https://github.com/ismail-ahmed0149/Time-Tracker
Update #1 June 2. 2021 (Response to most recent comment)
Here is my most recent code my background script.
function handleUpdated(tabId, changeInfo, tabInfo) {
console.log("Updated tab: " + tabId);
console.log("Changed attributes: ");
console.log(changeInfo);
console.log("New tab Info: ");
console.log(tabInfo);
}
chrome.tabs.onUpdated.addListener(handleUpdated);
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
var activeTab = tabs[0];
var activeTabUrl = activeTab.url;
alert(activeTabUrl);
});
You'll find docs for chrome.tabs events here:
LINK
(scroll down till the end)
You have to add a "onUpdated" event in your background script.
Recently, it is reported that the context menu of my app is vanished. If you remove the app and reinstall it, it works. But the vanishment happens again.
I found an error. I'm not sure if the error causes the vanishment of the context menu. But I'd like to fix this matter, because all I found is this.
This app shows texts you select in a page. When you select texts in an ordinaly page and click browser action button, it works without error. But if you try it on Google Docs, you will get error "Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist".
I'm afraid I don't know what to do with this. And I might have two problems. It'll be great help if you could give me some advice.
[manifest.js]
{
"manifest_version": 2,
"name": "Test Chrome Extension",
"short_name": "Test",
"version": "1.0",
"description": "This is a test.",
"icons": {
"128": "128.png"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["googleDocsUtil.js", "content_scripts.js"]
}],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"browser_action": {
"default_icon": {
"48": "48.png"
},
"default_title": "Test Chrome Extension"
},
"permissions": [
"contextMenus",
"tabs",
"background",
"http://*/*",
"https://*/*"
]
}
[background.js]
chrome.contextMenus.create({
type: 'normal',
id: 'testchromeextension',
title: 'Test Chrome Extension',
contexts:['selection']
});
chrome.contextMenus.onClicked.addListener(function(info,tab){
if( info.menuItemId == 'testchromeextension' ){
var selectedText = info.selectionText.replace(/ /g, "\n");
doSomething(selectedText);
}
});
chrome.browserAction.onClicked.addListener( function(tab) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {method: "getSelection"}, function(response) {
doSomething(response.data);
});
});
});
function doSomething(selectedText) {
console.log(selectedText);
}
[content_scripts.js]
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) {
if (request.method == "getSelection") {
var post_val = window.getSelection().toString();
if ( !post_val ) {
var googleDocument = googleDocsUtil.getGoogleDocument();
post_val = googleDocument.selectedText;
}
sendResponse({data: post_val});
}
});
I believe this error is caused when you update the local version of an extension and then try to use the extension with its old/not-updated source code.
The fix: after you reload your local extension at chrome://extensions/, make sure you refresh the page you're using the extension on. You should no longer see the error.
I'm trying to make an extension that scrapes email IDs from the current tab open in the Chrome browser.
After reloading the extension from chrome://extensions when I go to the tab where I want to test the extension I'm having to refresh the page in order to see the desired results in the console in spite of executing the Content Script in background.js using chrome.tabs.executeScript in order to reinject it into the current tab in the browser.
Content Script - Relevant portion
var jsonData = scrape();
console.log(jsonData); //THIS I SEE WITHOUT PAGE REFRESH
chrome.runtime.sendMessage(jsonData, function(response) {
console.log(response); //WITHOUT PAGE REFRESH shows undefined, AFTER PAGE REFRESH shows the desired response
});
background.js
var background = {
injectScript: function() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "myscript.js"});
});
}
};
background.injectScript();
manifest.json
{
"manifest_version": 2,
"name": "emailScraper",
"version": "1.0",
"description": "Email Scraping Chrome Extension",
"icons": {
"64": "tiki_1.3.png"
},
"browser_action": {
"default_icon": "tiki_1.3.png",
"default_popup": "popup.html"
},
"background": {
"scripts": ["js/app/background.js",
"js/lib/socket.io/socket.io.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*", "https://mail.google.com/*", "https://google.com/*", "file://*/*"],
"js": ["js/lib/jquery/jquery.min.js", "js/app/myscript.js"],
"all_frames": false
}
],
"permissions": [
"tabs",
"http://*/*",
"https://*/*"
],
"content_security_policy": "script-src 'self' http://localhost:1441/; object-src 'self'"
}
I'd also like to add that the Content Script is communicating with the popup.js of my extension. It sends the list of the email IDs scraped to popup.js.popup.js on receiving the list sends a response to Content Script. This exchange of information takes place only after the current page is refreshed but not otherwise. I wonder why so.
popup.js
var app = angular.module('emailScraper',[]);
app.controller('AppCtrl', ['$scope', '$http', function($scope, $http) {
//Fetch URL of current Tab open in Chrome
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
// and use that tab to fill in out title and url
var tab = tabs[0];
$scope.cpUrl = tab.url;
console.log($scope.cpUrl); //I SEE ONLY THIS LINE WHEN I INSPECT POPUP
});
$scope.appLoaded = false;
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log("Message received: ", request); //I SEE ONLY AFTER PAGE REFRESH IN Inspect Popup BUT NOT IN popup.html view
$scope.emailList = request;
$scope.count = Object.keys($scope.emailList).length;
console.log("Emails found: " + $scope.count); //I SEE ONLY AFTER PAGE REFRESH IN Inspect Popup BUT NOT IN popup.html view
$scope.appLoaded = true;
sendResponse({status: "Received JSON data!"});
});
}]);
I appreciate your response.
I want to manipulate a web page based on answer of ajax request. Basicly I'll search title of page in youtube and retrieve first youtube.
var search_input = $("#title").text();
var keyword= encodeURIComponent(search_input);
// Youtube API
var yt_url='http://gdata.youtube.com/feeds/api/videos?q='+keyword+'&format=5&max-results=1&v=2&alt=jsonc';
$.ajax
({
type: "GET",
url: yt_url,
dataType:"jsonp",
success: function(response)
{
console.log("succeded");
if(response.data.items)
{
$.each(response.data.items, function(i,data)
{
var video_id=data.id;
var video_title=data.title;
var video_viewCount=data.viewCount;
// IFRAME Embed for YouTube
var video_frame="<iframe src='http://www.youtube.com/embed/"+video_id+"' frameborder='0' type='text/html'></iframe>";
var final="<div>"+video_frame+"</div><div id='count'>"+video_viewCount+" Views</div>";
$("#videos").html(final); // Result
});
}
else
{
$("#videos").html("<div id='no'>No Video</div>");
}
}
});
And here's manifest.json
{
"content_scripts": [
{
"matches": [
"https://*.website.com/*",
"*://*.youtube.com/*"
],
"js": [
"jquery.js",
"mymanipulatır.js"
]
}
],
"name": "Name",
"icons": {
"128": "128x128.png"
},
"homepage_url": "http://github.com/",
"version": "1.4",
"manifest_version": 2,
"developer": {
"name": "may"
},
"description": "youtube"
}
Extension throws Uncaught ReferenceError: jQuery11100021788313053548336_1393869626682 is not defined when trying to make ajax request. What am I missing?
When doing cross-site XHR's from a content script injected into a web page, you need to declare the url patterns you want to be able to connect to in the "permissions" section of your manifest the same way as if you were doing the XHR from inside one of your extensions own standalone pages (eg the background page, a browser action popup, etc.).
See: https://developer.chrome.com/extensions/xhr