diff --git a/lib/application.js b/lib/application.js index a82332df..590b83ab 100644 --- a/lib/application.js +++ b/lib/application.js @@ -79,6 +79,14 @@ app.model = function (Model, config) { return Model; } +/** + * Get a Model by name. + */ + +app.getModel = function (modelName) { + this.models +}; + /** * Get all exposed models. */ diff --git a/lib/loopback.js b/lib/loopback.js index 418abe98..423a3f99 100644 --- a/lib/loopback.js +++ b/lib/loopback.js @@ -172,5 +172,5 @@ loopback.memory = function (name) { loopback.Model = require('./models/model'); loopback.Email = require('./models/email'); loopback.User = require('./models/user'); -loopback.Session = require('./models/session'); loopback.Application = require('./models/application'); +loopback.AccessToken = require('./models/access-token'); diff --git a/lib/middleware/token.js b/lib/middleware/token.js new file mode 100644 index 00000000..c642c84a --- /dev/null +++ b/lib/middleware/token.js @@ -0,0 +1,28 @@ +/** + * Module dependencies. + */ + +var loopback = require('../loopback'); +var RemoteObjects = require('strong-remoting'); + +/** + * Export the middleware. + */ + +module.exports = token; + +/** + * + */ + +function token(app, options) { + options = options || {}; + var tokenModelName = options.tokenModelName || 'Token'; + var TokenModel = app.getModel(tokenModelName); + var tokenHeaderName = options.tokenHeaderName || 'X-Access-Token'; + + return function (req, res, next) { + next(); + } +} + diff --git a/lib/models/session.js b/lib/models/access-token.js similarity index 57% rename from lib/models/session.js rename to lib/models/access-token.js index 9099db1a..df8a95ab 100644 --- a/lib/models/session.js +++ b/lib/models/access-token.js @@ -7,7 +7,7 @@ var Model = require('../loopback').Model , crypto = require('crypto'); /** - * Default Session properties. + * Default AccessToken properties. */ var properties = { @@ -20,16 +20,16 @@ var properties = { * Extends from the built in `loopback.Model` type. */ -var Session = module.exports = Model.extend('Session', properties); +var AccessToken = module.exports = Model.extend('access-token', properties); /** - * Create a cryptographically random session id. + * Create a cryptographically random access token id. * * @param {Function} callback */ -Session.createSessionId = function (fn) { - crypto.randomBytes(this.settings.sessionIdLength || 64, function(err, buf) { +AccessToken.createAccessTokenId = function (fn) { + crypto.randomBytes(this.settings.accessTokenIdLength || 64, function(err, buf) { if(err) { fn(err); } else { @@ -39,13 +39,13 @@ Session.createSessionId = function (fn) { } /*! - * Hook to create session id. + * Hook to create accessToken id. */ -Session.beforeCreate = function (next, data) { +AccessToken.beforeCreate = function (next, data) { data = data || {}; - Session.createSessionId(function (err, id) { + AccessToken.createAccessTokenId(function (err, id) { if(err) { next(err); } else { diff --git a/lib/models/index.js b/lib/models/index.js index 1ab7d7f4..295acccd 100644 --- a/lib/models/index.js +++ b/lib/models/index.js @@ -1,7 +1,7 @@ exports.Model = require('./model'); exports.Email = require('./email'); exports.User = require('./user'); -exports.Session = require('./session'); +exports.AccessToken = require('./access-token'); exports.Application = require('./application'); exports.ACL = require('./acl'); diff --git a/lib/models/user.js b/lib/models/user.js index 581262be..dc4685a4 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -50,8 +50,8 @@ var User = module.exports = Model.extend('User', properties); /** * Login a user by with the given `credentials`. * - * User.login({username: 'foo', password: 'bar'}, function (err, session) { - * console.log(session.id); + * User.login({username: 'foo', password: 'bar'}, function (err, token) { + * console.log(token.id); * }); * * @param {Object} credentials @@ -79,7 +79,7 @@ User.login = function (credentials, fn) { if(err) { fn(defaultError); } else if(isMatch) { - createSession(user, fn); + createAccessToken(user, fn); } else { fn(defaultError); } @@ -89,41 +89,41 @@ User.login = function (credentials, fn) { } }); - function createSession(user, fn) { - var Session = UserCtor.session; + function createAccessToken(user, fn) { + var AccessToken = UserCtor.accessToken; - Session.create({uid: user.id}, function (err, session) { + AccessToken.create({uid: user.id}, function (err, accessToken) { if(err) { fn(err); } else { - fn(null, session) + fn(null, accessToken) } }); } } /** - * Logout a user with the given session id. + * Logout a user with the given accessToken id. * * User.logout('asd0a9f8dsj9s0s3223mk', function (err) { * console.log(err || 'Logged out'); * }); * - * @param {String} sessionID + * @param {String} accessTokenID */ User.logout = function (sid, fn) { var UserCtor = this; - var Session = UserCtor.settings.session || loopback.Session; + var AccessToken = UserCtor.settings.accessToken || loopback.AccessToken; - Session.findById(sid, function (err, session) { + AccessToken.findById(sid, function (err, accessToken) { if(err) { fn(err); - } else if(session) { - session.destroy(fn); + } else if(accessToken) { + accessToken.destroy(fn); } else { - fn(new Error('could not find session')); + fn(new Error('could not find accessToken')); } }); } @@ -266,7 +266,7 @@ User.setup = function () { accepts: [ {arg: 'credentials', type: 'object', required: true, http: {source: 'body'}} ], - returns: {arg: 'session', type: 'object', root: true}, + returns: {arg: 'accessToken', type: 'object', root: true}, http: {verb: 'post'} } ); @@ -305,7 +305,7 @@ User.setup = function () { // default models UserModel.email = require('./email'); - UserModel.session = require('./session'); + UserModel.accessToken = require('./access-token'); UserModel.validatesUniquenessOf('email', {message: 'Email already exists'}); var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; diff --git a/package.json b/package.json index d03d0bda..d8978bb0 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "nodemailer": "~0.4.4", "ejs": "~0.8.4", "bcryptjs": "~0.7.10", - "underscore.string": "~2.3.3" + "underscore.string": "~2.3.3", + "underscore": "~1.5.2" }, "devDependencies": { "blanket": "~1.1.5", diff --git a/test/access-token.test.js b/test/access-token.test.js new file mode 100644 index 00000000..f65a30e1 --- /dev/null +++ b/test/access-token.test.js @@ -0,0 +1,35 @@ +var loopback = require('../'); +var Token = loopback.AccessToken.extend('MyToken'); + +// attach Token to testing memory ds +Token.attachTo(loopback.memory()); + +describe('loopback.token(app, options)', function() { + beforeEach(createTestingToken); + + it('should populate req.token from the query string', function (done) { + var app = loopback(); + var options = {}; + var testToken = this.token; + app.use(loopback.token(app, options)); + app.get('/', function (req, res) { + assert(req.token === testToken); + res.send('ok'); + done(); + }); + + request(app) + .get('/?access_token=' + this.token.id) + .expect(200) + .end(done); + }); +}); + +function createTestingToken(done) { + var test = this; + Token.create({}, function (err, token) { + if(err) return done(err); + test.token = token; + done(); + }); +} \ No newline at end of file diff --git a/test/user.test.js b/test/user.test.js index e664c73a..a70c0047 100644 --- a/test/user.test.js +++ b/test/user.test.js @@ -1,5 +1,5 @@ var User = loopback.User.extend('user'); -var Session = loopback.Session; +var AccessToken = loopback.AccessToken; var passport = require('passport'); var MailConnector = require('../lib/connectors/mail'); @@ -15,7 +15,7 @@ describe('User', function(){ transports: [{type: 'STUB'}] }); User.attachTo(userMemory); - User.session.attachTo(userMemory); + User.accessToken.attachTo(userMemory); User.email.attachTo(mailDataSource); // allow many User.afterRemote's to be called @@ -30,7 +30,7 @@ describe('User', function(){ afterEach(function (done) { User.destroyAll(function (err) { - User.session.destroyAll(done); + User.accessToken.destroyAll(done); }); }); @@ -84,8 +84,8 @@ describe('User', function(){ it('Requires a password to login with basic auth', function(done) { User.create({email: 'b@c.com'}, function (err) { - User.login({email: 'b@c.com'}, function (err, session) { - assert(!session, 'should not create a session without a valid password'); + User.login({email: 'b@c.com'}, function (err, accessToken) { + assert(!accessToken, 'should not create a accessToken without a valid password'); assert(err, 'should not login without a password'); done(); }); @@ -100,10 +100,10 @@ describe('User', function(){ describe('User.login', function() { it('Login a user by providing credentials', function(done) { - User.login({email: 'foo@bar.com', password: 'bar'}, function (err, session) { - assert(session.uid); - assert(session.id); - assert.equal((new Buffer(session.id, 'base64')).length, 64); + User.login({email: 'foo@bar.com', password: 'bar'}, function (err, accessToken) { + assert(accessToken.uid); + assert(accessToken.id); + assert.equal((new Buffer(accessToken.id, 'base64')).length, 64); done(); }); @@ -117,11 +117,11 @@ describe('User', function(){ .send({email: 'foo@bar.com', password: 'bar'}) .end(function(err, res){ if(err) return done(err); - var session = res.body; + var accessToken = res.body; - assert(session.uid); - assert(session.id); - assert.equal((new Buffer(session.id, 'base64')).length, 64); + assert(accessToken.uid); + assert(accessToken.id); + assert.equal((new Buffer(accessToken.id, 'base64')).length, 64); done(); }); @@ -129,9 +129,9 @@ describe('User', function(){ it('Login should only allow correct credentials', function(done) { User.create({email: 'foo22@bar.com', password: 'bar'}, function(user, err) { - User.login({email: 'foo44@bar.com', password: 'bar'}, function(err, session) { + User.login({email: 'foo44@bar.com', password: 'bar'}, function(err, accessToken) { assert(err); - assert(!session); + assert(!accessToken); done(); }); }); @@ -139,19 +139,19 @@ describe('User', function(){ }); describe('User.logout', function() { - it('Logout a user by providing the current session id (using node)', function(done) { + it('Logout a user by providing the current accessToken id (using node)', function(done) { login(logout); function login(fn) { User.login({email: 'foo@bar.com', password: 'bar'}, fn); } - function logout(err, session) { - User.logout(session.id, verify(session.id, done)); + function logout(err, accessToken) { + User.logout(accessToken.id, verify(accessToken.id, done)); } }); - it('Logout a user by providing the current session id (over rest)', function(done) { + it('Logout a user by providing the current accessToken id (over rest)', function(done) { login(logout); function login(fn) { @@ -162,12 +162,12 @@ describe('User', function(){ .send({email: 'foo@bar.com', password: 'bar'}) .end(function(err, res){ if(err) return done(err); - var session = res.body; + var accessToken = res.body; - assert(session.uid); - assert(session.id); + assert(accessToken.uid); + assert(accessToken.id); - fn(null, session.id); + fn(null, accessToken.id); }); } @@ -186,8 +186,8 @@ describe('User', function(){ return function (err) { if(err) return done(err); - Session.findById(sid, function (err, session) { - assert(!session, 'session should not exist after logging out'); + AccessToken.findById(sid, function (err, accessToken) { + assert(!accessToken, 'accessToken should not exist after logging out'); done(err); }); }