PageRenderTime 70ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/authentication.js

https://github.com/nherment/Sybeol
JavaScript | 339 lines | 304 code | 30 blank | 5 comment | 68 complexity | 5ec3f7cbf85176c947f9962ff19968d0 MD5 | raw file
  1. var db = require('./db.js');
  2. var logger = require('./logger.js').getLogger('authentication');
  3. var mail = require("./mail.js");
  4. var ErrorUtil = require("./util.js").Error;
  5. var User = db.User;
  6. var Measure = db.Measure;
  7. var isAuthenticated = function(req, cb) {
  8. var err;
  9. logger.info("session id: " + req.session.id);
  10. req.session.reload(function(err){
  11. if(err) {
  12. logger.error(err);
  13. // cb(false);
  14. // throw err;
  15. }
  16. //} else {
  17. logger.debug(JSON.stringify(req.session));
  18. logger.info('isAuthenticated: ' + req.session.authenticated);
  19. logger.debug('isAuthenticated email: ' + req.session.email);
  20. logger.debug("session cookie:" + JSON.stringify(req.session.cookie));
  21. if(req.session.authenticated) {
  22. if(req.session.email) {
  23. cb(true);
  24. } else {
  25. logger.error("Inconsistent session state. authenticated=true but email is missing");
  26. cb(false);
  27. }
  28. } else {
  29. cb(false);
  30. }
  31. //}
  32. });
  33. }
  34. var getCurrentUser = function(req, cb) {
  35. isAuthenticated(req, function(isAuth) {
  36. if(isAuth) {
  37. db.getUser(req.session.email, function(err, user) {
  38. if(err) {
  39. cb(err, null);
  40. } else if(user) {
  41. cb(null, user);
  42. } else {
  43. var error = new Error("User is authenticated but could not find it in DB. IP["+req.connection.remoteAddress+"]");
  44. logger.error(error);
  45. cb(error, null);
  46. }
  47. });
  48. } else {
  49. var err = new Error("Authentication required");
  50. logger.warn(err);
  51. cb(err, null);
  52. }
  53. });
  54. }
  55. var handleAuth = function(request, response) {
  56. isAuthenticated(request, function(isAuth) {
  57. if(isAuth) {
  58. logger.info('Already authenticated');
  59. response.end('{"result": "success"}');
  60. } else {
  61. logger.info('Not yet authenticated');
  62. if(request.method == "GET") {
  63. exports.authenticateUserParams(request, response);
  64. } else {
  65. exports.authenticateUserJson(request, response);
  66. }
  67. }
  68. })
  69. }
  70. var handleAuthJson = function(request, response) {
  71. isAuthenticated(request, function(isAuth) {
  72. if(isAuth) {
  73. logger.info('Already authenticated');
  74. response.end('{"result": "success"}');
  75. } else {
  76. logger.info('Not yet authenticated');
  77. exports.authenticateUserJson(request, response);
  78. }
  79. });
  80. }
  81. var authenticateUser = function(request, response, email, password) {
  82. if(request.body) {
  83. logger.info("authenticating " + email);
  84. db.getUser(email, function(err, user) {
  85. logger.info("processing...");
  86. if(err) {
  87. logger.error("Error:"+err);
  88. response.end('{"result": "Failed"}');
  89. }
  90. if(user) {
  91. if(user.active) {
  92. if(user.authenticate(password)) {
  93. request.session.authenticated = true;
  94. request.session.email = user.email;
  95. request.session.save(function(err){
  96. logger.info("session saved");
  97. if(err) {
  98. logger.error(err);
  99. throw err;
  100. }
  101. });
  102. logger.debug("session cookie:" + JSON.stringify(request.session.cookie));
  103. //logger.info("session email: "+request.session.email);
  104. logger.info('user with email ['+request.session.email+'] is now authenticated');
  105. response.send('{"result": "success"}');
  106. } else {
  107. logger.info('authentication failed because the password is wrong. user['+user.email+']');
  108. response.end('{"result": "Failed", "cause":"Wrong password"}');
  109. }
  110. } else {
  111. logger.info('authentication failed because acount is inactive. user['+user.email+']');
  112. response.end('{"result": "Failed", "cause":"The account needs to be activated"}');
  113. }
  114. } else {
  115. logger.info('Could not find user with email['+email+']');
  116. response.end('{"result": "Failed", "cause":"Unknown email"}');
  117. }
  118. });
  119. } else {
  120. logger.info("request body is empty for authentication query");
  121. response.end('{"result": "Failed"}');
  122. }
  123. }
  124. var authenticateUserJson = function(request, response) {
  125. logger.info('Attempting JSON parsing of the request body');
  126. if(request.body) {
  127. authenticateUser(request, response, request.body.email, request.body.password);
  128. } else {
  129. logger.info('The request\'s body is empty. Cannot proceed with authentication');
  130. response.end('{"result": "Failed"}');
  131. }
  132. }
  133. var authenticateUserParams = function(request, response) {
  134. authenticateUser(request, response, request.param('email'), request.param('password'));
  135. }
  136. var emailPattern = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i ;
  137. var handleRegister = function(request, response) {
  138. if(request.body) {
  139. var email = request.body.email;
  140. var password = request.body.password;
  141. if(emailPattern.test(email)) {
  142. db.createUser(email, password, function(err, user) {
  143. if(err) {
  144. logger.error(err);
  145. response.send(ErrorUtil.reduce(err));
  146. } else {
  147. logger.info("Registered new user: " + JSON.stringify(user));
  148. sendActivationMail(user);
  149. response.send({ result: "success" });
  150. }
  151. });
  152. } else {
  153. var err = new Error("Email is invalid ["+email+"]");
  154. logger.error(err);
  155. response.send(ErrorUtil.reduce(err));
  156. }
  157. } else {
  158. response.end('{"result": "Failed"}');
  159. }
  160. }
  161. var sendActivationMail = function(user) {
  162. logger.info("sending registration mail to user: " + JSON.stringify(user));
  163. var mailOpts = {
  164. subject: "Regarding your new Sybeol account",
  165. body: "Thank you for registering for a new account. \n\nThe product is currently in Beta and we are manually activating each account.\nWe want to know about your amazing project so you will hear from us in the next 48 hours! \n\nThank you !\n- The Sybeol team"
  166. }
  167. var mailOptsAdmin = {
  168. subject: "New registration on Sybeol",
  169. body: "Click on this link to activate your account: http://www.sybeol.com/activate/?u=" + user.email + "&k=" + user.validationKey
  170. }
  171. mail.send(user.email, mailOpts.subject, mailOpts.body, function(e) {
  172. if(e) {
  173. logger.error("Error sending email to [" + user.email + "]" + e);
  174. } else {
  175. logger.info("Validation email sent: " + JSON.stringify(mailOpts));
  176. }
  177. });
  178. mail.send("nicolas@sybeol.com", mailOptsAdmin.subject, mailOptsAdmin.body, function(e) {
  179. if(e) {
  180. logger.error("Error sending email to [" + user.email + "]" + e);
  181. } else {
  182. logger.info("Validation email sent: " + JSON.stringify(mailOpts));
  183. }
  184. });
  185. }
  186. var sendAccountActiveEmail = function(user) {
  187. var mailOpts = {
  188. subject: "Your Sybeol account is now active",
  189. body: "Thank you for your patience for a new account. \n\nYour account is now active. Please go take a look: http://www.sybeol.com.\n\nThank you !\n- The Sybeol team"
  190. }
  191. mail.send(user.email, mailOpts.subject, mailOpts.body, function(e) {
  192. if(e) {
  193. logger.error("Error sending email to [" + user.email + "]" + e);
  194. } else {
  195. logger.info("'Account activated' notification email sent: " + JSON.stringify(mailOpts));
  196. }
  197. });
  198. }
  199. var activate = function(email, validationKey, callback) {
  200. if(email && validationKey) {
  201. logger.info("Activating " + email + " with key " + validationKey);
  202. db.getUser(email, function(err, user) {
  203. if(err) {
  204. logger.error("Error:"+err);
  205. callback(err, null);
  206. } else if(user) {
  207. logger.info("found matching user [" + user.email + "] for activation");
  208. if(user.validationKey === validationKey) {
  209. logger.debug("Activation key match for user [" + user.email + "]");
  210. user.active = true;
  211. user.validationKey = undefined;
  212. user.save();
  213. logger.info("User [" + user.email + "] is now active");
  214. sendAccountActiveEmail(user);
  215. callback(null, user);
  216. } else {
  217. var msg = "Activation key does not match the one expected. Expected ["+user.validationKey+"] but got ["+validationKey+"]";
  218. logger.warn(msg);
  219. callback("Activation key is not valid", null);
  220. }
  221. } else{
  222. logger.info('Activation: Could not find user with email['+email+']');
  223. callback("User not found", null);
  224. }
  225. });
  226. } else {
  227. callback(new Error("Wrong arguments"), null);
  228. }
  229. }
  230. var sendPasswordResetMail = function(user, password) {
  231. logger.info("sending new password to user: " + JSON.stringify(user));
  232. var mailOpts = {
  233. subject: "Your new Sybeol password",
  234. body: "Your new password is: " + password
  235. }
  236. mail.send(user.email, mailOpts.subject, mailOpts.body, function(e) {
  237. if(e) {
  238. logger.error("Error sending email to [" + user.email + "]" + e);
  239. } else {
  240. logger.info("Reset password email sent to [" + user.email + "]");
  241. }
  242. });
  243. }
  244. var resetPassword = function(email, callback) {
  245. if(emailPattern.test(email)) {
  246. logger.info("Resetting password for [" + email + "]");
  247. db.getUser(email, function(err, user) {
  248. if(err) {
  249. callback(err);
  250. } else if(user) {
  251. try {
  252. var newPassword = generatePassword(8);
  253. user.password = newPassword;
  254. user.save();
  255. sendPasswordResetMail(user, newPassword);
  256. callback();
  257. } catch(err) {
  258. callback(err);
  259. }
  260. } else {
  261. var noSuchUserError = new Error("Could not find user with email ["+email+"]");
  262. logger.warn(noSuchUserError);
  263. callback(noSuchUserError);
  264. }
  265. });
  266. } else {
  267. var err = new Error("Email is invalid ["+email+"]");
  268. logger.error(err);
  269. res.send(ErrorUtil.reduce(err));
  270. callback(err);
  271. }
  272. }
  273. exports.authenticateUserParams = authenticateUserParams;
  274. exports.authenticateUserJson = authenticateUserJson;
  275. exports.handleAuthJson = handleAuthJson;
  276. exports.handleAuth = handleAuth;
  277. exports.isAuthenticated = isAuthenticated;
  278. exports.handleRegister = handleRegister;
  279. exports.activate = activate;
  280. exports.resetPassword = resetPassword;
  281. exports.getCurrentUser = getCurrentUser;
  282. function getRandomNum(lbound, ubound) {
  283. return (Math.floor(Math.random() * (ubound - lbound)) + lbound);
  284. }
  285. function getRandomChar(number, lower, upper, other) {
  286. var numberChars = "123456789123456789";
  287. var lowerChars = "abcdefghijklmnpqrstuvwxyz";
  288. var upperChars = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
  289. var otherChars = "------______";
  290. var charSet = "";
  291. if (number == true)
  292. charSet += numberChars;
  293. if (lower == true)
  294. charSet += lowerChars;
  295. if (upper == true)
  296. charSet += upperChars;
  297. if (other == true)
  298. charSet += otherChars;
  299. return charSet.charAt(getRandomNum(0, charSet.length));
  300. }
  301. function generatePassword(length) {
  302. var rc = "";
  303. if (length > 0)
  304. rc = rc + getRandomChar(true, true, true, true);
  305. for (var idx = 1; idx < length; ++idx) {
  306. rc = rc + getRandomChar(true, true, true, true);
  307. }
  308. return rc;
  309. }