2013-07-01 23:50:03 +00:00
|
|
|
/**
|
|
|
|
* Module Dependencies.
|
|
|
|
*/
|
|
|
|
|
2013-07-02 23:51:38 +00:00
|
|
|
var Model = require('../asteroid').Model
|
|
|
|
, asteroid = require('../asteroid')
|
|
|
|
, passport = require('passport')
|
|
|
|
, LocalStrategy = require('passport-local').Strategy;
|
2013-07-01 23:50:03 +00:00
|
|
|
|
2013-07-02 00:01:26 +00:00
|
|
|
/**
|
|
|
|
* Default User properties.
|
|
|
|
*/
|
|
|
|
|
|
|
|
var properties = {
|
|
|
|
id: {type: String, required: true},
|
|
|
|
realm: {type: String},
|
|
|
|
username: {type: String, required: true},
|
2013-07-02 23:51:38 +00:00
|
|
|
password: {type: String, transient: true}, // Transient property
|
2013-07-02 00:01:26 +00:00
|
|
|
hash: {type: String}, // Hash code calculated from sha256(realm, username, password, salt, macKey)
|
|
|
|
salt: {type: String},
|
|
|
|
macKey: {type: String}, // HMAC to calculate the hash code
|
|
|
|
email: String,
|
|
|
|
emailVerified: Boolean,
|
|
|
|
credentials: [
|
|
|
|
'UserCredential' // User credentials, private or public, such as private/public keys, Kerberos tickets, oAuth tokens, facebook, google, github ids
|
|
|
|
],
|
|
|
|
challenges: [
|
|
|
|
'Challenge' // Security questions/answers
|
|
|
|
],
|
|
|
|
// https://en.wikipedia.org/wiki/Multi-factor_authentication
|
|
|
|
/*
|
|
|
|
factors: [
|
|
|
|
'AuthenticationFactor'
|
|
|
|
],
|
|
|
|
*/
|
|
|
|
status: String,
|
|
|
|
created: Date,
|
|
|
|
lastUpdated: Date
|
|
|
|
}
|
|
|
|
|
2013-07-01 23:50:03 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Extends from the built in `asteroid.Model` type.
|
|
|
|
*/
|
|
|
|
|
2013-07-02 00:01:26 +00:00
|
|
|
var User = module.exports = Model.extend('user', properties);
|
2013-07-01 23:50:03 +00:00
|
|
|
|
2013-07-02 23:51:38 +00:00
|
|
|
/**
|
|
|
|
* 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);
|