1. Async JS Pattern

  2. Write Promises/callback/async-await/generators/observables/async events

Async Node Pattern

What is async

events

callback

stream

xhr

I/O

doThing('value', (err, result) => {
    if (err) {
        // handle error here
        console.error(err);
    } else {
        // handle success here
        console.log(result);
    }
});

callback

for (var i = 0; i < 100; i++) {
   (function (i) {
      setTimeout(function () {
         console.log(i);
      }, 100);
   })(i); 
// The current value of 
//i is captured by self executing function
}
console.log('this still gets printed first.');

basic async in a loop

Promises

doThing('value')
    .then(value => {
        // handle success here
        console.log(value);
    })
    .catch(reason => {
        // handle error here
        console.error(reason);
    });

Promises chaining 1-2-3-4...

asyncCount()
    .then(function(count){
        console.log(count); //1
        return asyncCount();
    })
    .then(function(){
        throw 
       new Error("Oops an error occurred");
    })
    .then(function(){
       return asyncCount();
    })
    .then(function(res){/*wont be called*/}, function (err){
        console.log(err.message);
       //Oops an error occurred ...
    }).catch((err) => {
})
try {
    const result = await doThing('value');
    // handle success here
    console.log(result);
} catch (ex) {
    // handle error here
    console.error(ex);
}

Async await

async function myFunction(inputValue) {
    try {
        const a = await asyncFunc1('value');
        const b = await asyncFunc2(a);
        const c = syncFunc3(b);
        return await asyncFunc4(c);
    } catch (ex) {
        // handle exception
    }
}

Code like a king !!

function* formatAnswer() {
  const answer = yield 'foo';
  return `The answer is ${ answer }`;
}

const generator = formatAnswer();
console.log(generator.next()); 
// {value: "foo", done: false}
console.log(generator.next(42));
 // {value: "The answer is 42", done: true}

Generators **

async function main () {
  const [user, product] = await Promise.all([
    Users.fetch(userId),
    Products.fetch(productId)
  ])

  await makePurchase(user, product)
}

async await running things parallel ---level 2

 async.waterfall(
        [
          (cb) => {
                  cb(null, solution[0]);
          },
          (solution, cb) => {
                cb(null, pGetTree, solution);
          },
          (pGetTree, solution, cb) => {
            cb(null, tempPGetTree);
          }
        ],
      );
    });
  }

Waterfall using Async

Handling Rejections !!

async function main () {
  await new Promise((resolve, reject) => {
    reject(new Error('đź’Ą'))
  })
}

main()
  .then(console.log)

Handling Rejections proper way !!

const util = require('util')

async function main () {
  try {
    await new Promise((resolve, reject) => {
      reject(new Error('đź’Ą'))
    })
  } catch (err) {
    // handle error case
    // maybe throwing is okay depending on your use-case
  }
}

main()
  .then(console.log)
  .catch(console.error)

I know promises only !!

const util = require('util')
const {readFile} = require('fs')

const readFileAsync = util.promisify(readFile)

async function main () {
  const result = await readFileAsync('.gitignore')
  return result
}

main()
  .then(console.log)
  .catch(console.error)

Preventing HTTP Parameter Pollution (HPP)

var hpp = require('hpp');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();

app.use(bodyParser.urlencoded({extended: false}));
 //body parser should be placed before using hpp
app.use(hpp());

app.get('/', function(req, res, next){
  console.log('Query Parameters : ' + JSON.stringify(req.query));
  console.log('Polluted Query Parameters : '+ JSON.stringify(req.queryPolluted));
  res.render('index');
});

Setting Security Response Headers

var express = require('express');
var app = express();

app.disable('x-powered-by');   // disable X-Powered-By header

app.use(function(req, res, next){
  res.header('X-XSS-Protection', '1; mode=block');
  res.header('X-Frame-Options', 'deny');
  res.header('X-Content-Type-Options', 'nosniff');
  next();
});

Setting Security Response Headers

  • X-Frame-Options — Prevents your application being displayed in iframes
  • X-XSS-Protection — Invokes browser XSS protection mechanisms
  • X-Content-Type-Options — Prevents mime sniffing

Setting Security Response Headers

var helmet = require('helmet');

app.use(helmet.hidePoweredBy({setTo: 'DummyServer 1.0'})); 
//change value of X-Powered-By header to given value
app.use(helmet.noCache({noEtag: true})); 
//set Cache-Control header
app.use(helmet.noSniff());    
// set X-Content-Type-Options header
app.use(helmet.frameguard()); 
// set X-Frame-Options header
app.use(helmet.xssFilter());  
// set X-XSS-Protection header

NPM Modules

  • csurf — Implement Anti-CSRF tokens to prevent cross site request forgery
  • cors — Enable Cross origin resource sharing
  • hpp — Protection from HTTP Parameter Pollution
  • express-content-length-validator — Prevent DOS attacks
  • rate-limiter — Prevent DOS attacks
  • helmet — Set custom security headers
  • nsp — Scan for deprecated/vulnerable npm modules used in your app
  • retire — Scan for deprecated/vulnerable npm modules used in your app
  • mocha, should, supertest — Writing node.js tests
  • bunyan — Logging

Use explicit package versions

{
  "name": "My App",
  "version": "0.0.0",
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "express": "~4.13.1",
    "http-auth": "~2.2.8",
    "jade": "~1.11.0",
    "jsonfile": "~2.2.1",
    "morgan": "~1.6.1",
    "nodemon": "~1.4.1",
    "serve-favicon": "~2.3.0"
  }
}

No sensitive data inside your repo !!!

app.use(session({
    name: 'SESS_ID',
    secret: process.env.EXPRESS_SESSION_SECRET,
    resave: false,
    saveUninitialized: true,
    cookie: {
        secure: true,
        httpOnly: true
    }
}));

always keep your application components up-to-date. Following are few tools that you can use to identify potential outdated components in your application.

And also keep your Node.js version and NPM up to date. Node.js version can be updated with “n” npm module.

sudo npm install n 
sudo n stable

You can update npm using npm (weired right?)

sudo npm install -g npm

Can we, effectively, build a program using this notion?

Meet your new friend:

 The Observable

Your friendly neighbor: RxJS

Reactive Extensions

Are a set of libraries for composing asynchronous and event-based programs using observable sequences and fluent query operators

Rx is everywhere

Java

JavaScript

.Net

Ruby

Swift

C++

Clojure

Scala

What is the most asynchronous?

User

More async data streams

  • XHR requests

  • WebSocket

  • Promises

  • Events

  • Dom Inputs

  • Web Worker

  • Web RTC

RxJS operators

RxJS operators

RxJS operators: map

resStream

RxJS operators: delay

resStream

RxJS operators: debounce

resStream

RxJS operators: merge

resStream

RxJS operators: combineLatest

resStream

RxJS operators: zip

resStream

Let's create a morse-code decoder!

Morse-code decoder

click...

click...

click.............

click...

Morse-code decoder

click...

click...

click.............

click...

Morse-code decoder

  • Dom events (keydown, keyup)

  • Start signal/End signal

  • Dot/Dash/Whitespace

  • Letter

  • Word/Sentence

Morse-code decoder

Morse-code decoder

  • "." = ~400ms

  • "_" = 3 * "."

  • between codes = "."

  • between letters = 3 * "." 

  • between words = 7 * "."

Morse-code decoder

const keyUps = Rx.Observable
                 .fromEvent(document, 'keyup');

const keyDowns = Rx.Observable
                   .fromEvent(document, 'keydown');

Morse-code decoder

const spaceKeyUps = keyUps.filter((data) => data.keyCode === 32);

const spaceKeyDowns = keyDowns.filter((data) => data.keyCode === 32);

Morse-code decoder

const signalStartsRaw = spaceKeyDowns.map(() => "start");
const signalEndsRaw = spaceKeyUps.map(() => "end");


const signalStartsEnds = Rx.Observable
                            .merge(signalStartsRaw, signalEndsRaw)
                            .distinctUntilChanged();

Morse-code decoder

const signalStarts = signalStartsEnds
                           .filter((ev) => ev === "start")
                           .timestamp();
const signalEnds = signalStartsEnds
                           .filter((ev) => ev === "end")
                           .timestamp();



const spanStream = signalStarts.flatMap((start) => {
    return signalEnds.map((end) => end.timestamp - start.timestamp)
                     .first();
});

Morse-code decoder

Morse-code decoder

const SPAN = 400;

const dotsStream = spanStream
                        .filter((v) => v <= SPAN)
                        .map(() => ".");

const lineStream = spanStream
                        .filter((v) => v > SPAN)
                        .map(() => "-");

Morse-code decoder

const dotsAndLines = Rx.Observable.merge(dotsStream, lineStream);

// [['.', '.', '-'], ['-', '.', '-'] ... ] 
const letterCodes = dotsAndLines.buffer(letterWhitespaces); 

 // ['A', 'B' ...]
const lettersStream = letterCodes
                        .map((codes) => morse.decode(codes.join("")));

Morse-code decoder

Morse-code decoder

What else?

Component bindings

Component bindings

click...

click...

click.............

click...

click

category.

comp.

bundle.

package.

Component bindings

Component bindings

Problems RxJS solves

  • Data Manipulation

  • Events handling

  • Callback Hell

  • Promise Hell

  • Comet/Async Manipulation

  • Race Conditions

  • Complex State

  • Tests 

RxJS problems

Complexity

Integration with imperative part of code

Documentation

Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences or Promises or array/iterable into one observable sequence.

Cascade Updating

Cascade Updating

Cascade Updating/Exceptions

RxJS with other frameworks

RxJS with Angular - rx.angular.js

angular.module('example', ['rx'])
  .controller('AppCtrl', function($scope, $http, rx) {

    function searchWikipedia (term) {
      return rx.Observable
        .fromPromise($http({}))
        .map(function(response){ return response.data[1]; });             
    }

    $scope.search = '';
    $scope.results = [];

    $scope.$createObservableFunction('click')
      .map(function () { return $scope.search; })
      .flatMapLatest(searchWikipedia)
      .subscribe(function(results) {
        $scope.results = results;
      });
  });

RxJS with Angular2 - inside

RxJS with React - rx-react

RxJS with others

Alternative?

Bacon

Kefir

Highland

I want more hardcore!

Javelin and ClosureScript

(defc test-results
  {:scores [74 51 97 88 89 91 72 77 69 72 45 63]
   :proctor "Mr. Smith"
   :subject "Organic Chemistry"
   :sequence "CHM2049"})

(defc= test-results-with-mean
  (let [scores (:scores test-results)
        mean   (/ (reduce + scores) (count scores))
        grade  (cond (<= 90 mean) :A
                     (<= 80 mean) :B
                     (<= 70 mean) :C
                     (<= 60 mean) :D
                     :else        :F)]
    (assoc test-results :mean mean :grade grade)))

Cycle.js

  • RxJS

  • Side effects/Logic

  • Composition

  • Streams, streams, streams, streams

Questions?

node js security webinar 02

By Tarun Sharma

node js security webinar 02

  • 645