loopback/lib/models/access-token.js

185 lines
3.9 KiB
JavaScript
Raw Normal View History

2013-07-02 23:51:38 +00:00
/**
* Module Dependencies.
*/
2013-07-16 17:49:25 +00:00
var Model = require('../loopback').Model
, loopback = require('../loopback')
, assert = require('assert')
2013-11-14 21:01:47 +00:00
, crypto = require('crypto')
2013-11-14 23:27:36 +00:00
, uid = require('uid2')
, DEFAULT_TTL = 1209600 // 2 weeks in seconds
2013-11-15 04:19:46 +00:00
, DEFAULT_TOKEN_LEN = 64
2013-12-10 23:57:55 +00:00
, Role = require('./role').Role
2013-11-15 04:19:46 +00:00
, ACL = require('./acl').ACL;
2013-07-02 23:51:38 +00:00
/**
2013-11-13 19:49:08 +00:00
* Default AccessToken properties.
2013-07-02 23:51:38 +00:00
*/
var properties = {
2013-10-04 22:51:48 +00:00
id: {type: String, generated: true, id: 1},
ttl: {type: Number, ttl: true, default: DEFAULT_TTL}, // time to live in seconds
created: {type: Date, default: function() {
return new Date();
}}
2013-07-02 23:51:38 +00:00
};
/**
2013-07-16 17:49:25 +00:00
* Extends from the built in `loopback.Model` type.
2013-07-02 23:51:38 +00:00
*/
2013-12-10 23:57:55 +00:00
var AccessToken = module.exports = Model.extend('AccessToken', properties, {
acls: [
{
principalType: ACL.ROLE,
principalId: Role.EVERYONE,
permission: 'DENY'
},
{
principalType: ACL.ROLE,
principalId: Role.EVERYONE,
property: 'create',
permission: 'ALLOW'
}
]
});
AccessToken.ANONYMOUS = new AccessToken({id: '$anonymous'});
2013-07-12 22:47:58 +00:00
/**
2013-11-13 19:49:08 +00:00
* Create a cryptographically random access token id.
2013-07-12 22:47:58 +00:00
*
* @param {Function} callback
*/
2013-11-13 19:49:08 +00:00
AccessToken.createAccessTokenId = function (fn) {
2013-11-14 23:27:36 +00:00
uid(this.settings.accessTokenIdLength || DEFAULT_TOKEN_LEN, function(err, guid) {
2013-07-12 22:47:58 +00:00
if(err) {
fn(err);
} else {
2013-11-14 23:27:36 +00:00
fn(null, guid);
2013-07-12 22:47:58 +00:00
}
});
}
/*!
2013-11-13 19:49:08 +00:00
* Hook to create accessToken id.
2013-07-12 22:47:58 +00:00
*/
2013-11-13 19:49:08 +00:00
AccessToken.beforeCreate = function (next, data) {
2013-07-12 22:47:58 +00:00
data = data || {};
2013-11-13 19:49:08 +00:00
AccessToken.createAccessTokenId(function (err, id) {
2013-07-12 22:47:58 +00:00
if(err) {
next(err);
} else {
data.id = id;
2013-11-15 00:47:24 +00:00
2013-07-12 22:47:58 +00:00
next();
}
});
2013-11-11 21:35:54 +00:00
}
2013-11-14 21:01:47 +00:00
/**
* Find a token for the given `ServerRequest`.
*
* @param {ServerRequest} req
* @param {Object} [options] Options for finding the token
* @param {Function} callback Calls back with a token if one exists otherwise null or an error.
*/
AccessToken.findForRequest = function(req, options, cb) {
var id = tokenIdForRequest(req, options);
if(id) {
this.findById(id, function(err, token) {
if(err) {
cb(err);
} else {
token.validate(function(err, isValid) {
if(err) {
cb(err);
} else if(isValid) {
cb(null, token);
} else {
cb(new Error('Invalid Access Token'));
}
});
}
});
2013-11-14 21:01:47 +00:00
} else {
process.nextTick(function() {
cb();
});
}
}
AccessToken.prototype.validate = function(cb) {
try {
assert(
this.created && typeof this.created.getTime === 'function',
'token.created must be a valid Date'
);
assert(this.ttl !== 0, 'token.ttl must be not be 0');
assert(this.ttl, 'token.ttl must exist');
assert(this.ttl >= -1, 'token.ttl must be >= -1');
var now = Date.now();
var created = this.created.getTime();
var elapsedSeconds = (now - created) / 1000;
var secondsToLive = this.ttl;
var isValid = elapsedSeconds < secondsToLive;
if(isValid) {
cb(null, isValid);
} else {
this.destroy(function(err) {
cb(err, isValid);
});
}
} catch(e) {
cb(e);
}
}
2013-11-14 21:01:47 +00:00
function tokenIdForRequest(req, options) {
var params = options.params || [];
var headers = options.headers || [];
var cookies = options.cookies || [];
var i = 0;
var length;
var id;
params.push('access_token');
headers.push('X-Access-Token');
headers.push('authorization');
cookies.push('access_token');
cookies.push('authorization');
for(length = params.length; i < length; i++) {
id = req.param(params[i]);
if(typeof id === 'string') {
return id;
}
}
2013-11-14 23:27:36 +00:00
for(i = 0, length = headers.length; i < length; i++) {
id = req.header(headers[i]);
2013-11-14 21:01:47 +00:00
if(typeof id === 'string') {
return id;
}
}
2013-11-14 23:27:36 +00:00
for(i = 0, length = headers.length; i < length; i++) {
id = req.signedCookies[cookies[i]];
2013-11-14 21:01:47 +00:00
if(typeof id === 'string') {
return id;
}
}
return null;
}