Skip to content

Commit 0a2092c

Browse files
committed
add resetPasswordSuccessOnInvalidEmail
1 parent 2124488 commit 0a2092c

File tree

5 files changed

+32
-13
lines changed

5 files changed

+32
-13
lines changed

spec/ValidationAndPasswordsReset.spec.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
10831083
});
10841084
});
10851085

1086-
it('should throw on an invalid reset password', async () => {
1086+
it('should throw on an invalid reset password with resetPasswordSuccessOnInvalidEmail', async () => {
10871087
await reconfigureServer({
10881088
appName: 'coolapp',
10891089
publicServerURL: 'http://localhost:1337/1',
@@ -1092,6 +1092,9 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
10921092
apiKey: 'k',
10931093
domain: 'd',
10941094
}),
1095+
passwordPolicy: {
1096+
resetPasswordSuccessOnInvalidEmail: false,
1097+
},
10951098
});
10961099
await expectAsync(Parse.User.requestPasswordReset('[email protected]')).toBeRejectedWith(
10971100
new Parse.Error(

src/Options/Definitions.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,13 @@ module.exports.PasswordPolicyOptions = {
818818
'Set the number of previous password that will not be allowed to be set as new password. If the option is not set or set to `0`, no previous passwords will be considered.<br><br>Valid values are >= `0` and <= `20`.<br>Default is `0`.',
819819
action: parsers.numberParser('maxPasswordHistory'),
820820
},
821+
resetPasswordSuccessOnInvalidEmail: {
822+
env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_PASSWORD_SUCCESS_ON_INVALID_EMAIL',
823+
help:
824+
'Set to true if password resets should return success if the email is invalid<br><br>Default is `true`.',
825+
action: parsers.booleanParser,
826+
default: true,
827+
},
821828
resetTokenReuseIfValid: {
822829
env: 'PARSE_SERVER_PASSWORD_POLICY_RESET_TOKEN_REUSE_IF_VALID',
823830
help:

src/Options/docs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
* @property {Boolean} doNotAllowUsername Set to `true` to disallow the username as part of the password.<br><br>Default is `false`.
191191
* @property {Number} maxPasswordAge Set the number of days after which a password expires. Login attempts fail if the user does not reset the password before expiration.
192192
* @property {Number} maxPasswordHistory Set the number of previous password that will not be allowed to be set as new password. If the option is not set or set to `0`, no previous passwords will be considered.<br><br>Valid values are >= `0` and <= `20`.<br>Default is `0`.
193+
* @property {Boolean} resetPasswordSuccessOnInvalidEmail Set to true if password resets should return success if the email is invalid<br><br>Default is `true`.
193194
* @property {Boolean} resetTokenReuseIfValid Set to `true` if a password reset token should be reused in case another token is requested but there is a token that is still valid, i.e. has not expired. This avoids the often observed issue that a user requests multiple emails and does not know which link contains a valid token because each newly generated token would invalidate the previous token.<br><br>Default is `false`.
194195
* @property {Number} resetTokenValidityDuration Set the validity duration of the password reset token in seconds after which the token expires. The token is used in the link that is set in the email. After the token expires, the link becomes invalid and a new link has to be sent. If the option is not set or set to `undefined`, then the token never expires.<br><br>For example, to expire the token after 2 hours, set a value of 7200 seconds (= 60 seconds * 60 minutes * 2 hours).<br><br>Default is `undefined`.
195196
* @property {String} validationError Set the error message to be sent.<br><br>Default is `Password does not meet the Password Policy requirements.`

src/Options/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,11 @@ export interface PasswordPolicyOptions {
487487
Default is `false`.
488488
:DEFAULT: false */
489489
resetTokenReuseIfValid: ?boolean;
490+
/* Set to true if password resets should return success if the email is invalid
491+
<br><br>
492+
Default is `true`.
493+
:DEFAULT: true */
494+
resetPasswordSuccessOnInvalidEmail: ?boolean;
490495
}
491496

492497
export interface FileUploadOptions {

src/Routers/UsersRouter.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ export class UsersRouter extends ClassesRouter {
384384
}
385385
}
386386

387-
handleResetRequest(req) {
387+
async handleResetRequest(req) {
388388
this._throwOnBadEmailConfig(req);
389389

390390
const { email } = req.body;
@@ -398,19 +398,22 @@ export class UsersRouter extends ClassesRouter {
398398
);
399399
}
400400
const userController = req.config.userController;
401-
return userController.sendPasswordResetEmail(email).then(
402-
() => {
403-
return Promise.resolve({
404-
response: {},
405-
});
406-
},
407-
err => {
408-
if (err.code === Parse.Error.OBJECT_NOT_FOUND) {
409-
err.message = `A user with the email ${email} does not exist.`;
401+
try {
402+
await userController.sendPasswordResetEmail(email);
403+
return {
404+
response: {},
405+
};
406+
} catch (err) {
407+
if (err.code === Parse.Error.OBJECT_NOT_FOUND) {
408+
if (req.config.passwordPolicy.resetPasswordSuccessOnInvalidEmail) {
409+
return {
410+
response: {},
411+
};
410412
}
411-
throw err;
413+
err.message = `A user with the email ${email} does not exist.`;
412414
}
413-
);
415+
throw err;
416+
}
414417
}
415418

416419
handleVerificationEmailRequest(req) {

0 commit comments

Comments
 (0)