mirror of
https://github.com/cnodejs/nodeclub.git
synced 2025-12-08 19:55:55 +00:00
348 lines
9.9 KiB
JavaScript
348 lines
9.9 KiB
JavaScript
|
||
var validator = require('validator');
|
||
var eventproxy = require('eventproxy');
|
||
|
||
var crypto = require('crypto');
|
||
var config = require('../config');
|
||
|
||
var User = require('../proxy').User;
|
||
var Message = require('../proxy').Message;
|
||
var mail = require('../common/mail');
|
||
var mongoose = require('mongoose');
|
||
var UserModel = mongoose.model('User');
|
||
var tools = require('../common/tools');
|
||
var utility = require('utility');
|
||
|
||
//sign up
|
||
exports.showSignup = function (req, res) {
|
||
res.render('sign/signup');
|
||
};
|
||
|
||
exports.signup = function (req, res, next) {
|
||
var loginname = validator.trim(req.body.loginname).toLowerCase();
|
||
var pass = validator.trim(req.body.pass);
|
||
var rePass = validator.trim(req.body.pass);
|
||
var email = validator.trim(req.body.email).toLowerCase();
|
||
|
||
var ep = new eventproxy();
|
||
ep.fail(next);
|
||
ep.on('prop_err', function (msg) {
|
||
res.render('sign/signup', {error: msg, loginname: loginname, email: email});
|
||
});
|
||
|
||
// 验证信息的正确性
|
||
if ([loginname, pass, rePass, email].some(function (item) { return item === ''; })) {
|
||
ep.emit('prop_err', '信息不完整。');
|
||
return;
|
||
}
|
||
if (loginname.length < 5) {
|
||
ep.emit('prop_err', '用户名至少需要5个字符。');
|
||
return;
|
||
}
|
||
if (!tools.validateId(loginname)) {
|
||
return ep.emit('prop_err', '用户名不合法。');
|
||
}
|
||
if (!validator.isEmail(email)) {
|
||
return ep.emit('prop_err', '邮箱不合法。');
|
||
}
|
||
if (pass !== rePass) {
|
||
return ep.emit('prop_err', '两次密码输入不一致。');
|
||
}
|
||
// END 验证信息的正确性
|
||
|
||
User.getUsersByQuery({'$or': [
|
||
{'loginname': loginname},
|
||
{'email': email}
|
||
]}, {}, function (err, users) {
|
||
if (err) {
|
||
return next(err);
|
||
}
|
||
if (users.length > 0) {
|
||
ep.emit('prop_err', '用户名或邮箱已被使用。');
|
||
return;
|
||
}
|
||
|
||
// md5 the pass
|
||
pass = utility.md5(pass);
|
||
// create gravatar
|
||
var avatarUrl = User.makeGravatar(email);
|
||
|
||
User.newAndSave(loginname, loginname, pass, email, avatarUrl, false, function (err) {
|
||
if (err) {
|
||
return next(err);
|
||
}
|
||
// 发送激活邮件
|
||
mail.sendActiveMail(email, utility.md5(email + config.session_secret), loginname);
|
||
res.render('sign/signup', {
|
||
success: '欢迎加入 ' + config.name + '!我们已给您的注册邮箱发送了一封邮件,请点击里面的链接来激活您的帐号。'
|
||
});
|
||
});
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Show user login page.
|
||
*
|
||
* @param {HttpRequest} req
|
||
* @param {HttpResponse} res
|
||
*/
|
||
exports.showLogin = function (req, res) {
|
||
req.session._loginReferer = req.headers.referer;
|
||
res.render('sign/signin');
|
||
};
|
||
|
||
/**
|
||
* define some page when login just jump to the home page
|
||
* @type {Array}
|
||
*/
|
||
var notJump = [
|
||
'/active_account', //active page
|
||
'/reset_pass', //reset password page, avoid to reset twice
|
||
'/signup', //regist page
|
||
'/search_pass' //serch pass page
|
||
];
|
||
|
||
/**
|
||
* Handle user login.
|
||
*
|
||
* @param {HttpRequest} req
|
||
* @param {HttpResponse} res
|
||
* @param {Function} next
|
||
*/
|
||
exports.login = function (req, res, next) {
|
||
var loginname = validator.trim(req.body.name).toLowerCase();
|
||
var pass = validator.trim(req.body.pass);
|
||
|
||
if (!loginname || !pass) {
|
||
return res.render('sign/signin', { error: '信息不完整。' });
|
||
}
|
||
|
||
var getUser;
|
||
if (loginname.indexOf('@') !== -1) {
|
||
getUser = User.getUserByMail;
|
||
} else {
|
||
getUser = User.getUserByLoginName;
|
||
}
|
||
|
||
getUser(loginname, function (err, user) {
|
||
if (err) {
|
||
return next(err);
|
||
}
|
||
if (!user) {
|
||
return res.render('sign/signin', { error: '这个用户不存在。' });
|
||
}
|
||
pass = utility.md5(pass);
|
||
if (pass !== user.pass) {
|
||
return res.render('sign/signin', { error: '密码错误。' });
|
||
}
|
||
if (!user.active) {
|
||
// 从新发送激活邮件
|
||
mail.sendActiveMail(user.email, utility.md5(user.email + config.session_secret), user.loginname);
|
||
return res.render('sign/signin', { error: '此帐号还没有被激活,激活链接已发送到 ' + user.email + ' 邮箱,请查收。' });
|
||
}
|
||
// store session cookie
|
||
gen_session(user, res);
|
||
//check at some page just jump to home page
|
||
var refer = req.session._loginReferer || '/';
|
||
for (var i = 0, len = notJump.length; i !== len; ++i) {
|
||
if (refer.indexOf(notJump[i]) >= 0) {
|
||
refer = '/';
|
||
break;
|
||
}
|
||
}
|
||
res.redirect(refer);
|
||
});
|
||
};
|
||
|
||
// sign out
|
||
exports.signout = function (req, res, next) {
|
||
req.session.destroy();
|
||
res.clearCookie(config.auth_cookie_name, { path: '/' });
|
||
res.redirect(req.headers.referer || '/');
|
||
};
|
||
|
||
exports.active_account = function (req, res, next) {
|
||
var key = req.query.key;
|
||
var name = req.query.name;
|
||
|
||
User.getUserByLoginName(name, function (err, user) {
|
||
if (err) {
|
||
return next(err);
|
||
}
|
||
if (!user || utility.md5(user.email + config.session_secret) !== key) {
|
||
return res.render('notify/notify', {error: '信息有误,帐号无法被激活。'});
|
||
}
|
||
if (user.active) {
|
||
return res.render('notify/notify', {error: '帐号已经是激活状态。'});
|
||
}
|
||
user.active = true;
|
||
user.save(function (err) {
|
||
if (err) {
|
||
return next(err);
|
||
}
|
||
res.render('notify/notify', {success: '帐号已被激活,请登录'});
|
||
});
|
||
});
|
||
};
|
||
|
||
exports.showSearchPass = function (req, res) {
|
||
res.render('sign/search_pass');
|
||
};
|
||
|
||
exports.updateSearchPass = function (req, res, next) {
|
||
var email = validator.trim(req.body.email).toLowerCase();
|
||
if (!validator.isEmail(email)) {
|
||
return res.render('sign/search_pass', {error: '邮箱不合法', email: email});
|
||
}
|
||
|
||
// 动态生成retrive_key和timestamp到users collection,之后重置密码进行验证
|
||
var retrieveKey = randomString(15);
|
||
var retrieveTime = new Date().getTime();
|
||
User.getUserByMail(email, function (err, user) {
|
||
if (!user) {
|
||
res.render('sign/search_pass', {error: '没有这个电子邮箱。', email: email});
|
||
return;
|
||
}
|
||
user.retrieve_key = retrieveKey;
|
||
user.retrieve_time = retrieveTime;
|
||
user.save(function (err) {
|
||
if (err) {
|
||
return next(err);
|
||
}
|
||
// 发送重置密码邮件
|
||
mail.sendResetPassMail(email, retrieveKey, user.loginname);
|
||
res.render('notify/notify', {success: '我们已给您填写的电子邮箱发送了一封邮件,请在24小时内点击里面的链接来重置密码。'});
|
||
});
|
||
});
|
||
};
|
||
|
||
/**
|
||
* reset password
|
||
* 'get' to show the page, 'post' to reset password
|
||
* after reset password, retrieve_key&time will be destroy
|
||
* @param {http.req} req
|
||
* @param {http.res} res
|
||
* @param {Function} next
|
||
*/
|
||
exports.reset_pass = function (req, res, next) {
|
||
var key = req.query.key;
|
||
var name = req.query.name;
|
||
User.getUserByQuery(name, key, function (err, user) {
|
||
if (!user) {
|
||
return res.render('notify/notify', {error: '信息有误,密码无法重置。'});
|
||
}
|
||
var now = new Date().getTime();
|
||
var oneDay = 1000 * 60 * 60 * 24;
|
||
if (!user.retrieve_time || now - user.retrieve_time > oneDay) {
|
||
return res.render('notify/notify', {error: '该链接已过期,请重新申请。'});
|
||
}
|
||
return res.render('sign/reset', {name: name, key: key});
|
||
});
|
||
};
|
||
|
||
exports.update_pass = function (req, res, next) {
|
||
var psw = req.body.psw || '';
|
||
var repsw = req.body.repsw || '';
|
||
var key = req.body.key || '';
|
||
var name = req.body.name || '';
|
||
if (psw !== repsw) {
|
||
return res.render('sign/reset', {name: name, key: key, error: '两次密码输入不一致。'});
|
||
}
|
||
User.getUserByQuery(name, key, function (err, user) {
|
||
if (err) {
|
||
return next(err);
|
||
}
|
||
if (!user) {
|
||
return res.render('notify/notify', {error: '错误的激活链接'});
|
||
}
|
||
user.pass = utility.md5(psw);
|
||
user.retrieve_key = null;
|
||
user.retrieve_time = null;
|
||
user.active = true; // 用户激活
|
||
user.save(function (err) {
|
||
if (err) {
|
||
return next(err);
|
||
}
|
||
return res.render('notify/notify', {success: '你的密码已重置。'});
|
||
});
|
||
});
|
||
};
|
||
|
||
// auth_user middleware
|
||
exports.auth_user = function (req, res, next) {
|
||
var ep = new eventproxy();
|
||
ep.fail(next);
|
||
|
||
ep.all('get_user', function (user) {
|
||
if (!user) {
|
||
return next();
|
||
}
|
||
user = res.locals.current_user = req.session.user = new UserModel(user);
|
||
|
||
if (config.admins.hasOwnProperty(user.loginname)) {
|
||
user.is_admin = true;
|
||
}
|
||
Message.getMessagesCount(user._id, ep.done(function (count) {
|
||
user.messages_count = count;
|
||
next();
|
||
}));
|
||
|
||
});
|
||
|
||
if (req.session.user) {
|
||
ep.emit('get_user', req.session.user);
|
||
} else {
|
||
var cookie = req.cookies[config.auth_cookie_name];
|
||
if (!cookie) {
|
||
return next();
|
||
}
|
||
|
||
var auth_token = decrypt(cookie, config.session_secret);
|
||
if (!auth_token) {
|
||
res.cookie(config.auth_cookie_name, '');
|
||
return res.send('session 过期,请刷新并重新登录');
|
||
}
|
||
var auth = auth_token.split('\t');
|
||
var user_id = auth[0];
|
||
User.getUserById(user_id, ep.done('get_user'));
|
||
}
|
||
};
|
||
|
||
// private
|
||
function gen_session(user, res) {
|
||
var auth_token = encrypt(user._id + '\t' + user.loginname + '\t' + user.pass + '\t' + user.email, config.session_secret);
|
||
res.cookie(config.auth_cookie_name, auth_token, {path: '/', maxAge: 1000 * 60 * 60 * 24 * 30}); //cookie 有效期30天
|
||
}
|
||
|
||
exports.gen_session = gen_session;
|
||
|
||
function encrypt(str, secret) {
|
||
var cipher = crypto.createCipher('aes192', secret);
|
||
var enc = cipher.update(str, 'utf8', 'hex');
|
||
enc += cipher.final('hex');
|
||
return enc;
|
||
}
|
||
|
||
function decrypt(str, secret) {
|
||
try {
|
||
var decipher = crypto.createDecipher('aes192', secret);
|
||
var dec = decipher.update(str, 'hex', 'utf8');
|
||
dec += decipher.final('utf8');
|
||
return dec;
|
||
} catch (e) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
function randomString(size) {
|
||
size = size || 6;
|
||
var code_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||
var max_num = code_string.length + 1;
|
||
var new_pass = '';
|
||
while (size > 0) {
|
||
new_pass += code_string.charAt(Math.floor(Math.random() * max_num));
|
||
size--;
|
||
}
|
||
return new_pass;
|
||
}
|