Skip to content

Instantly share code, notes, and snippets.

@esayler
Last active November 21, 2018 16:09
Show Gist options
  • Save esayler/28dd8c587d66d32da9db1aeb3bd592aa to your computer and use it in GitHub Desktop.
Save esayler/28dd8c587d66d32da9db1aeb3bd592aa to your computer and use it in GitHub Desktop.
Notes on FE Masters course 'The Good Parts of JavaScript and the Web'

The Good Parts of JavaScript and the Web

Table of Contents


JavaScript Style

always use curly braces on right

// bad
block
{
 ...
}

// good
block {
   ...
}

why?

// bad (SILENT ERROR)
return      // <-- auto semicolon insertion will insert a semicolon here
{
  ok: false // useless expression statement (allowed), another semicolon auto-inserted here
};

// compiler thinks above is:
return;     // returns `undefined`
{
  ok: false;
}


// good
return {
  ok: true
};

Always use break; in switch statement cases

  • fall-through behavior is hard to change/debug

Use a space after a comma, not before

  • matches literary style that we are used to
// bad
var i = 0 ,j = 1;

// good
var i = 0, j = 1;

Use spaces to disambiguate parens

  • no space between a function name and (
  • one space between all other names and (
// bad
foo (bar);
return(a+b);
if(a=== 0) {}
function foo (b) {}
function(x) {..}

// good
foo(bar);
return (a + b);     // return is not a function!
if (a === 0) {};
function foo(b) {} // named function, no space
function (x)        // anon function, put a space

Wrap Immediately Invoked Function Expressions (IIFE) in parens

Note: webpack/babel/ES6 seem to only like 'dog balls' unless you probably include babel-preset-latest

// bad:
(function () {
   ...
})() // dog balls

// good
(function () {
  ...
}());

Never rely on auto-semicolon insertion

// bad
x = y           // will not insert semicolon
(function () {  // will call y as a function, passing another function as its argument
  ...
 }());

// good
x = y;
(function () {
  ...
 }());

Don’t use the with statement

why?

// bad
with (0) {
  foo = koda;
}

// any of these statements could work depending on `o`, and `o` isn't known at compile time
o.foo = koda;
o.foo - o.koda;
foo = koda;
foo = o.koda;

Always use ===, never ==

Why? Because of JavaScript's crazy-bad type coercion.

0 == ''          // true
0 == '0'         // true
'' == '0'        // false
false == 'false' // false
false == '0'     // true
"\t\r\n " == 0   // true

Don't use multi-line string literals

Why? Because you'll get a syntax error if you leave a space after the \, and many editors won't easily catch this

// ok
var long_line_1 = "This is a \
long line";

//syntax error (space after `\`)
var long_line_1 = "This is a \ 
long line";

Never use assignment inside conditionals

// bad
if (a = b) {...}

// actually does this:
a = b;
if (a) {...}

// doesn't do this:
if (a === b) {...}

JavaScript Scope

Declare variables at top of function, declare functions before you call them

Why? variable hoisting:

var statement get split into two parts:

  1. declaration gets hoisted to the top of the function, initialized with undefined
  2. initialization turns into ordinary assignment
function foo() {
     ...
  var hoistedVar = 0, hoistedVarTwo;
}

// expands to:
function foo() {
  var hoistedVar = undefined,    // variable declarations are hoisted to the top and set to `undefined`
      hoistedVarTwo = undefined;
     ...
  hoistedVar = 0;                // variable is assigned at the original point of declaration

}

Never use var inside for loops

Why? var has entire function scope, not block scope

// bad
for (var i = 0 ...) {...} // variable `i` is not scoped to block, but entire function

// better
var i;
for (i = 0 ...) {...} // variable `i` is not scoped to block, but entire function

// best
for (let i = 0 ...) {...} // let respects block scope

Avoid global variables as much as possible, name them in UPPER_CASE

  • global variables evil, avoid them (why? globals cause coupling, accidental collisions, and security hazards)
  • browsers require global variables, but use as few globals as possible
  • name globals in upper case: UPPER_CASE

Avoid new, but use InitialCaps with and only with constructor function names

  • try to avoid new prefix
  • Why? Forgetting new in front a constructor function causes a constructor to clobber global variables without warning (fixed ES5/strict mode/ES6)

Don't do multiple assignment

// bad
var a = b = 0;

// doesn't do this:
var a = 0, b = 0; // do this from the start

// instead, does this:
b = 0; // makes b a global variable
var a = b;

Always use curly braces around if statement blocks

why? easier to add statements later, prevents confusion

// bad
if (a) b(); c();

// doesn't do this:
if (a) {
  b();
  c();
}

// instead, does this:
if (a) {
  b();
}

c();      // always calls c

avoid ++ operator

why?

  • ++ causes security errors, inclines one to write hard-to-understand one-liners
  • avoid pre-increment (++i) vs. post-increment confusion (i++)
// bad
i++;

// good
i += 1;

Performance

Favor clean code over premature optimization

premature optimization is the root of all evil -Donald Knuth

  • don't try to optimize code until you measure its performance
  • optimize later, then re-measure performance and if no improvement, scrap the changes
  • most "code fiddling" has a negligible impact on performance
  • algorithm replacement is vastly more effective than "code fiddling"

JavaScript Syntax

JavaScript Objects

  • an object is a dynamic collection of properties
  • every property has a key String that is unique to that object
  • keys must be strings (automatic type coercion)

Get, set, and delete

get
object.name
object[expression]
set
object.name = value;
object[expression]= value;
delete
delete object.name
delete object[expression]

Classes v Prototypes

Working with Prototypes

  • make an object that you like
  • create new instances that inherit from that object
  • customize the new objects
  • classification and taxonomy are not necessary (yay)
    • good: you don't worry about structure as much as class-based languages early on in a project when things are the most uncertain
  • JavaScript implements a Delegation model (aka Differential Inheritance)
    • if an object is asked to do something it can't do, it will delegate to another object (up the prototype chain)

Object.create(prototype)

  • object literals inherit from Object.prototype
  • objects created from a prototype using Object.create(prototype) inherit from defined prototype
  • storing operations always go into bottom most object, reading operations can go all the up the chain to Object.prototype
  • can add material to child object that has no relation to parent
  • typically add methods to a parent object, instances will inherit those methods

Use Object.create null if you want a container of stuff (a hash)

  • avoids inheriting stuff from Object.prototype

Numbers

NaN (Not a Number)

  • result of undefined or erroneous operations
  • NaN is toxic: any arithmetic operation with NaN as input will have NaN as a result
  • NaN is not equal to anything, including NaN
NaN === NaN // false
NaN !== NaN // true
isNaN(NaN)  // true

Strings

  • No separate character type, characters are strings with length of 1
  • Strings are immutable, can make new strings by concatenating multiple strings together
  • Similar strings are equal (===)
  • String literals can use single or double quotes
    • suggested use:
      • use double quotes (") for external strings
      • use single quotes (') for internal strings and characters

Number to String conversion: Use global String function

  • for Number to String conversion, you may:
    • use the global String function (preferred)
    • use Number's toString method
str = num.toString(); // ok
str = String(num); // better, works with things without defined `toString` function

String to Number conversion: use the + prefix operator

  • for string to number conversion, you can:
  • use the Number function
  • use the + prefix operator (preferred)
  • use the parseInt(str, [radix]) function (avoid)

why? Avoid the confusing parseInt, if you use it, always specify the optional radix argument:

  • ⚠️ parseInt stops at the first non-digit character
    • parseInt(12em) === 12
<!--- `parseInt("08") === 0`-->
<!--- `parseInt("08", 10) === 8`-->

Arrays

  • Array inherits from Object
  • JavaScript arrays are really Objects in which indexes are converted to strings and used as names from retrieving values
  • efficient for small arrays, not efficient for large arrays
  • advantage: no need to provide a length or type when creating an array (you can do let a = [])
  • every value is "in bounds"

Array.prototype.length

  • arrays, unlike objects, have a special length property
  • length always returns 1 larger than the highest integer subscript
    • ⚠️ length is not necessarily the same as the number of elements in the array

Array Literals

  • uses []
  • can contain any number of expressions separated by commas
    • let list = ['one', 'two', 'three']
  • can append items using the array's length(:exclamation:)
    • list[list.length] = 'four'
  • don't use dot notation with arrays

Array.prototype.sort()

⚠️ sorts by default lexicographically (according to string Unicode code points)

let n = [4, 8, 15, 16, 23, 42];
n.sort();

// n is now [15, 16, 23, 4, 42, 8] // (!) compares strings

to sort by value use arr.sort(compareFunction)

  • compare function needs to return a value less than zero, 0, or greater than zero
n.sort( (a, b) => a - b ); // will compare numbers instead of strings, sort ascending

use splice() method (not delete keyword) to remove elements from an array

// bad
let arr = ['a', 'b', 'c', 'd'];
delete arr[1];

// arr is ['a', undefined, 'c', 'd'];

// good

let arr = ['a', 'b', 'c', 'd'];
arr.splice(1, 1);

// arr is ['a', 'c', 'd']

Arrays v Objects

  1. use objects when names are arbitrary strings
  2. use arrays when names are sequential integers

don't get confused by the term Associative Array

  • in JavaScript, Object is an Associative Array

only use undefined, not null

  • All values are objects (except null and undefined)
  • null and undefined are used to indicate an absence of an object
  • undefined is the default value for declared variables and unused parameters
  • undefined is the value of missing members in objects and arrays

typeof prefix operator

Returns a string identifying the type of a value

⚠️ typeof returns 'object' for arrays and null

use Array.isArray or Object.prototype.toString.call to differentiate regular objects from arrays -MDN

typeof objectName    // 'object'
typeof functionName  // 'function'
typeof arrayName     // 'object'    (!)
typeof numberName    // 'number'
typeof stringName    // 'string'
typeof booleanName   // 'boolean'
typeof null          // 'object'     !)
typeof undefined     // 'undefined'

Falsy Values

⚠️ the strings "0" and "false" are truthy

// "falsy" values

false     // is falsy
null      // is falsy
undefined // is falsy
""        // is falsy
0         // is falsy
NaN       // is falsy

// everything else is "truthy" (including all objects and all arrays)

"0"     // is truthy (!)
"false" // is truthy (!)

Objects are passed by Reference

  • objects in JavaScript can be passed as arguments to functions and be returned by functions

    • objects are passed by reference
    • objects are not passed by value
  • the === operator compares object references, not values

    • true only if both operands are the same object

Identifiers

  • starts with letter, _, or $
  • followed by zero or more letters, digits, _ or $
  • convention, start all variables, parameters, members, function names with lower case
  • except for constructor functions which start with upper case
  • initial _ should be reserved for implementations
  • $ should be reserved for machines

Comments

  • use // line format
  • RegEx can interfere with using /* ... */

plus (+) operator

  • does both addition and concatenation:exclamation:

  • ⚠️ if both operands are numbers, add them

    • otherwise, convert both to strings and concatenate them:exclamation:
      • '$' + 3 + 4 = '$34'
  • use + unary operator (with parens) to convert strings to numbers ✅

+"42"              // 42
Number("42")       // 42
parseInt("42", 10) // 42
+("3") + (+"4")    // 7

/

division of two integers can produce a non-integer result

10 / 3             // 3.3333333333333335

% is the remainder operator, not the modulo operator

-1 % 8             // -1 (not 7)

"equal" (==) and "not equal" (!=) operators do type coercion

  • always better to use === and !== which don't do type coercion
// evils of type coercion
0 == ''            // true
0 == '0'           // true
'' == '0'          // false

false == 'false'   // false
false == '0'       // true

false == undefined // false
false == null      // false
null == undefined  // true

'\t\r\n ' == 0     // true
1 == [1]           // true
true == [1]        // true
true == [true]     // false

Boolean

&& (logical and)

'first' && 'second'

if: 'first' operand is 'truthy',
  then: result is 'second' operand
  else: result is 'first' operand

|| (logical or)

'first' || 'second'

if: 'first' operand is 'truthy',
  then: result is 'first' operand
  else: result is 'second' operand

! prefix operator (logical not)

 !operand

 if the operand is truthy,
   then: `false`
   else: `true`
  • !! turns a 'boolish' value into a booleans value

Statements

//expression
if
switch
while
do
for
break
continue
return
try
throw

labeled break statement

  • statements can have labels
  • break statements can refer to those labels
  • can use labels to break out of inner statements inside nested statements
loop: for (;;) {
   ...
     if (...) {
        break loop;
     }
   ...
}

use forEach or map instead of for statement

for statement used to iterate through the elements of an array

for (i = 0; i < array.length; i += 1) {
      // within loop,
      // i is the index of current element
      // array[i] is the current element's value
}

Use Object.keys instead of a for...in statement

Object.keys will return an array of strings of just enumerable own properties of an object

  • for...in will iterate through all the names of properties of an object
  • ⚠️ for...in will include names of inherited properties
for (name in object) {
  if (object.hasOwnProperty(name)) {
      
      // within the loop,
      // name is the key of current property
      // object[name] is the current value

    }
}

switch statement

  • multi-way branch
  • switch value can be a string or a number
  • case values can be expressions
  • danger: cases fall through to next case unless you use a disruptive statement like break or return

Exception Handling

throw statement

  • can throw "anything"
throw new Error(reason);

throw {
  name: exceptionName,
  message: reason
};

try statement

  • simple, only one catch block catches everything (no exception types in JavaScript)
  • good, since this discourages complicated control paths when using different exceptions
try {
  plan_a();
} catch (ignore) {
  plan_b();
}

JavaScript Functions

JS functions can do the work of:

  • method
  • class
  • constructor
  • module

function expression

  • function expression or literal returns a new function object which can be invoked

  • optional name

  • parameters

    • wrapped in parens
    • zero or more names
    • separated by commas
  • body

    • wrapped in curly braces
    • zero or more statements
  • produces an instance of a function object

  • every time a function expression is evaluated it creates a new instance function object

  • functions objects are first class objects

    • may be passed as an argument to a function
    • may be returned from a function
    • may be assigned to a variable
    • may be stored in an object or array
  • function objects inherit from Function.prototype

function scope

  • use the var statement to declare/initialize variables within function scope
  • variables declared anywhere within a function with var are visible everywhere within the function
  • remember: var gets split into two parts
    • declaration gets hoisted to the top of the function
    • initialization part turns into an ordinary assignment

function statement (function declaration)

  • starts with function

  • mandatory name

  • params/body same as function expression

  • is shorthand for a var statement

function foo() {}

// expands to:

var foo = function foo() {};

// which further expands to:

var foo = undefined;        // hoisted to function top
foo = function foo() {};    // also hoisted to top of function (should prevent you from declaring a function inside an if statement)

function expression v function statement

how to tell them apart?

  • if the first token in a statement is function then it's a function statement (declaration)
  • otherwise, its a function expression

Scope

  • with var, {blocks} don't have scope, only functions have scope
// don't declare var indexes with same name inside nested loops

// bad

function asssure_positve(matrix, n) {
  for (var i = 0; i < n; i += 1) {
    var row = matrix[i];
    for (var i = 0; i < row.length; i += 1) {
      if (row[i] < 0) {
        throw new Error('Negative');
      }
    }
  }
}
  • declare all variables at the top of the function
  • declare functions before you call them
  • you don't have to do this two things above, but they are problematic

return statement

return expression;

// or

return; // returns `undefined`, expect for constructors which return `this` by default

don't make function objects in a loop

  • is wasteful, new function objects created on iteration
  • can be confusing because the new function closes over the loops variables, not over their current values
// bad.

for (var i ...) {
  div_id = divs[i].id;
  divs[i].onclick = function () {
    alert(div_id);
  };
}

// above,  all divs will display the same id, the last one in the loop
// inner function captures the current value of div_id,
// not the value at the time the function was created.   (!)

// good

divs.forEach(function (div) {
    div.onclick = function () {
      alert(div.id);
    };
});

Function Invocation

Four ways to call a function:

// 1. Function form
functionObject(arguments)

// 2. Method form
thisObject.methodName(arguments)
thisObject["methodName"] (arguments)

// 3. Constructor form
new FunctionObject(arguments)

// 4. Apply form
functionObject.apply(thisObject, [arguments])
functionObject.call(thisObject, argument...)
  • the ( ) suffix contains zero or more comma-separated arguments
  • the arguments will be bound to parameters
  • If a function is called with too many arguments, the extra arguments are ignored
  • if a function is called with too few arguments, the missing values will be undefined
  • no implicit type checking on the arguments

Function pseudo parameters (arguments and this)

neither is recommended

arguments

  • contains all the arguments from the invocation in an array-like objecti (doesn't inherit all array prototype methods)
  • arguments.length is the number of arguments passed
  • weird interaction with parameters (changing arguments[0] changes the first parameter, etc)
function sum() {
  var i, n = arguments.length, total = 0;
  for (i = 0; i < n; i += 1) {
    total += arguments[i];
  }
  return total;
}

var ten = sum (1, 2, 3, 4); // ten is now 10

this

  • this contains a reference to the object of invocation
  • this allows a method to know what object it is concerned with
  • this allows a single function object to service many objects
  • this is key to prototypal inheritance
  • this is bound at invocation time

this in Method form

allows methods to have a reference to the object of interest

thisObject.methodName(arguments)     // `this` is set to `thisObject`
thisObject["methodName"] (arguments) // `this` is set to `thisObject`

this in Function form

functionObject(arguments)  // `this` is set to the global object (prevented in
                           // ES5/Strict mode, `this` is bound to undefined instead)
                           // inner function will not get access to the outer `this`

                           // workaround to use outside inner function to get
var that = this;           // `this` in scope of inner functions.
var self = this;           // use `that` or `self` inside the inner function.

this in Constructor form

new FunctionValue(arguments)  // a new object is created and assigned to `this`.
                              // `this` will be returned if there is no explicit
                              // return value in the constructor function.
                              // used in the pseudoclassical style.

this in Apply/Call form

functionObject.apply(thisObject, [arguments])  // allows one to specify value of `this` as
functionObject.call(thisObject, argument...)   // `thisObject`.

Function.prototype.call = function (thisObject) {   // can also take an array of parameters or a
  return this.apply(thisObject, Array               // sequence of parameters
     .prototype.slic.apply(arguments, [1]));
};

wrapping statements in a function

  • changes meaning of
this
arguments
var
function
break
continue
return

Closure (aka Lexical Scoping/Static Scope)

  • a result of the fact that functions can nest, and functions are first class values/objects

Closure definition

  • the BIG idea in functional programming
  • the context of an inner function includes the scope of the outer function
  • an inner function enjoys that context even after the parent functions have returned

Closure function scope works like block scope

// block scope
{
  let a;
  {
    let b;
    ... a ...  // inner block can see it's variables and the variables of the outer block
    ... b ...
  }

  ... a ...   // outer block can only see it's own variables
}
// function scope
function green() {
  let a;
  function yellow() {
    let b;
    ... a ...  // inner function yellow() can see it's variables and the variables of
    ... b ...  // the outer function
  }
  ... a ...    // outer function can only see it's own variables (and not yellow()'s)
}

Inner function survives the outer function

inner function can still access context of outer function after outer function returns

JavaScript introduced closure to the mainstream, was then adopted by python, ruby, C#, c++, and recently Java

// inner yellow() function can survive the life of the outer green() function
// powerful construct

function green() {
  let a;
  function yellow() {
    let b;
    ... a ...  // inner function yellow() can stil see it's variables and the variables of
    ... b ...  // the outer function, even after green() has returned
  }
  ... a ...    // outer function can still only see it's own variables (and not yellow()'s)
}

Closure Example 1

Example 1 v1.0 -- Global (no closure)

problem: using global variable called names, if anywhere else in the entire code base (your code and the libraries you use) contains a global variable called names, there's a conflict and your function will fail or a third party function will fail

// global variable `names` is defined

var names = ['zero', 'one', 'two', 'three',
             'four', 'five', 'six', 'seven',
             'eight', 'nine'];


// function digit_name() uses global variable `names`

var digit_name = function (n) {
  return names[n];
};


digit_name(3); // 'three'

Example 1 v2.0 -- Slow (no closure)

no closure, but private array defined again in every function call

// function digit_name() constructs a new private array on every call

var digit_name = function (n) {
  var names = ['zero', 'one', 'two', 'three',
               'four', 'five', 'six', 'seven',
               'eight', 'nine'];

  return names[n];
};


digit_name(3); // 'three'


// good: no global variable that could cause conflicts
// bad: everytime you call digit_name(), you construct a new array with ten things in it
//      just to take one thing out of it (inefficient)

Example 1 v3.0 -- Closure

now immediate function digit_name returns a function

  • every time we nest a function, a new scope is created
  • even after digit_name returns, names is still in scope for future calls to digit_name's returned anonymous function
// closure

var digit_name = (function (n) {
  var names = ['zero', 'one', 'two', 'three',
               'four', 'five', 'six', 'seven',
               'eight', 'nine'];

   return function (n) {
     return  names[n];
   };

}());


digit_name(3); // 'three'


// good: no global variable that could cause conflicts, and the
//       array `names` is created during the one IIFE call

Closure Example 2

// `fade()` transitions color of element `id` from yellow to white

function fade(id) {

  var dom = document.getElementById(id), // Look up `id` of DOM element.
      level = 1;                         // Initialize `level` to 1.

  function step() {
    var h = level.toString(16);          // Turn `level` into Hex char.
    dom.style.backgroundColor =          // Step the color one step closer to white.
      '#FFFF' + h + h;
    if (level < 15) {                    // Check where we are in the transition.
      level += 1;                        // If not done, increment `level`.
      setTimeout(step, 100);             // Recursive call to `step()` in 100 ms.
    }
  }

  setTimeout(step, 100);                 // start the fade transition in 100ms by calling `step`
}

// All recursive calls to step are able to modify `level` because its in scope due to closure.

// At the end of the recursive calls, the garbage collector will clear everything up.

// Will work (no conflict) if fade() is called with multiple DOM elements at
// the same time, since each call to fade() sets a new `dom` variable, new
// `level` variable, and new step() function within their own function scopes.

// They won't interfere with one another because the closure encapsulates and provides seperation.

Pseudoclassical OOP - How JavaScript is implemented (worse)

// make a gizmo using `Gizmo` contructor function, pass in `id` and set to
// newly created property named `id`

function Gizmo(id) {
  this.id = id;
}

Gizmo.prototype.toString = function () {
  return "gizmo " + this.id;
}

Pseudoclassical inheritance Example 1

Gizmo Example illustrated

// --> denotes pointer
// ==> denotes delegation link

// `Gizmo function`'s `prototype` property points to the Gizmo's prototype
Gizmo.prototype --> `Gizmo's prototype`;

// Gizmo's prototype's `constructor` property points back to `Gizmo` function
Gizmo.prototype.constructor --> `Gizmo`

// same idea with `Object`
Object.prototype --> `Object's prototype`;
Object.prototype.constructor --> `Object`

// `Gizmo` intance inherits from Gizo's prototype
gizmo = new Gizmo(string);
gizmo ==> `Gizmo's prototype`;

// `Gizmo's prototype` inherits from `Object's prototype`
`Gizmo's prototype` ==> `Object's prototype`
// in other words:
Gizmo.prototype ==> Object.prototype

Gizmo

Gizmo instance (new Gizmo(string))

id string
Gizmo's prototype

Gizmo function (constructor function) (all functions created have a prototype property)

prototype Gizmo's prototype

Gizmo's prototype

constructor Gizmo function
toString function
Object's prototype

Object

Object function (constructor function) (constructor of all objects)

prototype Object's prototype

Object's prototype (all object literals inherit this)

constructor Object function
toString function

if new was a method

Function.prototype.new = function new() {
  var self = Object.create(this.prototype), // create a new Object that inherits from Function's `prototype` property
      result = this.apply(self, arguments); // call that method, passing in the object and binding it to `this`

  return (
    typeof result === 'object' && result !== null
   )
     ? result
     : self;
};

Pseudoclasical Inheritance Example 2

If we replace the original prototype object, then we can inherit another object's stuff.

Hoozit Example

// 'extends' in JavaScript's prototypal inheritance model

function Hoozit(id) {  // create a `Hoozit` constructor
  this.id = id;
}

Hoozit.prototype = new Gizmo();  // `Hoozit` inherits from `Gizmo`

Hoozit.prototype.test = function (id) {
  return this.id === id;
};
// --> denotes pointer
// ==> denotes delegation link

// `Gizmo function`'s `prototype` property points to the Gizmo's prototype
Gizmo.prototype --> `Gizmo's prototype`;

// Gizmo's prototype's `constructor` property points back to `Gizmo` function
Gizmo.prototype.constructor --> `Gizmo`

// same idea with `Object`
Object.prototype --> `Object's prototype`;
Object.prototype.constructor --> `Object`

// `Gizmo` instance inherits from Gizmo's prototype
gizmo = new Gizmo(string);
gizmo ==> `Gizmo's prototype`;

// `Gizmo's prototype` inherits from `Object's prototype`
`Gizmo's prototype` ==> `Object's prototype`
// in other words:
Gizmo.prototype ==> Object.prototype

// `Hoozit function`'s `prototype` property points to Gizmo's instance (not its own prototype)
// Gizmo's instance now includes new instance method test (?)

Gizmo.prototype --> `Gizmo's Instance`;

// `Hoozit's instance` inherits from `Gizmo's instance`
hoozit = new Hoozit(string);
hoozit ==> `Gizmo's instance`;

Gizmo

Gizmo's instance (new Gizmo(string))

id string
'test' function
Gizmo's prototype

Gizmo function (constructor function)

prototype Gizmo's prototype

Gizmo's prototype

constructor Gizmo function
toString function
Object's prototype

Hoozit

Hoozit's instance (new Hoozit(string))

id string
Gizmo's instance

Hoozits's prototype is now unused since Hoozit.prototype now points to Gizmo's instance

constructor Hoozit function

Hoozit function (constructor function)

prototype Gizmo's instance

Object

Object function (constructor function) (constructor of all objects)

prototype Object's prototype

Object's prototype (all object literals inherit this)

constructor Object function
toString function

Prototypal Inheritance (better)

As a workaround to improve on the Pseudoclassical style/syntax, some people make a new_constructor (not recommended)

  • can do better than this, by using Functional Inheritance and the Module pattern (described below)
  • similar to pseudoclassical inheritance, we save memory by have only one copy of each method per instance
var gizmo = new_constructor(Object, function (id) { // pass in thing you wan to inherit from.
  this.id = id;                                     // pass in constructor function.
}, {
    toString: function () {                         // pass in object containing  methods you want
      return "gizmo" + this.id;                     // instances to inherit
     }
});

var hoozit = new_constructor(gizmo, function (id) {
  this.id = id;
}, {
    test: function (id) {
      return thsi.id === id;
    }

});

// looks more like class-based syntax

new_constructor

function new_constructor(initializer, methods, extend) {
  var prototype = Object.create(typeof extend === 'function'
    ? extend.prototype
    : extend);

  if (methods) {
    methods.keys().forEach(function (key) {
      prototype[key] = methods[key];
    });
  }
  function constructor() {
    var self = Object.create(prototype);
    if (typeof initializer === 'function') {
      initializer.apply(self, arguments);
    }
    return self;
  }
  constructor.prototype = prototype;
  prototype.constructor = constructor;
  return constructor;
}

Functional Inheritance (best)

Module Pattern (using closures) (recommended)

  • good: avoids using global variables
  • okay: causes creation of many instances of functions

Example 1 - Singleton

make one instance of an object containing two methods that share private variables/functions

  • no easy way to get privacy in JavaScript without using function Modules as described here
  • Module Pattern uses closure and IIFE that returns two methods that close over the private state held by private variables in the enclosing IIFE
  • Module Pattern allows for sharing of private variables, if one method changes the value of one private variable, the other will see the change

Module Pattern Example 1

var singleton = (function () {
  var privateVariable;
  function privateFunction(x) {
    ...privateVariable...
  }
  return {
    firstMethod: function  (a, b) {
      ...privateVariable...
    },
    secondMethod: function(c) {
       ...privateFunction()...
    }
  };
}());

Module Pattern Example 1 Variation - Global

instead of returning an object of methods, could modify a global variable that is the container of everything in your application, and you want to add to it

  • works because you are invoking the function immediately
var singleton = (function () {
  var privateVariable;
  function privateFunction(x) {
    ...privateVariable...
  }
  GLOBAL.methodical {
    firstMethod: function  (a, b) {
      ...privateVariable...
    },
    secondMethod: function(c) {
       ...privateFunction()...
    }
  };
}());
  • if you don't invoke the function immediately, you can hold on to that function and make lots of instances

Module Pattern Power Constructors

The Module Pattern is easily transformed into a powerful constructor pattern

Four steps:

  1. Make an object
  • Object literal
  • new
  • Object.create
  • call another power constructor
  1. Define some variables and functions
  • these become private members
  1. Augment the object with privileged methods
  • privileged methods are publicly available methods of an object which close over the private stuff
  1. Return the object

Make a constructor function that uses closure (flexible pattern)

  • allows to make private state within an Object
  • this is a flexible pattern, many different styles of implementations are possible
  • the general gist of it is shown below
  • makes use of closure to provide private state within the object
// can can with `new` prefix (will be slower) but nothing will go wrong
// `spec` is an object of named parameters

function constructor(spec) {
  var self = otherMaker(spec),    // 1. Call another constructor to make an object.
      member,                     // 2. Can make as many private member variables as you need (not visible outside object due to function scope)
      method = function () {      //    Create private methods.
        // spec, member, method
      };
  self.method = method;           // 3. Priviledge methods (public) assigned to outgoing object.
  return self;                    // 4. Return the object.
}

Pseudoclassical Inheritance vs. Functional Inheritance

  • functional inheritance will create a new instance of functions for every instance of the object
    • uses slightly more memory, but closure allows use to hide properties/behavior from the global scope

gizmo and hoozit implemented with Functional Inheritance

function gizmo(id) {
  return {
    id: id,
    toString: function () {
      return "gizmo " + this.id;
    }
  };
}

function hoozit(id) {
  var self = gizmo(id);
  self.test = function (testid) {
    return testid === this.id;
  };

  return self;
}

Privacy using Functional Inheritance

  • We want privacy, the only way to access id is through the methods of the object
  • JavaScript doesn't provide a way for privacy in the Pseudoclassical Model
  • The Functional Model does allow for privacy because of closure
  • also allows us to pull out methods into outside variables

to hide id, instead of using this.id, just use id

no longer specify this.id in gizmo (since that would make it accessible)

function gizmo(id) {
  return {
    toString: function () {
      return "gizmo " + id;
    }
  };
}

function hoozit(id) {
  var self = gizmo(id);
  self.test = function (testid) {
    return testid === id;
  };

  return self;
}

old Pseudoclassical Hoozit

function Hoozit(id) {
  this.id = id;
}

Hoozit.prototype = new Gizmo();
Hoozit.prototype.test = function (id) {
  return this.id === id;
}

// if we try to pull out the test() method from the object
// (you can copy any object reference and put it in a seperate variable)

// var my_hoozit = new Hoozit("success"),
       test = my_hoozit.test;

test("success"); // Boom! Fails

// test() fails here because `this` is not bound to the object but something else
// (`this` will be bound to either `undefined` or the global object)

new Functional Hoozit

functional model allows you to pull out functions from the object and call them, they will work exactly the same way (due to closure)

function hoozit(id) {
  var self = gizmo(id);
  self.test = function (testid) {
    return testid === id;
  };
  return self;
}


// var my_hoozit = hoozit("success"),
       test = my_hoozit.test;

test("success"); // true

// works because methods don't have `this` in them

Building a better constructor

functional pattern: using a function to construct objects

ES5 Version

function constructor(init) {          // 1. Pass in initialization object.
  var self = other_constructor(init), // 2. Call another constructor to inherit what `init` obj does.
    member,                           // 3. Member var(s): store state that internal methods will access.
    method = function () {            // 4. Member method(s): local functions within this object's scope.
       // init, member, method        //      - Each close over `init` obj, member variables and methods.
    };                                //          -  (no need for `this`)
  self.method = method;               // 5. Anything that needs to be public is assigned to outgoing obj.
  return self;
}

ES6 Version

function constructor(spec) {
  let {member} = spec;                     // New es6 syntax: same as `let member = spec.member`.
  const {other} = other_constructor(spec);
  const method = function () {
    // spec, member, other, method
  };

  return Object.freeze({                   // `freeze` gives good security and reliablity for this object.
    method,                                // New es6 object literal syntax: same as `method: method,`.
    other
  });
}

Function Challenge 11 (Security)

Make an array wrapper object with methods get, store and append, such that an attacker cannot get access to the private array.

myvector = vector();
myvector.apend(7);
myvector.store(1, 8);
myvector.get(0);      // 7
myvector.get(1);      // 8

Iteration 1

What's could be an attack on the following code? (standard behavior of the language).

Assume that Array.prototype is fixed.

function vector() {
  var array = [];

  return {
    get: function get(i) {
      return array[i];
    },
    store: function store(i, v) {
      array[i] = v;
    },
    append: function append(v) {
      array.push(v);
    }
  };
}


// attack:

// Store a new locally defined push method into the array that uses `this`.
// Then call the method using append() which will dynamically bind `this` 
// to the array object at invocation.

var stash;
myvector.store('push'), function () { // store(i, v), i is just a key (doesn't have to be a number)
  stash = this;

});
myvector.append();                    // append() will invoke locally defined push method instead,
                                      // array.push is a method invocation, so `this` bind to array

// stash is `array`

How to fix this code?

Iteration 2 (Fix)

function vector() {
  var array = [];

  return {
    get: function get(i) {
      return array[+i];           // turn a string into a number (will turn 'push' into NaN)
    },
    store: function store(i, v) {
      array[+i] = v;
    },
    append: function append(v) {
      array[array.length] = v;    // appending to an array should be an operator
    }
  };
}

Function Challenge 12 (Security)

Make a function that makes a publish/subscribe object. It will reliably deliver all publications to all subscribers in the right order. (Subscribers are functions.)

my_pubsub = pubsub();
my_pubsub.subscribe(log);
my_pubsub.publish("It works!"); // log("It works!")

Iteration 1

What could be an attack on the following code?

i.e. if an attacker is one of the subscribers, how can he screw it up for all the other subscribers?

Hint: Is possible to prevent publish/subscribe, allows messages to publish out of order.

function pubsub() {
  var subscribers = [];
  return {
    subscribe: function (subscriber) {
      subscribers.push(subscriber);
    },
    publish: function (publication) {
      var i, length = subscribers.length;
      for (i = 0; i < length; i += 1) {
        subscribers[i](publication);
      }
    }
  };
}

// Simple Attack:

my_pubsub.subscribe();  // push undefined onto the subscribers array

Iteration 2

Q: How to fix Iteration 1?

A: Could do typeof on the subscriber argument for the subscribe function, or use try..catch. See below.

Q2: What else is vulnerable?

function pubsub() {
  var subscribers = [];
  return {
    subscribe: function (subscriber) {
      subscribers.push(subscriber);
    },
    publish: function (publication) {
      var i, length = subscribers.length;
      for (i = 0; i < length; i += 1) {
        try {                               // fix 1: catch the error and ignore it
          subscribers[i](publication);
        } catch (ignore) {}
      }
    }
  };
}

// Attack 2:

my_pubsub.publish = undefined; // possible to tamper with pubusb instance and delete property or
                               // even replace with more insidious functions

Iteration 3

Q: How to prevent tampering with instance's methods and variables?

A: Freeze the object

Q2: What else is vulnerable?

function pubsub() {
  var subscribers = [];
  return Object.freeze({                    // fix 2: freeze the object to prevent tampering
    subscribe: function (subscriber) {
      subscribers.push(subscriber);
    },
    publish: function (publication) {
      var i, length = subscribers.length;
      for (i = 0; i < length; i += 1) {
        try {                               // fix 1: catch the error and ignore it
          subscribers[i](publication);
        } catch (ignore) {}
      }
    }
  });
}

// Attack 3:

my_pubsub.subscribe(function () {          // takes advantage of fact that `subscribers[i](publication);`
   this.length = 0;                        // is a method invocation (!) using bracket notation
                                           // and will `bind` this
});

Iteration 3

Q: How to fix Attack 3?

A: within the loop's try statement could use subscribers[i].call() or assign subscribers[i] to a local variable, or...

Q2: What will cause the messages to post out of order?

function pubsub() {
  var subscribers = [];
  return Object.freeze({                    // Fix 2: freeze the object to prevent tampering
    subscribe: function (subscriber) {
      subscribers.push(subscriber);
    },
    publish: function (publication) {
      subscribers.forEach(function (s) {    // Fix 3: use forEach and pass a
        try {                               // function will call on each element (s) of array.
          s(publication);                   // Fix 1: catch the error and ignore it
        } catch (ignore) {}
      });
    }
  });
}

// Attack 4:

my_pubsub.subscribe(limit(function () {  // uses limit to limit to just a single call (otherwise will
   my_pubsub.publish("Out of order")     // call recursively and effectively be a DoS attack)
                                         // and will `bind` this
}, 1));

Iteration 4

Q: How to fix Attack 4?

A: could use a boolean at the top that says we're in subscribe mode, or...

Q2: Solution below also introduces another vulnerability, what is it?

function pubsub() {
  var subscribers = [];
  return Object.freeze({                    // Fix 2: freeze the object to prevent tampering
    subscribe: function (subscriber) {
      subscribers.push(subscriber);
    },
    publish: function (publication) {
      subscribers.forEach(function (s) {    // Fix 3: use forEach and pass a
        setTimeout(function () {            // function will call on each element (s) of array.
          s(publication);
        }, 0);                              // Fix 4: (asyncronous) use `setTimeout` that receives a function
      });                                   // and adds that function to be called into a timer queue
    }                                       // (keeps stuff in order, also don't need to use `try...catch`,
  });                                       // if one fails it will fail during that turn and keep going)
}



// Attack 5: (to be solved for another day)

// `setTimeout` returns a number and you can pass that number to 
// `clearTimout` to prevent further execution. The number is
// easily guessable by an attacker to prevent messages from being
// delivered by canceling messages still in the queue.

Principles of Cryptography

The Kerckhoffs Principle

The design of a system should not require secrecy; and compromise of the system should not inconvenience the correspondents.

Cryptography is not security, but cryptography can teach us about security.

If there are obvious security vulnerabilities in a system, often the architect's first thought is...

We need to encrypt something

...which turns out doesn't work

Security = thinking like a cryptographer

To build secure applications, we can think like cryptographers

Cast of characters

  • 👩 Alice
  • :squirrel: Eve (eavesdropper)
  • 👤 Mallory (Man-in-the-middle)
  • :person_with_blond_hair: Bob
  • 😈 Satan (malicious attacker)

Principles of Security

Security is not hats.

White hats vs. black hats

Security is everyone's job.

Don't leave it to specialists.

Things Change

It is not unusual for the purpose or use or scope of software to change over its life.

Rarely are the security properties of software systems reexamined in the context of new or evolving missions.

This leads to insecure systems.

Don't nobody do nothing stupid and nobody gets hurt.

And this means you.

Only adhering to Principles works

Not trix and hax.

Deterrence is not effective.

You can't punish an invisible attacker.

Security must be factored into every decision

We have the responsibility to limit the capabilities of 'Satan' so he cannot cause us harm.

"We'll go back and make it secure later."

Rarely works, is really hard to do.

You can't add security, just as you can't add reliability.

Insecurity and unreliability must be removed.

Having survived to this point does not guarantee future survival.

The Impossible is not Possible

If a measure is not effective, it is ineffective.

Don't prohibit what you can't prevent.

What you don't prevent, you allow.

False security is worse than no security.

Unnecessary expense and confusion of risk.

If you know you're not secure, you'll be cautious.

If you think you're secure and you're not, you'll be reckless.

Security and the Browser

The Web Browser Platform

  • historically and horribly insecure

  • still "fixing it later."

  • HTML5 made it even more vulnerable

  • But it is still the best application delivery system

The Web does not use the "Blame the victim" security model

Blame the Victim Model

  • if a system has to make a decision about security and doesn't have enough information to make a correct decision, it will ask the user for permission (typically using language that the user cannot understand).
  • If the user says "no", then the system fails (or doesn't work).
  • If the user says "yes", then its the user's fault for giving up their security.

Whose interest does the program represent?

  • The browser got this right.

  • Every other platform got this wrong.

  • From the beginning of computing it's been assumed that the program represents the owner of the machine, or at least the owner of the account.

  • The browser affirms that the program represents a site, that doesn't necessarily represent the user

What the web got wrong

  • The web didn't anticipate that there can be more interests involved in a page than the user's and the site's interests.
  • A malicious party can exploit coding conventions to inject malicious code
  • That malicious code gets all of the rights of the site.
  • This is known as the XSS problem

What can an attacker do if he gets some script into your page (via XSS)?

An Attacker can request additional scripts from any server in the world.

Once the attacker gets a foothold, it can obtain all of the scripts they need.

  • browsers implement a "Same Origin Policy", which limits the ability of the browser to get data from other servers

  • but there is no limit on how much program you can load from the most evil server in the world

An Attacker can read the document.

The attacker can see everything the user sees. And stuff the user can't see (everything we transmit to the browser DOM)

An Attacker can make requests of your server

Your server cannot detect that the request did not originate with your application.

If you're using SSL, the attacker gets access the this secure connection.

If your server accepts raw SQL queries, then the attacker gets access to your database.

If instead your server constructs raw SQL queries internally, based on information received from the browser, then the attacker might get access to the database (yay)

Because SQL was optimized for SQL injection attacks. 😉

An attacker has control over the display and can request information from the user

The user cannot detect that the request did not originate with your application.

An attack can send information to servers anywhere in the world

The browser does not prevent any of these.

Web standards require these weaknesses

The consequences of a successful attack are horrible.

Harm to customers. Loss of trust. Legal liabilities.

XSS Cross Site Scripting

  • the name 'XSS' is sort of a misnomer
  • cross site scripting is highly desirable, we want sites (businesses and services) to cooperate with each other
  • there are forms of the 'XSS' attack that don't require a second site

Baby Steps to Security against XSS

  • Content Security Policy now in browsers

    • WSC Editor's Draft 15 April 2013
    • most sites aren't using CSP
    • barrier to CSP adoption: to use it, a lot of common practices become illegal
  • <iframe sandbox> W3C Candidate Recommendation 17 Dec 2012

  • Browsers still unsafe by default

A 'mashup' is a self-inflicted XSS attack

Advertising is a mashup

The most reliable, cost effective method to inject evil code is to buy an ad.

Why is there XSS?

  • The web stack is too complicated
    • Too many languages, each with its own encoding, quoting, commenting, and escapement conventions.
    • Each can be nested inside of each other.
    • Browsers do heroic things to make sense of malformed content.
  • Template-based web frameworks are optimized for XSS injection
  • The JavaScript global object gives every scrap of script the same set of powerful capabilities.
  • As bad as it is at security, the browser is a vast improvement over everything else.

Problem is not XSS, it is a "Confusion of Interests"

  • The browser distinguishes between the interests of the user and the interests of the site.
  • It did not anticipate that multiple interests might be represented.

Within a page, interests are confused.

Anything that gets loaded from a third party must be trusted!

An ad or a widget or an Ajax library gets the same rights as the site's own scripts.

JavaScript got close to getting it right.

It can be repaired, becoming an object capability language.

HTML Security Problems Won't Be Fixed Anytime Soon

  • HTML grants power to confusers.
  • HTML is easily confused.
  • HTML is forgiving because webmasters were/are incompetent.
  • HTML's API, the DOM, is also insecure.

It is up to the web developer to create secure applications on an insecure platform.

But there is hope in the 'Principle of Least Authority' and the object capability /actor model

Object Capabilities

The Principle of Least Authority

Any unit of software should be given just the capabilities it needs to do its work, and no more.

Capabilities can be seen in the Actor Model that originated in 1973 at MIT that led to the invention of Scheme which led to higher order functions and actors.

The Actor Model

  • An actor is a computational entity.
  • An actor can send a message to another actor only if it knows its address.
  • An actor can create a new actor.
  • An actor can receive messages.
  • Web workers are actors.
  • Web services are not...

Waterken applies the actor model to web services.

Distributed, reliable services. http://www.waterken.com/

Capability

  • An address of an actor is a capability.
  • A reference to an object is a capability.

An Introduction to Object Capabilities in OOP

🅰️

  • 🅰️ is an Object
  • Object 🅰️ has state and behavior

objects contain state and behavior


🅰️ ----> 🅱️

has-a

  • Object 🅰️ has a reference to Object 🅱️

an object can have references to other objects


🅰️ --💬--> 🅱️

  • Object 🅰️ can communicate with Object B...
  • because it has a reference to Object 🅱️

Objects can communicate with other objects they have reference to

  • Object 🅱️ provides an interface that constrains access to its own state and references
    • Object 🅰️ does not get access to Object 🅱️'s innards
    • in JavaScript, must use freeze to guarantee limited access

🅰️ ----> 🅱️

🅾️

  • Object 🅰️ does not have a reference to Object 🅾️, so Object A cannot communicate with Object 🅾️

In an Object Capability System, an object can only communicate with objects that it has references to.


An Object Capability System is produced by constraining the ways that references are obtained

A reference cannot be obtained simply by knowing the name of a global variable or a public class

Three ways to obtain a reference

  1. By creation
  2. By Construction
  3. By Introduction

1. By Creation

If a function creates an object, it gets a reference to that object.

1. By Construction

An object may be endowed by its constructor with references.

This can include references in the constructor's context and inherited references.

1. By Introduction

🅰️🅱️

🅾️

  • 🅰️ has references to both 🅱️ and 🅾️
  • 🅱️ has no references, so it cannot communicate with 🅰️ or 🅾️
  • 🅾️ has no references, so it cannot communicate with 🅰️ or 🅱️

  • But, 🅰️ wants 🅱️ and 🅾️ to be able to communicate:

🅰️ --💬--> 🅱️

↓ ↙︎

🅾️

  • 🅰️ calls 🅱️, passing reference to 🅾️

🅰️ --> 🅱️

↓ __ ↙︎

🅾️

  • 🅱️ is now able to communicate with 🅾️
    • it has acquired the capability

If references can only by Obtained by Creation, Construction, or Introduction, then you may have a safe system.

Potential Weaknesses of the Object Capability Model

  1. Arrogation
  2. Corruption
  3. Confusion
  4. Collusion

1. Arrogation

  • Arrogation = to take or claim for oneself without right
  • includes:
    • global variables
    • public static methods
    • Standard libraries that grant powerful capabilities like access to the file system or the network or the operating system to all programs
    • address generation (why c++ can never be a secure language)
    • known URLs

2. Corruption

It should not be possible to tamper with or circumvent the system or other objects

  • why Object.freeze is so critically important

3. Confusion

It should be possible to create objects that are not subject to confusion.A confused object can be tricked into misusing its capabilities.

4. Collusion

  • It must not be possible for two objects to communicate until they are introduced
  • If two independent objects can collude, they might be able to pool their capabilities to cause harm

Rights Attenuation

  • Some capabilities are too dangerous to give to guest code.
  • We can instead give those capabilities to intermediate objects that will constrain their power.
  • For example, an intermediate object for a file system might limit access to a particular device or directory, or limit the size of files, or the number of files, or the longevity of file, or the type of files

Capabilities should be granted on a need-to-do basis

Ultimately, every object should be given exactly the capabilities it needs to do its work and no more.

  • Information Hiding (good system design) is enhanced when focused on Capability Hiding.

Facets

Intermediate objects, or facets can be very lightweight

  • class-free languages can be especially effective

[Guest] --> [Facet] --> [Powerful]

  • The Facet Object limits the Guest Object's access to the Powerful object
  • The Guest Object cannot tamper with the Facet object to get a direct reference to the dangerous Powerful Object

References are not revocable

Once you introduce an object, you can't ask it to forget it.

  • You can ask, but you should not depend on your request being honored.

[Guest] --> [Agency] --> [Powerful]

The Guest Object has a reference to an Agency Object. The Guest asks for an introduction to the Powerful Object.

  • The Facet might be a simple pass through
[Guest] ➜  [Agency]
     |    ╱    |
     ↓  ↙︎      ↓
   [Facet] ➜ [Powerful]

Revoking Capability

When the Agency wants to revoke the capability, it tells the Facet to forget its capability.

  • The Facet is now useless to the Guest
[Guest] ➜  [Agency]
     |    ╱    |
     ↓  ↙︎      ↓
   [Facet]  [Powerful]

[Guest] --> [Facet] --> [Powerful]

a Facet can mark requests so that the Powerful object can know where the request came from (gives us accountability)

Facets

  • Very expressive
  • Easy to construct
  • Lightweight
  • Attenuation: Power Reduction
  • Revocation
  • Notification
  • Delegation

The best OO patterns are also capability patterns

Thinking about security (what's the least amount of power I can give this object to make sure it works correctly) can make the design of systems inherently better and easier, not harder.

Attenuation is your friend

  • Facets can reduce the power of dangerous objects
  • Most code should not be given direct access to dangerous things like innerHTML or document.write
  • Instead of trying to guess if a piece of code can do something bad, give if safe capabilities instead
  • Capabilities can aid in API design

Reducing Complexity

Function the Ultimate

Corrupting a single object results in a corrupted object, not a corrupted system

  • The object capability model completely changes the economics of hacking
  • in most system architectures, if you can confuse (corrupt) an object, you can get access to everything in the system
  • in the Object Capability Model, if you confuse/corrupt (i.e. create an object incorrectly) an object, you get the capabilities of that object, but only that object
  • confusion attack: see Function Challenge 11

The Lazy Programmer's Guide to Secure Computing

Marc Stiegler

https://www.youtube.com/watch?v=eL5o4PFuxTY

Confusion aids the enemy

Bugs/security exploits are a manifestation of confusion

With great complexity comes great confusion

Keep it simple. Keep it clean.

  • be a minimalist, find the simplest solution possible
  • code that is harder to understand is more likely to be exploited

Code Well

  • Good code is ultimately cheaper to produce than bad code, so we might as well always write good code.
  • Good code is easier to reason about.
  • Code that is difficult to reason about is more likely to be problematic
  • Strict conformance to good style rules.

Never trust a machine that is not under your absolute control

Don't get more intimate than sharing JSON payloads.

Never trust the browser

  • It cannot and will not protect your interests
  • Properly filter and validate all input
  • Properly encode all output
  • Context is everything
  • Filter and encode for the correct context

A Simple Attack

XSS


Confusion and Concatenation

Properly encode all of the non-literal pieces

  • use good encoders and writers instead of just plus-ing things together

"Why would anyone do that?"

  • Inconvenience is not security
  • Identity is not security
  • Taint ain't security
  • Intrusion detection is not security

The Biggest Avoidable source of insecurity is Mismanagement

  • "we gonna get this past the security guys because we've got to get this out"

Managing Asynchronicity

Managing Asynchronicity with RQ and JSCheck

Synchronous Functions

Two Kinds of Functions

  1. Synchronous Functions
  2. Asynchronous functions

Synchronous functions

Do not return until the work is complete or failed

  • useful because its easy to reason about its behavior over time
  • when a synchronous function calls another synchronous function, the caller is suspended in time. Nothing advances until the callee returns
  • not easy to reason about if we need things to happen at the same time

The Problems With Threads

  • Races
  • Deadlocks
  • Reliability
  • Performance

Threading Model Pros/Cons

Pros

  • No rethinking is necessary
  • Blocking programs are ok
  • Execution continues as long as any thread is not blocked

Cons

  • Stack memory per thread (ok)
  • If two threads use the same memory, a race may occur

Q: When are we going to get threads in JavaScript?

A: Never

Why? Two threads Example:

// two programs, will run possibly on their own thread

my_array[my_array.length] = 'a'; // program 1
my_array[my_array.length] = 'b'; // program 2

// race condition 1: where we don't know order of execution
// ['a', 'b']
// ['b', 'a']

// race condition 2: where we lose "half of our data" (!)
// ['a']
// ['b']

What's happening here?

Expanding the Array code

my_array[my_array.length] = 'a'; // thread 1
my_array[my_array.length] = 'b'; // thread 2

// thread 1 is implemented like this:

length_a = my_array.length;
my_array[length_a] = 'a';
if (length_a >= my_array.length) {
  my_array.length = length_a + 1;
}

// thread 2 is implemented like this:

length_b = my_array.length;
my_array[length_b] = 'b';
if (length_b >= my_array.length) {
  my_array.length = length_b + 1;
}

Race condition in expanded code

  • We cannot control what order these will execute in
  • One possible ordering: both capture the length at the same time:
  • (whichever one runs second will probably win out, and my_array will end up with one item)
length_a = my_array.length;        // thread 1
length_b = my_array.length;        // thread 2

my_array[length_a] = 'a';          // thread 1
if (length_a >= my_array.length) { // thread 1
my_array[length_b] = 'b';          // thread 2 - executes during thread1 loop
  my_array.length = length_a + 1;  // thread 1
}

if (length_b >= my_array.length) { // thread 2
  my_array.length = length_b + 1;  // thread 2
}
  • it can be even worse than this, since each of the statements above can expand in to multiple machine language statements, which we don't know how will interleave, and each of those statements can expand into multiple micro instructions which order cannot be guaranteed.

It is impossible to have application integrity when subject to race conditions

Mutual Exclusion

  • Used to mitigate race conditions

  • Allows only one thread to be running in a critical section of memory at a time

  • this used to be operating system stuff

  • but has leaked into applications because of networking and multi-cores

    • accessing the network is slow, we want to have stuff happening when slow stuff is occurring
    • CPU makers give us more cores, which we don't know how to use
      • most of what we do is not parallel, but serial

mutual exclusion techniques

  • semaphore
  • monitor
  • rendezvous
  • synchronization

Mutual Exclusion Definition

  • Only one thread can be executing on a critical section at a time

  • all other threads wanted to execute the critical section are blocked

  • if threads don't interact, then the program runs at full speed

  • if threads do interact, then races will occur unless mutual exclusion is employed

Mutual exclusion has its own dark side: Deadlock

Asynchronous functions

  • Return immediately (almost no passage of time). Success or failure will be determined somehow in the future.

Turn Systems

  • turns as in turns in a game of chess, one player doesn't touch any pieces until the other players turn is done. Similar thing is happening with events and functions.
  • A turn is started by an external event, such as the delivery of a message, completion of an asynchronous request, a user action, or the ticking of the clock
  • A callback function associated with the event is called. It runs to completion.When it returns, the turn ends.
  • No need for threads. No races. No deadlocks.

The Law of Turns

  • Never block.
  • Never wait.
  • Finish fast.

Any code that must do any of these things must be isolated and run in a separate process. It is not allowed to run in the turn system.

Event Loop

  • Event loops are used in Turn-based systems

Pros

  • Completely free of races and deadlocks
  • Only one stack
  • Very low overhead.
  • Resilient. If a turn fails, the program can still go on.

Cons

  • Programs must never block.
  • Turns must finish quickly
  • Programs are inside out! (aka different style of program design than usual)

Event Driven Systems

  • Turn based. No pre-emption.
  • Associate events with actions.
  • Easy (beginners can do it)
  • How User Interfaces have been always implemented

JavaScript on the Server

  • JavaScript is moving to the server.
  • What servers do is quite different from what browsers do.

node.js

  • node.js implements a web server in a JavaScript event loop
  • It is a high-performance event pump
  • It has asynchronous file I/O that is non-blocking
    • fs.readFile(filename, encoding, function (err, data) {...})
  • Everything is (or can be) non-blocking.
    • Except:
      • some synchronous functions
      • require (is also blocking) (fixed in es6's module system)

Servers

  • Instead of events (browser), servers are message driven, message queue
  • Actor-like
  • Simple events don't fit:
    • Sequential
      • A sequence of requests, each dependent on the result of the previous
      • Naive approach: deeply nested callbacks (brittle, low-performance, hard-to-maintain)
    • Parallel
      • Do a bunch of independent things (request goes to several systems at the same time, only wait for the slowest) (how to deal with unexpected return times, orders?)
      • Naive approach: wastes time, increases latency
    • Limited time
      • SLAs or other polices that require a response within a certain amount of milliseconds
      • If we don't get a response in time, go to Plan B (can't just let the request hang)
    • Cancellation
      • If we go to Plan B, how do we stop unnecessary work? (not easy to do in deeply nested event handlers)

Functional Programming to the Rescue

  • Futures (Dataflow and LISP)
    • a an object that represents something that isn't knowable yet, but might be in the future
    • you can begin to interact with the future object, eventually it will communicate your interest to whatever the answer turns out to be
  • Promise
    • Influenced by Futures, have now reached JavaScript
  • Monads
  • Arrows
  • RX
    • Microsoft: reactive extensions, allows for composing of event streams (badly documented)
    • influenced Functional Reactive Programming (FRP): Flapjax, bacon.js, elm
    • RQ

RQ

  • A small JavaScript library (by Doug Crockford) for managing asynchronicity in server applications

Four Methods

  1. RQ.sequence(requestors)
  2. RQ.parallel(requestors) RQ.parallel(requestors, optionals)
  3. RQ.race(requestors)
  4. RQ.fallback(requestors)

RQ.sequence

  • Takes an array of requestor functions, calls them one at a time, passing the result of the previous requestor to the next requestor

  • implements continuation passing style: at each step we don't return the result, instead we pass the result to the next function in the sequence

  • RQ.sequence returns a function, when that function gets called with a provided callback, it will call the first function in the sequence with that callback asan argument

getNav = RQ.sequence([
  read_file(file_name),
  getPreference,
  getCustomNav
]);

RQ.parallel

  • Takes an array of requestor functions, calls them one all at once, and gives an array of results
  • not adding parallelism of JavaScript, just utilizing the natural parallelism of the universe
getStuff = RQ.parallel([
  getNav,
  getAds,
  getMessageOfTheDay
]);
  • Also takes an optional array of optional requestors.
  • Their results will be included if they can be obtained before the required requestors finish.
getStuff = RQ.parallel([
  getNav,
  getAds,
  getMessageOfTheDay
], [
  getHoroscope, // Will not wait for these, if these don't complete before
  getGossip     // the main three, they will be cancelled.
]);

RQ.race

  • Takes an array of requestor functions, calls them one all at once, and gives the result of the first success
getAds = RQ.race([
  getAd(adnet.klikHaus),
  getAd(adnet.inUFace),
  getAd(adnet.trackPipe)
]);

RQ.fallback

  • Takes an array of requestor functions and gives the result of the first success
  • could use a race, but hierarchy allows us to go to the remote DB as a last resort
getWeather = RQ.fallback([
  fetch("weather", localCache),
  fetch("weather", localDB),
  fetch("weather", remoteDB)
]);

RQ Example

RQ.parallel([
  RQ.sequence([
    widget('Seq A1'),
    widget('Seq A2'),
    widget('Seq A3')
  ]),
  RQ.sequence([
    widget('Seq B1'),
    widget('Seq B2'),
    widget('Seq B3')
  ]),
  widget('C'),
  RQ.race([
    widget('Race D1'),
    widget('Race D2'),
    widget('Race D3')
  ]),
  RQ.fallback([
    widget('Fall E1'),
    widget('Fall E2'),
    widget('Fall E3')
  ])
], [                        // optional set
  RQ.sequence([
    widget('Opt Seq O1'),
    widget('Opt Seq O2'),
    widget('Opt Seq O3')
  ]),
  RQ.sequence([
    widget('Opt Seq P1'),
    widget('Opt Seq P2'),
    widget('Opt Seq P3')
  ]),
  widget('Opt Q'),
  RQ.race([
    widget('Opt Race R1'),
    widget('Opt Race R2'),
    widget('Opt Race R3')
  ]),
  RQ.fallback([
    widget('Opt Fall S1'),
    widget('Opt Fall S2'),
    widget('Opt Fall S3')
  ])
])(show);

RQ reqestories with timeouts

  • RQ also takes timeouts
    • can indicate that something needs to complete successfully in this much time, otherwise it will fail
  1. RQ.sequence(requestors, millisecond)
  2. RQ.parallel(requestors, millisecond) RQ.parallel(requireds, milliseconds, optionals, untilliseconds)
  3. RQ.race(requestors, milliseconds)
  4. RQ.fallback(requestors, milliseconds)
  • untilliseconds = gives the optional set a certain amount of time until it gets cancelled, in case the main ones finish early

Cancellation

  • Any requestor can optional return a cancel function
  • A cancel function, when called, will attempt to cancel a request
  • No guarantee that the cancellation will happen before the request completes (bc of possible network races, etc.)
  • Cancellation is intended to stop unnecessary work. It does not undo.

RQ function Types

  1. requestor
  • A function that can execute a request
  1. callback
  • A continuation function that will be passed to a requestor
  1. factory
  • A function that takes arguments and returns a requestor function
  1. cancel
  • A function returned by a requestor that may be used to cancel a request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment