diff --git a/src/jwt/decode.js b/src/jwt/decode.js index 0ab1e4529..6abc06dc1 100644 --- a/src/jwt/decode.js +++ b/src/jwt/decode.js @@ -13,7 +13,7 @@ export default async (driver, authorizationHeader) => { const session = driver.session() const query = ` MATCH (user:User {id: {id} }) - RETURN user {.id, .slug, .name, .avatar, .email, .role} as user + RETURN user {.id, .slug, .name, .avatar, .email, .role, .disabled} LIMIT 1 ` const result = await session.run(query, { id }) @@ -22,6 +22,7 @@ export default async (driver, authorizationHeader) => { return record.get('user') }) if (!currentUser) return null + if (currentUser.disabled) return null return { token, ...currentUser diff --git a/src/resolvers/user_management.js b/src/resolvers/user_management.js index 36865646f..26dfb81db 100644 --- a/src/resolvers/user_management.js +++ b/src/resolvers/user_management.js @@ -32,7 +32,7 @@ export default { const session = driver.session() const result = await session.run( 'MATCH (user:User {email: $userEmail}) ' + - 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role} as user LIMIT 1', + 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role, .disabled} as user LIMIT 1', { userEmail: email } @@ -45,10 +45,15 @@ export default { if ( currentUser && - (await bcrypt.compareSync(password, currentUser.password)) + (await bcrypt.compareSync(password, currentUser.password)) && + !currentUser.disabled ) { delete currentUser.password return encode(currentUser) + } else if (currentUser && + currentUser.disabled + ) { + throw new AuthenticationError('Your account has been disabled.') } else { throw new AuthenticationError('Incorrect email address or password.') } diff --git a/src/resolvers/user_management.spec.js b/src/resolvers/user_management.spec.js index c4b09df37..1c21adac1 100644 --- a/src/resolvers/user_management.spec.js +++ b/src/resolvers/user_management.spec.js @@ -26,6 +26,14 @@ const jennyRostocksHeaders = { 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc' } +const disable = async (id) => { + const moderatorParams = { email: 'moderator@example.org', role: 'moderator', password: '1234' } + const asModerator = Factory() + await asModerator.create('User', moderatorParams) + await asModerator.authenticateAs(moderatorParams) + await asModerator.mutate('mutation($id: ID!) { disable(id: $id) }', { id }) +} + beforeEach(async () => { await factory.create('User', { avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg', @@ -73,11 +81,26 @@ describe('isLoggedIn', () => { }) describe('and a corresponding user in the database', () => { - it('returns true', async () => { - // see the decoded token above - await factory.create('User', { id: 'u3' }) - await expect(client.request(query)).resolves.toEqual({ - isLoggedIn: true + describe('user is enabled', () => { + it('returns true', async () => { + // see the decoded token above + await factory.create('User', { id: 'u3' }) + await expect(client.request(query)).resolves.toEqual({ + isLoggedIn: true + }) + }) + }) + + describe('user is disabled', () => { + beforeEach(async () => { + await factory.create('User', { id: 'u3' }) + await disable('u3') + }) + + it('returns false', async () => { + await expect(client.request(query)).resolves.toEqual({ + isLoggedIn: false + }) }) }) }) @@ -168,6 +191,21 @@ describe('login', () => { }) }) + describe('valid email/password but user is disabled', () => { + it('responds with "Your account has been disabled."', async () => { + await disable('acb2d923-f3af-479e-9f00-61b12e864666') + await expect( + request( + host, + mutation({ + email: 'test@example.org', + password: '1234' + }) + ) + ).rejects.toThrow('Your account has been disabled.') + }) + }) + describe('with a valid email but incorrect password', () => { it('responds with "Incorrect email address or password."', async () => { await expect(