Skip to content

Commit 3fa085e

Browse files
authored
Merge branch 'alpha' into realDBAdapterLoader
2 parents 48e23fc + 655e2c4 commit 3fa085e

File tree

5 files changed

+105
-11
lines changed

5 files changed

+105
-11
lines changed

changelogs/CHANGELOG_alpha.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# [7.0.0-alpha.10](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.9...7.0.0-alpha.10) (2024-01-17)
2+
3+
4+
### Features
5+
6+
* Add password validation via POST request for user with unverified email using master key and option `ignoreEmailVerification` ([#8895](https://github.com/parse-community/parse-server/issues/8895)) ([633a9d2](https://github.com/parse-community/parse-server/commit/633a9d25e4253e2125bc93c02ee8a37e0f5f7b83))
7+
18
# [7.0.0-alpha.9](https://github.com/parse-community/parse-server/compare/7.0.0-alpha.8...7.0.0-alpha.9) (2024-01-15)
29

310

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "parse-server",
3-
"version": "7.0.0-alpha.9",
3+
"version": "7.0.0-alpha.10",
44
"description": "An express module providing a Parse-compatible API server",
55
"main": "lib/index.js",
66
"repository": {

spec/VerifyUserPassword.spec.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,4 +585,83 @@ describe('Verify User Password', () => {
585585
done();
586586
});
587587
});
588+
589+
it('verify password of user with unverified email with master key and ignoreEmailVerification=true', async () => {
590+
await reconfigureServer({
591+
publicServerURL: 'http://localhost:8378/',
592+
appName: 'emailVerify',
593+
verifyUserEmails: true,
594+
preventLoginWithUnverifiedEmail: true,
595+
emailAdapter: MockEmailAdapterWithOptions({
596+
fromAddress: '[email protected]',
597+
apiKey: 'k',
598+
domain: 'd',
599+
}),
600+
});
601+
602+
const user = new Parse.User();
603+
user.setUsername('user');
604+
user.setPassword('pass');
605+
user.setEmail('[email protected]');
606+
await user.signUp();
607+
608+
const { data: res } = await request({
609+
method: 'POST',
610+
url: Parse.serverURL + '/verifyPassword',
611+
headers: {
612+
'X-Parse-Master-Key': Parse.masterKey,
613+
'X-Parse-Application-Id': Parse.applicationId,
614+
'X-Parse-REST-API-Key': 'rest',
615+
'Content-Type': 'application/json',
616+
},
617+
body: {
618+
username: 'user',
619+
password: 'pass',
620+
ignoreEmailVerification: true,
621+
},
622+
json: true,
623+
});
624+
expect(res.objectId).toBe(user.id);
625+
expect(Object.prototype.hasOwnProperty.call(res, 'sessionToken')).toEqual(false);
626+
expect(Object.prototype.hasOwnProperty.call(res, 'password')).toEqual(false);
627+
});
628+
629+
it('fails to verify password of user with unverified email with master key and ignoreEmailVerification=false', async () => {
630+
await reconfigureServer({
631+
publicServerURL: 'http://localhost:8378/',
632+
appName: 'emailVerify',
633+
verifyUserEmails: true,
634+
preventLoginWithUnverifiedEmail: true,
635+
emailAdapter: MockEmailAdapterWithOptions({
636+
fromAddress: '[email protected]',
637+
apiKey: 'k',
638+
domain: 'd',
639+
}),
640+
});
641+
642+
const user = new Parse.User();
643+
user.setUsername('user');
644+
user.setPassword('pass');
645+
user.setEmail('[email protected]');
646+
await user.signUp();
647+
648+
const res = await request({
649+
method: 'POST',
650+
url: Parse.serverURL + '/verifyPassword',
651+
headers: {
652+
'X-Parse-Master-Key': Parse.masterKey,
653+
'X-Parse-Application-Id': Parse.applicationId,
654+
'X-Parse-REST-API-Key': 'rest',
655+
'Content-Type': 'application/json',
656+
},
657+
body: {
658+
username: 'user',
659+
password: 'pass',
660+
ignoreEmailVerification: false,
661+
},
662+
json: true,
663+
}).catch(e => e);
664+
expect(res.status).toBe(400);
665+
expect(res.text).toMatch(/User email is not verified/);
666+
});
588667
});

src/Routers/UsersRouter.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export class UsersRouter extends ClassesRouter {
7575
) {
7676
payload = req.query;
7777
}
78-
const { username, email, password } = payload;
78+
const { username, email, password, ignoreEmailVerification } = payload;
7979

8080
// TODO: use the right error codes / descriptions.
8181
if (!username && !email) {
@@ -144,13 +144,18 @@ export class UsersRouter extends ClassesRouter {
144144
installationId: req.auth.installationId,
145145
object: Parse.User.fromJSON(Object.assign({ className: '_User' }, user)),
146146
};
147-
// Get verification conditions which can be booleans or functions; the purpose of this async/await
148-
// structure is to avoid unnecessarily executing subsequent functions if previous ones fail in the
149-
// conditional statement below, as a developer may decide to execute expensive operations in them
150-
const verifyUserEmails = async () => req.config.verifyUserEmails === true || (typeof req.config.verifyUserEmails === 'function' && await Promise.resolve(req.config.verifyUserEmails(request)) === true);
151-
const preventLoginWithUnverifiedEmail = async () => req.config.preventLoginWithUnverifiedEmail === true || (typeof req.config.preventLoginWithUnverifiedEmail === 'function' && await Promise.resolve(req.config.preventLoginWithUnverifiedEmail(request)) === true);
152-
if (await verifyUserEmails() && await preventLoginWithUnverifiedEmail() && !user.emailVerified) {
153-
throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.');
147+
148+
// If request doesn't use master or maintenance key with ignoring email verification
149+
if (!((req.auth.isMaster || req.auth.isMaintenance) && ignoreEmailVerification)) {
150+
151+
// Get verification conditions which can be booleans or functions; the purpose of this async/await
152+
// structure is to avoid unnecessarily executing subsequent functions if previous ones fail in the
153+
// conditional statement below, as a developer may decide to execute expensive operations in them
154+
const verifyUserEmails = async () => req.config.verifyUserEmails === true || (typeof req.config.verifyUserEmails === 'function' && await Promise.resolve(req.config.verifyUserEmails(request)) === true);
155+
const preventLoginWithUnverifiedEmail = async () => req.config.preventLoginWithUnverifiedEmail === true || (typeof req.config.preventLoginWithUnverifiedEmail === 'function' && await Promise.resolve(req.config.preventLoginWithUnverifiedEmail(request)) === true);
156+
if (await verifyUserEmails() && await preventLoginWithUnverifiedEmail() && !user.emailVerified) {
157+
throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User email is not verified.');
158+
}
154159
}
155160

156161
this._sanitizeAuthData(user);
@@ -658,6 +663,9 @@ export class UsersRouter extends ClassesRouter {
658663
this.route('GET', '/verifyPassword', req => {
659664
return this.handleVerifyPassword(req);
660665
});
666+
this.route('POST', '/verifyPassword', req => {
667+
return this.handleVerifyPassword(req);
668+
});
661669
this.route('POST', '/challenge', req => {
662670
return this.handleChallenge(req);
663671
});

0 commit comments

Comments
 (0)