login.js 6.1 KB

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