A simple file sharing site with an easy to use API and online panel.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

132 行
4.2KB

  1. const express = require('express');
  2. const router = express.Router();
  3. const config = require('config');
  4. const fs = require('fs').promises;
  5. const ModelPath = '../../models/';
  6. const User = require(ModelPath + 'User.js');
  7. const Invite = require(ModelPath + 'Invite.js');
  8. const passport = require('passport');
  9. const canonicalizeRequest = require('../../util/canonicalize').canonicalizeRequest;
  10. const requireAuth = require('../../util/auth').requireAuth;
  11. const wrap = require('../../util/wrap.js');
  12. const bodyVerifier = require('../../util/verifyBody').bodyVerifier;
  13. // Wraps passport.authenticate to return a promise
  14. const authenticate = (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 for async usage
  22. const login = (user, req) => {
  23. return new Promise((resolve) => {
  24. req.login(user, resolve);
  25. });
  26. };
  27. // Query the database for a valid invite code. An error message property is set if invalid.
  28. const validateInvite = wrap(async (req, res, next) => {
  29. const invite = await Invite.findOne({code: req.body.invite}).catch(next);
  30. if (!invite) {
  31. // Log failure
  32. await fs.appendFile('auth.log', `${new Date().toISOString()} register ${req.connection.remoteAddress}`);
  33. return res.status(422).json({message: 'Invalid invite code.'});
  34. }
  35. if (invite.used)
  36. return res.status(422).json({message: 'Invite already used.'});
  37. if (invite.expires != null && invite.expires < Date.now())
  38. return res.status(422).json({message: 'Invite expired.'});
  39. req.invite = invite;
  40. next();
  41. });
  42. // Check if the requested username is valid
  43. const validateUsername = wrap(async (req, res, next) => {
  44. const username = req.body.username;
  45. const count = await User.countDocuments({username: username}).catch(next);
  46. if (count !== 0)
  47. return res.status(422).json({message: 'Username in use.'});
  48. next();
  49. });
  50. const registerProps = [
  51. {
  52. name: 'displayname',
  53. type: 'string',
  54. maxLength: config.get('User.Username.maxLength'),
  55. sanitize: true,
  56. restrict: new RegExp(config.get('User.Username.restrictedChars')),
  57. },
  58. {name: 'password', type: 'string'},
  59. {name: 'invite', type: 'string'}];
  60. router.post('/register',
  61. bodyVerifier(registerProps), canonicalizeRequest,
  62. validateInvite, validateUsername,
  63. wrap(async (req, res, next) => {
  64. // Update the database
  65. await Promise.all([
  66. User.register({
  67. username: req.body.username,
  68. displayname: req.body.displayname,
  69. scope: req.invite.scope,
  70. date: Date.now()
  71. }, req.body.password).catch(next),
  72. Invite.updateOne({code: req.invite.code}, {recipient: req.body.username, used: Date.now()}).catch(next)
  73. ]);
  74. res.status(200).json({'message': 'Registration successful.'});
  75. }));
  76. const loginProps = [
  77. {name: 'username', type: 'string', optional: true},
  78. {name: 'displayname', type: 'string', optional: true},
  79. {name: 'password', type: 'string'}];
  80. router.post('/login', bodyVerifier(loginProps), canonicalizeRequest, wrap(async (req, res, next) => {
  81. // Authenticate
  82. const user = await authenticate(req, res, next);
  83. if (!user) {
  84. // Log failure
  85. await fs.appendFile('auth.log', `${new Date().toISOString()} login ${req.connection.remoteAddress}`);
  86. return res.status(401).json({'message': 'Unauthorized.'});
  87. }
  88. // Create session
  89. await login(user, req);
  90. // Set session vars
  91. req.session.passport.displayname = user.displayname;
  92. req.session.passport.scope = user.scope;
  93. res.status(200).json({'message': 'Logged in.'});
  94. }));
  95. router.post('/logout', function (req, res) {
  96. if (!req.isAuthenticated())
  97. return res.status(400).json({message: 'Not logged in.'});
  98. req.logout();
  99. res.status(200).json({'message': 'Logged out.'});
  100. });
  101. router.get('/whoami', requireAuth(), (req, res) => {
  102. res.status(200).json({
  103. username: req.username,
  104. displayname: req.displayname,
  105. scope: req.scope,
  106. key: req.key
  107. });
  108. });
  109. module.exports = router;