Using Facebook's invariant vs if throw - javascript

I've been looking at various Node.js projects' source, and I've noticed that some people use invariant. From what I understood, invariant is a tool that lets you put assertions in your code, and raise errors as needed.
Question:
When would you favor using invariant vs throwing errors the traditional way?
// Using invariant
function doSomething(a, b) {
invariant(a > b, 'A should be greater than B');
}
// If throw
function doSomething(a, b) {
if(a <= b) {
throw new Error('A should be greater than B');
}
}

There are a few reasons:
It's easier to read when you want to stack them. If you have, say, 3 preconditions to validate, you always see invariant(x ..., and it's easy to see what's being checked:
function f(xs, x) {
// all the invariants are lined up, one after another
invariant(xs.type == x.type, "adding an element with the same type");
invariant(xs.length != LIST_MAX_SIZE, "the list isn't full");
invariant(fitting(x), "x is fitting right in the list");
}
Compare with the usual throw approach:
function f(xs, x) {
if (xs.type != x.type)
throw new Error("adding an element with the same type");
if (xs.length == LIST_MAX_SIZE)
throw new Error("the list isn't full");
if (!fitting(x))
throw new Error("x is fitting right in the list");
}
It makes it easy to eliminate it in release build.
It's often that you want preconditions checked in dev/test, but don't want them in release because of how slow they'd be.
If you have such an invariant function, you can use a tool like babel (or some other) to remove these calls from production builds
(this is somewhat like how D does it).

zertosh/invariant allows to add code guards
As said in the readme it is A way to provide descriptive errors in development but generic errors in production.
however it is a replication of some internal facebook's systems and imo is pretty bad documented and not maintained. Scary thing is the 4.4M uses :thinking:
nothing will be striped out of the box
if you don't have a build tool that somehow remove your message in production you will still have the original error
the usage in node is for ssr/react native, or useless outside of the "we have less lines" thing
it uses error.framesToPop which also is a facebook thing
see: https://github.com/zertosh/invariant/issues?q=is%3Aissue
Note:
A better aproach will be to wait for the es proposal throw inline and actually do
cond || throw x
cond ?? throw x
that way the error will not be evaluated anyway and stripped if cond includes a falsy var env in the browser

Usefulness in TypeScript projects
...Adding on to previous answers of making it easier to read, less lines of code, stripping from dev builds:
If you're using typescript, you can use it help narrow down types + get dev time feedback.
Imagine the scenario below:
We're reading from our filesystem in node/js, the type system has no idea what's in there, so we need a runtime check, for that we'll want an invariant method to make runtime checks like this easy.
Note:
there is a modern & popular version Facebook's invariant package called tiny-invariant which I recommend called tiny-variant: https://github.com/alexreardon/tiny-invariant

Related

Detect old Internet explorer Javascript functions ( < ES6)

There is a web online, library or something to detect old IE functions that are not compatible with Chrome/Firefox or just ES6?
Like: document.all, event.returnValue, etc
JsHint/Jslint are not detecting them as deprecated or incompatibles
It's not quite fair to say JSLint won't tell you about deprecated properties. Let me explain.
Recall first that JavaScript is a dynamic language. You can assign any property to [almost] any object. You could assign all to window in a browser context if you wanted just by saying window.all = "Muahahaha!!! I'm evil!!!". You could add .all to a string with...
var spam = "a string";
spam.all = "I'm still evil!!!"
Or, worse, some piece of code could have changed the prototype for String (or any other object type) somewhere outside of your file. Try this in a browser console:
String.prototype.all = String.prototype.all || "This is beyond evil.";
// 'This is beyond evil.'
var spam = "spam"
// undefined
spam.all
// 'This is beyond evil.'
So JSLint doesn't, by default, check for properties on objects by names. Especially for objects that could live outside of your file's context (because JSLint lints file-by-file), it simply can't know what's happened to an object's properties and identify what's valid and what isn't.
(That's what TypeScript is for, btw.)
Unless you tell JSLint how!! -- the JSLint property directive ftw
Or you can use the JSLint property directive, which does exactly what you want, if you're willing to do some work.
If you put the property directive at the top of your file, JSLint will show errors for any properties that are used by objects on the page that aren't in that list.
For instance, try this on the official JSLint.com page:
/*property
log
*/
/*jslint browser, devel */
function mySpam() {
var spam = document.all;
console.log(spam);
}
See how I'm using document.all but all isn't in the property directive? It's going to error for me.
1. Unregistered property name 'all'.
var spam = document.all;
You might be saying, "But it will take me FOREVER to get all the good properties from my 3000 line file I'm linting into that directive!!"
Not so! Here's a tip: Paste your file, even unlinted, into JSLint.com. It will create a property directive for you in its report.
Here's one I made from AngularJS' [sic] route.js in just a few seconds:
/*property
$$minErr, $evalAsync, $get, angularVersion, caseInsensitiveMatch, create,
defaultPrevented, eagerInstantiationEnabled, extend, info, isArray,
isDefined, isObject, isUndefined, length, module, noop, originalPath,
otherwise, preventDefault, provider, redirectTo, reload, reloadOnSearch,
reloadOnUrl, routes, run, substr, when
*/
Alphabetical, even.
Now just remove the ones you don't want and presto! You'll catch everything you need.
Is this a little tedious, and will it take a little massaging/training on files that use document properly? Yes, but, again, in a dynamic language, this is close to the best you can hope for with file-by-file linters.
NOTE: If this doesn't solve your issue, however imperfectly, that's when we need to see more of your files and hear more precisely what problem you're trying to solve in practice.

Limiting values to a variable in Node.js

I'm not sure if this question makes sense but when I'm using an IDE and for example I type:
x = 5
s = typeof(x)
if (s === ) //Cursor selection after === (before i finished the statement)
the IDE's autocomplete feature gives me a list of the possible values. And if I type value that doesn't exist in that list it's highlighted, and when I execute the program (in other examples, not this one), it throws an error.
I want to achieve a similar functionality with my own variables so that I can only assign specific values to it.
I'd recommend using TypeScript. See this question.
For example, your code will throw a TypeScript error if you try to compare the result of typeof against anything that isn't a proper JavaScript type:
x = 5
s = typeof(x)
if (s === 'foobar') {
}
results in
In a reasonable IDE with TypeScript (such as VSCode), any line of code that doesn't make sense from a type perspective will be highlighted with the error.
If you want to permit only particular values for some variable, you can use | to alternate, eg:
let someString: 'someString' | 'someOtherString' = 'someString';
will mean that only those two strings can occur when doing
someString =
later.
TypeScript makes writing large applications so much easier. It does take some time to get used to, but it's well worth it IMO. It turns many hard-to-debug runtime errors into (usually) trivially-fixable compile-time errors.

How to prevent script injection attacks

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.

Simple way to check/validate javascript syntax

I have some big set of different javascript-snippets (several thousands), and some of them have some stupid errors in syntax (like unmatching braces/quotes, HTML inside javascript, typos in variable names).
I need a simple way to check JS syntax. I've tried JSLint but it send too many warnings about style, way of variable definitions, etc. (even if i turn off all flags). I don't need to find out style problems, or improve javascript quality, i just need to find obvious syntax errors. Of course i can simply check it in browser/browser console, but i need to do it automatically as the number of that snippets is big.
Add:
JSLint/JSHint reports a lot of problems in the lines that are not 'beauty' but working (i.e. have some potential problems), and can't see the real problems, where the normal compiler will simply report syntax error and stop execution. For example, try to JSLint that code, which has syntax errors on line 4 (unmatched quotes), line 6 (comma required), and line 9 (unexpected <script>).
document.write('something');
a = 0;
if (window.location == 'http://google.com') a = 1;
document.write("aaa='andh"+a+"eded"');
a = {
something: ['a']
something2: ['a']
};
<script>
a = 1;
You could try JSHint, which is less verbose.
Just in case anyone is still looking you could try Esprima,
It only checks syntax, nothing else.
I've found that SpiderMonkey has ability to compile script without executing it, and if compilation failed - it prints error.
So i just created small wrapper for SpiderMonkey
sub checkjs {
my $js = shift;
my ( $js_fh, $js_tmpfile ) = File::Temp::tempfile( 'XXXXXXXXXXXX', EXLOCK => 0, UNLINK => 1, TMPDIR => 1 );
$| = 1;
print $js_fh $js;
close $js_fh;
return qx(js -C -f $js_tmpfile 2>&1);
}
And javascriptlint.com also deals very good in my case. (Thanks to #rajeshkakawat).
Lots of options if you have an exhaustive list of the JSLint errors you do want to capture.
JSLint's code is actually quite good and fairly easy to understand (I'm assuming you already know JavaScript fairly well from your question). You could hack it to only check what you want and to continue no matter how many errors it finds.
You could also write something quickly in Node.js to use JSLint as-is to check every file/snippet quickly and output only those errors you care about.
Just use node --check filename
Semantic Designs' (my company) JavaScript formatter read JS files and formats them. You don't want the formatting part.
To read the files it will format, it uses a full JavaScript parser, which does a complete syntax check (even inside regular expressions). If you run it and simply ignore the formatted result, you get a syntax checker.
You can give it big list of files and it will format all of them. You could use this to batch-check your large set. (If there are any syntax errors, it returns a nonzero error status to a shell).

Get argument expression before evaluation

I'm trying to create an assert method in Javascript. I've been struggling with arguments.callee.caller and friends for a while, but I can't find a way to reliably get the full text of the calling function and find which match in that text called the current function.
I want to be able to use my function like this:
var four = 5;
function calculate4() { return 6; }
assert(4 == 2 + 3);
assert(4 == four);
assert(4 == calculate4());
assert(4 != 3 && 2 < 1)
and get output like this:
Assertion 4 == 2 + 3 failed.
Assertion 4 == four failed.
Assertion 4 == calculate4() failed.
Assertion 4 != 3 && 2
Right now, I can't get much beyond Assertion false failed. which isn't very useful...
I'd like to avoid passing in extra parameters (such as this) because I want to keep the assert code as clean as possible and because it will be typed many, many times. I don't really mind making it a string, but I'm concerned about issues of scoping when trying to eval() that string. If I have no other options, or if my concerns are ill-founded, please say so.
I'm running this in an .hta application on Windows, so it's really jscript and I have full access to the filesystem, ActiveX etc. so system specific solutions are fine (as long as they don't require Firebug etc.). However, I'd prefer a general solution.
There's no reliable way you can do this passing only a single argument. Even with eval, the variables used would be out of scope. Parsing arguments.caller would work if arguments.caller made only one call to assert, by searching for it and parsing the argument expression. Unfortunately, none of the proprietary tools available to you will help.
I ended up using the following function, which allows me to optionally duplicate the text of the assertion as a second argument. It seemed simplest.
function assert(expression, message)
{
if (!expression) {
if (message + "" != "undefined" && message + "" != "") {
document.write("<h2>Assertion <pre>" +
message +
"</pre> failed.</h2><br>");
} else {
document.write("<h2>Assertion failed.</h2><br>");
}
}
}
Maybe that helps someone. There are probably better methods available, but this worked for me.
Note that I've only been programming in Javascript for three days, so there's probably a number of improvements that could be made.
It is actually possible, at least in browsers and Node.js. I don't know about .hta applications.
Modern browsers, Node.js and hopefully your environment put a stack property on error objects, containing a stack trace. You can construct a new error, and then parse out the file path to the file containing the assert() call, as well as the line number and column number (if available) of the call. Then read the source file, and cut out the assert expression at the given position.
Construct an error
Parse error.stack, to get filepath, lineNumber and columnNumber
Read the file at filepath
Cut out the bits you want near lineNumber and columnNumber in file
I've written such an assert function, called yaba, that might get you going.

Categories

Resources