diff --git a/server/api/middlewares/authentication.js b/server/api/middlewares/authentication.js index 050f0e0f..c1a0701e 100644 --- a/server/api/middlewares/authentication.js +++ b/server/api/middlewares/authentication.js @@ -2,7 +2,7 @@ import JWT from 'jsonwebtoken'; import { type Context } from 'koa'; import { User, ApiKey } from '../../models'; -import { AuthenticationError } from '../../errors'; +import { AuthenticationError, UserSuspendedError } from '../../errors'; export default function auth() { return async function authMiddleware( @@ -35,53 +35,53 @@ export default function auth() { if (!token) throw new AuthenticationError('Authentication required'); - if (token) { - let user; + let user; - if (String(token).match(/^[\w]{38}$/)) { - // API key - let apiKey; - try { - apiKey = await ApiKey.findOne({ - where: { - secret: token, - }, - }); - } catch (e) { - throw new AuthenticationError('Invalid API key'); - } - - if (!apiKey) throw new AuthenticationError('Invalid API key'); - - user = await User.findById(apiKey.userId); - if (!user) throw new AuthenticationError('Invalid API key'); - } else { - // JWT - // Get user without verifying payload signature - let payload; - try { - payload = JWT.decode(token); - } catch (e) { - throw new AuthenticationError('Unable to decode JWT token'); - } - - if (!payload) throw new AuthenticationError('Invalid token'); - - user = await User.findById(payload.id); - - try { - JWT.verify(token, user.jwtSecret); - } catch (e) { - throw new AuthenticationError('Invalid token'); - } + if (String(token).match(/^[\w]{38}$/)) { + // API key + let apiKey; + try { + apiKey = await ApiKey.findOne({ + where: { + secret: token, + }, + }); + } catch (e) { + throw new AuthenticationError('Invalid API key'); } - ctx.state.token = token; - ctx.state.user = user; - // $FlowFixMe - ctx.cache[user.id] = user; + if (!apiKey) throw new AuthenticationError('Invalid API key'); + + user = await User.findById(apiKey.userId); + if (!user) throw new AuthenticationError('Invalid API key'); + } else { + // JWT + // Get user without verifying payload signature + let payload; + try { + payload = JWT.decode(token); + } catch (e) { + throw new AuthenticationError('Unable to decode JWT token'); + } + + if (!payload) throw new AuthenticationError('Invalid token'); + + user = await User.findById(payload.id); + + try { + JWT.verify(token, user.jwtSecret); + } catch (e) { + throw new AuthenticationError('Invalid token'); + } } + if (user.isSuspended) throw new UserSuspendedError(); + + ctx.state.token = token; + ctx.state.user = user; + // $FlowFixMe + ctx.cache[user.id] = user; + return next(); }; } diff --git a/server/api/middlewares/authentication.test.js b/server/api/middlewares/authentication.test.js index 2fec3842..da6606eb 100644 --- a/server/api/middlewares/authentication.test.js +++ b/server/api/middlewares/authentication.test.js @@ -1,5 +1,6 @@ /* eslint-disable flowtype/require-valid-file-annotation */ import { flushdb, seed } from '../../test/support'; +import { buildUser } from '../../test/factories'; import { ApiKey } from '../../models'; import randomstring from 'randomstring'; import auth from './authentication'; @@ -155,4 +156,29 @@ describe('Authentication middleware', async () => { ); expect(state.user.id).toEqual(user.id); }); + + it('should return an error for suspended users', async () => { + const state = {}; + const user = await buildUser({ + suspendedAt: new Date(), + }); + const authMiddleware = auth(); + + try { + await authMiddleware( + { + request: { + get: jest.fn(() => `Bearer ${user.getJwtToken()}`), + }, + state, + cache: {}, + }, + jest.fn() + ); + } catch (e) { + expect(e.message).toEqual( + 'Your access has been suspended by the team admin' + ); + } + }); }); diff --git a/server/errors.js b/server/errors.js index e9df32d2..da60eec0 100644 --- a/server/errors.js +++ b/server/errors.js @@ -19,6 +19,12 @@ export function AdminRequiredError( return httpErrors(403, message, { id: 'admin_required' }); } +export function UserSuspendedError( + message: string = 'Your access has been suspended by the team admin' +) { + return httpErrors(403, message, { id: 'user_suspended' }); +} + export function InvalidRequestError(message: string = 'Request invalid') { return httpErrors(400, message, { id: 'invalid_request' }); }