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.

87 lines
2.8KB

  1. const fs = require('fs').promises;
  2. const config = require('config');
  3. const ModelPath = '../models/';
  4. const Key = require(ModelPath + 'Key.js');
  5. const User = require(ModelPath + 'User.js');
  6. const wrap = require('./wrap.js');
  7. const verifyScope = require('./verifyScope.js');
  8. const rateLimit = require('express-rate-limit');
  9. const checkSession = (req, scope, status) => {
  10. if (req.isAuthenticated()) {
  11. status.authenticated = true;
  12. if (!scope || verifyScope(req.session.passport.scope, scope)) {
  13. req.username = req.session.passport.user;
  14. req.displayname = req.session.passport.displayname;
  15. req.scope = req.session.passport.scope;
  16. req.key = null;
  17. status.permission = true;
  18. }
  19. }
  20. };
  21. const checkKey = async (req, scope, status) => {
  22. if (req.body.key) {
  23. const key = await Key.findOne({key: req.body.key});
  24. if (key) {
  25. status.authenticated = true;
  26. if (!scope || verifyScope(key.scope, scope)) {
  27. req.username = key.issuer;
  28. req.displayname = key.issuer;
  29. req.scope = key.scope;
  30. req.key = key.key;
  31. status.permission = true;
  32. }
  33. } else {
  34. // Log failure
  35. await fs.appendFile('auth.log', `${new Date().toISOString()} key ${req.ip}\n`);
  36. }
  37. }
  38. };
  39. const apiLimiter = config.get('RateLimit.enable')
  40. ? rateLimit({
  41. windowMs: config.get('RateLimit.api.window') * 1000,
  42. max: config.get('RateLimit.api.max'),
  43. skip: (req, res) => res.statusCode !== 401 && res.statusCode !== 403
  44. })
  45. : (req, res, next) => { next(); };
  46. // Middleware that checks for authentication by either API key or session
  47. // sets req.username, req.displayname, req.scope, and req.key if authenticated properly,
  48. // otherwise throws an error code.
  49. // If the user is banned, also throw an error.
  50. const requireAuth = scope => (req, res, next) => {
  51. apiLimiter(req, res, wrap(async () => {
  52. const status = {
  53. authenticated: false,
  54. permission: false
  55. };
  56. // First, check the session
  57. checkSession(req, scope, status);
  58. // If not authenticated yet, check for a key
  59. if (!status.authenticated)
  60. await checkKey(req, scope, status);
  61. if (!status.authenticated)
  62. return res.status(401).json({message: 'Unauthorized.'});
  63. else if (!status.permission)
  64. return res.status(403).json({message: 'Forbidden.'});
  65. // Check if the user is banned
  66. const user = await User.findOne({username: req.username});
  67. if (user && user.banned)
  68. return res.status(403).json({message: 'Forbidden.'});
  69. next();
  70. }));
  71. };
  72. module.exports.checkSession = checkSession;
  73. module.exports.checkKey = checkKey;
  74. module.exports.requireAuth = requireAuth;