|
- const express = require('express');
- const router = express.Router();
- const config = require('config');
- const fs = require('fs').promises;
- const passport = require('passport');
-
- const canonicalize = require('../../util/auth/canonicalize');
-
- const ModelPath = '../../models/';
- const User = require(ModelPath + 'User.js');
- const Invite = require(ModelPath + 'Invite.js');
-
-
- const authenticate = require('../../util/auth/authenticateRequest');
- const verifyBody = require('../../util/verifyBody');
- const rateLimit = require('../../util/rateLimit');
-
- // Wraps passport.authenticate to return a promise
- const passportAuthenticate = (req, res, next) => {
- return new Promise((resolve) => {
- passport.authenticate('local', (err, user) => {
- resolve(user);
- })(req, res, next);
- });
- };
-
- // Wraps passport session creation to return a promise
- const passportLogin = (user, req) => {
- return new Promise((resolve) => {
- req.login(user, resolve);
- });
- };
-
- const registerParams = [
- {name: 'displayname', type: 'string', maxLength: config.get('User.Username.maxLength'), sanitize: true, restrict: new RegExp(config.get('User.Username.restrictedChars'))},
- {name: 'password', type: 'string'},
- {name: 'invite', type: 'string'}];
-
- router.post('/register',
- rateLimit(config.get('RateLimit.register.window'), config.get('RateLimit.register.max'), true),
- verifyBody(registerParams),
- async (req, res) => {
- const username = canonicalize(req.body.displayname);
-
- // Retrieve invite and username status
- const [invite, usernameCount] = await Promise.all([
- Invite.findOne({code: req.body.invite}),
- User.countDocuments({username: username})
- ]);
-
- // Validate the invite
- if (!invite)
- return res.status(422).json({message: 'Invalid invite code.'});
- if (invite.used)
- return res.status(422).json({message: 'Invite already used.'});
- if (invite.expires != null && invite.expires < Date.now())
- return res.status(422).json({message: 'Invite expired.'});
-
- // Validate the username
- if (usernameCount !== 0)
- return res.status(422).json({message: 'Username in use.'});
-
- // Create the user object
- await User.register({
- username: username,
- displayname: req.body.displayname,
- scope: invite.scope,
- date: Date.now()
- }, req.body.password);
-
- // Update the invite as used
- await Invite.updateOne({code: invite.code}, {recipient: username, used: Date.now()});
-
- res.status(200).json({'message': 'Registration successful.'});
- });
-
-
-
- const loginParams = [
- {name: 'displayname', type: 'string'},
- {name: 'password', type: 'string'}];
-
- router.post('/login',
- rateLimit(config.get('RateLimit.login.window'), config.get('RateLimit.login.max'), true),
- verifyBody(loginParams),
- async (req, res, next) => {
- req.body.username = canonicalize(req.body.displayname);
-
- // Authenticate
- const user = await passportAuthenticate(req, res, next);
- if (!user) {
- // Log failure
- await fs.appendFile('auth.log', `${new Date().toISOString()} login ${req.ip}\n`);
- return res.status(401).json({'message': 'Unauthorized.'});
- }
-
- // Create session
- await passportLogin(user, req);
-
- // Set session vars
- req.session.passport.displayname = user.displayname;
- req.session.passport.scope = user.scope;
-
- res.status(200).json({'message': 'Logged in.'});
- });
-
-
-
- router.post('/logout', (req, res) => {
- if (!req.isAuthenticated())
- return res.status(400).json({message: 'Not logged in.'});
-
- req.logout();
- res.status(200).json({'message': 'Logged out.'});
- });
-
-
-
- router.get('/whoami', authenticate(), (req, res) => {
- res.status(200).json({
- username: req.username,
- displayname: req.displayname,
- scope: req.scope,
- key: req.key
- });
- });
-
- module.exports = router;
|