authController.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. const fs = require('fs');
  2. const path = require('path');
  3. const passport = require('passport');
  4. const JWT = require('jsonwebtoken');
  5. const config = require('../config');
  6. const transporter = require('../mail/mail');
  7. const { resetMailText, verifyMailText } = require('../mail/text');
  8. const {
  9. createUser,
  10. changePassword,
  11. generateApiKey,
  12. getUser,
  13. verifyUser,
  14. requestPasswordReset,
  15. resetPassword,
  16. } = require('../db/user');
  17. /* Read email template */
  18. const resetEmailTemplatePath = path.join(__dirname, '../mail/template-reset.html');
  19. const verifyEmailTemplatePath = path.join(__dirname, '../mail/template-verify.html');
  20. const resetEmailTemplate = fs
  21. .readFileSync(resetEmailTemplatePath, { encoding: 'utf-8' })
  22. .replace(/{{domain}}/gm, config.DEFAULT_DOMAIN);
  23. const verifyEmailTemplate = fs
  24. .readFileSync(verifyEmailTemplatePath, { encoding: 'utf-8' })
  25. .replace(/{{domain}}/gm, config.DEFAULT_DOMAIN);
  26. /* Function to generate JWT */
  27. const signToken = user =>
  28. JWT.sign(
  29. {
  30. iss: 'ApiAuth',
  31. sub: user.email,
  32. iat: new Date().getTime(),
  33. exp: new Date().setDate(new Date().getDate() + 7),
  34. },
  35. config.JWT_SECRET
  36. );
  37. /* Passport.js authentication controller */
  38. const authenticate = (type, error, isStrict = true) =>
  39. function auth(req, res, next) {
  40. if (req.user) return next();
  41. return passport.authenticate(type, (err, user) => {
  42. if (err) return res.status(400);
  43. if (!user && isStrict) return res.status(401).json({ error });
  44. req.user = user;
  45. return next();
  46. })(req, res, next);
  47. };
  48. exports.authLocal = authenticate('local', 'Login email and/or password are wrong.');
  49. exports.authJwt = authenticate('jwt', 'Unauthorized.');
  50. exports.authJwtLoose = authenticate('jwt', 'Unauthorized.', false);
  51. exports.authApikey = authenticate('localapikey', 'API key is not correct.', false);
  52. exports.signup = async (req, res) => {
  53. const { email, password } = req.body;
  54. if (password.length > 64) {
  55. return res.status(400).json({ error: 'Maximum password length is 64.' });
  56. }
  57. if (email.length > 64) {
  58. return res.status(400).json({ error: 'Maximum email length is 64.' });
  59. }
  60. const user = await getUser({ email });
  61. if (user && user.verified) return res.status(403).json({ error: 'Email is already in use.' });
  62. const newUser = await createUser({ email, password });
  63. const mail = await transporter.sendMail({
  64. from: config.MAIL_USER,
  65. to: newUser.email,
  66. subject: 'Verify your account',
  67. text: verifyMailText.replace('{{verification}}', newUser.verificationToken),
  68. html: verifyEmailTemplate.replace('{{verification}}', newUser.verificationToken),
  69. });
  70. if (mail.accepted.length) {
  71. return res.status(201).json({ email, message: 'Verification email has been sent.' });
  72. }
  73. return res.status(400).json({ error: "Couldn't send verification email. Try again." });
  74. };
  75. exports.login = ({ user }, res) => {
  76. const token = signToken(user);
  77. return res.status(200).json({ token });
  78. };
  79. exports.renew = ({ user }, res) => {
  80. const token = signToken(user);
  81. return res.status(200).json({ token });
  82. };
  83. exports.verify = async (req, res, next) => {
  84. const { verificationToken = '' } = req.params;
  85. const user = await verifyUser({ verificationToken });
  86. if (user) {
  87. const token = signToken(user);
  88. req.user = { token };
  89. }
  90. return next();
  91. };
  92. exports.changePassword = async ({ body: { password }, user }, res) => {
  93. if (password.length < 8) {
  94. return res.status(400).json({ error: 'Password must be at least 8 chars long.' });
  95. }
  96. if (password.length > 64) {
  97. return res.status(400).json({ error: 'Maximum password length is 64.' });
  98. }
  99. const changedUser = await changePassword({ email: user.email, password });
  100. if (changedUser) {
  101. return res.status(200).json({ message: 'Your password has been changed successfully.' });
  102. }
  103. return res.status(400).json({ error: "Couldn't change the password. Try again later" });
  104. };
  105. exports.generateApiKey = async ({ user }, res) => {
  106. const { apikey } = await generateApiKey({ email: user.email });
  107. if (apikey) {
  108. return res.status(201).json({ apikey });
  109. }
  110. return res.status(400).json({ error: 'Sorry, an error occured. Please try again later.' });
  111. };
  112. exports.userSettings = ({ user }, res) =>
  113. res.status(200).json({ apikey: user.apikey || '', customDomain: user.domain || '' });
  114. exports.requestPasswordReset = async ({ body: { email } }, res) => {
  115. const user = await requestPasswordReset({ email });
  116. if (!user) {
  117. return res.status(400).json({ error: "Couldn't reset password." });
  118. }
  119. const mail = await transporter.sendMail({
  120. from: config.MAIL_USER,
  121. to: user.email,
  122. subject: 'Reset your password',
  123. text: resetMailText
  124. .replace('{{resetpassword}}', user.resetPasswordToken)
  125. .replace('{{domain}}', config.DEFAULT_DOMAIN),
  126. html: resetEmailTemplate
  127. .replace('{{resetpassword}}', user.resetPasswordToken)
  128. .replace('{{domain}}', config.DEFAULT_DOMAIN),
  129. });
  130. if (mail.accepted.length) {
  131. return res.status(200).json({ email, message: 'Reset password email has been sent.' });
  132. }
  133. return res.status(400).json({ error: "Couldn't reset password." });
  134. };
  135. exports.resetPassword = async (req, res, next) => {
  136. const { resetPasswordToken = '' } = req.params;
  137. const user = await resetPassword({ resetPasswordToken });
  138. if (user) {
  139. const token = signToken(user);
  140. req.user = { token };
  141. }
  142. return next();
  143. };