end
Version:
a Realtime BaaS like Firebase by Socket.io and MongoDB
291 lines (263 loc) • 8.57 kB
JavaScript
/**
* Author: desenHome
* Date: 13-4-16
* Time: 下午5:06
* Desc:
*/
var account = exports = module.exports = {};
var mongo = require('../utils/mongo'),
crypto = require('crypto'),
accounts = global.db.collection('accounts'),
moment = require('moment'),
email = require('../utils/email');
/* login validation methods */
account.addUser = function (newData, socket) {
var result = {
mark: 'addUser',
success: false
};
accounts.findOne({user: newData.user}, function (e, o) {
if (o) {
result.err = {
code: '1-1',
info: 'user-taken'
};
socket.emit('callback', result);
} else {
accounts.findOne({email: newData.email}, function (e, o) {
if (o) {
result.err = {
code: '1-2',
info: 'email-taken'
};
socket.emit('callback', result);
} else {
saltAndHash(newData.pass, function (token,hash) {
newData.token = token;
newData.pass = hash;
// append date stamp when record was created //
newData.date = moment().format('MMMM Do YYYY, h:mm:ss a');
accounts.insert(newData, {safe: true}, function (err) {
if (!err) {
result.success = true;
socket.emit('callback', result);
}
else {
result.err = err;
socket.emit('callback', result);
}
});
});
}
});
}
});
};
account.login = function (user, socket) {
var result = {
mark: 'login',
success: false
};
accounts.findOne({user: user.user}, function (e, o) {
if (o == null) {
result.err = {
code: '2-1',
info: 'user-not-found'
};
socket.emit('callback', result);
} else {
validatePassword(user.pass, o.pass, function (err, res) {
if (res) {
if (user.rememberMe) {
result.token = o.token;
result.user = o.user;
}
result.success = true;
socket.handshake.group = o.group;
socket.emit('callback', result);
} else {
result.err = {
code: '2-2',
info: 'invalid-password'
};
socket.emit('callback', result);
}
});
}
});
};
account.autoLogin = function (user, socket) {
var result = {
mark: 'autoLogin',
success: false
};
accounts.findOne({user: user.user}, function (e, o) {
if (e) {
result.err = {
code: '2-2',
info: e
};
socket.emit('callback', result);
}
else if (o.token === user.token) {
socket.handshake.group = o.group;
result.success = true;
socket.emit('callback', result);
}
});
};
account.passwordReset = function(userEmail,socket){
var result = {
mark: 'passwordReset',
success: false
};
accounts.findOne({email: userEmail}, function (e, o) {
if (e) {
result.err = {
code: '2-2',
info: e
};
socket.emit('callback', result);
}
else if (o) {
var salt = generateSalt();
o.resetToken = sha256(salt);
o.resetDate = moment().format('X');
accounts.save(o, {safe: true}, function(err,item){
if(!err){
email.passwordReset(o,function(err,message){
if(!err){
result.success = true;
socket.emit('callback', result);
console.log(message);
}
else{
console.log(message);
socket.emit('callback', result);
}
});
}
else{
console.log(err);
}
});
}
});
};
/* record insertion, update & deletion methods */
account.updateUser = function (newData, callback) {
accounts.findOne({user: newData.user}, function (e, o) {
o.name = newData.name;
o.email = newData.email;
o.country = newData.country;
if (newData.pass == '') {
accounts.save(o, {safe: true}, callback);
} else {
saltAndHash(newData.pass, function (token,hash) {
o.token = token;
o.pass = hash;
accounts.save(o, {safe: true}, callback);
});
}
});
};
account.updatePassword = function (email, newPass, callback) {
accounts.findOne({email: email}, function (e, o) {
if (e) {
callback(e, null);
} else {
saltAndHash(newPass, function (token,hash) {
o.token = token;
o.pass = hash;
o.resetToken = '';
accounts.save(o, {safe: true}, callback);
});
}
});
}
/* account lookup methods */
account.deleteAccount = function (id, callback) {
accounts.remove({_id: getObjectId(id)}, callback);
}
account.getAccountByEmail = function (email, callback) {
accounts.findOne({email: email}, function (e, o) {
callback(o);
});
}
account.validateReset = function (data,socket) {
var result = {
mark: 'validateReset',
success: false
};
accounts.findOne({email: data.email}, function (e, o) {
if(!e){
var dataNow = o.resetDate = moment().format('X');
if(dataNow- o.resetDate >=3600){
result.err = {
code:'5',
info:'token out date'
}
socket.emit('callback', result);
}
else if(o.resetToken === data.token){
account.updatePassword(data.email,data.newpass,function(err,res){
if(!err&&res){
result.success = true;
socket.emit('callback', result);
}
});
}
else{
result.err = {
code:'5',
info:'token wrong'
}
socket.emit('callback', result);
}
}
});
}
var generateSalt = function () {
var set = '0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ';
var salt = '';
for (var i = 0; i < 10; i++) {
var p = Math.floor(Math.random() * set.length);
salt += set[p];
}
return salt;
}
var md5 = function (str) {
return crypto.createHash('md5').update(str).digest('hex');
}
var sha256 = function(salt){
return crypto.createHash('sha256',global.tokenSecurt).update(salt).digest('hex');
};
var saltAndHash = function (pass, callback) {
var salt = generateSalt();
// callback(salt + md5(pass + salt));
var hashpass = md5(pass + global.tokenSecurt);
callback(salt+sha256(salt+hashpass),hashpass);
};
var validatePassword = function (plainPass, hashedPass, callback) {
var validHash = md5(plainPass + global.tokenSecurt);
callback(null, hashedPass === validHash);
};
/* auxiliary methods */
var getObjectId = function (id) {
return accounts.db.bson_serializer.ObjectID.createFromHexString(id)
}
var findById = function (id, callback) {
accounts.findOne({_id: getObjectId(id)},
function (e, res) {
if (e) callback(e)
else callback(null, res)
});
};
var findByMultipleFields = function (a, callback) {
// this takes an array of name/val pairs to search against {fieldName : 'value'} //
accounts.find({ $or: a }).toArray(
function (e, results) {
if (e) callback(e)
else callback(null, results)
});
}