Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions spec/ParseUser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,113 @@ describe('Parse.User testing', () => {
done();
});

describe('autoSignupOnLogin option', () => {
it('does not auto sign up when disabled', async () => {
await reconfigureServer({ autoSignupOnLogin: false });
await expectAsync(Parse.User.logIn('ghost-user', 'hunter2')).toBeRejectedWith(
jasmine.objectContaining({ code: Parse.Error.OBJECT_NOT_FOUND })
);
const count = await new Parse.Query(Parse.User)
.equalTo('username', 'ghost-user')
.count({ useMasterKey: true });
expect(count).toBe(0);
});

it('creates user on login when enabled (username + password)', async () => {
await reconfigureServer({ autoSignupOnLogin: true });
const user = await Parse.User.logIn('auto-login-user', 'pass1234');
expect(user.id).toBeDefined();
expect(user.getSessionToken()).toBeDefined();
const stored = await new Parse.Query(Parse.User)
.equalTo('username', 'auto-login-user')
.first({ useMasterKey: true });
expect(stored).toBeTruthy();
expect(stored.id).toBe(user.id);
});

it('creates user on login when enabled with email + password', async () => {
await reconfigureServer({ autoSignupOnLogin: true });
const email = 'auto-email@example.com';
const res = await request({
method: 'POST',
url: 'http://localhost:8378/1/login',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': 'rest',
},
body: {
email,
password: 'pass1234',
},
});
expect(res.data.username).toBe(email);
expect(res.data.email).toBe(email);
expect(res.data.sessionToken).toBeDefined();
const stored = await new Parse.Query(Parse.User)
.equalTo('email', email)
.first({ useMasterKey: true });
expect(stored).toBeTruthy();
expect(stored.get('username')).toBe(email);
});

it('uses existing user when present and does not duplicate', async () => {
await reconfigureServer({ autoSignupOnLogin: true });
const existing = new Parse.User();
existing.setUsername('existing-login');
existing.setPassword('pass123');
await existing.signUp();

const logged = await Parse.User.logIn('existing-login', 'pass123');
expect(logged.id).toBe(existing.id);
const count = await new Parse.Query(Parse.User)
.equalTo('username', 'existing-login')
.count({ useMasterKey: true });
expect(count).toBe(1);
});

it('respects preventLoginWithUnverifiedEmail when auto-signing up', async () => {
await reconfigureServer({
appName: 'preventLoginWithUnverifiedEmail',
autoSignupOnLogin: true,
verifyUserEmails: true,
preventLoginWithUnverifiedEmail: true,
emailAdapter: {
sendVerificationMail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
},
publicServerURL: 'http://localhost:8378/1',
});
const email = 'unverified@example.com';
await expectAsync(
request({
method: 'POST',
url: 'http://localhost:8378/1/login',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': 'rest',
},
body: {
email,
password: 'pass1234',
},
})
).toBeRejectedWith(
jasmine.objectContaining({
data: jasmine.objectContaining({ code: Parse.Error.EMAIL_NOT_FOUND }),
})
);
const storedCount = await new Parse.Query(Parse.User)
.equalTo('email', email)
.count({ useMasterKey: true });
expect(storedCount).toBe(0);

// Ensure no session persists for the rejected login
const sessions = await new Parse.Query('_Session')
.find({ useMasterKey: true });
expect(sessions.length).toBe(0);
});
});

it('should respect ACL without locking user out', done => {
const user = new Parse.User();
const ACL = new Parse.ACL();
Expand Down
7 changes: 7 additions & 0 deletions src/Options/Definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ module.exports.ParseServerOptions = {
'Configuration for your authentication providers, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication',
action: parsers.objectParser,
},
autoSignupOnLogin: {
env: 'PARSE_SERVER_AUTO_SIGNUP_ON_LOGIN',
help:
'Set to `true` to allow the login endpoint to automatically create a user with the provided username/email and password when no existing user is found. Default is `false`.',
action: parsers.booleanParser,
default: false,
},
cacheAdapter: {
env: 'PARSE_SERVER_CACHE_ADAPTER',
help: 'Adapter module for the cache',
Expand Down
1 change: 1 addition & 0 deletions src/Options/docs.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ export interface ParseServerOptions {
Requires option `verifyUserEmails: true`.
:DEFAULT: false */
preventSignupWithUnverifiedEmail: ?boolean;
/* Set to `true` to allow the login endpoint to automatically create a user with the provided username/email and password when no existing user is found. Default is `false`.
:DEFAULT: false */
autoSignupOnLogin: ?boolean;
/* Set the validity duration of the email verification 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).
Expand Down
Loading
Loading