Initial users
This commit is contained in:
parent
c14ef9af8c
commit
2f13c53161
|
@ -55,9 +55,7 @@ app.model = function (Model) {
|
||||||
this._models.push(Model);
|
this._models.push(Model);
|
||||||
Model.shared = true;
|
Model.shared = true;
|
||||||
Model.app = this;
|
Model.app = this;
|
||||||
if(Model._remoteHooks) {
|
Model.emit('attached', this);
|
||||||
Model._remoteHooks.emit('attached', app);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -216,8 +216,8 @@ asteroid.createModel = function (name, properties, options) {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var args = arguments;
|
var args = arguments;
|
||||||
this._remoteHooks.once('attached', function () {
|
this.once('attached', function () {
|
||||||
self.beforeRemote.apply(ModelCtor, args);
|
self.beforeRemote.apply(self, args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,15 +232,12 @@ asteroid.createModel = function (name, properties, options) {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var args = arguments;
|
var args = arguments;
|
||||||
this._remoteHooks.once('attached', function () {
|
this.once('attached', function () {
|
||||||
self.afterRemote.apply(ModelCtor, args);
|
self.afterRemote.apply(ModelCtor, args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow hooks to be added before attaching to an app
|
|
||||||
ModelCtor._remoteHooks = new EventEmitter();
|
|
||||||
|
|
||||||
return ModelCtor;
|
return ModelCtor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,3 +263,4 @@ asteroid.remoteMethod = function (fn, options) {
|
||||||
|
|
||||||
asteroid.Model = asteroid.createModel('model');
|
asteroid.Model = asteroid.createModel('model');
|
||||||
asteroid.User = require('./models/user');
|
asteroid.User = require('./models/user');
|
||||||
|
asteroid.Session = require('./models/session');
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var asteroid = require('../asteroid')
|
||||||
|
, passport = require('passport');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the middleware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a temp app for mounting resources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function auth() {
|
||||||
|
return function (req, res, next) {
|
||||||
|
var sub = asteroid();
|
||||||
|
|
||||||
|
// TODO clean this up
|
||||||
|
sub._models = req.app._models;
|
||||||
|
sub._remotes = req.app._remotes;
|
||||||
|
|
||||||
|
sub.use(asteroid.session({secret: 'change me'}))
|
||||||
|
sub.use(passport.initialize());
|
||||||
|
sub.use(passport.session());
|
||||||
|
|
||||||
|
sub.handle(req, res, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* Module Dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Model = require('../asteroid').Model
|
||||||
|
, asteroid = require('../asteroid');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Session properties.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var properties = {
|
||||||
|
id: {type: String, required: true},
|
||||||
|
uid: {type: String},
|
||||||
|
ttl: {type: Number, ttl: true}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends from the built in `asteroid.Model` type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Session = module.exports = Model.extend('session', properties);
|
|
@ -2,7 +2,10 @@
|
||||||
* Module Dependencies.
|
* Module Dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Model = require('../asteroid').Model;
|
var Model = require('../asteroid').Model
|
||||||
|
, asteroid = require('../asteroid')
|
||||||
|
, passport = require('passport')
|
||||||
|
, LocalStrategy = require('passport-local').Strategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default User properties.
|
* Default User properties.
|
||||||
|
@ -12,7 +15,7 @@ var properties = {
|
||||||
id: {type: String, required: true},
|
id: {type: String, required: true},
|
||||||
realm: {type: String},
|
realm: {type: String},
|
||||||
username: {type: String, required: true},
|
username: {type: String, required: true},
|
||||||
// password: {type: String, transient: true}, // Transient property
|
password: {type: String, transient: true}, // Transient property
|
||||||
hash: {type: String}, // Hash code calculated from sha256(realm, username, password, salt, macKey)
|
hash: {type: String}, // Hash code calculated from sha256(realm, username, password, salt, macKey)
|
||||||
salt: {type: String},
|
salt: {type: String},
|
||||||
macKey: {type: String}, // HMAC to calculate the hash code
|
macKey: {type: String}, // HMAC to calculate the hash code
|
||||||
|
@ -42,3 +45,89 @@ var properties = {
|
||||||
|
|
||||||
var User = module.exports = Model.extend('user', properties);
|
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);
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {Object} credentials
|
||||||
|
*/
|
||||||
|
|
||||||
|
User.login = function (credentials, fn) {
|
||||||
|
var UserCtor = this;
|
||||||
|
|
||||||
|
this.findOne({username: credentials.username}, function(err, user) {
|
||||||
|
var defaultError = new Error('login failed');
|
||||||
|
|
||||||
|
if(err) {
|
||||||
|
fn(defaultError);
|
||||||
|
} else if(user) {
|
||||||
|
user.hasPassword(credentials.password, function(err, isMatch) {
|
||||||
|
if(err) {
|
||||||
|
fn(defaultError);
|
||||||
|
} else if(isMatch) {
|
||||||
|
createSession(user, fn);
|
||||||
|
} else {
|
||||||
|
fn(defaultError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fn(defaultError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function createSession(user, fn) {
|
||||||
|
var Session = UserCtor.settings.session || asteroid.Session;
|
||||||
|
|
||||||
|
Session.create({uid: user.id}, function (err, session) {
|
||||||
|
if(err) {
|
||||||
|
fn(err);
|
||||||
|
} else {
|
||||||
|
fn(null, session)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the given `password` with the users hashed password.
|
||||||
|
*
|
||||||
|
* @param {String} password The plain text password
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
User.prototype.hasPassword = function (plain, fn) {
|
||||||
|
// TODO - bcrypt
|
||||||
|
fn(null, this.password === plain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the extend method to setup any extended user models.
|
||||||
|
*/
|
||||||
|
|
||||||
|
User.extend = function () {
|
||||||
|
var EUser = Model.extend.apply(User, arguments);
|
||||||
|
|
||||||
|
setup(EUser);
|
||||||
|
|
||||||
|
return EUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup(UserModel) {
|
||||||
|
asteroid.remoteMethod(
|
||||||
|
UserModel.login,
|
||||||
|
{
|
||||||
|
accepts: [
|
||||||
|
{arg: 'credentials', type: 'object', required: true, http: {source: 'body'}}
|
||||||
|
],
|
||||||
|
returns: {arg: 'session', type: 'object'},
|
||||||
|
http: {verb: 'post'}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return UserModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup(User);
|
|
@ -10,7 +10,10 @@
|
||||||
"express": "~3.1.1",
|
"express": "~3.1.1",
|
||||||
"jugglingdb": "git+ssh://git@github.com:strongloop/jugglingdb.git",
|
"jugglingdb": "git+ssh://git@github.com:strongloop/jugglingdb.git",
|
||||||
"sl-remoting": "git+ssh://git@github.com:strongloop/sl-remoting.git",
|
"sl-remoting": "git+ssh://git@github.com:strongloop/sl-remoting.git",
|
||||||
"inflection": "~1.2.5"
|
"inflection": "~1.2.5",
|
||||||
|
"bcrypt": "~0.7.6",
|
||||||
|
"passport": "~0.1.17",
|
||||||
|
"passport-local": "~0.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "latest",
|
"mocha": "latest",
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
var User = asteroid.User;
|
||||||
|
var passport = require('passport');
|
||||||
|
|
||||||
|
describe('User', function(){
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var memory = asteroid.createDataSource({
|
||||||
|
connector: asteroid.Memory
|
||||||
|
});
|
||||||
|
asteroid.User.attachTo(memory);
|
||||||
|
asteroid.Session.attachTo(memory);
|
||||||
|
app.use(asteroid.cookieParser());
|
||||||
|
app.use(asteroid.auth());
|
||||||
|
app.use(asteroid.rest());
|
||||||
|
app.model(asteroid.User);
|
||||||
|
|
||||||
|
asteroid.User.create({email: 'foo@bar.com', password: 'bar'}, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('User.login', function(){
|
||||||
|
it('Login a user by providing credentials.', function(done) {
|
||||||
|
request(app)
|
||||||
|
.post('/users/login')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.send({email: 'foo@bar.com', password: 'bar'})
|
||||||
|
.end(function(err, res){
|
||||||
|
if(err) return done(err);
|
||||||
|
var session = res.body;
|
||||||
|
|
||||||
|
assert(session.uid);
|
||||||
|
assert(session.id);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue