Chrome extension, using localStorage to save ip, tabid, serverfingerprint per tab - javascript

I should mention up front I'm new to code/stackoverflow so my apologies if this question doesn't makes sense. I'm beyond stumped, I'm trying to build a chrome extension that saves the ip address, url and a server finger print. The serverfingerprint is a field that lives within the response headers. Using my background.js and localStorage I can save this information and then display it in my pop up window. This is all fine and dandy except I can't figure out how to save it on a per tab basis, aka... if I have 5 tabs open, I'd like to click my extension and have it display the url for each corresponding tab. example: click tab4 and shows tab4's url, then click tab2 and it shows the url of tab2.
the below code works except for it doesn't tie to the tabId so it's not exactly ideal. Any ideas of where to start researching would be very appreciated!
what i've done thus far:
background.js:
chrome.experimental.webRequest.onCompleted.addListener(function (details)
{
var headers = details.responseHeaders;
localStorage['ip'] = details.ip;
localStorage['url'] = details.url;
for (var i = 0, length = headers.length; i < length; i++)
{
var header = headers[i];
if (header.name == 'X-Server-Fingerprint')
{
localStorage['XServerFingerprint'] = header.value.toString();
break;
}
}
},{'urls': ['http://www.someurl.com/*']},['responseHeaders']);
popup.js:
document.getElementById('url').innerText = localStorage['url'];
document.getElementById('ip').innerText = localStorage['ip'];
document.getElementById('XServerFingerPrint').innerText = localStorage['XServerFingerPrint'];

As each tab has unique id (until browser restart), you can use it to identify tabs.
You are probably interested only in current tabs, which makes things simpler as you don't need localStorage for this (which persists data between browser restarts). Just use background page's namespace to store data about all tabs:
// background.js
var tabs = {}; //all tab data
chrome.experimental.webRequest.onCompleted.addListener(function (details)
{
var tabInfo = {};
tabInfo["ip"] = ...;
tabInfo["url"] = ...;
tabInfo["XServerFingerprint"] = ...;
tabs[details.tabId] = tabInfo;
}
// popup.js
chrome.tabs.getSelected(null, function(tab){
var tabInfo = chrome.extension.getBackgroundPage().tabs[tab.id]; // get from bg page
document.getElementById('url').innerText = tabInfo['url'];
document.getElementById('ip').innerText = tabInfo['ip'];
document.getElementById('XServerFingerPrint').innerText = tabInfo['XServerFingerPrint'];
});
If you do need localStorage then you can convert tabs object to json string and store it there.

Ok, so I've sorted out my issues! Well the ones concerning chrome extensions haha, which appears to be pretty much exactly what Serg is saying (thx Serg!!) I wrote it a bit different tho.
// background.js
chrome.experimental.webRequest.onCompleted.addListener(function (details)
{
var headers = details.responseHeaders;
var tabId = details.tabId;
var ip = details.ip;
var url = details.url;
for (var i = 0, length = headers.length; i < length; i++) {
var header = headers[i];
//custom field in response headers from my site
if (header.name == 'X-Server-Fingerprint') {
var XServerFingerprint = header.value.toString();
var data = {
ip: ip,
url: url,
fingerprint: XServerFingerprint
}
//store it
localStorage[tabId] = JSON.stringify(data);
break;
}
}
},{'urls': ['http://www.corbisimages.com/*']},['responseHeaders']);
}
// and then on my popup.js
chrome.tabs.getSelected(null, function(tab) {
var parseData = JSON.parse(localStorage[tab.id]);
document.getElementById('XServerFingerprint').innerText = parseData.fingerprint;
document.getElementById('url').innerText = parseData.url;
document.getElementById('ip').innerText = parseData.ip;
});

Related

PhantomJS Memory Exhausted error when using JavaScript

I've searched all over the web for a solution with no luck so far. I know this is a documented issue, but I am only trying to load a single web page and all the responses have been "this happens trying to do tests on 200 pages".
I have tried:
page.settings.loadImages = true;
page.settings.loadplugins = false;
I added the ``page.close()` even though like I said, it's only with one URL right now.
I've tried setting loadImages to false as well. It works fine when I remove my one line of JavaScript (for example replacing it with document.title but as soon as that line is there, the memory usage rockets to 1000MB and then it quits.
My only goal is to check if a certain element exists on the page. How can I resolve this issue? None of the solutions I've found online are working for me.
The code in question:
var system = require('system');
var page = require('webpage').create();
page.settings.userAgent = 'Chrome/52.0.2743.116';
var url = 'http://www.example.com/';
var ending = system.args[1];
ending = encodeURIComponent(ending);
url = url + ending;
page.settings.loadImages = false;
page.settings.loadplugins = false;
page.viewportSize = { width: 1680, height: 1050 };
page.open(url, function(status) {
setTimeout(function(){
var elem = page.evaluate(function() {
return $(".primary-info")[0];
});
if(!elem){
console.log('no image found');
page.render(ending+'.png');
}
page.close();
phantom.exit();
}, 5000);
});
Don't just return the whole object, there could be quite a lot of its attributes. Only take what is necessary:
var elem = page.evaluate(function() {
var data = {};
var item = $(".primary-info")[0];
data.title = item.value;
data.color = item.style.color;
return data;
});

Using an online tool to generate a random name

I found this website http://www.mess.be/inickgenwuname.php
It allows you to type in a name and it will generate a random rapper name. I wanted to have a button on my website that just generates the name for you so I decided to write some javascript that will send a request to this website and parse the response to get the random name.
Here is the node.js code I wrote.
function getRandomName() {
var http = require('http');
var data = {
realname:"something"
};
var querystring = require("querystring");
var qs = querystring.stringify(data);
var qslength = qs.length;
var options = {
hostname: "www.mess.be",
path: "/inickgenwuname.php",
method: 'POST',
headers:{
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': qslength
}
};
var str = "";
var req = http.request(options, function(res) {
res.on('data', function (chunk) {
str+=chunk;
});
res.on('end', function() {
var s = str.slice(str.indexOf("From this day forward, I will be known as... ") + "From this day forward, I will be known as... ".length,
str.indexOf("-And you"));
s = s.replace("\n", "").trim();
console.log(s);
});
});
req.write(qs);
req.end();
}
When I went to the website and pressed f12 on chrome and inspected the code, I found this little segment...
So this is what I used to formulate the request to the php. However, I only guessed through trial and error that the data that needed to be send was key-value pair object where the key is realname. My question is, how would I have known this otherwise? Is there no way to find out from the website, where the data being send with the POST is being received from?
Why by guessing? The form tells you everything that needs to be sent.
Also you could press F12 -> Network, and then send the request. After this you look at the sent requests and search for a POST request. When you click on the /inickgenwuname.php request you get more information about it. In there you can see Response Headers / Request Headers and as a last category "Form Data". There you can see all the data that is sent with this form.
I hope this is the answer you were looking for.
Stealing bandwidth without proper compensation (so called web-scraping) is quite commonly frowned upon. I couldn't find anything on that site that allows for it although I did not search thoroughly.
Why don't you roll your own? It's very simple, as can be seen in this Q&D hack:
function wu_names(input){
// some nice, fitting adjectives. Add more
var adjectives = ["annoying", "crazy", "expert", "insane", "lucky", "sardonic", "pestering"];
// some nice, fitting nouns. Add more
var nouns = ["assassin", "bastard", "conjurer", "destroyer", "ninja", "prophet", "wizard"];
var first = "";
var second = "";
var hash = 0;
var primitive_hash = function(s){
var h = 0;
for(var i = 0;i < s.length;i++){
var c = s.charCodeAt(i);
// standard hash = hash * 31 + c
h = ((h << 5) - h>>>0) + c;
}
return h;
};
first = input.split(" ")[0];
// no useful entry at all
if(first === undefined){
return null;
}
hash = primitive_hash(first);
first = adjectives[hash % adjectives.length];
second = input.split(" ")[1];
// no second entry
if(second === undefined){
return null;
}
hash = primitive_hash(second);
second = nouns[hash % nouns.length];
return first + " " + second;
}
The lists of adjectives and nouns is quite short, you might add to them, as the comments suggest.

Incorrect user profile picture being displayed from JS array - How to address this?

Sorry for the long post, but I'm not sure the issue comes across without all the code.
I'm using parse.com and the JavaScript SDK.
The below code is part of my users profile page, it displays their profile picture to them on screen and allows them to change it.
Changing the profile picture works fine and is uploaded as expected. The issue is that on the profile page the profile is taking the first users picture and displaying it on page for any user. Basically its not looking at the current user.
I think that I need to update the query to include something like var currentUser = Parse.User.current(); and introduce it into my code. Whatever why I try and do this I'm hitting a brick wall. Any help would be great
I'm struggling if this is the case to understand how to change my code to avoid this happening?
/////////////////////////Queries the users profile picture and shows on page////////////////////////
var UserProfilePic = Parse.Object.extend("_User");
var query = new Parse.Query(UserProfilePic);
query.exists("ProfilePic");
query.find({
success: function(results) {
// If the query is successful, store each image URL in an array of image URL's
imageURLs = [];
for (var i = 0; i < results.length; i++) {
var object = results[i];
imageURLs.push(object.get('ProfilePic').url());
}
// If the imageURLs array has items in it, set the src of an IMG element to the first URL in the array
if (imageURLs.length > 0) {
$('#profile_pic').attr('src', imageURLs[0]);
}
$('#Image01').attr('src', imageURLs[0]); //first image
},
error: function(error) {
// If the query is unsuccessful, report any errors
alert("Error: " + error.code + " " + error.message);
}
});
///////// Saves the users profile image and fields after the #save button is clicked//////
var profileSave = Parse.User.current();
function ProfileSave() {
var User = Parse.Object.extend("_User");
var profileSave = Parse.User.current();
var saveusername = $('#username').val();
var saveemail = $('#email').val();
var savegender = $('#gender').val();
profileSave.set("username", saveusername);
profileSave.set("email", saveemail);
profileSave.set("gender", savegender);
profileSave.save(null, {
success: function(profileSave) {
profileSave.save();
console.log("DONE");
alert("Profile Saved");
},
error: function(profileSave, error) {
// Fail
}
});
}
///////////////Allows the user to upload a profile image and store///////////////////////
$(document).ready(function() {
var parseAPPID = "XXXXXX";
var parseJSID = "XXXXXX";
//Initialize Parse
Parse.initialize(parseAPPID, parseJSID);
$("#fileUploadBtn").on("click", function(e) {
var fileUploadControl = $("#fileUploader")[0];
if (fileUploadControl.files.length > 0) {
var file = fileUploadControl.files[0];
var name = file.name;
console.log("here goes nothing...");
var parseFile = new Parse.File(name, file);
parseFile.save().then(function() {
console.log("Worked!");
console.dir(arguments);
var User = Parse.Object.extend("_User");
var jobApplication = Parse.User.current();
jobApplication.set("ProfilePic", parseFile);
jobApplication.save();
var profilePhoto = jobApplication.get("ProfilePic");
console.log("Done");
//jobApplication.get("ProfilePic").url;
}, function(error) {
console.log("Error");
console.dir(error);
});
}
});
});
Just found this in the featured/bounties, even though I answered it here for you, so here's my copy/pasted answer:
You're not using query.exists() the way you think you are. Also, are you just trying to check to see if the current user has a profile image? Because you can just use the .has("key") method of objects, and a user is an object. If this is in cloud code, rather than client code, you may have to fetch the user first. If it is client code, you should already have an up to date user.
You should not be extending the user object. Not necessary at all. Use the Parse.User object type, so if you're querying for users, do var query = new Parse.Query( Parse.User );
So I think what you want is something more like:
var user = Parse.User.current();
if( user.has("ProfilePic") )
{
//Do your stuff with the image
var imageURL = user.get("ProfilePic").url();
$('#Image01').attr('src', imageURL);
}
else
{
alert("Error: User does not have a 'ProfilePic' set");
}
The way your code is set up, you're just querying through all the users with profilePics and taking the first one. My code only gets the profilePic of the current user.

How to know if browser tab is already open using Javascript?

How to know or check if the two browser tab is already open and if those tab are open, the user will receive an alert box or msg box saying that 'the url is already open', something like that, in pure/native JavaScript? This browser tab is contain an external website which is I don't have any privileges to manipulate or change it. Thanks
Example URLs
yahoo.com and google.com
I want to alert the user if there's already open tab for yahoo.com and google.com
And I want to use tabCreate to open the url like this:
tabCreate("http://maps.google.com/", "tabMapsPermanentAddress");
mean to open a new tab, it is use in creating chrome extension
You may use something like following
<!-- HTML -->
<a id="opener">Open window</a>
// JavaScript
var a = document.getElementById('opener'), w;
a.onclick = function() {
if (!w || w.closed) {
w = window.open("https://www.google.com","_blank","menubar = 0, scrollbars = 0");
} else {
console.log('window is already opened');
}
w.focus();
};
Working jsBin | More on window.open method
If you want to control more than one window, use the snippet below
<!-- HTML -->
Open google.com |
Open yahoo.com
//JavaScript
window.onload = function(){
var a = document.querySelectorAll('.opener'), w = [], url, random, i;
for(i = 0; i < a.length; i++){
(function(i){
a[i].onclick = function(e) {
if (!w[i] || w[i].closed) {
url = this.href;
random = Math.floor((Math.random() * 100) + 1);
w[i] = window.open(url, "_blank", random, "menubar = 0, scrollbars = 0");
} else {
console.log('window ' + url + ' is already opened');
}
e.preventDefault();
w[i].focus();
};
})(i);
}
};
Working jsBin
If you don't want them to load in separated window, just exclude this line
random = Math.floor((Math.random()*100)+1);
and remove random reference from the next line
w[i] = window.open(url, "_blank", random, "menubar=0,scrollbars=0");
Side note: As you can see above, we created two windows with some third party content; you should know that there's no way to get any reference (to the parent/opener window) from them.
One basic idea is to store the tab count in either a cookie or localStorage, incrementing it on page load and decrementing it on page unload:
if (+localStorage.tabCount > 0)
alert('Already open!');
else
localStorage.tabCount = 0;
localStorage.tabCount = +localStorage.tabCount + 1;
window.onunload = function () {
localStorage.tabCount = +localStorage.tabCount - 1;
};
Try opening this fiddle in multiple tabs.
Note that this technique is pretty fragile, though. For example, if for some reason the browser crashes, the unload handler won't run, and it'll go out of sync.
The answer by Casey Chu works fine until the browser crashes with the page open. On any next execution, the localStorage object will have initialized tabCount with non zero value. Therefore a better solution is to store the value in a session cookie. The session cookie will be removed when browser exits successfully. When the browser crashes the session cookie will actually be preserved but fortunately only for one next execution of the browser.
Object sessionStorage is distinct for each tab so it cannot be used for sharing tab count.
This is the improved solution using js-cookie library.
if (+Cookies.get('tabs') > 0)
alert('Already open!');
else
Cookies.set('tabs', 0);
Cookies.set('tabs', +Cookies.get('tabs') + 1);
window.onunload = function () {
Cookies.set('tabs', +Cookies.get('tabs') - 1);
};
This answer: https://stackoverflow.com/a/28230846 is an alternative that doesn't require Cookies/js-cookie library. It better suited my needs. In a nutshell (see linked answer for full description):
$(window).on('storage', message_receive);
...
// use local storage for messaging. Set message in local storage and clear it right away
// This is a safe way how to communicate with other tabs while not leaving any traces
//
function message_broadcast(message)
{
localStorage.setItem('message',JSON.stringify(message));
localStorage.removeItem('message');
}
// receive message
//
function message_receive(ev)
{
if (ev.originalEvent.key!='message') return; // ignore other keys
var message=JSON.parse(ev.originalEvent.newValue);
if (!message) return; // ignore empty msg or msg reset
// here you act on messages.
// you can send objects like { 'command': 'doit', 'data': 'abcd' }
if (message.command == 'doit') alert(message.data);
// etc.
}
Just going to throw this up here, because I wish I had something like it. Make what you will of it.
If you want a solution for checking if you are the active tab that doesn't require a cookie, works as a React hook, and works whether or not the browser crashes, you can use this useIsActiveTab webhook which returns true if you are the most recent active tab/window. You can also set yourself as the active tab with activateTab.
import { useEffect, useState } from 'react';
const CHARACTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const CHARACTERS_LENGTH = CHARACTERS.length;
function generateTabId() {
let result = '';
const prefix = 'TAB_';
const length = 15;
for (let i = 0; i < length - prefix.length; i++) {
result += CHARACTERS.charAt(Math.floor(Math.random() * CHARACTERS_LENGTH));
}
if (prefix.includes('_')) {
return `${prefix}${result}`;
}
return `${prefix}_${result}`;
};
const tabId = generateTabId();
export function activateTab(): void {
localStorage.setItem('activeTab', tabId);
const event = new Event('thisStorage');
window.dispatchEvent(event);
}
export function useIsActiveTab(): boolean {
const [isActiveTab, setIsActiveTab] = useState(false);
useEffect(() => {
setActiveTab();
function updateIsActiveTab() {
setIsActiveTab(checkIfActiveTab());
}
window.addEventListener('storage', updateIsActiveTab);
window.addEventListener('thisStorage', updateIsActiveTab);
updateIsActiveTab();
return () => {
window.removeEventListener('storage', updateIsActiveTab);
window.removeEventListener('thisStorage', updateIsActiveTab);
};
}, []);
return isActiveTab;
}
function checkIfActiveTab(): boolean {
const activeTab = localStorage.getItem('activeTab');
if (!activeTab) {
console.error('localStorage.activeTab is not set');
return true;
}
if (activeTab === tabId) {
return true;
}
return false;
}
function setActiveTab(): void {
localStorage.setItem('activeTab', tabId);
}

Chrome App Extension not working with Oauth Javascript

I'm getting this error "Uncaught TypeError: Cannot call method 'setBadgeText' of undefined "
This is my code below:
This used to work in Chrome 27.0, but now with Chrome 29.0 it seems to have stopped functioning. I'm not sure if it's this or the.. manifest.json file which loads this in the background.
var DOCLIST_SCOPE = 'https://docs.google.com/feeds';
var DOCLIST_FEED = DOCLIST_SCOPE + '/default/private/full/';
var docs = []; // In memory cache for the user's entire doclist.
var refreshRate = localStorage.refreshRate || 300; // 5 min default.
var pollIntervalMin = 1000 * refreshRate;
var requests = [];
var oauth = ChromeExOAuth.initBackgroundPage({
'request_url': 'https://www.google.com/accounts/OAuthGetRequestToken',
'authorize_url': 'https://www.google.com/accounts/OAuthAuthorizeToken',
'access_url': 'https://www.google.com/accounts/OAuthGetAccessToken',
'consumer_key': 'anonymous',
'consumer_secret': 'anonymous',
'scope': DOCLIST_SCOPE,
'app_name': 'App Name'
});
function setIcon(opt_badgeObj) {
if (opt_badgeObj) {
var badgeOpts = {};
if (opt_badgeObj && opt_badgeObj.text != undefined) {
badgeOpts['text'] = opt_badgeObj.text;
}
if (opt_badgeObj && opt_badgeObj.tabId) {
badgeOpts['tabId'] = opt_badgeObj.tabId;
}
chrome.browserAction.setBadgeText(badgeOpts);
}
};
function clearPendingRequests() {
for (var i = 0, req; req = requests[i]; ++i) {
window.clearTimeout(req);
}
requests = [];
};
function logout() {
docs = [];
setIcon({'text': ''});
oauth.clearTokens();
clearPendingRequests();
};
If your code is based off of the OAuth tutorial,
the problem is most likely due to http://crbug.com/310870, which is a bug in the samples. (The samples worked before because of a bug in Chrome.)
Make sure that any resources in your extension that are part of the OAuth flow are included in the "web_accessible_resources" key of the manifest. In the case of the contacts sample, this fragment needs to be included.
"web_accessible_resources": [
"chrome_ex_oauth.html",
"chrome_ex_oauthsimple.html"
],

Categories