Always normalize email in backend

This commit is contained in:
roschaefer 2019-11-04 23:41:46 +01:00
parent bcf06dff25
commit 61a8914989
7 changed files with 29 additions and 23 deletions

View File

@ -3,11 +3,14 @@ import Resolver from './helpers/Resolver'
import existingEmailAddress from './helpers/existingEmailAddress' import existingEmailAddress from './helpers/existingEmailAddress'
import { UserInputError } from 'apollo-server' import { UserInputError } from 'apollo-server'
import Validator from 'neode/build/Services/Validator.js' import Validator from 'neode/build/Services/Validator.js'
import { normalizeEmail } from 'validator'
export default { export default {
Mutation: { Mutation: {
AddEmailAddress: async (_parent, args, context, _resolveInfo) => { AddEmailAddress: async (_parent, args, context, _resolveInfo) => {
let response let response
args.email = normalizeEmail(args.email)
try { try {
const { neode } = context const { neode } = context
await new Validator(neode, neode.model('UnverifiedEmailAddress'), args) await new Validator(neode, neode.model('UnverifiedEmailAddress'), args)
@ -16,13 +19,13 @@ export default {
} }
// check email does not belong to anybody // check email does not belong to anybody
await existingEmailAddress(_parent, args, context) await existingEmailAddress({ args, context })
const nonce = generateNonce() const nonce = generateNonce()
const { const {
user: { id: userId }, user: { id: userId },
} = context } = context
const { email } = args
const session = context.driver.session() const session = context.driver.session()
const writeTxResultPromise = session.writeTransaction(async txc => { const writeTxResultPromise = session.writeTransaction(async txc => {
const result = await txc.run( const result = await txc.run(
@ -32,7 +35,7 @@ export default {
SET email.createdAt = toString(datetime()) SET email.createdAt = toString(datetime())
RETURN email, user RETURN email, user
`, `,
{ userId, email, nonce }, { userId, email: args.email, nonce },
) )
return result.records.map(record => ({ return result.records.map(record => ({
name: record.get('user').properties.name, name: record.get('user').properties.name,

View File

@ -12,9 +12,9 @@ describe('createPasswordReset', () => {
close() {}, close() {},
run: jest.fn().mockReturnValue({ run: jest.fn().mockReturnValue({
records: { records: {
map: jest.fn(() => []) map: jest.fn(() => []),
} },
}) }),
} }
driver = { session: () => mockSession } driver = { session: () => mockSession }
}) })
@ -22,10 +22,14 @@ describe('createPasswordReset', () => {
it('lowercases email address', async () => { it('lowercases email address', async () => {
const email = 'stRaNGeCaSiNG@ExAmplE.ORG' const email = 'stRaNGeCaSiNG@ExAmplE.ORG'
await createPasswordReset({ driver, email, issuedAt, nonce }) await createPasswordReset({ driver, email, issuedAt, nonce })
expect(mockSession.run.mock.calls) expect(mockSession.run.mock.calls).toEqual([
.toEqual([[expect.any(String), expect.objectContaining({ [
email: 'strangecasing@example.org' expect.any(String),
})]]) expect.objectContaining({
email: 'strangecasing@example.org',
}),
],
])
}) })
}) })
}) })

View File

@ -1,7 +1,6 @@
import { UserInputError } from 'apollo-server' import { UserInputError } from 'apollo-server'
export default async function alreadyExistingMail(_parent, args, context) {
let { email } = args export default async function alreadyExistingMail({ args, context }) {
email = email.toLowerCase()
const cypher = ` const cypher = `
MATCH (email:EmailAddress {email: $email}) MATCH (email:EmailAddress {email: $email})
OPTIONAL MATCH (email)-[:BELONGS_TO]-(user) OPTIONAL MATCH (email)-[:BELONGS_TO]-(user)
@ -10,7 +9,7 @@ export default async function alreadyExistingMail(_parent, args, context) {
let transactionRes let transactionRes
const session = context.driver.session() const session = context.driver.session()
try { try {
transactionRes = await session.run(cypher, { email }) transactionRes = await session.run(cypher, { email: args.email })
} finally { } finally {
session.close() session.close()
} }

View File

@ -1,7 +1,6 @@
import uuid from 'uuid/v4' import uuid from 'uuid/v4'
import bcrypt from 'bcryptjs' import bcrypt from 'bcryptjs'
import createPasswordReset from './passwordReset/createPasswordReset' import createPasswordReset from './helpers/createPasswordReset'
export default { export default {
Mutation: { Mutation: {

View File

@ -1,7 +1,7 @@
import Factory from '../../seed/factories' import Factory from '../../seed/factories'
import { gql } from '../../jest/helpers' import { gql } from '../../jest/helpers'
import { neode as getNeode, getDriver } from '../../bootstrap/neo4j' import { neode as getNeode, getDriver } from '../../bootstrap/neo4j'
import { createPasswordReset } from './passwordReset/createPasswordReset' import { createPasswordReset } from './helpers/createPasswordReset'
import createServer from '../../server' import createServer from '../../server'
import { createTestClient } from 'apollo-server-testing' import { createTestClient } from 'apollo-server-testing'

View File

@ -4,6 +4,7 @@ import fileUpload from './fileUpload'
import encryptPassword from '../../helpers/encryptPassword' import encryptPassword from '../../helpers/encryptPassword'
import generateNonce from './helpers/generateNonce' import generateNonce from './helpers/generateNonce'
import existingEmailAddress from './helpers/existingEmailAddress' import existingEmailAddress from './helpers/existingEmailAddress'
import { normalizeEmail } from 'validator'
const instance = neode() const instance = neode()
@ -29,9 +30,9 @@ export default {
return response return response
}, },
Signup: async (_parent, args, context) => { Signup: async (_parent, args, context) => {
const nonce = generateNonce() args.nonce = generateNonce()
args.nonce = nonce args.email = normalizeEmail(args.email)
let emailAddress = await existingEmailAddress(_parent, args, context) let emailAddress = await existingEmailAddress({ args, context })
if (emailAddress) return emailAddress if (emailAddress) return emailAddress
try { try {
emailAddress = await instance.create('EmailAddress', args) emailAddress = await instance.create('EmailAddress', args)
@ -42,8 +43,8 @@ export default {
}, },
SignupByInvitation: async (_parent, args, context) => { SignupByInvitation: async (_parent, args, context) => {
const { token } = args const { token } = args
const nonce = generateNonce() args.nonce = generateNonce()
args.nonce = nonce args.email = normalizeEmail(args.email)
let emailAddress = await existingEmailAddress(_parent, args, context) let emailAddress = await existingEmailAddress(_parent, args, context)
if (emailAddress) return emailAddress if (emailAddress) return emailAddress
try { try {
@ -78,7 +79,7 @@ export default {
args.termsAndConditionsAgreedAt = new Date().toISOString() args.termsAndConditionsAgreedAt = new Date().toISOString()
let { nonce, email } = args let { nonce, email } = args
email = email.toLowerCase() email = normalizeEmail(email)
const result = await instance.cypher( const result = await instance.cypher(
` `
MATCH(email:EmailAddress {nonce: {nonce}, email: {email}}) MATCH(email:EmailAddress {nonce: {nonce}, email: {email}})