document.write in Chrome Extension - javascript

I'm new to this so please bear with me. I am trying to write a chrome extension that does the following:
Detect www.website.com/anypage.html. If this website is detected, then do the following.
Don't load the URL.
Instead, write a blank document with a hyperlink to www.website.com/anypage.html?ie=UTF8
The script is set to run at document start (in the manifest).
Here is my code:
Detect URL:
var regExp = /website.com/gi;
var match = 0;
testString = window.location.href.toString();
if(regExp.test(testString) {
match = 1;
Write blank document with link to the URL with the UTF8 encoding tag:
document.write("<a href=" + window.location.href + "?ie=UTF8>Title of Link</a>");
This doesn't work as expected, and just shows a blank page. Anyone have any ideas?
Thanks!
EDIT: Here is the full code:
checklink(); // If there is a match, then checklink will return a 1. If it's already tagged, it will return a 5.
var matchLink = null;
if (checklink() === 1) {
matchLink = window.location.href.toString();
if (checklink() != 1) {
matchLink = null;
function checklink() { //checks to see if the current URL matches website.com
var regExp = /website.com/gi,
testString = window.location.href.toString(),
match = 0,
tagged = 0;
if (regExp.test(testString)) { //if there is a match, returns 1
match = 1;
var regExp2 = /UTF8/gi;
if (regExp2.test(testString)) { //if UTF8 is found, then it returns 5
tagged = 5;
return(match + tagged);
function tagUTF() {
if (matchLink) {
var newLink = matchLink + "?ie=UTF8";
document.write("Link");
if (matchLink) {
tagUTF();
}

The chrome content script has access to the DOM, so you could just replace the contents of the body element of the current page with a new node that has your anchor tag either using dom manipulation methods or innerHTML:
document.body.innerHTML = "<a href=" + window.location.href + "?ie=UTF8>Title of Link</a>";
Please note, this assumes that the JavaScript that is doing the DOM manipulation was properly added for your Chrome extension as a "content script":
http://code.google.com/chrome/extensions/content_scripts.html
EDIT:
Here is the code I used to make it work for me locally:
manifest.json
{
"name": "Test",
"version": "1.0",
"description": "Test",
"permissions": [
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"],
"run_at": "document_end"
}
]
}
content-script.js
document.body.innerHTML = "<a href='test'>test</a>";

Related

Chrome Extension onMessage listener not receiving the second message

I'm working on a private chrome extension which is designed to rake data from one tab, sanitize it, and populate the form data in another tab.
The logic flows like this:
The background script gets the tabids of the two tabs of interest and populates variables named feedId and targetId - background.js line 7ff
The Background script listens for the indication that the icon is clicked - background.js line 30
The background script sends a message to the content.js script to "Rake the Data." - background.js line 38
The content.js receives the message and looks for the text "Rake the Data" then rakes the data and puts the data into an object - content.js line 17ff
The content.js sends a message back to the background script with an object of the data - content.js line 49
The background script receives the message with the object and then works to sanitize the data - background.js line 43ff
The background script then sends the sanitized data (I'm only sending one element at this stage of the script) to the targetId tab to begin the process of populating the fields by utilizing chrome.tabs.sendMessage - background.js line 73ff
I am expecting the message "Populate the Form" to show in the alert box in content.js line but it never gets alerted.
What am I doing wrong in this last stage of the process?
Here is my manifest.js:
{
"manifest_version":
2,
"name":
"Rake and Populate",
"version":
"0.3",
"description" :
"Rake data and populate a web form." ,
"permissions" : [
"tabs"
],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"content.js"
]
}
],
"background": {
"scripts": [
"background.js"
],
"persistent": false
},
"icons" : {
"16" : "rake16.png" ,
"32" : "rake32.png" ,
"48" : "rake48.png" ,
"128" : "rake128.png"
},
"browser_action" : {
"default_icon" : "rake16.png"
}
}
Here is my background.js script:
// Let define some parameters for the query
// These are the websites we want to work with
var players = ["*://*.domain-one.com/*", "*://*.domain-two/add.html*"];
feedId = targetId = 0;
// query the tabs to get the Ids of the two tabs of interest
chrome.tabs.query({url: players}, mytabs);
// take the returned data from the query and find the ID for each
function mytabs(myinfo){
var regex = /domain-one\.com/;
if (myinfo[0].url.match(regex)){
window.feedId = myinfo[0].id;
window.targetId = myinfo[1].id;
console.log('matched');
console.log(window.feedId);
} else {
window.feedId = myinfo[1].id;
window.targetId = myinfo[0].id;
};
};
// let's listen for the button in the addres bar being clicked
// when the button is clicked, the function "iChooseToRake" will get executed
chrome.browserAction.onClicked.addListener(iChooseToRake);
// This function is called when the button is onClicked
function iChooseToRake(tab) { //the tab object is passed into the function
//chrome.tabs.sendMessage(tab.id, "Rake the Data");
var rakeMessage = {message: "Rake the Data"};
chrome.tabs.sendMessage(tab.id, rakeMessage);
}
// Set up a listener to receive the message from the rake
// saying "I have the data"
chrome.runtime.onMessage.addListener(
function(unsanitizedData, sender){
// The data has been sent back in the object. Sanitize the data in the next few lines
// Let's get the zip from the end of the full address
// Check to see if there is a zip+4 code in the address
var regex = /[0-9]{5}-[0-9]{4}/; // does it match the pattern nnnnn-nnnn
if (unsanitizedData.physical_address_full.match(regex)){
var tempAddress = unsanitizedData.physical_address_full.match(regex)[0]; //populates tempAddress if matched
} else {
// We get here if the zip+4 matched failed.
// Check to see if there is a match for a 5 digit zip
var regex = /[0-9]{5}$/; //the pattern nnnnn at the end of the string
var tempAddress = unsanitizedData.physical_address_full.match(regex)[0]; //populates tempAddress if matched
console.log('I matched the 5 digit zip pattern: ' +tempAddress);
};
//pack the sanitized data into an object
var address = {
zip: tempAddress
};
sendNeededData(targetId, address);
});
// send the opject back to the correct tab
function sendNeededData(targetId, address){
// append the correct message in the object
address.message = "Populate the Form";
console.log(address);
chrome.tabs.sendMessage(targetId, address);
};
Here is my content.js script:
// Function to Convert text to Initial Caps
function titleCase(str) {
return str.toLowerCase().split(' ').map(function(word) {
return (word.charAt(0).toUpperCase() + word.slice(1));
}).join(' ');
}
// The content script listens for a message from the background script
// which tells the browser to rake the data
chrome.runtime.onMessage.addListener(messageRecieved);
function messageRecieved(txt, sender, sendResponse) {
alert(txt.message);
if (txt.message == "Rake the Data"){
console.log('I was just told to rake the data');
// Let's first read the data from the website
var owner_name = document.getElementsByTagName("li")[6].innerText.trim(); // Owner Name
owner_name = titleCase(owner_name); // Give it initial Caps
var owner_address_full = document.getElementsByTagName("li")[7].innerText.trim(); // owner_full_address
owner_address_full = titleCase(owner_address_full); // Give it initial Caps
var physical_address_full = document.getElementsByTagName("li")[10].innerText.trim(); // Situs Address Content:
physical_address_full = titleCase(physical_address_full); // Give it initial Caps
var area_land = document.getElementsByTagName("li")[11].innerText.trim(); // Land Area: e.g. 11,260 Sq.Ft.
var area_roof = document.getElementsByTagName("td")[7].innerText.trim(); // Gross Area: e.g. 2,709
var area_air = document.getElementsByTagName("td")[8].innerText.trim(); // Living Area: e.g. 1,952
// Now let's pack this data into an object and send it back to
// the background script to be processed and fed to the form
var parcelInfo = {
owner_name: owner_name,
owner_address_full: owner_address_full,
physical_address_full: physical_address_full,
area_land: area_land,
area_roof: area_roof,
area_air: area_air
};
console.log(parcelInfo);
// send the message with the data packed into the object named "parcelInfo"
chrome.runtime.sendMessage(parcelInfo);
};
};

Get data from script code

I want to get data from a website, can I get url data from code?
Example code:
<script type="application/json" id="store">
{
"url":{"host":"localhost"},
"resources":
{
"xxfff":
{
"stream":
{
"streamId":"","duration":212714,"videos":
[
{
"url":"www.test.com"
},
{
"url":"www.site.net"
}
]
}
}
},
}
</script>
I just want to get "www.site.net" from script code, is it possible?
This is absolutely possible. To demonstrate, I'm going to show you how you could create such an element in the first place, and then how to retrieve the data. If you are manually putting the code in the script tag, I would suggest stringifying it first.
let src = document.createElement('script');
src.setAttribute('id', 'store');
let json = {
url : {
host : "localhost"
},
resources : {
xxfff : {
stream : {
streamId : "",
duration : 212714,
videos : [
{
url : "www.test.com"
},
{
url : "www.site.net"
}
]
}
}
}
};
json = JSON.stringify(json);
src.innerText = json;
const body = document.getElementsByTagName('body')[0];
const footer = document.getElementById('footer');
body.insertBefore(src, footer);
// Now you have created the element,
// so you reverse the process to get your data
src = document.getElementById('store');
json = src.innerText;
json = JSON.parse(json);
let sites = json.resources.xxfff.stream.videos;
sites.map(site => console.log(site.url));
If you mean you have this script tag somewhere in your webpage, you can read it as any other tag, using innerHTML (right in the first line of this snippet):
var json=document.getElementById("store").innerHTML;
var data=JSON.parse(json);
var videos=data.resources.xxfff.stream.videos;
var table=document.getElementById("tbl");
videos.forEach(function(urlObj){
var td=document.createElement("td");
td.innerHTML=urlObj.url;
var tr=document.createElement("tr");
tr.appendChild(td);
table.appendChild(tr);
});
<script type="application/json" id="store">
{
"url":{"host":"localhost"},
"resources":
{
"xxfff":
{
"stream":
{
"streamId":"","duration":212714,"videos":
[
{
"url":"www.test.com"
},
{
"url":"www.site.net"
}
]
}
}
}
}
</script>
<table border="1" id="tbl"></table>
On a side note, there was a surplus comma in your original post (right before the last closing curly brace) which made the entire thing invalid. I removed it in the hopes of it was just some copy-paste issue, perhaps you had more fields just wanted to cut the post shorter.
Also, if you generate this data immediately into the page, you could just let it be "normal" script, and surround it with a simple var data= and ; pair. Then it would be a variable already, without the need for parsing.

Chrome extension / Oauth /Tumblr

I am (trying to) implementing a Chrome Extension, that uses the Tumblr API. For that to work I need to authorize via OAuth (1.0a).
I managed to get most of the authorization to work but I think I am missing something...
My manifest.json of the Chrome Extension I am writing looks like this for now:
{
"name": "Tumblr - Tiled Dashboard",
"version": "0.1.1",
"manifest_version": 2,
"description": "This extension modifies the look of your Tumblr dashboard.",
"icons": {
"16": "images/icon_16.png",
"48": "images/icon_48.png",
"128": "images/icon_128.png"
},
"background": {
"page": "background.html"
},
"content_scripts": [
{
"matches": [ "*://*.tumblr.com/dashboard" ],
"css": [ "styles.css" ],
"js": [ "jquery-2.1.3.min.js", "masonry.min.js", "code.js" ]
}
],
"permissions": [
"https://www.google-analytics.com/",
"https://api.tumblr.com/v2/*",
"webRequest",
"storage",
"tabs",
"https://www.google.com/accounts/OAuthGetRequestToken", "https://www.google.com/accounts/OAuthAuthorizeToken", "https://www.google.com/accounts/OAuthGetAccessToken"
],
"web_accessible_resources": [ "chrome_ex_oauth.html", "injectedCode.js" ],
"content_security_policy": "script-src 'self' https://api.tumblr.com/v2/ https://ssl.google-analytics.com; object-src 'self'",
"homepage_url": "http://desvre.tumblr.com/",
"author": "Franz Spitaler"
}
...I think this should be ok. In my background.html there are in fact only the included scripts (google analytics and the three oauth files I got from here: https://developer.chrome.com/extensions/tut_oauth . Those three files are also included in the fourth file I downloaded from the previous source ("chrome_ex_oauth.html").
Now when I reload the Chrome Extension in the Extensions (Ctrl + r) the Redirecting page opens and redirects me to the Tumblr authorization page, where I can allow the access.
Since I also added the "chrome_ex_oauth.html" to the "web_accessible_resources" in the manifest.json this works.
The problem occurs after the click on the 'allow' button. I simply get back to the redirecting page ("chrome_ex_oauth.html") and nothing more happens. When I open up the console, I can see an error message like the following:
GET https://www.tumblr.com/oauth/access_token?oauth_consumer_key=MY_CONSUMER_KEY&oauth_nonce=D3VeV&oauth_signature=kvhL%2F9GSMuiODoPR%2FyUrUiqzqF0%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1424250463&oauth_token=6khqzjiMFbM7hcqqnNf8hm9ttDELKUVYo2TBQmyLOtepGN9KhJ&oauth_verifier= 400 (Bad Request)
As described in the OAuth tutorial page from Google I use this to initialize the 'background page' (which leads to the error message):
var oauth = ChromeExOAuth.initBackgroundPage({
'request_url': 'https://www.tumblr.com/oauth/request_token',
'authorize_url': 'https://www.tumblr.com/oauth/authorize',
'access_url': 'https://www.tumblr.com/oauth/access_token',
'consumer_key': 'MY_CONSUMER_KEY',
'consumer_secret': 'MY_SECRET_CONSUMER_KEY',
'app_name': 'Tumblr Tiled Dashboard'
});
Did I miss something important here? I think the manifest.json file is ok (permissions, web_accessible_resources?!).
Thank you for any help. There is really no really great tutorial for OAuth out there for Google Extensions (except that linked page)...
As #abraham pointed out, there was a missing parameter, as seen in my posted error.
I was able to track down the problem and found it in the function of the chrome_ex_oauth.js file. I changed the function from:
ChromeExOAuth.formDecode = function(encoded) {
var params = encoded.split("&");
var decoded = {};
for (var i = 0, param; param = params[i]; i++) {
var keyval = param.split("=");
if (keyval.length == 2) {
var key = ChromeExOAuth.fromRfc3986(keyval[0]);
var val = ChromeExOAuth.fromRfc3986(keyval[1]);
decoded[key] = val;
}
}
return decoded;
};
to this:
ChromeExOAuth.formDecode = function(encoded) {
var params = encoded.split("&");
var decoded = {};
for (var i = 0, param; param = params[i]; i++) {
var keyval = param.split("=");
if (keyval.length == 2) {
var key = ChromeExOAuth.fromRfc3986(keyval[0]);
var val = ChromeExOAuth.fromRfc3986(keyval[1]);
decoded[key] = val;
}
else if (keyval.length == 3){
var key = ChromeExOAuth.fromRfc3986(keyval[0]);
var val = ChromeExOAuth.fromRfc3986(keyval[1].split("#")[0]);
decoded[key] = val;
}
}
return decoded;
};
Where the last parameter was not identified correctly because the ending of the url I got looks like this: #_=_
With the keyval[1].split('#')[0] I get the exact part of the parameter, that I need!
Thank you for the help, everything seems to work now. A request that needs OAuth authorization did, at least!

Why is Chrome ignoring my executeScript command in my extension?

I'm trying to figure out exactly how Content Scripts work.
I'm writing an extension with a context menu that, once the option is clicked, the next click will result in an alert dialog with information about the page the element is on and the id and name of the element clicked.
I think my problem is including the name of the content script file somewhere on my manifest, since I am using executeScript to use it instead of having it injected on every single web page but I cannot figure out where to put it.
Please let me know if I can provide more helpful information.
Here are copies of my manifest, the main script I use and the script that I am trying to insert.
Manifest.json
{
"name": "Omnixx Page Object Builder",
"description": "Finds information about an element clicked, started with a context menu",
"version": "0.3",
"permissions": ["tabs", "contextMenus", "activeTab"],
"background": {
"persistent": false,
"scripts": ["menuBuilder.js"]
},
"manifest_version": 2
}
menuBuilder.js
function onClickHandler(info, tab) {
if (info.menuItemId == "start") {
console.log("Started trying to find elements");
chrome.tabs.executeScript(null, {file:"elementTracker.js"});
console.log("Started listening...");
}
};
chrome.contextMenus.onClicked.addListener(onClickHandler);
chrome.runtime.onInstalled.addListener(function() {
chrome.contextMenus.create({"title": "Find element information", "id": "start", "contexts":["all", "page", "frame", "selection", "link", "editable", "image","video", "audio"], });
});
elementTracker.js
function click(event) {
// Begin building the message
var msgToWrite = "";
var curscreen = window.HIDEFRAME.document.getElementsByName("curscreen")[1].value;
msgToWrite += "curscreen: '" + curscreen + "'\n";
var url = content.document.URL;
msgToWrite += "URL: " + url + "\n";
// A try-catch block is necessary for finding the frame; otherwise the code
// will fail for pages without frames
try {
var frame = event.originalTarget.ownerDocument.defaultView.frameElement;
var frameName = frame.getAttribute("name");
if (frameName != null) {
msgToWrite += "Frame: '" + frameName + "'\n";
} else {
msgToWrite += "No frame found\n";
}
} catch (e) {
msgToWrite += "No frame found\n";
}
// Get the element's ID
var elemID = event.target.getAttribute("id");
if (elemID != null) {
msgToWrite += "ID: '" + elemID + "'\n";
} else {
msgToWrite += "No ID found\n";
}
// Get the element's name
var elemName = event.target.getAttribute("name");
if (elemName != null) {
msgToWrite += "Name: '" + elemName + "'";
} else {
msgToWrite += "No name found";
}
// Create a pop-up message
alert(msgToWrite);
}
document.addEventListener('click', click);
What I think is happening is that you're trying to call another event listener at the end of your elementTracker.js file. You don't need that because you're initializing the script from the context menu call.
Change the last line in that script to click(event). The script will be injected to the page from the context menu.

Get remote url's last modified date with javascript

I am trying to get the last date that a remote url was updated using javascript. I have currently come up with this:
function getlastmod(url)
{
var ifrm = document.createElement("IFRAME");
ifrm.setAttribute("src", url);
ifrm.setAttribute("id", "oIFRAME");
ifrm.style.display = "none";
var spanTag = document.createElement("span");
spanTag.id = "oSpan";
try
{
var oIFrame = document.getElementById("oIFrame");
var oSpan = document.getElementById("oSpan");
oSpan.innerHTML = oIFrame.src + " last modified " +
oIFrame.document.lastModified;
outUpdate=oSpan;
}
catch(E) {setTimeout("getlastmod();",50);}
}
However, this code seems to always change 'outUpdate' to "undefined". The code is supposed to load the url contents into a frame and then use the document.lastModified function to get the last modified date.
Any ideas on how to fix this?
Thanks!
Josh
You are accessing the element oIFRAME & oSpan before adding them to your document, you have to add these 2 lines before the try block:
document.body.appendChild(ifrm);
document.body.appendChild(spanTag);
The id of your iFrame is oIFRAME and not oIFrame, replace this line:
var oIFrame = document.getElementById("oIFrame");
By
var oIFrame = document.getElementById("oIFRAME");
document is not a property of your iFrame object, contentDocument is. Replace this line
oIFrame.document.lastModified;
by
oIFrame.contentDocument.lastModified;
Why is it in try catch statement? Do you expect it to throw any error? Because you basically rely on that. Do you set initial value for outUpdate? Does it ever enters catch statement?
Why do you have to functions here getlastmod() and getLastModified()?
What happens when you set it to:
var outUpdate = "init";
...
...
getlastmod("/");
console.log("outUpdate is: ", outUpdate);
If your not going to display the page you could save yourself some bandwidth by using xhr.
Here's something to get you going...
manifest.json
{
"name": "Get last modified header with XHR.",
"version": "1.0",
"permissions": [
"tabs", "<all_urls>"
],
"browser_action": {
"default_title": "Get last modified header with XHR.",
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"manifest_version" : 2
}
popup.html
<html>
<head>
<script src="popup.js"></script>
</head>
<body style='width : 400px;'>
<div id="message">Getting File.....</div>
</body>
</html>
popup.js
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.w3schools.com/jsref/lastmodified.htm', true);
xhr.onerror = function() {
var message = document.querySelector('#message');
message.innerText = 'Error getting url';
}
xhr.onreadystatechange = function() {
// readystate 2, headers recieved
if (this.readyState == 2){
var message = document.querySelector('#message');
if (this.getResponseHeader("Last-Modified")){
message.innerText = 'Got the headers\n';
message.innerText += 'Last Last-Modified : ' + this.getResponseHeader("Last-Modified");
} else {
message.innerText = 'Got the headers\n';
message.innerText += 'But there was no Last-Modified\n';
// If the file doesnt exist your still going to get headers
message.innerText += 'Or there was an error in getting the file';
}
// Make sure you access the headers before this abort, as they wont be available afterwards
this.abort();
}
}
xhr.send();

Categories

Resources