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
Related
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
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 am trying to develop a Chrome extension to open Office documents stored in Confluence in a new tab using the IE Tab extension.
In the 'View Page Attachment' screen, there is an 'Edit in Office' link for Office file attachments. The link has a click event that creates a new instance of a URLLauncher, which is used to open the document. This feature is not supported in Chrome, so I want to add my own URLLauncher prototype into the web page to make it work.
In short, this is my idea:
Create a Chrome extension with a content script that injects a URLLauncher prototype into the 'View Page Attachment' page (I don't know if this is the right approach, so I am open to suggestions).
When the user clicks on the 'Edit in Office' link, the URLLauncher.open method opens the file attachment in a new tab by calling the IE Tab extension.
I can see the 'Hi there!' alert every time I load a web page, and that confirms that content.js is being injected. Nevertheless, the URLLauncher is not available in the web page. I think this is because the global window object of the content script is distinct from the page/extension's global namespace (i.e., window.URLLauncher is undefined). How could I reorganize my code to overcome this obstacle?
These are my files:
manifest.json
{
"manifest_version": 2,
"background": {
"scripts": [
"background.js"
]
},
"content_scripts": [ {
"js": [ "content.js" ],
"matches": [ "<all_urls>" ]
} ],
"description": "This is a test extension",
"permissions": [
"tabs", "http://*/*", "https://*/*"
],
"name": "Test extension",
"version": "1.0.0"
}
background.js
chrome.tabs.executeScript(null, {
code: "document.body.appendChild(document.createElement('script')).src='" +
chrome.extension.getURL("content.js") + "';"
}, null);
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.id == "doUrlLaunch") {
chrome.tabs.create({ url: request.nUrl, selected: true });
sendResponse({result: "goodbye"});
}
}
);
content.js
var prefixUrl = 'chrome-extension://hehijbfgiekmjfkfjpbkbammjbdenadd/iecontainer.html#url=';
alert('Hi there!');
function URLLauncher() {
}
URLLauncher.prototype = {
open : function(urlStr) {
var newUrl = prefixUrl + 'https://host.com' + encodeURI(urlStr);
chrome.runtime.sendMessage({id: "doUrlLaunch", nUrl: newUrl}, function(response) {
});
}
}
Thanks in advance.
UPDATE 1
I edited the files following the instructions given by Rob W and this page ('Message Passing'); now the code is injected in the page itself, but a major problem still remains. The actual JS code sends a message to the content script, but the message is not caught by the listener, so the new tab is not created and the callback function does not receive a response; the error message I got: Error in event handler for (unknown): TypeError: Cannot read property 'success' of undefined.
These are the updated files:
manifest.json
{
"manifest_version": 2,
"content_scripts": [ {
"js": [ "content.js" ],
"matches": [ "<all_urls>" ]
} ],
"web_accessible_resources": [ "script.js" ],
"description": "This is a test extension",
"permissions": [
"tabs", "http://*/*", "https://*/*"
],
"name": "Test extension",
"version": "1.0.0",
"externally_connectable": {
"ids": ["*"],
"matches": ["*://*.hostname.com/*"]
}
}
content.js
var s = document.createElement('script');
s.src = chrome.extension.getURL("script.js");
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
chrome.runtime.onMessage.addListener(
//Unreachable code!
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.id == "doUrlLaunch") {
chrome.tabs.create({ url: request.nUrl, selected: true });
sendResponse({result: "goodbye"});
}
}
);
script.js
var prefixUrl = 'chrome-extension://hehijbfgiekmjfkfjpbkbammjbdenadd/iecontainer.html#url=';
function URLLauncher() {
}
URLLauncher.prototype = {
open : function(urlStr) {
var newUrl = prefixUrl + 'https://hostname.com' + encodeURI(urlStr);
chrome.runtime.sendMessage({id: "doUrlLaunch", nUrl: newUrl}, function(response) {
if (!response.success)
console.log('Something went wrong...');
});
}
}
Not sure if you're still interested in an answer, but in your edited files your problem is where your listener sits.
chrome.runtime.sendMessage does not reach content scripts; it is intended for extension pages. Message passing to content scripts works through chrome.tabs.sendMessage, but this is irrelevant for this task.
Content scripts can't call chrome.tabs as they do not have the required API access.
A solution would be to call a background script, that can receive those messages and can call the required API.
Therefore, you need a third script, taking out this code from content.js:
// background.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.id == "doUrlLaunch") {
chrome.tabs.create({ url: request.nUrl, selected: true });
sendResponse({result: "goodbye"});
}
}
);
And modify your manifest:
"background": { "scripts": [ "background.js" ] },
I've written a google chrome extension. It's okay and works now but I want the extension to be usebale only on two domains because it's written for these two websites only and is useless for others. There is a context menu only. For now it hasn't even popup, or action button in the top right corner (hidden by default). How can achieve this?
My current manifest.json:
{
"manifest_version": 2,
"background": {
"scripts": ["scripts/jquery.min.js", "scripts/background.js"]
},
"name": "Export Entries",
"description": "some descriptions here",
"version": "1.0",
"icons": {
"16": "images/logo.png",
"48": "images/logo.png",
"128": "images/logo.png"
},
"permissions": ["downloads", "tabs", "contextMenus", "http://my-own-domain-accessed-via-ajax-for-creating-some-files-there.com/*"],
"content_scripts": [{
"matches": ["*://allowed-domain1.com/*", "*://allowed-domain2.com/*"],
"css": ["styles/style.css"],
"js": ["scripts/jquery.min.js", "scripts/popup.js", "scripts/background.js"],
"run_at": "document_end"
}],
"web_accessible_resources": [
"images/logo.png"
]
}
As I understand the extension cannot be disabled absolutely, its process will run in background again. But it's not a problem. I just want to not display the context menu item on other websites.
background.js creates the context menu item and handles its click event:
function exportEntries(info, tab) {
if (info['linkUrl'].indexOf('domain1.com/user/') > -1) {
var user = info['linkUrl'].substr('27');
} else {
var user = null; // export all entries from this topic
}
$.ajax({
url: 'http://my-own-domain-which-creates-the-file.eu/exportEntries/create.php',
method: 'POST',
data: {
topic: tab.url,
user: user
}
}).done(function(url) {
forceDownload(url);
});
}
function forceDownload(url) {
var filename = url.replace(/^.*\/|\.[^.]*$/g, '');
chrome.downloads.download({
url: url,
saveAs: true
}, // options array
function(id) {
// callback function
}
);
};
document.addEventListener('DOMContentLoaded', function() {
chrome.contextMenus.create({
'title': 'Export Entries',
'contexts': ['link'],
'onclick': function(info, tab) {
exportEntries(info, tab);
}
});
});
create.php is on my own domain. It just gets the current page's URL and the user's nickname. Then export all entries from the given topic (i.e. page URL) for the given user, creates a file (.txt, .pdf etc.) and sends back url for downloading the file.
popup.html, popup.js, css file and other stuff is not used for now.
Remove all of your content scripts, they're useless, because the chrome.contextMenus API can only be used on the background page.
To limit the context menu entry to certain domains, pecify the documentUrlPatterns key when you create the context menu using the chrome.contextMenus.create:
chrome.contextMenus.create({
'title': 'Export Entries',
'contexts': ['link'],
'onclick': function(info, tab) {
exportEntries(info, tab);
},
'documentUrlPatterns': [
'*://allowed-domain1.com/*',
'*://allowed-domain2.com/*'
]
});
According to the content scripts documentation:
"If you want to inject the code only sometimes, use the permissions field instead, as described in Programmatic injection."
So instead of
"content_scripts": [
{
"matches": [ "http://allowed-domain.com" ]
}
],
use
permissions: [
"tabs", "http://allowed-domain.com"
],
I'm trying to open up a rich notification using the following:
var options = {
templateType: "basic",
title: "John Doe",
message: "Lorem ipsum",
iconUrl: "https://www.MyExternalURL.com/image.jpg"
};
chrome.experimental.notification.create("notifyId", options, function(id) {
console.log("Succesfully created notification");
});
But for some reason this does not work, but if I replace the options with the following:
var options = {
templateType: "basic",
title: request.name,
message: request.message,
iconUrl: chrome.runtime.getURL("/images/cat.png"),
};
And the notification works perfectly.
Here are the important stuff in my manifest file
{
"manifest_version": 2,
"name": ...,
"description": ...,
"version": ...,
"icons": {
...
},
"content_scripts": [
...
],
"background": {
"scripts": ["background.js"]
},
"permissions": [
"tabs",
"experimental"
],
"web_accessible_resources": [
"https://www.MyExternalURL.com/*"
]
}
How should I use an external image as the iconURL?
Script and object resources can only be loaded from the extension's package, not from the web at large. This ensures that your extension only executes the code you've specifically approved, preventing an active network attacker from maliciously redirecting your request for a resource.
So, your code does not work for loading an external JPEG Icon iconUrl: "https://www.MyExternalURL.com/image.jpg".
Instead download the file from https://www.MyExternalURL.com/image.jpg and put it inline as in approach #2.
More over web_accessible_resources does not accept any content with HTTP URL(S), it only accepts an array of strings specifying the paths (relative to the package root) of packaged resources that are expected to be usable in the context of a web page.
Reference
CSP
Web Accessible Resources
Fetching the blob of an external image by Ajax, apply data URI that is converted it.
var options = {
type: "basic",
title: "TITLE",
message: "MESSAGE"
};
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.MyExternalURL.com/image.jpg");
xhr.responseType = "blob";
xhr.onload = function(){
var blob = this.response;
options.iconUrl = window.URL.createObjectURL(blob);
chrome.notifications.create("notifyId", options, function(notId){});
};
xhr.send(null);