* reload the right data More passing postgres tests Handle schema updates, and $in for non array columns remove authdata from user and implement ensureUniqueness Make some tests work, detect existing classes Throw proper error for unique index violation fix findOneAndUpdate Support more types support more type Support boolean, fix _rperm/_wperm, add TODO Support string types and also simplify tests Move operator flattening into Parse Server and out of mongo adapters Move authdata transform for create into Parse Server Move authdata transforms completely in to Parse Server Fix test setup inline addSchema Inject default schema to response from DB adapter * Mark tests that don't work in Postgres * Exclude one more test * Exclude some more failing tests * Exclude more tests
603 lines
20 KiB
JavaScript
603 lines
20 KiB
JavaScript
"use strict";
|
||
|
||
let MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions');
|
||
let request = require('request');
|
||
let Config = require("../src/Config");
|
||
|
||
describe("Custom Pages, Email Verification, Password Reset", () => {
|
||
it("should set the custom pages", (done) => {
|
||
reconfigureServer({
|
||
appName: 'unused',
|
||
customPages: {
|
||
invalidLink: "myInvalidLink",
|
||
verifyEmailSuccess: "myVerifyEmailSuccess",
|
||
choosePassword: "myChoosePassword",
|
||
passwordResetSuccess: "myPasswordResetSuccess"
|
||
},
|
||
publicServerURL: "https://my.public.server.com/1"
|
||
})
|
||
.then(() => {
|
||
var config = new Config("test");
|
||
expect(config.invalidLinkURL).toEqual("myInvalidLink");
|
||
expect(config.verifyEmailSuccessURL).toEqual("myVerifyEmailSuccess");
|
||
expect(config.choosePasswordURL).toEqual("myChoosePassword");
|
||
expect(config.passwordResetSuccessURL).toEqual("myPasswordResetSuccess");
|
||
expect(config.verifyEmailURL).toEqual("https://my.public.server.com/1/apps/test/verify_email");
|
||
expect(config.requestResetPasswordURL).toEqual("https://my.public.server.com/1/apps/test/request_password_reset");
|
||
done();
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('sends verification email if email verification is enabled', done => {
|
||
var emailAdapter = {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => Promise.resolve()
|
||
}
|
||
reconfigureServer({
|
||
appName: 'unused',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
spyOn(emailAdapter, 'sendVerificationEmail');
|
||
var user = new Parse.User();
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.setEmail('testIfEnabled@parse.com');
|
||
user.signUp(null, {
|
||
success: function(user) {
|
||
expect(emailAdapter.sendVerificationEmail).toHaveBeenCalled();
|
||
user.fetch()
|
||
.then(() => {
|
||
expect(user.get('emailVerified')).toEqual(false);
|
||
done();
|
||
});
|
||
},
|
||
error: function(userAgain, error) {
|
||
fail('Failed to save user');
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
it('does not send verification email when verification is enabled and email is not set', done => {
|
||
var emailAdapter = {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => Promise.resolve()
|
||
}
|
||
reconfigureServer({
|
||
appName: 'unused',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
spyOn(emailAdapter, 'sendVerificationEmail');
|
||
var user = new Parse.User();
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.signUp(null, {
|
||
success: function(user) {
|
||
expect(emailAdapter.sendVerificationEmail).not.toHaveBeenCalled();
|
||
user.fetch()
|
||
.then(() => {
|
||
expect(user.get('emailVerified')).toEqual(undefined);
|
||
done();
|
||
});
|
||
},
|
||
error: function(userAgain, error) {
|
||
fail('Failed to save user');
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('does send a validation email when updating the email', done => {
|
||
var emailAdapter = {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => Promise.resolve()
|
||
}
|
||
reconfigureServer({
|
||
appName: 'unused',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
spyOn(emailAdapter, 'sendVerificationEmail');
|
||
var user = new Parse.User();
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.signUp(null, {
|
||
success: function(user) {
|
||
expect(emailAdapter.sendVerificationEmail).not.toHaveBeenCalled();
|
||
user.fetch()
|
||
.then((user) => {
|
||
user.set("email", "testWhenUpdating@parse.com");
|
||
return user.save();
|
||
}).then((user) => {
|
||
return user.fetch();
|
||
}).then(() => {
|
||
expect(user.get('emailVerified')).toEqual(false);
|
||
// Wait as on update email, we need to fetch the username
|
||
setTimeout(function(){
|
||
expect(emailAdapter.sendVerificationEmail).toHaveBeenCalled();
|
||
done();
|
||
}, 200);
|
||
});
|
||
},
|
||
error: function(userAgain, error) {
|
||
fail('Failed to save user');
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('does send a validation email with valid verification link when updating the email', done => {
|
||
var emailAdapter = {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => Promise.resolve()
|
||
}
|
||
reconfigureServer({
|
||
appName: 'unused',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
spyOn(emailAdapter, 'sendVerificationEmail').and.callFake((options) => {
|
||
expect(options.link).not.toBeNull();
|
||
expect(options.link).not.toMatch(/token=undefined/);
|
||
Promise.resolve();
|
||
});
|
||
var user = new Parse.User();
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.signUp(null, {
|
||
success: function(user) {
|
||
expect(emailAdapter.sendVerificationEmail).not.toHaveBeenCalled();
|
||
user.fetch()
|
||
.then((user) => {
|
||
user.set("email", "testValidLinkWhenUpdating@parse.com");
|
||
return user.save();
|
||
}).then((user) => {
|
||
return user.fetch();
|
||
}).then(() => {
|
||
expect(user.get('emailVerified')).toEqual(false);
|
||
// Wait as on update email, we need to fetch the username
|
||
setTimeout(function(){
|
||
expect(emailAdapter.sendVerificationEmail).toHaveBeenCalled();
|
||
done();
|
||
}, 200);
|
||
});
|
||
},
|
||
error: function(userAgain, error) {
|
||
fail('Failed to save user');
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('does send with a simple adapter', done => {
|
||
var calls = 0;
|
||
var emailAdapter = {
|
||
sendMail: function(options){
|
||
expect(options.to).toBe('testSendSimpleAdapter@parse.com');
|
||
if (calls == 0) {
|
||
expect(options.subject).toEqual('Please verify your e-mail for My Cool App');
|
||
expect(options.text.match(/verify_email/)).not.toBe(null);
|
||
} else if (calls == 1) {
|
||
expect(options.subject).toEqual('Password Reset for My Cool App');
|
||
expect(options.text.match(/request_password_reset/)).not.toBe(null);
|
||
}
|
||
calls++;
|
||
return Promise.resolve();
|
||
}
|
||
}
|
||
reconfigureServer({
|
||
appName: 'My Cool App',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
var user = new Parse.User();
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.set("email", "testSendSimpleAdapter@parse.com");
|
||
user.signUp(null, {
|
||
success: function(user) {
|
||
expect(calls).toBe(1);
|
||
user.fetch()
|
||
.then((user) => {
|
||
return user.save();
|
||
}).then((user) => {
|
||
return Parse.User.requestPasswordReset("testSendSimpleAdapter@parse.com").catch((err) => {
|
||
fail('Should not fail requesting a password');
|
||
done();
|
||
})
|
||
}).then(() => {
|
||
expect(calls).toBe(2);
|
||
done();
|
||
});
|
||
},
|
||
error: function(userAgain, error) {
|
||
fail('Failed to save user');
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('fails if you include an emailAdapter, set verifyUserEmails to false, dont set a publicServerURL, and try to send a password reset email (regression test for #1649)', done => {
|
||
reconfigureServer({
|
||
appName: 'unused',
|
||
verifyUserEmails: false,
|
||
emailAdapter: MockEmailAdapterWithOptions({
|
||
fromAddress: 'parse@example.com',
|
||
apiKey: 'k',
|
||
domain: 'd',
|
||
}),
|
||
})
|
||
.then(() => {
|
||
let user = new Parse.User();
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.set("email", "testInvalidConfig@parse.com");
|
||
user.signUp(null)
|
||
.then(user => Parse.User.requestPasswordReset("testInvalidConfig@parse.com"))
|
||
.then(result => {
|
||
console.log(result);
|
||
fail('sending password reset email should not have succeeded');
|
||
done();
|
||
}, error => {
|
||
expect(error.message).toEqual('An appName, publicServerURL, and emailAdapter are required for password reset functionality.')
|
||
done();
|
||
});
|
||
})
|
||
.catch(error => {
|
||
fail(JSON.stringify(error));
|
||
done();
|
||
});
|
||
});
|
||
|
||
it('does not send verification email if email verification is disabled', done => {
|
||
var emailAdapter = {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => Promise.resolve()
|
||
}
|
||
reconfigureServer({
|
||
appName: 'unused',
|
||
verifyUserEmails: false,
|
||
emailAdapter: emailAdapter,
|
||
})
|
||
.then(() => {
|
||
spyOn(emailAdapter, 'sendVerificationEmail');
|
||
var user = new Parse.User();
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.signUp(null, {
|
||
success: function(user) {
|
||
user.fetch()
|
||
.then(() => {
|
||
expect(emailAdapter.sendVerificationEmail.calls.count()).toEqual(0);
|
||
expect(user.get('emailVerified')).toEqual(undefined);
|
||
done();
|
||
});
|
||
},
|
||
error: function(userAgain, error) {
|
||
fail('Failed to save user');
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('receives the app name and user in the adapter', done => {
|
||
var emailAdapter = {
|
||
sendVerificationEmail: options => {
|
||
expect(options.appName).toEqual('emailing app');
|
||
expect(options.user.get('email')).toEqual('user@parse.com');
|
||
done();
|
||
},
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => {}
|
||
}
|
||
reconfigureServer({
|
||
appName: 'emailing app',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
var user = new Parse.User();
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.set('email', 'user@parse.com');
|
||
user.signUp(null, {
|
||
success: () => {},
|
||
error: function(userAgain, error) {
|
||
fail('Failed to save user');
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
})
|
||
|
||
it_exclude_dbs(['postgres'])('when you click the link in the email it sets emailVerified to true and redirects you', done => {
|
||
var user = new Parse.User();
|
||
var emailAdapter = {
|
||
sendVerificationEmail: options => {
|
||
request.get(options.link, {
|
||
followRedirect: false,
|
||
}, (error, response, body) => {
|
||
expect(response.statusCode).toEqual(302);
|
||
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=user');
|
||
user.fetch()
|
||
.then(() => {
|
||
expect(user.get('emailVerified')).toEqual(true);
|
||
done();
|
||
}, (err) => {
|
||
console.error(err);
|
||
fail("this should not fail");
|
||
done();
|
||
});
|
||
});
|
||
},
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => {}
|
||
}
|
||
reconfigureServer({
|
||
appName: 'emailing app',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
user.setPassword("asdf");
|
||
user.setUsername("user");
|
||
user.set('email', 'user@parse.com');
|
||
user.signUp();
|
||
});
|
||
});
|
||
|
||
it('redirects you to invalid link if you try to verify email incorrecly', done => {
|
||
reconfigureServer({
|
||
appName: 'emailing app',
|
||
verifyUserEmails: true,
|
||
emailAdapter: {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => {}
|
||
},
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
request.get('http://localhost:8378/1/apps/test/verify_email', {
|
||
followRedirect: false,
|
||
}, (error, response, body) => {
|
||
expect(response.statusCode).toEqual(302);
|
||
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/invalid_link.html');
|
||
done()
|
||
});
|
||
});
|
||
});
|
||
|
||
it('redirects you to invalid link if you try to validate a nonexistant users email', done => {
|
||
reconfigureServer({
|
||
appName: 'emailing app',
|
||
verifyUserEmails: true,
|
||
emailAdapter: {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => {}
|
||
},
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
request.get('http://localhost:8378/1/apps/test/verify_email?token=asdfasdf&username=sadfasga', {
|
||
followRedirect: false,
|
||
}, (error, response, body) => {
|
||
expect(response.statusCode).toEqual(302);
|
||
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/invalid_link.html');
|
||
done();
|
||
});
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('does not update email verified if you use an invalid token', done => {
|
||
var user = new Parse.User();
|
||
var emailAdapter = {
|
||
sendVerificationEmail: options => {
|
||
request.get('http://localhost:8378/1/apps/test/verify_email?token=invalid&username=zxcv', {
|
||
followRedirect: false,
|
||
}, (error, response, body) => {
|
||
expect(response.statusCode).toEqual(302);
|
||
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/invalid_link.html');
|
||
user.fetch()
|
||
.then(() => {
|
||
expect(user.get('emailVerified')).toEqual(false);
|
||
done();
|
||
});
|
||
});
|
||
},
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => {}
|
||
}
|
||
reconfigureServer({
|
||
appName: 'emailing app',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.set('email', 'user@parse.com');
|
||
user.signUp(null, {
|
||
success: () => {},
|
||
error: function(userAgain, error) {
|
||
fail('Failed to save user');
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('should send a password reset link', done => {
|
||
var user = new Parse.User();
|
||
var emailAdapter = {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: options => {
|
||
request.get(options.link, {
|
||
followRedirect: false,
|
||
}, (error, response, body) => {
|
||
if (error) {
|
||
console.error(error);
|
||
fail("Failed to get the reset link");
|
||
return;
|
||
}
|
||
expect(response.statusCode).toEqual(302);
|
||
var re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=[a-zA-Z0-9]+\&id=test\&username=zxcv%2Bzxcv/;
|
||
expect(response.body.match(re)).not.toBe(null);
|
||
done();
|
||
});
|
||
},
|
||
sendMail: () => {}
|
||
}
|
||
reconfigureServer({
|
||
appName: 'emailing app',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv+zxcv");
|
||
user.set('email', 'user@parse.com');
|
||
user.signUp().then(() => {
|
||
Parse.User.requestPasswordReset('user@parse.com', {
|
||
error: (err) => {
|
||
console.error(err);
|
||
fail("Should not fail requesting a password");
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
});
|
||
|
||
it('redirects you to invalid link if you try to request password for a nonexistant users email', done => {
|
||
reconfigureServer({
|
||
appName: 'emailing app',
|
||
verifyUserEmails: true,
|
||
emailAdapter: {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: () => Promise.resolve(),
|
||
sendMail: () => {}
|
||
},
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
request.get('http://localhost:8378/1/apps/test/request_password_reset?token=asdfasdf&username=sadfasga', {
|
||
followRedirect: false,
|
||
}, (error, response, body) => {
|
||
expect(response.statusCode).toEqual(302);
|
||
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/invalid_link.html');
|
||
done();
|
||
});
|
||
});
|
||
});
|
||
|
||
it_exclude_dbs(['postgres'])('should programatically reset password', done => {
|
||
var user = new Parse.User();
|
||
var emailAdapter = {
|
||
sendVerificationEmail: () => Promise.resolve(),
|
||
sendPasswordResetEmail: options => {
|
||
request.get(options.link, {
|
||
followRedirect: false,
|
||
}, (error, response, body) => {
|
||
if (error) {
|
||
console.error(error);
|
||
fail("Failed to get the reset link");
|
||
return;
|
||
}
|
||
expect(response.statusCode).toEqual(302);
|
||
var re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=zxcv/;
|
||
var match = response.body.match(re);
|
||
if (!match) {
|
||
fail("should have a token");
|
||
done();
|
||
return;
|
||
}
|
||
var token = match[1];
|
||
|
||
request.post({
|
||
url: "http://localhost:8378/1/apps/test/request_password_reset" ,
|
||
body: `new_password=hello&token=${token}&username=zxcv`,
|
||
headers: {
|
||
'Content-Type': 'application/x-www-form-urlencoded'
|
||
},
|
||
followRedirect: false,
|
||
}, (error, response, body) => {
|
||
if (error) {
|
||
console.error(error);
|
||
fail("Failed to POST request password reset");
|
||
return;
|
||
}
|
||
expect(response.statusCode).toEqual(302);
|
||
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/password_reset_success.html');
|
||
|
||
Parse.User.logIn("zxcv", "hello").then(function(user){
|
||
let config = new Config('test');
|
||
config.database.adapter.find('_User', { fields: {} }, { 'username': 'zxcv' }, { limit: 1 })
|
||
.then(results => {
|
||
// _perishable_token should be unset after reset password
|
||
expect(results.length).toEqual(1);
|
||
expect(results[0]['_perishable_token']).toEqual(undefined);
|
||
done();
|
||
});
|
||
}, (err) => {
|
||
console.error(err);
|
||
fail("should login with new password");
|
||
done();
|
||
});
|
||
|
||
});
|
||
});
|
||
},
|
||
sendMail: () => {}
|
||
}
|
||
reconfigureServer({
|
||
appName: 'emailing app',
|
||
verifyUserEmails: true,
|
||
emailAdapter: emailAdapter,
|
||
publicServerURL: "http://localhost:8378/1"
|
||
})
|
||
.then(() => {
|
||
user.setPassword("asdf");
|
||
user.setUsername("zxcv");
|
||
user.set('email', 'user@parse.com');
|
||
user.signUp().then(() => {
|
||
Parse.User.requestPasswordReset('user@parse.com', {
|
||
error: (err) => {
|
||
console.error(err);
|
||
fail("Should not fail");
|
||
done();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
});
|
||
})
|