login.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import { SupportedAction } from '~/interfaces/activity';
  2. import loggerFactory from '~/utils/logger';
  3. // disable all of linting
  4. // because this file is a deprecated legacy of Crowi
  5. module.exports = function(crowi, app) {
  6. const debug = require('debug')('growi:routes:login');
  7. const logger = loggerFactory('growi:routes:login');
  8. const path = require('path');
  9. const User = crowi.model('User');
  10. const {
  11. configManager, appService, aclService, mailService,
  12. } = crowi;
  13. const activityEvent = crowi.event('activity');
  14. const actions = {};
  15. async function sendEmailToAllAdmins(userData) {
  16. // send mails to all admin users (derived from crowi) -- 2020.06.18 Yuki Takei
  17. const admins = await User.findAdmins();
  18. const appTitle = appService.getAppTitle();
  19. const promises = admins.map((admin) => {
  20. return mailService.send({
  21. to: admin.email,
  22. subject: `[${appTitle}:admin] A New User Created and Waiting for Activation`,
  23. template: path.join(crowi.localeDir, 'en_US/admin/userWaitingActivation.txt'),
  24. vars: {
  25. createdUser: userData,
  26. admin,
  27. url: appService.getSiteUrl(),
  28. appTitle,
  29. },
  30. });
  31. });
  32. const results = await Promise.allSettled(promises);
  33. results
  34. .filter(result => result.status === 'rejected')
  35. .forEach(result => logger.error(result.reason));
  36. }
  37. const registerSuccessHandler = async function(req, res, userData, registrationMode) {
  38. const parameters = { action: SupportedAction.ACTION_USER_REGISTRATION_SUCCESS };
  39. activityEvent.emit('update', res.locals.activity._id, parameters);
  40. if (registrationMode === aclService.labels.SECURITY_REGISTRATION_MODE_RESTRICTED) {
  41. await sendEmailToAllAdmins(userData);
  42. return res.apiv3({});
  43. }
  44. req.login(userData, (err) => {
  45. if (err) {
  46. logger.debug(err);
  47. }
  48. else {
  49. // update lastLoginAt
  50. userData.updateLastLoginAt(new Date(), (err) => {
  51. if (err) {
  52. logger.error(`updateLastLoginAt dumps error: ${err}`);
  53. }
  54. });
  55. }
  56. let redirectTo;
  57. if (userData.password == null) {
  58. // userData.password cann't be empty but, prepare redirect because password property in User Model is optional
  59. // https://github.com/weseek/growi/pull/6670
  60. redirectTo = '/me#password';
  61. }
  62. else if (req.session.redirectTo != null) {
  63. redirectTo = req.session.redirectTo;
  64. delete req.session.redirectTo;
  65. }
  66. else {
  67. redirectTo = '/';
  68. }
  69. return res.apiv3({ redirectTo });
  70. });
  71. };
  72. actions.preLogin = function(req, res, next) {
  73. // user has already logged in
  74. const { user } = req;
  75. if (user != null && user.status === User.STATUS_ACTIVE) {
  76. const { redirectTo } = req.session;
  77. // remove session.redirectTo
  78. delete req.session.redirectTo;
  79. return res.safeRedirect(redirectTo);
  80. }
  81. // set referer to 'redirectTo'
  82. if (req.session.redirectTo == null && req.headers.referer != null) {
  83. req.session.redirectTo = req.headers.referer;
  84. }
  85. next();
  86. };
  87. actions.register = function(req, res) {
  88. if (req.user != null) {
  89. return res.apiv3Err('message.user_already_logged_in', 403);
  90. }
  91. // config で closed ならさよなら
  92. if (configManager.getConfig('crowi', 'security:registrationMode') === aclService.labels.SECURITY_REGISTRATION_MODE_CLOSED) {
  93. return res.apiv3Err('message.registration_closed', 403);
  94. }
  95. if (!req.form.isValid) {
  96. const errors = req.form.errors;
  97. return res.apiv3Err(errors, 400);
  98. }
  99. const registerForm = req.form.registerForm || {};
  100. const name = registerForm.name;
  101. const username = registerForm.username;
  102. const email = registerForm.email;
  103. const password = registerForm.password;
  104. // email と username の unique チェックする
  105. User.isRegisterable(email, username, (isRegisterable, errOn) => {
  106. const errors = [];
  107. if (!User.isEmailValid(email)) {
  108. errors.push('message.email_address_could_not_be_used');
  109. }
  110. if (!isRegisterable) {
  111. if (!errOn.username) {
  112. errors.push('message.user_id_is_not_available');
  113. }
  114. if (!errOn.email) {
  115. errors.push('message.email_address_is_already_registered');
  116. }
  117. }
  118. if (errors.length > 0) {
  119. debug('isError user register error', errOn);
  120. return res.apiv3Err(errors, 400);
  121. }
  122. const registrationMode = configManager.getConfig('crowi', 'security:registrationMode');
  123. const isMailerSetup = mailService.isMailerSetup ?? false;
  124. if (!isMailerSetup && registrationMode === aclService.labels.SECURITY_REGISTRATION_MODE_RESTRICTED) {
  125. return res.apiv3Err(['message.email_settings_is_not_setup'], 403);
  126. }
  127. User.createUserByEmailAndPassword(name, username, email, password, undefined, async(err, userData) => {
  128. if (err) {
  129. const errors = [];
  130. if (err.name === 'UserUpperLimitException') {
  131. errors.push('message.can_not_register_maximum_number_of_users');
  132. }
  133. else {
  134. errors.push('message.failed_to_register');
  135. }
  136. return res.apiv3Err(errors, 405);
  137. }
  138. return registerSuccessHandler(req, res, userData, registrationMode);
  139. });
  140. });
  141. };
  142. return actions;
  143. };