lukefx
10/9/2015 - 12:04 PM

Node.js Destiny API Authentication

Node.js Destiny API Authentication

// Usage:
var login = require('./login');
var request = require('request');


// This simulates post data I would get from a login form in my web app.
// I don't think this is the right way to handle this...
var username = "email@email.com";
var password = "is_this_method_event_correct?";
var API_KEY = "yourkeyfrombungie";


// do the thing!
login({ username : username, password : password }).then(function(obj) {
  var url = "https://www.bungie.net/Platform/Destiny/MyAccount/Vault/";
  var opts = {};
  
  opts.headers = {};
  opts.headers['X-API-Key'] = API_KEY;
  opts.headers['x-csrf'] = obj.bungled;
  opts.jar = obj.cjar;
  opts.json = true;
  opts.qs = {};
  opts.qs.definitions = true;
  
  request.get(opts, function(err, response, body) {
    if (!err) {
      console.log(body.Response.data);
    }
    else {
      throw new Error(err);
    }
  })
}).catch(function(err) {
  console.error(err);
})
var request = require('request');
var Promise = require('es6-promise').Promise;
var cjar = request.jar();

var PSN_OAUTH_URI = "https://auth.api.sonyentertainmentnetwork.com/login.do";
var BUNGIE_SIGNIN_URI = "https://www.bungie.net/en/User/SignIn/Psnid";


// Returns a promise fullfilled with the response of the 
// request, or rejected with the error
function req(opts) {
  return new Promise(function(resolve, reject) {
    var ropts = {};

    for (var opt in opts) {
      ropts[opt] = opts[opt];
    }

    request(ropts, function(err, response) {
      if (err) {
        reject(err);
      }
      else {
        resolve(response);
      }
    })
  })
}


// exports login Promise;
module.exports = function(opts) {
  return new Promise(function(resolve, reject) {
    opts = opts || {};

    var username = opts.username;
    var password = opts.password;
    var bungieopts = {};

    if (!username || !password) {
      throw new Error("username or password not set!");
    }
  
    bungieopts.method = "GET";
    bungieopts.url = BUNGIE_SIGNIN_URI;
    bungieopts.jar = cjar;

    req(bungieopts).then(function(response) {
      var postopts = {};
      
      postopts.method = "POST";
      postopts.url = PSN_OAUTH_URI;
      postopts.form = {};
      postopts.form.j_username = username;
      postopts.form.j_password = password;
      postopts.jar = cjar;

      return req(postopts);

    }).then(function(response) {
      var getopts = {};
  
      getopts.method = "GET";
      getopts.url = response.headers['location'];
      getopts.followRedirect = false;
      getopts.jar = cjar;

      return req(getopts);

    }).then(function(response) {
      var grantCode = response.headers['x-np-grant-code'];
      var getopts = {};

      getopts.method = "GET";
      getopts.url = BUNGIE_SIGNIN_URI;
      getopts.qs = {};
      getopts.qs.code = grantCode;
      getopts.jar = cjar;

      return req(getopts);

    }).then(function(response) {
      var cookies = cjar.getCookies(BUNGIE_SIGNIN_URI);
      var out = {};
      var bungled;
      var bungleatk;

      for (var i = 0; i < cookies.length; i++) {
        if (cookies[i].key === "bungled") {
          bungled = cookies[i].value;
        }
        else if (cookies[i].key === "bungleatk") {
          bungleatk = cookies[i].value;
        }

        if (bungled && bungleatk) {
          break;
        }
      }
      
      out.cjar = cjar;
      out.bungled = bungled;
      out.bungleatk = bungleatk;
      
      // resolve and forward credentials
      // for subsequent requests
      resolve(out);

    }).catch(function(err) {
      reject(err);
    })
  })
}