Good practices for 'global' variables in chrome extensions - javascript

Recently I started developing some extensions for Chrome. I am doing this in manifest v3 and vanilla javascript. I have managed to make my extensions work. However, part of the fun of creating them is in learning to code better. I have been wondering whether I am handling variables in a correct way.
I have some data that I like to access from various points in my extension. Some of it is loaded dynamically and some I set in the code directly, like this:
const myExtensionData = {
someData: [],
config: [],
links: [],
}
1) Is it a good idea to store often-used data in a variable like myExtensionData.someData? Is there a better alternative?
myExtensionData.someData is loaded from externally at some point in time. As I use this data in various functions, I have exposed it like this, so that I don't have to pass the data every time. I could use the local storage, but I have been holding that back as that requires another permission.
2) Same question, but this time with stuff that is rarely used (myExtensionData.config)?
The data in myExtensionData.config is also created dynamically, but the contents are not used as much. For example: I store whether one of my other extensions is also installed. If it is, I enable a button to access it from the popup. Rather single-use.
3) How about static variables? (myExtensionData.links)?
I keep some links I use for onUpdate, onInstall and for release notes. They change regularly, so I needed to store them somewhere. How about storing them in myExtensionData (I actually keep them in a global const at the moment).
4) Any pointers are appreciated!
I hope this is a worthy question. It's not very specific at all, but I am sure I can learn a lot here. I have searched for good practices/best practices, but they are usually outside the context of extension. If I have been looking at all the wrong places, please let me know.
Trying to answer my own question
I found some interesting stuff in this very old question. As I understand it, it's not a bad thing to store a variable in an object. Additionally, I like that it is also suggested to add some methods to the object as well.

Related

Handling global variables in Meteor

I'm using a query on both server and client (pub/sub). So I have something like this at a few different locations.
const FOO = 'bar';
Collection.find({property:FOO})
Foo may potentially change and rather than have to update my code at separate locations, I was thinking it may be worth it to abstract this away to a global variable that is visible by both client and server.
I created a new file 'lib/constants.js' and simply did FOO = 'bar; (note no keyword). This seems to work just fine. I found this solution as the accepted answer How can I access constants in the lib/constants.js file in Meteor?
My question is if this a desired pattern in Meteor and even general JS.
I understand I can abstract this away into a module, but that may be overkill in this case. I also think using session/reactive vars is unsafe as it can kinda lead to action at a distance. I'm not even gonna consider using settings.json as that should only be for environment variables.
Any insights?
yes, If you are using older version of meteor then you can use setting.json but for updated version we have import option.
I don't think the pattern is that bad. I would put that file in /imports though and explicitly import it.
Alternatively, you can write into Meteor.settings.public from the server, e.g., on start-up, and those values will be available on the client in the same location. You can do this without having a settings file, which is nice because it doesn't require you to make any changes between development and production.
Server:
Meteor.startup(() => {
// code to run on server at startup
Meteor.settings.public.FOO = 'bar';
});
Client:
> console.log(Meteor.settings.public.FOO);
bar
This is actually a b̶a̶d̶ unfavoured pattern because with global variables you cannot track what things changed and in general constructing a modular and replaceable components is much better. This pattern was only made possible due to Meteor early days where imports directory/pattern was not supported yet and you'd have your entire code split up between both,server and client.
https://docs.meteor.com/changelog.html#v13220160415
You can find many write ups about it online and event stackoverflow answers so I don't want to restate the obvious.
Using a settings.json variable is not an option since we may dynamically change so what are our options? For me I'd say:
Store it the database and either publish it or retrieve it using methods with proper access scoping of course. Also you can dynamically modify it using methods that author DB changes.
Or, you may try using Meteor.EnvironmentVariable. I'd be lying if I said I know how to use it properly but I've seen it being used in couple Meteor projects to tackle a similar situation.
https://www.eventedmind.com/items/meteor-dynamic-scoping-with-environment-variables
Why are global variables considered bad practice?

How to store variables for other jQuery scripts to use on the page.

I am trying to find the best methodology and have the cleanest code as possible on a project that I am working on.
I am using php and jQuery and displaying information on the page via ajax. When something changes on the page, some of the variables that are passed back into the page change. I need to store these values for other scripts on the page to use. What is the best approach for this.
Currently I am just storing these variables in hidden input fields with id's and then using jQuery to access them when needed. Is this a good approach or is there a better methodology? I don't want to have junky code that other developers look at and use and their punch line to their jokes.
Thanks!
I find storing the variables inside your script is faster, especially since you're using them with existing JS. I would go further than some of the comments, however. If you're working with a series of fields and methods, it's best to build a JS object and keep everything together. This has the added benefit of being viewable inside your DOM inspector (Firebug, etc).
function MyClass(obj) {
this.myvar = obj.val
}
MyClass.prototype.myFunc() {
console.log(this.myvar);
}
newobj = new MyClass({"val":1});
newobj.myFunc();
You can make use of HTML5 sessionStorage object
an example of how you set it
sessionStorage.setItem("myKey", "myValue");
please check documentation below
Here

JavaScript Hacking

I am trying to figure out any and all ways to prevent CSS modification and DOM modification of specific elements. I understand this might not be completely possible or that a talented developer could get around it, however, I am not so concerned about people potentially getting around it, I just want to stop newbies. In particular those using jQuery. An example would be to delete certain properties on prototype objects etc..
But why you need/want this? If you want to "protect" your code, you can use some JavaScript minifier as Google Closure Compiler or YUI compressor. They will rewrite your script and it will be difficult to read by a human. Nowadays, with tools like Firebug and Grease Monkey it's almost impossible to do what you want.
Don't use CSS or JavaScript :p Depend completely on server side checks etc.
You cannot stop anyone from messing with your javascript or your objects in the page. The way the browser is designed, your code and objects in your page are simply not protected. Everything from bookmarklets to javascript entered at a console to browser plug-ins can mess with your page and code and variables. That is the architecture of a browser.
What you can do is make things a little more difficult such that a little more work is required for some things. Here are a couple of things you could do:
Obfuscating/compressing/minimizing your code will do things like remove comments, remove whitespace, remove some linebreaks, shorten variable names, etc... That does not prevent anyone from modifying things, but does make it more work to understand and figure out.
Putting variables inside closures and not using globals. This makes it harder to directly modify variables from outside of your scripts.
Keep all important data and secrets on your server. Use ajax calls to ask the server to carry out operations using that data or secrets such that the important information is never available in the browser client.
You cannot keep anyone from modifying the DOM. There simply are no protections against that. Your code can check the DOM and refuse to operate if the DOM has been messed with in non-standard ways. But, of course, the code would then be modified to remove that check too.
If you are looking for a jquery specific solution a crude approach will involve altering the jQuery ($) function and replacing it with a custom one that delegates to the original function only if the provided selector does not match the element you want to secure.
(function(){
jQueryOrig = jQuery;
window.jQuery = window.$ = function(){
if (jQueryOrig("#secure").is(arguments[0])) {
throw new Error("Security breach");
} else return jQueryOrig.apply(this, arguments);
}
}());
Of course people using direct DOM manipulation would not be affected.
Also, if you are actually including arbitrary third party code in your production code, you should take a look at Caja ( http://code.google.com/p/google-caja/ ), which limits users to a subset of javascript capabilities. There is a good explanation regarding Caja here : http://due-diligence.typepad.com/blog/2008/04/web-20-investor.html .
This is possible but requires that the JS file to always be loaded from your server. Using observers you can lock CSS properties and using the on DOM remove/add listeners you can lock it to a parent. This will be enough to discourage most modification.
You can actually go a step further and modify core javascript functions making it nearly impossible to modify the DOM without loading the JS file locally or through a proxy. Further security can be added by doing additional domain checks to make sure the JS file is loaded from where it is supposed to be loaded from.
You can make everything in Flash. In Chrome, there's even a bug that prevents users from opening a console if the flash element has focus (not sure how exactly this works, but you can see an example at http://www.twist-cube.com or http://www.gotmilk.com). Even if users do manage to get a console open (which isn't that hard...), still about all you can do is change the shape of the element.

Obtaining a reference to the streamManager of the internal object model on twitter.com

For a Greasemonkey script running on twitter.com, I need to access the twttr.streams.TweetStream instance of the main timeline (dubbed 'Home' internally) programmatically. I'm using Firebug and Javascript Deminifier to bring their JS code into a readable form. That way, I could previously work out that I could access it via twttr.app.currentPage().streamManager.streams.current in my GM script.
This has worked perfectly over the last months. Today, Twitter seems to have changed their code, breaking my approach (not their fault, obviously ;)).
I can still get to the current page via twttr.app.currentPage(). However, it doesn't have a streamManager field anymore.
I've tried various paths to get there, but all were dead ends. Unfortunately, I don't completely understand the class system they are using yet. It seems like the streamManager property is still there -- on a mixin called mixins/streamablePage, which should be provided by the class twttr.components.pages.Home. I can't figure out how to access it, though. (Or if the class system hides it in some impenetrable way.) That mixin also provides a getStreamManager() method, but I can't access that either, e.g. via twttr.app.currentPage().getStreamManager(). Is there any trick I need to perform to get access to these mixins from the outside?
Can anyone spot an alternative method to get to this instance? Note that I need the original instance used on the timeline page. Yes, I could easily create a new instance via new twttr.streams.TweetStream(), but I'm trying to hook into the original events.
I am perfectly aware that this use case is as unsupported as it gets, that's why I'm asking you, not them. :) For the record, I'm not attempting to do anything evil, just providing additional functionality for myself.
Until they change it again, twttr.app.currentPage()._instance.getStreamManager()

A question about referencing functions in Javascript

The problem: I have a jQuery heavy page that has a built in admin interface. The admin functions only trigger when an admin variable is set. These functions require a second library to work properly and the second file is only included if the user is an admin when the page is first created. The functions will never trigger for normal users and normal users do not get the include for the second library.
Is it bad to reference a function does not exist in the files currently included even if that function can never be called? (does that make sense :)
Pseudocode:
header: (notice that admin.js is not included)
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript" src="user.js"></script>
script.js: (admin functions referenced but can't be executed)
admin = false; // Assume this
$(".something").dblclick(function(){
if(admin)
adminstuff(); // Implemented in admin.js (not included)
else
userstuff();
});
Ideas:
I suppose two separate files for users and admins could be used but I feel that would be an overly complicated solution (don't want to maintain two large files with only a few lines of difference). The only reason I include a reference to the admin function in this file is I need to attach it to page elements that get refreshed as a part of the script. When jQuery refreshes the page I need to reattach function to interactive elements.
The Question:
I want to keep things very simple and not have to include file I don't have to if they will not be used by the user. Is this a good way to do this or should I be going another route?
The code should operate without error, since the admin functions without implementation will not be called. The only thing that is really being wasted is bandwidth to transmit the admin code that is not used.
However, let me caution against security through obscurity. If the user were to view this code and see that there are admin functions that they cannot access, they might get curious and try to download the "admin.js" file and see what these functions do. If your only block to keeping admin functions from being performed is to stop including the file, then some crafty user will probably quickly find a way to call the admin functions when they should not be able to.
If you already do server side authentication/permissions checking for the admin function calls just ignore my previous paragraph :-)
Personally, I would bind (or re-bind) the event in admin.js:
$(function() {
$(".something").dblclick(function(){
adminstuff();
});
});
function adminstuff()
{
// ...
}
That way, the adminstuff() call and the function will not be visible to "normal" users.
Good question. It shouldn't cause any JavaScript problems.
Other things to consider: you are potentially exposing your admin capabilities to the world when you do this, which might be useful to hackers. That's probably not much of a concern, but it is something to be aware of.
See also:
Why can I use a function before it’s defined in Javascript?
I don't think it matters. If it makes you feel better, you can make an empty stub function.
I don't think there's a dogmatic answer to this in my opinion. What you're doing is...creative. If you're not comfortable with it, that could be a sign to consider other options. But if you're even less comfortable with those then that could be a sign this is the right thing (or maybe the least wrong thing) to do. Ultimately you could mitigate the confusion by commenting the heck out of that line. I wouldn't let yourself get religious over best practices. Just be willing to stand by your choice. You've justified it to me, anyway.
Javascript is dynamic - it shouldn't care if the functions aren't defined.
If you put your admin functions in a namespace object (probably a good practice anyway), you have a couple of options.
Check for the existence of the function in the admin object
Check for the existence of the admin object (possibly replacing your flag)
Have an operations object instead, where the admin file replaces select functions when it loads. (Even better, use prototypical inheritance to hide them.)
I think you should be wary that you are setting yourself up for massive security issues. It is pretty trivial in firebug to change a variable such as admin to "true", and seeing as admin.js is publically accessible, its not enough to simple not include it on the page, as it is also simple to add another script tag to the page with firebug. A moderately knowledgeable user could easily give themselves admin rights in this scenario. I don't think you should ever rely on a purely client side security model.

Categories