I'm coding a function that takes an object and a projection to know on which field it has to work.
I'm wondering if I should use a string like this :
const o = {
a: 'Hello There'
};
function foo(o, str) {
const a = o[str];
/* ... */
}
foo(o, 'a');
Or with a function :
function bar(o, proj) {
const a = proj(o);
/* ... */
}
bar(o, o => o.a);
I think V8 is creating classes with my javascript objects. If I use a string to access dynamically a field, will it be still able to create a class with my object and not a hashtable or something else ?
V8 developer here. The answer to "which pattern should I use?" is probably "it depends". I can think of scenarios where the one or the other would (likely) be (a bit) faster, depending on your app's behavior. So I would suggest that you either try both (in real code, not a microbenchmark!) and measure yourself, or simply pick whichever you prefer and/or makes more sense in the larger context, and not worry about it until profiling shows that this is an actual bottleneck that's worth spending time on.
If the properties are indeed known at the call site, then the fastest option is probably to load the property before the call:
function baz(o, str, a) {
/* ... */
}
baz(o, "a", o.a);
I realize that if things actually were this simple, you probably wouldn't be asking this question; if that assumption is true then this is a great example for how simplifications in microbenchmarks can easily change what the right answer is.
The answer to the classes question is that this decision has no impact on how V8 represents your objects under the hood -- that mostly depends on how you modify your objects, not on how you read from them. Also, for the record:
every object has a "hidden class"; whether or not it uses hash table representation is orthogonal to that
whether hash table mode or shape-tracking mode is better for any given object is one of the things that depend on the use case, which is precisely why both modes exist. I wouldn't worry too much about it, unless you know (from profiling) that it happens to be a problem in your case (more often than not, V8's heuristics get it right; manual intervention is rarely necessary).
Related
Intro
This topic has been the bane of many questions and answers on StackOverflow -and in many other tech-forums; however, most of them are specific to exact conditions and even worse: "over-all" security in script-injection prevention via dev-tools-console, or dev-tools-elements or even address-bar is said to be "impossible" to protect. This question is to address these issues and serve as current and historical reference as technology improves -or new/better methods are discovered to address browser security issues -specifically related to script-injection attacks.
Concerns
There are many ways to either extract -or manipulate information "on the fly"; specifically, it's very easy to intercept information gathered from input -to be transmitted to the server - regardless of SSL/TLS.
intercept example
Have a look here
Regardless of how "crude" it is, one can easily use the principle to fabricate a template to just copy+paste into an eval() in the browser console to do all kinds of nasty things such as:
console.log() intercepted information in transit via XHR
manipulate POST-data, changing user-references such as UUIDs
feed the target-server alternative GET (& post) request information to either relay (or gain) info by inspecting the JS-code, cookies and headers
This kind of attack "seems" trivial to the untrained eye, but when highly dynamic interfaces are in concern, then this quickly becomes a nightmare -waiting to be exploited.
We all know "you can't trust the front-end" and the server should be responsible for security; however - what about the privacy/security of our beloved visitors? Many people create "some quick app" in JavaScript and either do not know (or care) about the back-end security.
Securing the front-end as well as the back-end would prove formidable against an average attacker, and also lighten the server-load (in many cases).
Efforts
Both Google and Facebook have implemented some ways of mitigating these issues, and they work; so it is NOT "impossible", however, they are very specific to their respective platforms and to implement requires the use of entire frameworks plus a lot of work -only to cover the basics.
Regardless of how "ugly" some of these protection mechanisms may appear; the goal is to help (mitigate/prevent) security issues to some degree, making it difficult for an attacker. As everybody knows by now: "you cannot keep a hacker out, you can only discourage their efforts".
Tools & Requirements
The goal is to have a simple set of tools (functions):
these MUST be in plain (vanilla) javascript
together they should NOT exceed a few lines of code (at most 200)
they have to be immutable, preventing "re-capture" by an attacker
these MUST NOT clash with any (popular) JS frameworks, such as React, Angular, etc
does NOT have to be "pretty", but readable at least, "one-liners" welcome
cross-browser compatible, at least to a good percentile
Runtime Reflection / Introspection
This is a way to address some of these concerns, and I don't claim it's "the best" way (at all), it's an attempt.
If one could intercept some "exploitable" functions and methods and see if "the call" (per call) was made from the server that spawned it, or not, then this could prove useful as then we can see if the call came "from thin air" (dev-tools).
If this approach is to be taken, then first we need a function that grabs the call-stack and discard that which is not FUBU (for us by us). If the result of this function is empty, hazaa! - we did not make the call and we can proceed accordingly.
a word or two
In order to make this as short & simple as possible, the following code examples follow DRYKIS principles, which are:
don't repeat yourself, keep it simple
"less code" welcomes the adept
"too much code & comments" scare away everybody
if you can read code - go ahead and make it pretty
With that said, pardon my "short-hand", explanation will follow
first we need some constants and our stack-getter
const MAIN = window;
const VOID = (function(){}()); // paranoid
const HOST = `https://${location.host}`; // if not `https` then ... ?
const stak = function(x,a, e,s,r,h,o)
{
a=(a||''); e=(new Error('.')); s=e.stack.split('\n'); s.shift(); r=[]; h=HOSTPURL; o=['_fake_']; s.forEach((i)=>
{
if(i.indexOf(h)<0){return}; let p,c,f,l,q; q=1; p=i.trim().split(h); c=p[0].split('#').join('').split('at ').join('').trim();
c=c.split(' ')[0];if(!c){c='anon'}; o.forEach((y)=>{if(((c.indexOf(y)==0)||(c.indexOf('.'+y)>0))&&(a.indexOf(y)<0)){q=0}}); if(!q){return};
p=p[1].split(' '); f=p[0]; if(f.indexOf(':')>0){p=f.split(':'); f=p[0]}else{p=p.pop().split(':')}; if(f=='/'){return};
l=p[1]; r[r.length]=([c,f,l]).join(' ');
});
if(!isNaN(x*1)){return r[x]}; return r;
};
After cringing, bare in mind this was written "on the fly" as "proof of concept", yet tested and it works. Edit as you whish.
stak() - short explanation
the only 2 relevant arguments are the 1st 2, the rest is because .. laziness (short answer)
both arguments are optional
if the 1st arg x is a number then e.g. stack(0) returns the 1st item in the log, or undefined
if the 2nd arg a is either a string -or an array then e.g. stack(undefined, "anonymous") allows "anonymous" even though it was "omitted" in o
the rest of the code just parses the stack quickly, this should work in both webkit & gecko -based browsers (chrome & firefox)
the result is an array of strings, each string is a log-entry separated by a single space as function file line
if the domain-name is not found in a log-entry (part of filename before parsing) then it won't be in the result
by default it ignores filename / (exactly) so if you test this code, putting in a separate .js file will yield better results than in index.html (typically) -or whichever web-root mechanism is used
don't worry about _fake_ for now, it's in the jack function below
now we need some tools
bore() - get/set/rip some value of an object by string reference
const bore = function(o,k,v)
{
if(((typeof k)!='string')||(k.trim().length<1)){return}; // invalid
if(v===VOID){return (new Function("a",`return a.${k}`))(o)}; // get
if(v===null){(new Function("a",`delete a.${k}`))(o); return true}; // rip
(new Function("a","z",`a.${k}=z`))(o,v); return true; // set
};
bake() - shorthand to harden existing object properties (or define new ones)
const bake = function(o,k,v)
{
if(!o||!o.hasOwnProperty){return}; if(v==VOID){v=o[k]};
let c={enumerable:false,configurable:false,writable:false,value:v};
let r=true; try{Object.defineProperty(o,k,c);}catch(e){r=false};
return r;
};
bake & bore - rundown
These are failry self-explanatory, so, some quick examples should suffice
using bore to get a property: console.log(bore(window,"XMLHttpRequest.prototype.open"))
using bore to set a property: bore(window,"XMLHttpRequest.prototype.open",function(){return "foo"})
using bore to rip (destroy carelessly): bore(window,"XMLHttpRequest.prototype.open",null)
using bake to harden an existing property: bake(XMLHttpRequest.prototype,'open')
using bake to define a new (hard) property: bake(XMLHttpRequest.prototype,'bark',function(){return "woof!"})
intercepting functions and constructions
Now we can use all the above to our advantage as we devise a simple yet effective interceptor, by no means "perfect", but it should suffice; explanation follows:
const jack = function(k,v)
{
if(((typeof k)!='string')||!k.trim()){return}; // invalid reference
if(!!v&&((typeof v)!='function')){return}; // invalid callback func
if(!v){return this[k]}; // return existing definition, or undefined
if(k in this){this[k].list[(this[k].list.length)]=v; return}; //add
let h,n; h=k.split('.'); n=h.pop(); h=h.join('.'); // name & holder
this[k]={func:bore(MAIN,k),list:[v]}; // define new callback object
bore(MAIN,k,null); let f={[`_fake_${k}`]:function()
{
let r,j,a,z,q; j='_fake_'; r=stak(0,j); r=(r||'').split(' ')[0];
if(!r.startsWith(j)&&(r.indexOf(`.${j}`)<0)){fail(`:(`);return};
r=jack((r.split(j).pop())); a=([].slice.call(arguments));
for(let p in r.list)
{
if(!r.list.hasOwnProperty(p)||q){continue}; let i,x;
i=r.list[p].toString(); x=(new Function("y",`return {[y]:${i}}[y];`))(j);
q=x.apply(r,a); if(q==VOID){return}; if(!Array.isArray(q)){q=[q]};
z=r.func.apply(this,q);
};
return z;
}}[`_fake_${k}`];
bake(f,'name',`_fake_${k}`); bake((h?bore(MAIN,h):MAIN),n,f);
try{bore(MAIN,k).prototype=Object.create(this[k].func.prototype)}
catch(e){};
}.bind({});
jack() - explanation
it takes 2 arguments, the first as string (used to bore), the second is used as interceptor (function)
the first few comments explain a bit .. the "add" line simply adds another interceptor to the same reference
jack deposes an existing function, stows it away, then use "interceptor-functions" to replay arguments
the interceptors can either return undefined or a value, if no value is returned from any, the original function is not called
the first value returned by an interceptor is used as argument(s) to call the original and return is result to the caller/invoker
that fail(":(") is intentional; an error will be thrown if you don't have that function - only if the jack() failed.
Examples
Let's prevent eval from being used in the console -or address-bar
jack("eval",function(a){if(stak(0)){return a}; alert("having fun?")});
extensibility
If you want a DRY-er way to interface with jack, the following is tested and works well:
const hijack = function(l,f)
{
if(Array.isArray(l)){l.forEach((i)=>{jack(i,f)});return};
};
Now you can intercept in bulk, like this:
hijack(['eval','XMLHttpRequest.prototype.open'],function()
{if(stak(0)){return ([].slice.call(arguments))}; alert("gotcha!")});
A clever attacker may then use the Elements (dev-tool) to modify an attribute of some element, giving it some onclick event, then our interceptor won't catch that; however, we can use a mutation-observer and with that spy on "attribute changes". Upon attribute-change (or new-node) we can check if changes were made FUBU (or not) with our stak() check:
const watchDog=(new MutationObserver(function(l)
{
if(!stak(0)){alert("you again! :D");return};
}));
watchDog.observe(document.documentElement,{childList:true,subtree:true,attributes:true});
Conclusion
These were but a few ways of dealing with a bad problem; though I hope someone finds this useful, and please feel free to edit this answer, or post more (or alternative/better) ways of improving front-end security.
I've been searching around for a simple-lightweight hashing algorithm for JavaScript. I did find this numerically-based answer on Stack Overflow here.
Unfortunately, I am unable to use this since it's numerically based and I'll need to use this hash as a unique index elsewhere in my code. Often this function returns negative numbers and that would be a big no-no (try 'hello world!'.hashCode() from the snippet linked above to see what I mean).
I've been tempted to use the md5 hashing libraries out there for JS but they're simply to bulky for my purpose and encryption libraries (such as this) are overkill.
It's worth noting that the information within this hash isn't sensitive in anyway and it wouldn't necessarily matter if it was decrypted. The purpose of this function would be to simply generate fixed-length output data that acts as a shortened reference to the original data that I would pass in.
Any help, tips and comments are much appreciated :)
The solution proposed by Kooilnc, to use the absolute value, should do the tric for you. However, if you want to use a hashing function to generate a reference, i assume that the reference you get should be unique as to match the exact element it was generated from. If this is the case, be aware of collisions. Hashing function can create hashes that are similar even though the original messages are different and we call this a collision. If i remember correctly, SHA-1 is also available for java script and is not all that bulk. Good luck
I am unable to use this since it's numerically based and I'll need to use this hash as a unique index elsewhere in my code.
Hash functions are normally numerically based and are rarely perfect (produce unique keys). I think you need something different:
function GuidGen()
{
this.items = {};
this.size = 0;
}
GuidGen.prototype.get = function(str)
{
if (!(str in this.items))
{
this.items[str] = this.size++;
}
return this.items[str];
}
// usage:
id = new GuidGen();
id.get("hello world"); // 0
id.get("spam"); // 1
id.get("eggs"); // 2
id.get("hello world"); // 0
I'm trying to sort an array of objects based on the objects' name property. Some of the names start with 'Æ', and I'd like for them to be sorted as though they were 'Ae'. My current solution is the following:
myArray.sort(function(a, b) {
var aName = a.name.replace(/Æ/gi, 'Ae'),
bName = b.name.replace(/Æ/gi, 'Ae');
return aName.localeCompare(bName);
});
I feel like there should be a better way of handling this without having to manually replace each and every special character. Is this possible?
I'm doing this in Node.js if it makes any difference.
There is no simpler way. Unfortunately, even the way described in the question is too simple, at least if portability is of any concern.
The localeCompare method is by definition implementation-dependent, and it usually depends on the UI language of the underlying operating system, though it may also differ between browsers (or other JavaScript implementations) in the same computer. It can be hard to find any documentation on it, so even if you aim at writing non-portable code, you might need to do a lot of testing to see which collation order is applied. Cf. to Sorting strings is much harder than you thought!
So to have a controlled and portable comparison, you need to code it yourself, unless you are lucky enough to find someone else’s code that happens to suit your needs. On the positive side, the case conversion methods are one of the few parts of JavaScript that are localization-ready: they apply Unicode case mapping rules, so e.g. 'æ'.toUpperCase() yields Æ in any implementation.
In general, sorting strings requires a complicated function that applies specific sorting rules as defined for a language or by some other rules, such as the Pan-European sorting rules (intended for multilingual content). But if we can limit ourselves to sorting rules that deal with just a handful of letters in addition to Ascii, we can use code like the following simplified sorting for German (extract from by book Going Global with JavaScript and Globalize.js):
String.prototype.removeUmlauts = function () {
return this.replace(/Ä/g,'A').replace(/Ö/g,'O').replace(/Ü/g,'U');
};
function alphabetic(str1, str2) {
var a = str1.toUpperCase().removeUmlauts();
var b = str2.toUpperCase().removeUmlauts();
return a < b ? -1 : a > b ? 1 : 0;
}
You could adds other mappings, like replace(/Æ/gi, 'Ae'), to this, after analyzing the characters that may appear and deciding how to deal with them. Removing diacritic marks (e.g. mapping É to E) is simplistic but often good enough, and surely better than leaving it to implementations to decide whether É is somewhere after Z. And at least you would get consistent results across implementations, and you would see what things go wrong and need fixing, instead of waiting for other users complain that your code sorts all wrong (in their environment).
I've been doing a lot of templating in JS lately, so I've invariably run across the "evil" with statement.
It makes templates much easier to work with as you don't have to preface your variables with an object.
Hearing that with statements are bad and also that they may cause poor performance, I set out for another solution:
My Solution: Function with a bunch of parameters
Here's my code:
var locals = {
name : "Matt",
email : "wahoo#wahoo.com",
phone : "(555) 555-5555"
};
var keys = [];
var values = [];
for (key in locals) {
local = locals[key];
keys.push(key)
values.push(local);
}
keys = keys.join(',');
var fn = new Function(keys, "**TEMPLATE STUFF**"); // function(name, email, phone) {...}
fn.apply(this, values); // fn("Matt","wahoo#wahoo.com","(555) 555-5555")
Note: these accomplish the exact same thing. Both are abstracted away from anyone so an obnoxiously long parameter list is no biggie.
I'm wondering which one is better: using a with statement or a function with the potential for a crazy number of parameters.
Unless someone has a better solution...?
Thanks!
Matt Mueller
I find your solution very bloated. It is totally non-trivial, while with is so simple (one line of code which in and of itself has very little cost vs. your object traversal and array instantiations).
Moreover, your solution requires a template object ready when making the templating function (to define its parameters), which may prove down the road less flexible in my opinion.
Check out MDC. A well designed template would presumably have little logic and heavy variable references (and if it isn't that way, then it should be!), which makes with the perfect candidate in such a situation, because there should be very few other lookups in the scope of the with.
Any extra performance that may be gained seems like it would be micro-optimisation, although rather than theorise, just perform some benchmarks. http://jsperf.com/with-vs-fn does all the setup code before the benchmark for your version, but performs the with stuff during the function execution, so it's not really fair, although even on the slowest iterations you get an idea of how fast it is; >400,000 ops/sec is the slowest. I doub't you need to render more than 400,000 templates a second...
Have you tried a JS templating engine? They are usually very fast, and save you some rendering code.
I'm the author of pure.js which is a bit original, but there are plenty of others available and for any taste.
The problems with with are not performance, they are ambiguity and unpredictable behaviour.
See, for example, Hidden Features of JavaScript?
Here's an implementation details question for JavaScript gurus.
I have a UI with a number of fields in which the values of the fields depend in a complicated fashion on the values of seven bits of inputs. Exactly what should be displayed for any one of the possible 128 values that is changing regularly as users see more of the application?
Right now, I've for this being implemented as a decision tree through an if-then-else comb, but it's brittle under the requirements changes and sort of hard to get right.
One implementation approach I've thought about is to make an array of values from 0x0 to 0x7F and then store a closure at each location --
var tbl; // initialize it with the values
...
tbl[0x42] = function (){ doAThing(); doAnotherThing(); }
and then invoke them with
tbl[bitsIn]();
This, at least makes the decision logic into a bunch of assignments.
Question: is there a better way?
(Update: holy crap, how'd that line about 'ajax iphone tags' get in there? No wonder it was a little puzzling.)
Update
So what happened? Basically I took a fourth option, although similar to the one I've checked. The logic was sufficiently complex that I finally built a Python program to generate a truth table in the server (generating Groovy code, in fact, the host is a Grails application) and move the decision logic into the server completely. Now the JavaScript side simply interprets a JSON object that contains the values for the various fields.
Eventually, this will probably go through one more iteration, and become data in a database table, indexed by the vector of bits.
The table driven part certainly came out to be the way to go; there have already been a half dozen new changes in the specific requirements for display.
I see two options...
Common to both solutions are the following named functions:
function aThing() {}
function anotherThing() {}
function aThirdThing() {}
The switch way
function exec(bits) {
switch(bits) {
case 0x00: aThing(); anotherThing(); break;
case 0x01: aThing(); anotherThing(); aThirdThing(); break;
case 0x02: aThing(); aThirdThing(); break;
case 0x03: anotherThing(); aThirdThing(); break;
...
case 0x42: aThirdThing(); break;
...
case 0x7f: ... break;
default: throw 'There is only 128 options :P';
}
}
The map way
function exec(bits) {
var actions = map[bits];
for(var i=0, action; action=actions[i]; i++)
action();
}
var map = {
0x00: [aThing, anotherThing],
0x01: [aThing, anotherThing, aThirdThing],
0x02: [aThing, aThirdThing],
0x03: [anotherThing, aThirdThing],
...
0x42: [aThirdThing],
...
};
in both cases you'd call
exec(0x42);
Since the situation (as you have described) is so irregular, there doesn't seem to be a better way. Although, I can suggest an improvement to your jump table. You mentioned that you have errors and duplicates. So instead of explicitly assigning them to a closure, you can assign them to named functions so that you don't have to duplicate the explicit closure.
var doAThingAndAnother = function (){ doAThing(); doAnotherThing(); }
var tbl; // initialize it with the values
...
tbl[0x42] = doAThingAndAnother;
tbl[0x43] = doAThingAndAnother;
Not that much of an improvement, but it's the only thing I could think of! You seem to have covered most of the other issues. Since it looks like the requirements change so much, I think you might have to forgo elegance and have a design that is not as elegant, but is still easy to change.
Have you considered generating your decision tree on the server rather than writing it by hand? Use whatever representation is clean, easy to work with, and modify and then compile that to ugly yet efficient javascript for the client side.
A decision tree is fairly easy to represent as data and it is easy to understand and work with as a traditional tree data structure. You can store said tree in whatever form makes sense for you. Validating and modifying it as data should also be straight forward.
Then, when you need to use the decision tree, just compile/serialize it to JavaScript as a big if-the-else, switch, or hash mess. This should also be fairly straight forward and probably a lot easier than trying to maintain a switch with a couple hundred elements.
I've got a rough example of a JavaScript decision tree tool if you want to take a look:
http://jsfiddle.net/danw/h8CFe/