Accessing array in another JS file - Chrome Extension - javascript

Hi I am making a chrome extension for some practice that is a simple website blocker. I have two different JS files that are needing to share the same array that contains URLs to be blocked.
background.js handles the webRequests and blocking websites
options.html is the options page where users can edit URLs to be blocked, it calls storeURL.js so that it can store all the elements in the list on the html page into a js array. No problem so far.
However I cannot access the array inside of storeURL.js from background.js. It seems as if they are being called in two separate instances. If I try to include both storeURL.js and background.js inside of my background.html, that results in two totally separate storeURL.js scripts running.
How should I go about doing this? Should I store the array contents from storeURL.js into a file?
Some examples:
background.js
chrome.webRequest.onBeforeRequest.addListener(
blocking,["blocking"]);
{ urls: blockedURLS, types: [] }, ["blocking"]);
storeURL.js populates the array based on the list in options.html
var blockedURLS = [];
$('li').each(function(i, elem) {
blockedURLS.push($(elem).text());
});
blockedURLS in my background.js appears as undefined. I have also tried to point my options.html file to background.js and just include all of the js in one file with the following:
<script type="text/javascript" src="background.js"></script>
However when I do this it seems that a second background.js is called rather than just pointing to the one already running.
Feels like I've reached a dead end with possibly a simple solution that is available to fix my problem. I'm fairly new to JS/chrome extensions as well.
Thanks for taking the time to read this!
EDIT:
After some more fiddling I am able to access my blockedURL array in my background.js. However it is never updated.
var blockedURLS = ["hi"] ;
var list = document.getElementById('list');
$("#saveList").click(function(e) {
e.preventDefault();
localStorage.setItem('todoList', list.innerHTML);
alertify.success("You have saved your list.");
//Pushes each element in the list from options.html into the urls array
blockedURLS = [];
$('li').each(function(i, elem) {
blockedURLS.push($(elem).text());
});
alert("Currently blocked:\n" + blockedURLS);
});
$("#reset").click(function(e) {
e.preventDefault();
localStorage.clear();
location.reload();
});
loadToDo();
function loadToDo() {
if (localStorage.getItem('todoList')){
list.innerHTML = localStorage.getItem('todoList');
}
}
What should be happening is that after I go into my options.html and save the list, "hi" should be replaced with all the different URLs I have in my list. However it is not. The blockedURL array is printed correctly in that alert though.

I haved to work with that kind of thing recently. I have never find a really good way to do... So I have used the Storage api of Chrome Extension API. But it's not really funny to use because all methods are asynchronus so you can't simply do
myValue = chrome.storage.local.get("MyValue")
If you want I have made an object that store data automatically in the chrome storage but allows simple and synchronus calls like myValue = storage.myValue or storage.myValue = "something"
Here the github link
It was written in CoffeeScript so you can find javascript file in bin folder. The generated javascript is not very easy to read/modified but you can understand the idea simply by reading the CoffeeScript code I guess.
I can explain more how it works if you want. Tell me in comment and I will update my response.
And pay attention that it's a code I have written for my use so it's not the cleaner and bugless code that I have ever made :-) but it works fine.
EDIT : I have forget to says that you need to include this tow files in all pages / Content Script where you need to use it, of course.
Ho and sorry for my poor english... it's not actually my principal language ;-)

I had to use the following command:
var bg = chrome.extension.getBackgroundPage();
then I could access the blockedURLS array by:
alert(bg.blockedURLS);
and also edit the array by
chrome.extension.getBackgroundPage().blockedURLS = [];
which would set it to an empty array.
Thanks guys for the help, it helped me in thinking of different possibilities on approaching this problem.

Related

How can I create a dynamic product page using HTML, CSS, and Javascript

I currently only know javascript. But the thing is I looked up how to do it and some people talk about something called localStorage. I have tried this and for some reason when I jump to a new page those variables aren't kept. Maybe I am doing something wrong? I jump to a new page via
and all I want do do is select a certain image. take that image to a new page and add it to that page.
I tried using the localStorage variables and even turning it into JSON.stringify and doing JSON.parse when trying to call the localstorage to another script. It didn't seem to work for me. Is there another solution?
This is some of my code. There are two scripts.
document.querySelectorAll(".card").forEach(item => {
item.addEventListener("click", onProductClick);
})
var div;
var productImg;
var ratingElement;
var reviewCount;
var price;
function onProductClick(){
// This took a week to find out (this.id)
// console.log(this.id);
div = document.getElementById(this.id);
productImg = div.getElementsByTagName('img')[0];
ratingElement = div.getElementsByTagName('a')[2];
reviewCount = div.getElementsByTagName('a')[3]
price = div.getElementsByTagName('a')[4];
console.log(div.getElementsByTagName('a')[4]);
var productData = [div, productImg,ratingElement,reviewCount,price];
window.localStorage.setItem("price", JSON.stringify(price));
}
function TranslateProduct(){
console.log("Hello");
}
This is script 2
var productPageImage = document.getElementById("product-image");
var myData = localStorage['productdata-local'];
var value =JSON.parse(window.localStorage.getItem('price'));
console.log(value);
// function setProductPage(img){
// if(productImg != null){
// return;
// }
// console.log(window.price);
// }
To explain my thought process on this code in the first script I have multiple images that have event listeners for a click. I wanted to Click any given image and grab all the data about it and the product. Then I wanted to move that to another script (script 2) and add it to a dynamic second page. yet I print my variables and they work on the first script and somehow don't on the second. This is my code. in the meantime I will look into cookies Thank you!
Have you tried Cookies
You can always use cookies, but you may run into their limitations. These days, cookies are not the best choice, even though they have the ability to preserve data even longer than the current window session.
or you can make a GET request to the other page by attaching your serialized object to the URL as follows:
http://www.app.com/second.xyz?MyObject=SerializedData
That other page can then easily parse its URL and deserialize data using JavaScript.
you can check this answer for more details Pass javascript object from one page to other

Getting Backbutton to work in single page website and implementing "speaking" URLs

I have a single page website and would like to achieve the following:
back button working as if it was a normal website
and instead of say,
www.mysite.com/index.php?p=#this-is-a-great-product
I'd like to have this url
www.mysite.com/this-is-a-great-product
while still having back button working properly.
Regarding 1.) I use the following code ive found which works great:
<!-- Getting BackButton to work properly -->
<script type="text/javascript">
var times = 0;
function doclick() {
times++;
}
function doclick() {
times++;
location.hash = times;
}
window.onhashchange = function() {
if (location.hash.length > 0) {
times = parseInt(location.hash.replace('#',''),10);
} else {
times = 0;
}
}
</script>
…but of course it just changes any anchors to /#1, then /#2 and so forth ro get the backbutton to work. But as I'm not a programmer I don't know how to change it… :(
Regarding 2.) i can add in htaccess this:
>RewriteEngine On
>RewriteRule ^([^/.]+)/?$ /index.php?page=$1
and this changes /index.php?p=products to /products.
So how do I change the above code (under 1.) so it doesn't change all anchors to #1, #2, etc. but instead references / uses the urls I achieved under 2, like
www.mysite.com/this-is-a-great-product
And (probably a very dumb question, but a very important one) -given I use only the new url links on my site- is there any danger that this still might result in duplicate content in any way?
Regarding this, should I (for that reason or any other) sefreferential my single page index.php to itself using rel canonical link=index.php?
Thanks so much in advance!
As mentioned, you will want to use the HTML5 History API. Please note, this API is relatively new and therefore browser support is a concern. At the time of writing, approximately 71% of global Internet users have support for it (see http://caniuse.com/#feat=history for browser support information). Therefore, you will want to ensure you have a fall-back solution for this. You will likely want to use the older #! solution that was popular before the HTML 5 History API was adopted.
If you use the history API to replace, for example, example.com/#!settings with example.com/settings and a user bookmarks that nicer URL, then when they go to visit it, their browser will make a request to the server for /settings (which doesn't actually exist in the web server's context). Therefore, you will need to make sure your web server has some redirection rules (i.e. RewriteEngine) such that it can take the pretty URLs and redirect them to the #! version (and then if the user's browser supports the history API it can replace that with the nice URL).
If you aren't very comfortable programming yourself, I'd recommend using a JavaScript library that does a lot of the work for you. I did some quick searching and discovered the following, though there might be better ones out there: https://github.com/browserstate/history.js
Basically i have created a small prototype on jsfiddle which tracks all the urls accessed via ajax calls.
Also contains navigation to access links back and forth .
How It Actually Works:
I have created a global array called history, which keeps track of all urls accessed via ajax in sequence.
also there a global index defined to keep track of the url being accessed when navigating back and forth the links in history array.
There is History section at the bottom of the jsfiddle, which shows the sequence in which the links are accessed by capturing the link names and posting them in the order in which they were accessed.
JS Code:
$(function () {
var history = [];
var index = 0;
$('.links').on('click', function () {
$('#history').append($(this).text());
var address = $(this).attr('data-ref');
index += 1;
history[index] = address;
$('.links').attr('disabled', 'disabled');
loadExternalPage(address);
console.log('list:' + history);
});
$('#back').on('click', function () {
console.log(index);
index -= 1;
console.log(index);
console.log(history[index]);
loadExternalPage(history[index]);
});
$('#forward').on('click', function () {
console.log(index);
index += 1;
console.log(index);
console.log(history[index]);
loadExternalPage(history[index]);
});
var loadExternalPage = function (address) {
console.log(history[index]);
$('#result-section').load(address, function () {
console.log('data-loaded');
$('.links').removeAttr('disabled');
});
};
});
Live Demo # JSFiddle:http://jsfiddle.net/dreamweiver/dpwmcu0b/8/
Note: This solution is far from being perfect, so dont consider it as final solution but rather use it as a base to build upon
On using BACK and FORWARD functions in the browser top-left button:
In principle, there is no great problem with this as long as you work with the existing storage object (a stack) for previously visited web pages on your browser. This object is the history object and you can see what is in it anytime by right-clicking and selecting "Inspect", then selecting the "Console" tab, then enter window.history and enter.
Check out the Browser Object Model (BOM) section of Pro Java For Web Developers (Frisbee) for the background to the history object. (Just a few pages, an easy read, don't worry.) Just remember that in this process you are storing the new page that you move to, not the old page that you are leaving !
For a simple SPA example, look at this example. codepen.io/tamjk/pen/NWxWOxL
In regard to the URL, the method that the history object uses to load a new page state into the history stack, i.e. pushState(...), has an optional third parameter for associating a dummy URL for each web page that is stored.
Personally, when I first sorted out the BACK & FORWARD functions, I did not use dummy URLs as the browser was being confused by them and I had enough to do sorting out the history sequence using just the first two parameters, i.e.
the state object - a JSON holding enough data to recreate the page stored
a title for the page I expect that you could also use a dummy URL but I will leave that to the student as an exercise, as they say.
But you can add the URL of the new page if you want to.
In the example above, for the state object I just used the IDs of the page's nav link and its content element.
For the title, I programmatically changed the HTML's page title element with each change of page. I did this after noticing that the browser listed the previous pages according to the title element in the HTML code.
Unfortunately, this title does not show up on CodePen when you right-click on the browser BACK and FORWARD buttons due to CodePen's system not allowing it. But it will show on your own sites.
It's important that whatever method you use to store current web page states when using the navbar links to navigate, you DO NOT ADD page states to the browser history when you arrive at them using BACK or FORWARD buttons. Otherwise your history stack will have repetitions of entries going back and deletion of entries going forward.
In the CodePen, this was achieved by having the addToHistory(..) function separate to and outside the scope of the switchPage(...) function. This allows you use of the switchPage function in both normal navbar navigation and browser BACK/FORWARD navigation. The third parameter of switchPage(...) is a boolean indicating if the page is to be stored in history or not.
Anyway, this is just something to get you started.

Is it possible for the admin to get the full sourcecode of my js-file if I redirect a Javascript file to a local modified Javascript file?

I created a google-chrome-extension which redirects all requests of a javascript-file on a website to a modified version of this file which is on my harddrive.
It works and I do it simplified like this:
... redirectUrl: chrome.extension.getURL("modified.js") ...
Modified.js is the same javascript file except that I modified a line in the code.
I changed something that looks like
var message = mytext.value;
to var message = aes.encrypt(mytext.value,"mysecretkey");
My question is now is it possible for the admin of this website where I redirect the javascript-file to modify his webpage that he can obtain "mysecretkey". (The admin knows how my extension works and which line is modified but doesn't know the used key)
Thanks in advance
Yes, the "admin" can read the source code of your code.
Your method is very insecure. There are two ways to read "mysecretkey".
Let's start with the non-trivial one: Get a reference to the source. Examples, assume that your aes.encrypt method looks like this:
(function() {
var aes = {encrypt: function(val, key) {
if (key.indexOf('whatever')) {/* ... */}
}};
})();
Then it can be compromised using:
(function(indexOf) {
String.prototype.indexOf = function(term) {
if (term !== 'known') (new Image).src = '/report.php?t=' + term;
return indexOf.apply(this, arguments);
};
})(String.prototype.indexOf);
Many prototype methods result in possible leaking, as well as arguments.callee. If the "admin" wants to break your code, he'll surely be able to achieve this.
The other method is much easier to implement:
var x = new XMLHttpRequest();
x.open('GET', '/possiblymodified.js');
x.onload = function() {
console.log(x.responseText); // Full source code here....
};
x.send();
You could replace the XMLHttpRequest method, but at this point, you're just playing the cat and mouse game. Whenever you think that you've secured your code, the other will find a way to break it (for instance, using the first described method).
Since the admin can control any aspect of the site, they could easily modify aes.encrypt to post the second argument to them and then continue as normal. Therefore your secret key would be immediately revealed.
No. The Web administrator would have no way of seeing what you set it to before it could get sent to the server where he could see it.

Chrome JavaScript location object

I am trying to start 3 applications from a browser by use of custom protocol names associated with these applications. This might look familiar to other threads started on stackoverflow, I believe that they do not help in resolving this issue so please dont close this thread just yet, it needs a different approach than those suggested in other threads.
example:
ts3server://a.b.c?property1=value1&property2=value2
...
...
to start these applications I would do
location.href = ts3server://a.b.c?property1=value1&property2=value2
location.href = ...
location.href = ...
which would work in FF but not in Chrome
I figured that it might by optimizing the number of writes when there will be effectively only the last change present.
So i did this:
function a ()
{
var apps = ['ts3server://...', 'anotherapp://...', '...'];
b(apps);
}
function b (apps)
{
if (apps.length == 0) return;
location.href = apps[0]; alert(apps[0]);
setTimeout(function (rest) {return function () {b(rest);};} (apps.slice(1)), 1);
}
But it didn't solve my problem (actually only the first location.href assignment is taken into account and even though the other calls happen long enough after the first one (thanks to changing the timeout delay to lets say 10000) the applications do not get started (the alerts are displayed).
If I try accessing each of the URIs separately the apps get started (first I call location.href = uri1 by clicking on one button, then I call location.href = uri2 by clicking again on another button).
Replacing:
location.href = ...
with:
var form = document.createElement('form');
form.action = ...
document.body.appendChild(form);
form.submit();
does not help either, nor does:
var frame = document.createElement('iframe');
frame.src = ...
document.body.appendChild(frame);
Is it possible to do what I am trying to do? How would it be done?
EDIT:
a reworded summary
i want to start MULTIPLE applications after one click on a link or a button like element. I want to achieve that with starting applications associated to custom protocols ... i would hold a list of links (in each link there is one protocol used) and i would try to do "location.src = link" for all items of the list. Which when used with 'for' does optimize to assigning only once (the last value) so i make the function something like recursive function with delay (which eliminates the optimization and really forces 3 distinct calls of location.src = list[head] when the list gets sliced before each call so that all the links are taken into account and they are assigned to the location.src. This all works just fine in Mozilla Firefox, but in google, after the first assignment the rest of the assignments lose effect (they are probably performed but dont trigger the associated application launch))
Are you having trouble looping through the elements? if so try the for..in statement here
Or are you having trouble navigating? if so try window.location.assign(new_location);
[edit]
You can also use window.location = "...";
[edit]
Ok so I did some work, and here is what I got. in the example I open a random ace of spades link. which is a custom protocol. click here and then click on the "click me". The comments show where the JSFiddle debugger found errors.

function call does not return to calling function

I'm using Shadowbox.js to display a slideshow on a website.
This slideshow shows several pictures and I would like to know who's looking at what pictures.
For this purpose I'm using statcounter.com.
Shadowbox offers a so called hook to call a function when the slideshow opens and when it changes to another picture.
I've written a small piece of code to get things moving, but for some reason, I get an entry in my statcounter log, but the shadowbox does not appear.
When I don't use the onopen and onchange in the options, the shadowbox does display.
As a test you can set up a directory where you place below code. Create to subdirs in this directory called "sb" and "pix". Get the Shadowbox-application from the website and store it in the "sb" directory (http://shadowbox-js.com/download.html).
Next to that store 3 testimages (called image1.jpg, image2.jpg and image3.jpg) in the "pix" directory.
To check if statcounter is picking up the pictures, you can use my testaccount on statcounter.com (just for viewing: account testcase, password casetest1).
Please find the html with the code here: http://www.heres-online.nl/test/index.html
Please take into account, I only just starting in javascript and html programming.
I can imagine I'm overlooking something terribly simple ...
Any help is highly appreciated.
Instead of trying to insert an image tag that way, just make one:
var img = new Image();
img.src = "... tracker URL ...";
That's all you need to do. edit Also get rid of all those backslashes in your URL strings; there's no point to them.
edit again I think this is all you need:
var nonsense = 1;
function tracker() {
var img = new Image();
img.src = "http://c.statcounter.com/counter.php?sc_project=5981755&security=582aa718&invisible=1&u=" +
encodeURIComponent("http://my.pix/" + Shadowbox.getCurrent().content) +
'&nonsense=' + new Date().getTime() + '_' + nonsense++);
return true;
}
(added a "nonsense" parameter to try and overcome possible caching issues)
edits — OK note the "return true" and the change of "escapeURIComponent" (wrong) to "encodeURIComponent". (I always get confused because the old deprecated function was called "escape".)
Please hold your horses on my last comment. I made a mistake myself (typo).
Instead of encodeURIComponent I typed enocdeURIComponent (why not copy/paste ... yeah, well I just didn't).
The script is now doing exactly what I intended it to do. I know have a Statcounter entry for every picture in the slideshow! Superb. I'm very pleased with your help, this was really nagging me, not being able to get it running. And the speed of getting an answer here was really amazing!
I've posted your solution on the Shadowbox.js forum as well. I posted my question there too, but no answers yet. But for anyone strugling with the same issue, this solution might be helpfull.
Thanks again, and have a nice weekend!

Categories

Resources