Merge pull request #223 from Human-Connection/212-change-password

Change password in the backend
This commit is contained in:
Robert Schäfer 2019-03-13 17:25:38 +01:00 committed by GitHub
commit af03b4958b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 179 additions and 34 deletions

View File

@ -56,11 +56,12 @@ const permissions = shield({
CreateBadge: isAdmin,
UpdateBadge: isAdmin,
DeleteBadge: isAdmin,
// addFruitToBasket: isAuthenticated
follow: isAuthenticated,
unfollow: isAuthenticated,
shout: isAuthenticated,
unshout: isAuthenticated,
changePassword: isAuthenticated,
enable: isModerator,
disable: isModerator
// CreateUser: allow,

View File

@ -30,22 +30,71 @@ export default {
// throw new Error('Already logged in.')
// }
const session = driver.session()
return session.run(
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} as user LIMIT 1',
{
userEmail: email
})
.then(async (result) => {
session.close()
const [currentUser] = await result.records.map(function (record) {
return record.get('user')
})
}
)
if (currentUser && await bcrypt.compareSync(password, currentUser.password)) {
delete currentUser.password
return encode(currentUser)
} else throw new AuthenticationError('Incorrect email address or password.')
})
session.close()
const [currentUser] = await result.records.map(function (record) {
return record.get('user')
})
if (
currentUser &&
(await bcrypt.compareSync(password, currentUser.password))
) {
delete currentUser.password
return encode(currentUser)
} else {
throw new AuthenticationError('Incorrect email address or password.')
}
},
changePassword: async (
_,
{ oldPassword, newPassword },
{ driver, user }
) => {
const session = driver.session()
let result = await session.run(
`MATCH (user:User {email: $userEmail})
RETURN user {.id, .email, .password}`,
{
userEmail: user.email
}
)
const [currentUser] = result.records.map(function (record) {
return record.get('user')
})
if (!(await bcrypt.compareSync(oldPassword, currentUser.password))) {
throw new AuthenticationError('Old password is not correct')
}
if (await bcrypt.compareSync(newPassword, currentUser.password)) {
throw new AuthenticationError(
'Old password and new password should be different'
)
} else {
const newHashedPassword = await bcrypt.hashSync(newPassword, 10)
session.run(
`MATCH (user:User {email: $userEmail})
SET user.password = $newHashedPassword
RETURN user
`,
{
userEmail: user.email,
newHashedPassword
}
)
session.close()
return encode(currentUser)
}
}
}
}

View File

@ -21,11 +21,14 @@ const factory = Factory()
// iss: 'http://localhost:4000',
// sub: 'u3'
// }
const jennyRostocksHeaders = { authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc' }
const jennyRostocksHeaders = {
authorization:
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc'
}
beforeEach(async () => {
await factory.create('User', {
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg',
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
id: 'acb2d923-f3af-479e-9f00-61b12e864666',
name: 'Matilde Hermiston',
slug: 'matilde-hermiston',
@ -43,7 +46,9 @@ describe('isLoggedIn', () => {
const query = '{ isLoggedIn }'
describe('unauthenticated', () => {
it('returns false', async () => {
await expect(request(host, query)).resolves.toEqual({ isLoggedIn: false })
await expect(request(host, query)).resolves.toEqual({
isLoggedIn: false
})
})
})
@ -52,7 +57,9 @@ describe('isLoggedIn', () => {
const client = new GraphQLClient(host, { headers })
it('returns false', async () => {
await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false })
await expect(client.request(query)).resolves.toEqual({
isLoggedIn: false
})
})
})
@ -60,14 +67,18 @@ describe('isLoggedIn', () => {
const client = new GraphQLClient(host, { headers: jennyRostocksHeaders })
it('returns false', async () => {
await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false })
await expect(client.request(query)).resolves.toEqual({
isLoggedIn: false
})
})
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 })
await expect(client.request(query)).resolves.toEqual({
isLoggedIn: true
})
})
})
})
@ -116,7 +127,7 @@ describe('currentUser', () => {
it('returns the whole user object', async () => {
const expected = {
currentUser: {
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg',
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
email: 'test@example.org',
id: 'acb2d923-f3af-479e-9f00-61b12e864666',
name: 'Matilde Hermiston',
@ -131,7 +142,7 @@ describe('currentUser', () => {
})
describe('login', () => {
const mutation = (params) => {
const mutation = params => {
const { email, password } = params
return `
mutation {
@ -142,10 +153,13 @@ describe('login', () => {
describe('ask for a `token`', () => {
describe('with valid email/password combination', () => {
it('responds with a JWT token', async () => {
const data = await request(host, mutation({
email: 'test@example.org',
password: '1234'
}))
const data = await request(
host,
mutation({
email: 'test@example.org',
password: '1234'
})
)
const token = data.login
jwt.verify(token, process.env.JWT_SECRET, (err, data) => {
expect(data.email).toEqual('test@example.org')
@ -157,10 +171,13 @@ describe('login', () => {
describe('with a valid email but incorrect password', () => {
it('responds with "Incorrect email address or password."', async () => {
await expect(
request(host, mutation({
email: 'test@example.org',
password: 'wrong'
}))
request(
host,
mutation({
email: 'test@example.org',
password: 'wrong'
})
)
).rejects.toThrow('Incorrect email address or password.')
})
})
@ -168,12 +185,89 @@ describe('login', () => {
describe('with a non-existing email', () => {
it('responds with "Incorrect email address or password."', async () => {
await expect(
request(host, mutation({
email: 'non-existent@example.org',
password: 'wrong'
}))
request(
host,
mutation({
email: 'non-existent@example.org',
password: 'wrong'
})
)
).rejects.toThrow('Incorrect email address or password.')
})
})
})
})
describe('change password', () => {
let headers
let client
beforeEach(async () => {
headers = await login({ email: 'test@example.org', password: '1234' })
client = new GraphQLClient(host, { headers })
})
const mutation = params => {
const { oldPassword, newPassword } = params
return `
mutation {
changePassword(oldPassword:"${oldPassword}", newPassword:"${newPassword}")
}`
}
describe('should be authenticated before changing password', () => {
it('throws not "Not Authorised!', async () => {
await expect(
request(
host,
mutation({
oldPassword: '1234',
newPassword: '1234'
})
)
).rejects.toThrow('Not Authorised!')
})
})
describe('old and new password should not match', () => {
it('responds with "Old password and new password should be different"', async () => {
await expect(
client.request(
mutation({
oldPassword: '1234',
newPassword: '1234'
})
)
).rejects.toThrow('Old password and new password should be different')
})
})
describe('incorrect old password', () => {
it('responds with "Old password isn\'t valid"', async () => {
await expect(
client.request(
mutation({
oldPassword: 'notOldPassword',
newPassword: '12345'
})
)
).rejects.toThrow('Old password is not correct')
})
})
describe('correct password', () => {
it('changes the password if given correct credentials "', async () => {
let response = await client.request(
mutation({
oldPassword: '1234',
newPassword: '12345'
})
)
await expect(
response
).toEqual(expect.objectContaining({
changePassword: expect.any(String)
}))
})
})
})

View File

@ -21,6 +21,7 @@ type Mutation {
"Get a JWT Token for the given Email and password"
login(email: String!, password: String!): String!
signup(email: String!, password: String!): Boolean!
changePassword(oldPassword:String!, newPassword: String!): String!
report(id: ID!, description: String): Report
disable(id: ID!): ID
enable(id: ID!): ID