forked from canada-ca/tracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreset-password.js
More file actions
171 lines (155 loc) · 5 KB
/
reset-password.js
File metadata and controls
171 lines (155 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import { GraphQLNonNull, GraphQLString } from 'graphql'
import { mutationWithClientMutationId } from 'graphql-relay'
import { t } from '@lingui/macro'
import { resetPasswordUnion } from '../unions'
export const resetPassword = new mutationWithClientMutationId({
name: 'ResetPassword',
description:
'This mutation allows the user to take the token they received in their email to reset their password.',
inputFields: () => ({
password: {
type: GraphQLNonNull(GraphQLString),
description: 'The users new password.',
},
confirmPassword: {
type: GraphQLNonNull(GraphQLString),
description: 'A confirmation password to confirm the new password.',
},
resetToken: {
type: GraphQLNonNull(GraphQLString),
description:
'The JWT found in the url, redirected from the email they received.',
},
}),
outputFields: () => ({
result: {
type: resetPasswordUnion,
description:
'`ResetPasswordUnion` returning either a `ResetPasswordResult`, or `ResetPasswordError` object.',
resolve: (payload) => payload,
},
}),
mutateAndGetPayload: async (
args,
{
i18n,
query,
collections,
transaction,
auth: { verifyToken, bcrypt },
loaders: { loadUserByKey },
validators: { cleanseInput },
},
) => {
// Cleanse input
const password = cleanseInput(args.password)
const confirmPassword = cleanseInput(args.confirmPassword)
const resetToken = cleanseInput(args.resetToken)
// Check if reset token is valid
const tokenParameters = verifyToken({ token: resetToken })
// Check to see if user id exists in token params !!!
if (
tokenParameters.userKey === 'undefined' ||
typeof tokenParameters.userKey === 'undefined'
) {
console.warn(
`When resetting password user attempted to verify account, but userKey is not located in the token parameters.`,
)
return {
_type: 'error',
code: 400,
description: i18n._(
t`Incorrect token value. Please request a new email.`,
),
}
}
// Check if user exists
const user = await loadUserByKey.load(tokenParameters.userKey)
// Replace with userRequired()
if (typeof user === 'undefined') {
console.warn(
`A user attempted to reset the password for ${tokenParameters.userKey}, however there is no associated account.`,
)
return {
_type: 'error',
code: 400,
description: i18n._(t`Unable to reset password. Please try again.`),
}
}
// Check if password in token matches token in db
if (tokenParameters.currentPassword !== user.password) {
console.warn(
`User: ${user._key} attempted to reset password, however the current password does not match the current hashed password in the db.`,
)
return {
_type: 'error',
code: 400,
description: i18n._(
t`Unable to reset password. Please request a new email.`,
),
}
}
// Check to see if newly submitted passwords match
if (password !== confirmPassword) {
console.warn(
`User: ${user._key} attempted to reset their password, however the submitted passwords do not match.`,
)
return {
_type: 'error',
code: 400,
description: i18n._(t`New passwords do not match.`),
}
}
// Check to see if password meets GoC requirements
if (password.length < 12) {
console.warn(
`User: ${user._key} attempted to reset their password, however the submitted password is not long enough.`,
)
return {
_type: 'error',
code: 400,
description: i18n._(t`Password does not meet requirements.`),
}
}
// Update users password in db
const hashedPassword = bcrypt.hashSync(password, 10)
// Generate list of collections names
const collectionStrings = []
for (const property in collections) {
collectionStrings.push(property.toString())
}
// Setup Transaction
const trx = await transaction(collectionStrings)
try {
await trx.step(
() => query`
WITH users
FOR user IN users
UPDATE ${user._key}
WITH {
password: ${hashedPassword},
failedLoginAttempts: 0
} IN users
`,
)
} catch (err) {
console.error(
`Trx step error occurred when user: ${user._key} attempted to reset their password: ${err}`,
)
throw new Error(i18n._(t`Unable to reset password. Please try again.`))
}
try {
await trx.commit()
} catch (err) {
console.error(
`Trx commit error occurred while user: ${user._key} attempted to authenticate: ${err}`,
)
throw new Error(i18n._(t`Unable to reset password. Please try again.`))
}
console.info(`User: ${user._key} successfully reset their password.`)
return {
_type: 'regular',
status: i18n._(t`Password was successfully reset.`),
}
},
})