A simple file sharing site with an easy to use API and online panel.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 line
4.0KB

  1. const express = require('express');
  2. const router = express.Router();
  3. const config = require('config');
  4. const fs = require('fs').promises;
  5. const passport = require('passport');
  6. const canonicalize = require('../../util/auth/canonicalize');
  7. const ModelPath = '../../models/';
  8. const User = require(ModelPath + 'User.js');
  9. const Invite = require(ModelPath + 'Invite.js');
  10. const authenticate = require('../../util/auth/authenticateRequest');
  11. const verifyBody = require('../../util/verifyBody');
  12. const rateLimit = require('../../util/rateLimit');
  13. // Wraps passport.authenticate to return a promise
  14. const passportAuthenticate = (req, res, next) => {
  15. return new Promise((resolve) => {
  16. passport.authenticate('local', (err, user) => {
  17. resolve(user);
  18. })(req, res, next);
  19. });
  20. };
  21. // Wraps passport session creation to return a promise
  22. const passportLogin = (user, req) => {
  23. return new Promise((resolve) => {
  24. req.login(user, resolve);
  25. });
  26. };
  27. const registerParams = [
  28. {name: 'displayname', type: 'string', maxLength: config.get('User.Username.maxLength'), sanitize: true, restrict: new RegExp(config.get('User.Username.restrictedChars'))},
  29. {name: 'password', type: 'string'},
  30. {name: 'invite', type: 'string'}];
  31. router.post('/register',
  32. rateLimit(config.get('RateLimit.register.window'), config.get('RateLimit.register.max'), true),
  33. verifyBody(registerParams),
  34. async (req, res) => {
  35. const username = canonicalize(req.body.displayname);
  36. // Retrieve invite and username status
  37. const [invite, usernameCount] = await Promise.all([
  38. Invite.findOne({code: req.body.invite}),
  39. User.countDocuments({username: username})
  40. ]);
  41. // Validate the invite
  42. if (!invite)
  43. return res.status(422).json({message: 'Invalid invite code.'});
  44. if (invite.used)
  45. return res.status(422).json({message: 'Invite already used.'});
  46. if (invite.expires != null && invite.expires < Date.now())
  47. return res.status(422).json({message: 'Invite expired.'});
  48. // Validate the username
  49. if (usernameCount !== 0)
  50. return res.status(422).json({message: 'Username in use.'});
  51. // Create the user object
  52. await User.register({
  53. username: username,
  54. displayname: req.body.displayname,
  55. scope: invite.scope,
  56. date: Date.now()
  57. }, req.body.password);
  58. // Update the invite as used
  59. await Invite.updateOne({code: invite.code}, {recipient: username, used: Date.now()});
  60. res.status(200).json({'message': 'Registration successful.'});
  61. });
  62. const loginParams = [
  63. {name: 'displayname', type: 'string'},
  64. {name: 'password', type: 'string'}];
  65. router.post('/login',
  66. rateLimit(config.get('RateLimit.login.window'), config.get('RateLimit.login.max'), true),
  67. verifyBody(loginParams),
  68. async (req, res, next) => {
  69. req.body.username = canonicalize(req.body.displayname);
  70. // Authenticate
  71. const user = await passportAuthenticate(req, res, next);
  72. if (!user) {
  73. // Log failure
  74. await fs.appendFile('auth.log', `${new Date().toISOString()} login ${req.ip}\n`);
  75. return res.status(401).json({'message': 'Unauthorized.'});
  76. }
  77. // Create session
  78. await passportLogin(user, req);
  79. // Set session vars
  80. req.session.passport.displayname = user.displayname;
  81. req.session.passport.scope = user.scope;
  82. res.status(200).json({'message': 'Logged in.'});
  83. });
  84. router.post('/logout', (req, res) => {
  85. if (!req.isAuthenticated())
  86. return res.status(400).json({message: 'Not logged in.'});
  87. req.logout();
  88. res.status(200).json({'message': 'Logged out.'});
  89. });
  90. router.get('/whoami', authenticate(), (req, res) => {
  91. res.status(200).json({
  92. username: req.username,
  93. displayname: req.displayname,
  94. scope: req.scope,
  95. key: req.key
  96. });
  97. });
  98. module.exports = router;