From b2ab32027031d048a4e72a2eeea25d2b8466583b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 2 Mar 2021 04:35:53 +0100 Subject: [PATCH] nonce changed to 5 digit string, ValidateNonce query added --- .../src/middleware/permissionsMiddleware.js | 1 + backend/src/schema/resolvers/emails.js | 21 +++++++++ backend/src/schema/resolvers/emails.spec.js | 43 ++++++++++++++++++- .../schema/resolvers/helpers/generateNonce.js | 5 ++- .../src/schema/types/type/EmailAddress.gql | 4 ++ 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 7aeb7252a..c64699ac3 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -121,6 +121,7 @@ export default shield( userData: isAuthenticated, MyInviteCodes: isAuthenticated, isValidInviteCode: allow, + VerifyNonce: allow, queryLocations: isAuthenticated, availableRoles: isAdmin, }, diff --git a/backend/src/schema/resolvers/emails.js b/backend/src/schema/resolvers/emails.js index 7986f2613..9ce68f067 100644 --- a/backend/src/schema/resolvers/emails.js +++ b/backend/src/schema/resolvers/emails.js @@ -6,6 +6,27 @@ import Validator from 'neode/build/Services/Validator.js' import normalizeEmail from './helpers/normalizeEmail' export default { + Query: { + VerifyNonce: async (_parent, args, context, _resolveInfo) => { + const session = context.driver.session() + const readTxResultPromise = session.readTransaction(async (txc) => { + const result = await txc.run( + ` + MATCH (email:UnverifiedEmailAddress {email: $email, nonce: $nonce}) + RETURN count(email) > 0 AS result + `, + { email: args.email, nonce: args.nonce }, + ) + return result + }) + try { + const txResult = await readTxResultPromise + return txResult.records[0].get('result') + } finally { + session.close() + } + }, + }, Mutation: { AddEmailAddress: async (_parent, args, context, _resolveInfo) => { let response diff --git a/backend/src/schema/resolvers/emails.spec.js b/backend/src/schema/resolvers/emails.spec.js index 94e7ede31..aa25da1ee 100644 --- a/backend/src/schema/resolvers/emails.spec.js +++ b/backend/src/schema/resolvers/emails.spec.js @@ -6,7 +6,7 @@ import { createTestClient } from 'apollo-server-testing' const neode = getNeode() -let mutate +let mutate, query let authenticatedUser let user let variables @@ -16,7 +16,8 @@ beforeEach(async () => { variables = {} }) -beforeAll(() => { +beforeAll(async () => { + await cleanDatabase() const { server } = createServer({ context: () => { return { @@ -27,6 +28,7 @@ beforeAll(() => { }, }) mutate = createTestClient(server).mutate + query = createTestClient(server).query }) afterEach(async () => { @@ -295,3 +297,40 @@ describe('VerifyEmailAddress', () => { }) }) }) + +describe('VerifyNonce', () => { + beforeEach(async () => { + await Factory.build('unverifiedEmailAddress', { + nonce: 'abcdef', + verifiedAt: null, + createdAt: new Date().toISOString(), + email: 'to-be-verified@example.org', + }) + }) + + const verifyNonceQuery = gql` + query($email: String!, $nonce: String!) { + VerifyNonce(email: $email, nonce: $nonce) + } + ` + + it('returns true when nonce and email match', async () => { + variables = { + nonce: 'abcdef', + email: 'to-be-verified@example.org', + } + await expect(query({ query: verifyNonceQuery, variables })).resolves.toMatchObject({ + data: { VerifyNonce: true }, + }) + }) + + it('returns false when nonce and email do not match', async () => { + variables = { + nonce: '---', + email: 'to-be-verified@example.org', + } + await expect(query({ query: verifyNonceQuery, variables })).resolves.toMatchObject({ + data: { VerifyNonce: false }, + }) + }) +}) diff --git a/backend/src/schema/resolvers/helpers/generateNonce.js b/backend/src/schema/resolvers/helpers/generateNonce.js index e9b758774..6da40b5c2 100644 --- a/backend/src/schema/resolvers/helpers/generateNonce.js +++ b/backend/src/schema/resolvers/helpers/generateNonce.js @@ -1,4 +1,5 @@ -import { v4 as uuid } from 'uuid' export default function generateNonce() { - return uuid().substring(0, 6) + return Array.from({ length: 5 }, (n = Math.floor(Math.random() * 10)) => { + return String.fromCharCode(n + 48) + }).join('') } diff --git a/backend/src/schema/types/type/EmailAddress.gql b/backend/src/schema/types/type/EmailAddress.gql index e09ec9e63..509a7ae28 100644 --- a/backend/src/schema/types/type/EmailAddress.gql +++ b/backend/src/schema/types/type/EmailAddress.gql @@ -4,6 +4,10 @@ type EmailAddress { createdAt: String } +type Query { + VerifyNonce(email: String!, nonce: String!): Boolean! +} + type Mutation { Signup(email: String!): EmailAddress SignupByInvitation(email: String!, token: String!): EmailAddress