update ddns, update oauth3
This commit is contained in:
		
							parent
							
								
									75b9a0e2b3
								
							
						
					
					
						commit
						f99ce93430
					
				@ -1,90 +0,0 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var PromiseA = require('bluebird').Promise;
 | 
			
		||||
var https = require('https');
 | 
			
		||||
var fs = PromiseA.promisifyAll(require('fs'));
 | 
			
		||||
 | 
			
		||||
module.exports.update = function (opts) {
 | 
			
		||||
  return new PromiseA(function (resolve, reject) {
 | 
			
		||||
    var options;
 | 
			
		||||
    var hostname = opts.hostname || opts.updater;
 | 
			
		||||
    var port = opts.port;
 | 
			
		||||
    var pathname = opts.pathname;
 | 
			
		||||
    var req;
 | 
			
		||||
 | 
			
		||||
    if (!hostname) {
 | 
			
		||||
      throw new Error('Please specify a DDNS host as opts.hostname');
 | 
			
		||||
    }
 | 
			
		||||
    if (!pathname) {
 | 
			
		||||
      throw new Error('Please specify the api route as opts.pathname');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    options = {
 | 
			
		||||
      host: hostname
 | 
			
		||||
    , port: port
 | 
			
		||||
    , method: 'POST'
 | 
			
		||||
    , headers: {
 | 
			
		||||
        'Content-Type': 'application/json'
 | 
			
		||||
      }
 | 
			
		||||
    , path: pathname
 | 
			
		||||
    //, auth: opts.auth || 'admin:secret'
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (opts.cacert) {
 | 
			
		||||
      if (!Array.isArray(opts.cacert)) {
 | 
			
		||||
        opts.cacert = [opts.cacert];
 | 
			
		||||
      }
 | 
			
		||||
      options.ca = opts.cacert;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (opts.token || opts.jwt) {
 | 
			
		||||
      options.headers.Authorization = 'Bearer ' + (opts.token || opts.jwt);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (false === opts.cacert) {
 | 
			
		||||
      options.rejectUnauthorized = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    options.ca = (options.ca||[]).map(function (str) {
 | 
			
		||||
      if ('string' === typeof str && str.length < 1000) {
 | 
			
		||||
        str = fs.readFileAsync(str);
 | 
			
		||||
      }
 | 
			
		||||
      return str;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return PromiseA.all(options.ca).then(function (cas) {
 | 
			
		||||
      options.ca = cas;
 | 
			
		||||
      options.agent = new https.Agent(options);
 | 
			
		||||
 | 
			
		||||
      req = https.request(options, function(res) {
 | 
			
		||||
        var textData = '';
 | 
			
		||||
 | 
			
		||||
        res.on('error', function (err) {
 | 
			
		||||
          reject(err);
 | 
			
		||||
        });
 | 
			
		||||
        res.on('data', function (chunk) {
 | 
			
		||||
          textData += chunk.toString();
 | 
			
		||||
          // console.log(chunk.toString());
 | 
			
		||||
        });
 | 
			
		||||
        res.on('end', function () {
 | 
			
		||||
          var err;
 | 
			
		||||
          try {
 | 
			
		||||
            resolve(JSON.parse(textData));
 | 
			
		||||
          } catch(e) {
 | 
			
		||||
            err = new Error("Unparsable Server Response");
 | 
			
		||||
            err.code = 'E_INVALID_SERVER_RESPONSE';
 | 
			
		||||
            err.data = textData;
 | 
			
		||||
            reject(err);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      req.on('error', function (err) {
 | 
			
		||||
        reject(err);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      req.end(JSON.stringify(opts.ddns, null, '  '));
 | 
			
		||||
    }, reject);
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var updateIp = require('../holepunch/helpers/update-ip.js').update;
 | 
			
		||||
var updateIp = require('ddns-cli').update;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @param {string[]} hostnames - A list of hostnames
 | 
			
		||||
 | 
			
		||||
@ -129,55 +129,5 @@ function touch(conf, state) {
 | 
			
		||||
  */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  //var config = require('./device.json');
 | 
			
		||||
 | 
			
		||||
  // require('ssl-root-cas').inject();
 | 
			
		||||
  // TODO try SNI loopback.example.com as result of api.ipify.com with loopback token
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
  function phoneHome() {
 | 
			
		||||
    var holepunch = require('./holepunch/beacon');
 | 
			
		||||
    var ports;
 | 
			
		||||
 | 
			
		||||
    ports = [
 | 
			
		||||
      { private: 65022
 | 
			
		||||
      , public: 65022
 | 
			
		||||
      , protocol: 'tcp'
 | 
			
		||||
      , ttl: 0
 | 
			
		||||
      , test: { service: 'ssh' }
 | 
			
		||||
      , testable: false
 | 
			
		||||
      }
 | 
			
		||||
    , { private: 650443
 | 
			
		||||
      , public: 650443
 | 
			
		||||
      , protocol: 'tcp'
 | 
			
		||||
      , ttl: 0
 | 
			
		||||
      , test: { service: 'https' }
 | 
			
		||||
      }
 | 
			
		||||
    , { private: 65080
 | 
			
		||||
      , public: 65080
 | 
			
		||||
      , protocol: 'tcp'
 | 
			
		||||
      , ttl: 0
 | 
			
		||||
      , test: { service: 'http' }
 | 
			
		||||
      }
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // TODO return a middleware
 | 
			
		||||
    holepunch.run(require('./redirects.json').reduce(function (all, redirect) {
 | 
			
		||||
      if (!all[redirect.from.hostname]) {
 | 
			
		||||
        all[redirect.from.hostname] = true;
 | 
			
		||||
        all.push(redirect.from.hostname);
 | 
			
		||||
      }
 | 
			
		||||
      if (!all[redirect.to.hostname]) {
 | 
			
		||||
        all[redirect.to.hostname] = true;
 | 
			
		||||
        all.push(redirect.to.hostname);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return all;
 | 
			
		||||
    }, []), ports).catch(function () {
 | 
			
		||||
      console.error("Couldn't phone home. Oh well");
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
module.exports.init = init;
 | 
			
		||||
module.exports.touch = touch;
 | 
			
		||||
 | 
			
		||||
@ -1,407 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var PromiseA = require('bluebird');
 | 
			
		||||
 | 
			
		||||
module.exports.inject = function (conf, app, pkgConf, pkgDeps) {
 | 
			
		||||
  var scoper = require('app-scoped-ids');
 | 
			
		||||
  var inProcessCache = {};
 | 
			
		||||
  var createClientFactory = require('sqlite3-cluster/client').createClientFactory;
 | 
			
		||||
  var dir = [
 | 
			
		||||
    { tablename: 'codes'
 | 
			
		||||
    , idname: 'uuid'
 | 
			
		||||
    , indices: ['createdAt']
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'logins' // coolaj86, coolaj86@gmail.com, +1-317-426-6525
 | 
			
		||||
    , idname: 'hashId'
 | 
			
		||||
    //, relations: [{ tablename: 'secrets', id: 'hashid', fk: 'loginId' }]
 | 
			
		||||
    , indices: ['createdAt', 'type', 'node']
 | 
			
		||||
    //, immutable: false
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'verifications'
 | 
			
		||||
    , idname: 'hashId' // hash(date + node)
 | 
			
		||||
    //, relations: [{ tablename: 'secrets', id: 'hashid', fk: 'loginId' }]
 | 
			
		||||
    , indices: ['createdAt', 'nodeId']
 | 
			
		||||
    //, immutable: true
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'secrets'
 | 
			
		||||
    , idname: 'hashId' // hash(node + secret)
 | 
			
		||||
    , indices: ['createdAt']
 | 
			
		||||
    //, immutable: true
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'recoveryNodes' // just for 1st-party logins
 | 
			
		||||
    , idname: 'hashId' //
 | 
			
		||||
      // TODO how transmit that something should be deleted / disabled?
 | 
			
		||||
    , indices: ['createdAt', 'updatedAt', 'loginHash', 'recoveryNode', 'deleted']
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Accounts
 | 
			
		||||
    //
 | 
			
		||||
  , { tablename: 'accounts_logins'
 | 
			
		||||
    , idname: 'id' // hash(accountId + loginId)
 | 
			
		||||
    , indices: ['createdAt', 'revokedAt', 'loginId', 'accountId']
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'accounts'
 | 
			
		||||
    , idname: 'id' // crypto random id? or hash(name) ?
 | 
			
		||||
    , unique: ['name']
 | 
			
		||||
    , indices: ['createdAt', 'updatedAt', 'deletedAt', 'name', 'displayName']
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // OAuth3
 | 
			
		||||
    //
 | 
			
		||||
  , { tablename: 'private_key'
 | 
			
		||||
    , idname: 'id'
 | 
			
		||||
    , indices: ['createdAt']
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'oauth_clients'
 | 
			
		||||
    , idname: 'id'
 | 
			
		||||
    , indices: ['createdAt', 'updatedAt', 'accountId']
 | 
			
		||||
    , hasMany: ['apiKeys'] // TODO
 | 
			
		||||
    , belongsTo: ['account']
 | 
			
		||||
    , schema: function () {
 | 
			
		||||
        return {
 | 
			
		||||
          test: true
 | 
			
		||||
        , insecure: true
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'api_keys'
 | 
			
		||||
    , idname: 'id'
 | 
			
		||||
    , indices: ['createdAt', 'updatedAt', 'oauthClientId']
 | 
			
		||||
    , belongsTo: ['oauthClient'] // TODO pluralization
 | 
			
		||||
    , schema: function () {
 | 
			
		||||
        return {
 | 
			
		||||
          test: true
 | 
			
		||||
        , insecure: true
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'tokens' // note that a token functions as a session
 | 
			
		||||
    , idname: 'id'
 | 
			
		||||
    , indices: ['createdAt', 'updatedAt', 'expiresAt', 'revokedAt', 'oauthClientId', 'loginId', 'accountId']
 | 
			
		||||
    }
 | 
			
		||||
  , { tablename: 'grants'
 | 
			
		||||
    , idname: 'id' // sha256(scope + oauthClientId + (accountId || loginId))
 | 
			
		||||
    , indices: ['createdAt', 'updatedAt', 'oauthClientId', 'loginId', 'accountId']
 | 
			
		||||
    }
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  function getAppScopedControllers(experienceId) {
 | 
			
		||||
    if (inProcessCache[experienceId]) {
 | 
			
		||||
      return PromiseA.resolve(inProcessCache[experienceId]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var mq = require('masterquest');
 | 
			
		||||
    var path = require('path');
 | 
			
		||||
    // TODO how can we encrypt this?
 | 
			
		||||
    var systemFactory = createClientFactory({
 | 
			
		||||
      // TODO only complain if the values are different
 | 
			
		||||
        algorithm: 'aes'
 | 
			
		||||
      , bits: 128
 | 
			
		||||
      , mode: 'cbc'
 | 
			
		||||
      , dirname: path.join(__dirname, '..', '..', 'var') // TODO info.conf
 | 
			
		||||
      //, prefix: appname.replace(/\//g, ':') // 'com.example.'
 | 
			
		||||
      //, dbname: 'cluster'
 | 
			
		||||
      , suffix: ''
 | 
			
		||||
      , ext: '.sqlcipher'
 | 
			
		||||
      , sock: conf.sqlite3Sock
 | 
			
		||||
      , ipcKey: conf.ipcKey
 | 
			
		||||
    });
 | 
			
		||||
    var clientFactory = createClientFactory({
 | 
			
		||||
    // TODO only complain if the values are different
 | 
			
		||||
      dirname: path.join(__dirname, '..', '..', 'var') // TODO info.conf
 | 
			
		||||
    , prefix: 'com.oauth3' // 'com.example.'
 | 
			
		||||
    //, dbname: 'config'
 | 
			
		||||
    , suffix: ''
 | 
			
		||||
    , ext: '.sqlite3'
 | 
			
		||||
    , sock: conf.sqlite3Sock
 | 
			
		||||
    , ipcKey: conf.ipcKey
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    inProcessCache[experienceId] = systemFactory.create({
 | 
			
		||||
      init: true
 | 
			
		||||
    //, key: '00000000000000000000000000000000'
 | 
			
		||||
    , dbname: experienceId // 'com.example.'
 | 
			
		||||
    }).then(function (sqlStore) {
 | 
			
		||||
      //var db = factory.
 | 
			
		||||
      return mq.wrap(sqlStore, dir).then(function (models) {
 | 
			
		||||
        return require('./oauthclient-microservice/lib/sign-token').create(models.PrivateKey).init().then(function (signer) {
 | 
			
		||||
          var CodesCtrl = require('authcodes').create(models.Codes);
 | 
			
		||||
          /* models = { Logins, Verifications } */
 | 
			
		||||
          var LoginsCtrl = require('./authentication-microservice/lib/logins').create({}, CodesCtrl, models);
 | 
			
		||||
          /* models = { ApiKeys, OauthClients } */
 | 
			
		||||
          var ClientsCtrl = require('./oauthclient-microservice/lib/oauthclients').createController({}, models, signer);
 | 
			
		||||
 | 
			
		||||
          return {
 | 
			
		||||
            Codes: CodesCtrl
 | 
			
		||||
          , Logins: LoginsCtrl
 | 
			
		||||
          , Clients: ClientsCtrl
 | 
			
		||||
          , SqlFactory: clientFactory
 | 
			
		||||
          , models: models
 | 
			
		||||
          };
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    }).then(function (ctrls) {
 | 
			
		||||
      inProcessCache[experienceId] = ctrls;
 | 
			
		||||
      return ctrls;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return inProcessCache[experienceId];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //var jwsUtils = require('./lib/jws-utils').create(signer);
 | 
			
		||||
  var CORS = require('connect-cors');
 | 
			
		||||
  var cors = CORS({ credentials: true, headers: [
 | 
			
		||||
    'X-Requested-With'
 | 
			
		||||
  , 'X-HTTP-Method-Override'
 | 
			
		||||
  , 'Content-Type'
 | 
			
		||||
  , 'Accept'
 | 
			
		||||
  , 'Authorization'
 | 
			
		||||
  ], methods: [ "GET", "POST", "PATCH", "PUT", "DELETE" ] });
 | 
			
		||||
 | 
			
		||||
  // Allows CORS access to API with ?access_token=
 | 
			
		||||
  // TODO Access-Control-Max-Age: 600
 | 
			
		||||
  // TODO How can we help apps handle this? token?
 | 
			
		||||
  // TODO allow apps to configure trustedDomains, auth, etc
 | 
			
		||||
 | 
			
		||||
  //function weakDecipher(secret, val) { return require('./weak-crypt').weakDecipher(val, secret); }
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Generic Session / Login / Account Routes
 | 
			
		||||
  //
 | 
			
		||||
  function parseAccessToken(req, opts) {
 | 
			
		||||
    var token;
 | 
			
		||||
    var parts;
 | 
			
		||||
    var scheme;
 | 
			
		||||
    var credentials;
 | 
			
		||||
 | 
			
		||||
    if (req.headers && req.headers.authorization) {
 | 
			
		||||
      parts = req.headers.authorization.split(' ');
 | 
			
		||||
 | 
			
		||||
      if (parts.length !== 2) {
 | 
			
		||||
        return PromiseA.reject(new Error("malformed Authorization header"));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      scheme = parts[0];
 | 
			
		||||
      credentials = parts[1];
 | 
			
		||||
 | 
			
		||||
      if (-1 !== (opts && opts.schemes || ['token', 'bearer']).indexOf(scheme.toLowerCase())) {
 | 
			
		||||
        token = credentials;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (req.body && req.body.access_token) {
 | 
			
		||||
      if (token) { PromiseA.reject(new Error("token exists in header and body")); }
 | 
			
		||||
      token = req.body.access_token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO disallow query with req.method === 'GET'
 | 
			
		||||
    // (cookies should be used for protected static assets)
 | 
			
		||||
    if (req.query && req.query.access_token) {
 | 
			
		||||
      if (token) { PromiseA.reject(new Error("token already exists in either header or body and also in query")); }
 | 
			
		||||
      token = req.query.access_token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    err = new Error(challenge());
 | 
			
		||||
    err.code = 'E_BEARER_REALM';
 | 
			
		||||
 | 
			
		||||
    if (!token) { return PromiseA.reject(err); }
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    return PromiseA.resolve(token);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getClient(req, token, priv, Controllers) {
 | 
			
		||||
    if (!token) {
 | 
			
		||||
      token = req.oauth3.token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var cacheId = '_' + token.k + 'Client';
 | 
			
		||||
 | 
			
		||||
    if (priv[cacheId]) {
 | 
			
		||||
      return PromiseA.resolve(priv[cacheId]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO could get client directly by token.app (id of client)
 | 
			
		||||
    priv[cacheId] = Controllers.Clients.login(null, token.k).then(function (apiKey) {
 | 
			
		||||
      if (!apiKey) {
 | 
			
		||||
        return PromiseA.reject(new Error("Client no longer valid"));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      priv[cacheId + 'Key'] = apiKey;
 | 
			
		||||
      priv[cacheId] = apiKey.oauthClient;
 | 
			
		||||
 | 
			
		||||
      return apiKey.oauthClient;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return priv[cacheId];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getAccountsByLogin(req, token, priv, Controllers, loginId, decrypt) {
 | 
			
		||||
    return getClient(req, req.oauth.token, priv).then(function (oauthClient) {
 | 
			
		||||
      if (decrypt) {
 | 
			
		||||
        loginId = scoper.unscope(loginId, oauthClient.secret);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return Controllers.models.AccountsLogins.find({ loginId: loginId }).then(function (accounts) {
 | 
			
		||||
        return PromiseA.all(accounts.map(function (obj) {
 | 
			
		||||
          return Controllers.models.Accounts.get(obj.accountId)/*.then(function (account) {
 | 
			
		||||
            account.appScopedId = weakCipher(oauthClient.secret, account.id);
 | 
			
		||||
            return account;
 | 
			
		||||
          })*/;
 | 
			
		||||
        }));
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getAccountsByArray(req, Controllers, arr) {
 | 
			
		||||
    return PromiseA.all(arr.map(function (accountId) {
 | 
			
		||||
      return Controllers.models.Accounts.get(accountId.id || accountId);
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getAccounts(req, token, priv, Controllers) {
 | 
			
		||||
    if (!token) {
 | 
			
		||||
      token = req.oauth3.token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var err;
 | 
			
		||||
 | 
			
		||||
    if (priv._accounts) {
 | 
			
		||||
      return PromiseA.resolve(priv._accounts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((req.oauth3.token.idx || req.oauth3.token.usr) && ('password' === req.oauth3.token.grt || 'login' === req.oauth3.token.as)) {
 | 
			
		||||
      priv._accounts = getAccountsByLogin(req, req.oauth3.token, priv, Controllers, (req.oauth3.token.idx || req.oauth3.token.usr), !!req.oauth3.token.idx);
 | 
			
		||||
    } else if (req.oauth3.token.axs && req.oauth3.token.axs.length || req.oauth3.token.acx) {
 | 
			
		||||
      req.oauth3._accounts = getAccountsByArray(req, Controllers, req.oauth3.token.axs && req.oauth3.token.axs.length && req.oauth3.token.axs || [req.oauth3.token.acx]);
 | 
			
		||||
    } else {
 | 
			
		||||
      err = new Error("neither login nor accounts were specified");
 | 
			
		||||
      err.code = "E_NO_AUTHZ";
 | 
			
		||||
      req.oauth3._accounts = PromiseA.reject(err);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    req.oauth3._accounts.then(function (accounts) {
 | 
			
		||||
      req.oauth3._accounts = accounts;
 | 
			
		||||
 | 
			
		||||
      return accounts;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return req.oauth3._accounts;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getLoginId(req, token, priv/*, Controllers*/) {
 | 
			
		||||
    if (!token) {
 | 
			
		||||
      token = req.oauth3.token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var cacheId = '_' + token.idx + 'LoginId';
 | 
			
		||||
 | 
			
		||||
    if (priv[cacheId]) {
 | 
			
		||||
      return PromiseA.resolve(priv[cacheId]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO
 | 
			
		||||
    // this ends up defeating part of the purpose of JWT (few database calls)
 | 
			
		||||
    // perhaps the oauthClient secret should be sent, encrypted with a master key,
 | 
			
		||||
    // with the request? Or just mash the oauthClient secret with the loginId
 | 
			
		||||
    // and encrypt with the master key?
 | 
			
		||||
    priv._loginId = getClient(req, token, priv).then(function (oauthClient) {
 | 
			
		||||
      var loginId;
 | 
			
		||||
 | 
			
		||||
      if (token.idx) {
 | 
			
		||||
        loginId = scoper.unscope(token.idx, oauthClient.secret);
 | 
			
		||||
      } else {
 | 
			
		||||
        loginId = token.usr;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      priv[cacheId] = loginId;
 | 
			
		||||
 | 
			
		||||
      return loginId;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return priv[cacheId];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getLogin(req, token, priv, Controllers) {
 | 
			
		||||
    if (!token) {
 | 
			
		||||
      token = req.oauth3.token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var cacheId = '_' + token.idx + 'Login';
 | 
			
		||||
 | 
			
		||||
    if (priv[cacheId]) {
 | 
			
		||||
      return PromiseA.resolve(priv[cacheId]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    priv[cacheId] = getLoginId(req, token, priv).then(function (loginId) {
 | 
			
		||||
      // DB.Logins.get(hashId)
 | 
			
		||||
      return Controllers.Logins.rawGet(loginId).then(function (login) {
 | 
			
		||||
        priv[cacheId] = login;
 | 
			
		||||
 | 
			
		||||
        return login;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return priv[cacheId];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function attachOauth3(req, res, next) {
 | 
			
		||||
    var privs = {};
 | 
			
		||||
    req.oauth3 = {};
 | 
			
		||||
 | 
			
		||||
    getAppScopedControllers(req.experienceId).then(function (Controllers) {
 | 
			
		||||
 | 
			
		||||
      return parseAccessToken(req).then(function (token) {
 | 
			
		||||
        if (!token) {
 | 
			
		||||
          next();
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var jwt = require('jsonwebtoken');
 | 
			
		||||
        var data = jwt.decode(token);
 | 
			
		||||
        var err;
 | 
			
		||||
 | 
			
		||||
        if (!data) {
 | 
			
		||||
          err = new Error('not a json web token');
 | 
			
		||||
          err.code = 'E_NOT_JWT';
 | 
			
		||||
          res.send({
 | 
			
		||||
            error: err.code
 | 
			
		||||
          , error_description: err.message
 | 
			
		||||
          , error_url: 'https://oauth3.org/docs/errors#' + (err.code || 'E_UNKNOWN_EXCEPTION')
 | 
			
		||||
          });
 | 
			
		||||
          // PromiseA.reject(err);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        req.oauth3.token = token;
 | 
			
		||||
 | 
			
		||||
        req.oauth3.getLoginId = function (token) {
 | 
			
		||||
          getLoginId(req, token || req.oauth3.token, privs, Controllers);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        req.oauth3.getLogin = function (token) {
 | 
			
		||||
          getLogin(req, token || req.oauth3.token, privs, Controllers);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // TODO modify prototypes?
 | 
			
		||||
        req.oauth3.getClient = function (token) {
 | 
			
		||||
          getClient(req, token || req.oauth3.token, privs, Controllers);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // TODO req.oauth3.getAccountIds
 | 
			
		||||
        req.oauth3.getAccounts = function (token) {
 | 
			
		||||
          getAccounts(req, token || req.oauth3.token, privs, Controllers);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        next();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  app.use('/', cors);
 | 
			
		||||
 | 
			
		||||
  app.use('/', attachOauth3);
 | 
			
		||||
};
 | 
			
		||||
@ -104,7 +104,7 @@ function loadPages(pkgConf, packagedPage, req, res, next) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getApi(conf, pkgConf, pkgDeps, packagedApi) {
 | 
			
		||||
  var PromiseA = require('bluebird');
 | 
			
		||||
  var PromiseA = pkgDeps.Promise;
 | 
			
		||||
  var path = require('path');
 | 
			
		||||
  var pkgpath = path.join(pkgConf.apipath, packagedApi.id/*, (packagedApi.api.version || '')*/);
 | 
			
		||||
 | 
			
		||||
@ -155,7 +155,9 @@ function getApi(conf, pkgConf, pkgDeps, packagedApi) {
 | 
			
		||||
      packagedApi._api = require('express-lazy')();
 | 
			
		||||
      packagedApi._api_app = myApp;
 | 
			
		||||
 | 
			
		||||
      require('./oauth3-auth').inject(conf, packagedApi._api, pkgConf, pkgDeps);
 | 
			
		||||
      pkgDeps.getOauth3Controllers =
 | 
			
		||||
      packagedApi._getOauth3Controllers = require('oauthcommon/example-oauthmodels').create(conf).getControllers;
 | 
			
		||||
      require('oauthcommon').inject(packagedApi._getOauth3Controllers, packagedApi._api, pkgConf, pkgDeps);
 | 
			
		||||
 | 
			
		||||
      // DEBUG
 | 
			
		||||
      //
 | 
			
		||||
@ -245,16 +247,18 @@ function layerItUp(pkgConf, router, req, res, next) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function runApi(opts, router, req, res, next) {
 | 
			
		||||
  var path = require('path');
 | 
			
		||||
  var pkgConf = opts.config;
 | 
			
		||||
  var pkgDeps = opts.deps;
 | 
			
		||||
  //var Services = opts.Services;
 | 
			
		||||
  var packagedApi;
 | 
			
		||||
  var pathname;
 | 
			
		||||
 | 
			
		||||
  // TODO compile packagesMap
 | 
			
		||||
  // TODO people may want to use the framework in a non-framework way (i.e. to conceal the module name)
 | 
			
		||||
  router.packagedApis.some(function (_packagedApi) {
 | 
			
		||||
    // console.log('[DEBUG _packagedApi.id]', _packagedApi.id);
 | 
			
		||||
    var pathname = router.pathname;
 | 
			
		||||
    pathname = router.pathname;
 | 
			
		||||
    if ('/' === pathname) {
 | 
			
		||||
      pathname = '';
 | 
			
		||||
    }
 | 
			
		||||
@ -284,7 +288,7 @@ function runApi(opts, router, req, res, next) {
 | 
			
		||||
    // TODO this identifier may need to be non-deterministic as to transfer if a domain name changes but is still the "same" app
 | 
			
		||||
    // (i.e. a company name change. maybe auto vs manual register - just like oauth3?)
 | 
			
		||||
    // NOTE: probably best to alias the name logically
 | 
			
		||||
  , value: (req.hostname + req.pathname).replace(/\/$/, '')
 | 
			
		||||
  , value: (path.join(req.hostname, pathname || '')).replace(/\/$/, '')
 | 
			
		||||
  });
 | 
			
		||||
  Object.defineProperty(req, 'escapedExperienceId', {
 | 
			
		||||
    enumerable: true
 | 
			
		||||
 | 
			
		||||
@ -193,6 +193,7 @@ module.exports.create = function (webserver, info, state) {
 | 
			
		||||
        , Promise: PromiseA
 | 
			
		||||
        , express: express
 | 
			
		||||
        , app: app
 | 
			
		||||
        //, oauthmodels: require('oauthcommon/example-oauthmodels').create(info.conf)
 | 
			
		||||
        };
 | 
			
		||||
        var Services = require('./services-loader').create(pkgConf, {
 | 
			
		||||
          memstore: memstore
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,7 @@
 | 
			
		||||
    "cookie-session": "1.x",
 | 
			
		||||
    "cookie-signature": "^1.0.6",
 | 
			
		||||
    "crc": "^3.2.1",
 | 
			
		||||
    "masterquest-sqlite3": "git://github.com/coolaj86/masterquest-sqlite3.git",
 | 
			
		||||
    "ddns-cli": "^1.2.1",
 | 
			
		||||
    "debug": "^2.1.3",
 | 
			
		||||
    "depd": "^1.0.0",
 | 
			
		||||
    "destroy": "^1.0.3",
 | 
			
		||||
@ -81,6 +81,7 @@
 | 
			
		||||
    "json-storage": "2.x",
 | 
			
		||||
    "jsonwebtoken": "^5.4.0",
 | 
			
		||||
    "lodash": "2.x",
 | 
			
		||||
    "masterquest-sqlite3": "git://github.com/coolaj86/masterquest-sqlite3.git",
 | 
			
		||||
    "media-typer": "^0.3.0",
 | 
			
		||||
    "methods": "^1.1.1",
 | 
			
		||||
    "mime": "^1.3.4",
 | 
			
		||||
@ -104,7 +105,7 @@
 | 
			
		||||
    "request": "2.44.0",
 | 
			
		||||
    "request-ip": "^1.1.1",
 | 
			
		||||
    "scmp": "1.x",
 | 
			
		||||
    "secret-utils": "1.x",
 | 
			
		||||
    "secret-utils": "^2.0.0",
 | 
			
		||||
    "semver": "^4.3.1",
 | 
			
		||||
    "send": "^0.12.2",
 | 
			
		||||
    "serve-favicon": "2.x",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user