diff --git a/backend/src/middleware/passwordMiddleware.js b/backend/src/middleware/passwordMiddleware.js index 0aff222c8..16272421a 100644 --- a/backend/src/middleware/passwordMiddleware.js +++ b/backend/src/middleware/passwordMiddleware.js @@ -11,10 +11,11 @@ export default { } }, Query: async (resolve, root, args, context, info) => { - const result = await resolve(root, args, context, info) - return walkRecursive(result, ['password'], () => { + let result = await resolve(root, args, context, info) + result = walkRecursive(result, ['password', 'privateKey'], () => { // replace password with asterisk return '*****' }) + return result } } diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 4ff334806..549499dcd 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -90,7 +90,8 @@ const permissions = shield({ }, User: { email: isMyOwn, - password: isMyOwn + password: isMyOwn, + privateKey: isMyOwn } }) diff --git a/backend/src/resolvers/user_management.spec.js b/backend/src/resolvers/user_management.spec.js index 1c21adac1..94ec04203 100644 --- a/backend/src/resolvers/user_management.spec.js +++ b/backend/src/resolvers/user_management.spec.js @@ -1,3 +1,4 @@ +import gql from 'graphql-tag' import Factory from '../seed/factories' import { GraphQLClient, request } from 'graphql-request' import jwt from 'jsonwebtoken' @@ -254,7 +255,7 @@ describe('change password', () => { } describe('should be authenticated before changing password', () => { - it('throws not "Not Authorised!', async () => { + it('throws "Not Authorised!"', async () => { await expect( request( host, @@ -309,3 +310,97 @@ describe('change password', () => { }) }) }) + +describe('do not expose private RSA key', () => { + let headers + let client + const queryUserPuplicKey = gql` + query($queriedUserSlug: String) { + User(slug: $queriedUserSlug) { + id + publicKey + } + }` + const queryUserPrivateKey = gql` + query($queriedUserSlug: String) { + User(slug: $queriedUserSlug) { + id + privateKey + } + }` + + const actionGenUserWithKeys = async () => { + // Generate user with "privateKey" via 'CreateUser' mutation instead of using the factories "factory.create('User', {...})", see above. + const variables = { + id: 'bcb2d923-f3af-479e-9f00-61b12e864667', + password: 'xYz', + slug: 'apfel-strudel', + name: 'Apfel Strudel', + email: 'apfel-strudel@test.org' + } + await client.request(gql` + mutation($id: ID, $password: String!, $slug: String, $name: String, $email: String) { + CreateUser(id: $id, password: $password, slug: $slug, name: $name, email: $email) { + id + } + }`, variables + ) + } + + // not authenticate + beforeEach(async () => { + client = new GraphQLClient(host) + }) + + describe('unauthenticated query of "publicKey" (does the RSA key pair get generated at all?)', () => { + it('returns publicKey', async () => { + await actionGenUserWithKeys() + await expect( + await client.request(queryUserPuplicKey, { queriedUserSlug: 'apfel-strudel' }) + ).toEqual(expect.objectContaining({ + User: [{ + id: 'bcb2d923-f3af-479e-9f00-61b12e864667', + publicKey: expect.any(String) + }] + })) + }) + }) + + describe('unauthenticated query of "privateKey"', () => { + it('throws "Not Authorised!"', async () => { + await actionGenUserWithKeys() + await expect( + client.request(queryUserPrivateKey, { queriedUserSlug: 'apfel-strudel' }) + ).rejects.toThrow('Not Authorised') + }) + }) + + // authenticate + beforeEach(async () => { + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + }) + + describe('authenticated query of "publicKey"', () => { + it('returns publicKey', async () => { + await actionGenUserWithKeys() + await expect( + await client.request(queryUserPuplicKey, { queriedUserSlug: 'apfel-strudel' }) + ).toEqual(expect.objectContaining({ + User: [{ + id: 'bcb2d923-f3af-479e-9f00-61b12e864667', + publicKey: expect.any(String) + }] + })) + }) + }) + + describe('authenticated query of "privateKey"', () => { + it('throws "Not Authorised!"', async () => { + await actionGenUserWithKeys() + await expect( + client.request(queryUserPrivateKey, { queriedUserSlug: 'apfel-strudel' }) + ).rejects.toThrow('Not Authorised') + }) + }) +})