Files
kami-parse-server/spec/ValidationAndPasswordsReset.spec.js

740 lines
24 KiB
JavaScript
Raw Normal View History

2016-02-27 14:46:29 -05:00
"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();
});
});
2016-02-27 14:46:29 -05:00
it_exclude_dbs(['postgres'])('sends verification email if email verification is enabled', done => {
2016-02-27 14:46:29 -05:00
var emailAdapter = {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve()
}
reconfigureServer({
2016-02-27 14:46:29 -05:00
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');
2016-02-27 14:46:29 -05:00
done();
}
});
2016-02-27 14:46:29 -05:00
});
});
2016-03-13 18:22:56 -04:00
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();
}
});
});
});
2016-03-13 18:22:56 -04:00
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();
}
});
});
});
2016-03-13 18:22:56 -04:00
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();
}
});
});
});
2016-02-27 14:46:29 -05:00
it_exclude_dbs(['postgres'])('prevents user from login if email is not verified but preventLoginWithUnverifiedEmail is set to true', done => {
reconfigureServer({
appName: 'test',
publicServerURL: 'http://localhost:1337/1',
verifyUserEmails: true,
preventLoginWithUnverifiedEmail: true,
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.logIn("zxcv", "asdf"))
.then(result => {
fail('login should have failed');
done();
}, error => {
expect(error.message).toEqual('User email is not verified.')
done();
});
})
.catch(error => {
fail(JSON.stringify(error));
done();
});
});
it_exclude_dbs(['postgres'])('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', done => {
var user = new Parse.User();
var sendEmailOptions;
var emailAdapter = {
sendVerificationEmail: options => {
sendEmailOptions = options;
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {}
}
reconfigureServer({
appName: 'emailing app',
verifyUserEmails: true,
preventLoginWithUnverifiedEmail: true,
emailAdapter: emailAdapter,
publicServerURL: "http://localhost:8378/1"
})
.then(() => {
user.setPassword("other-password");
user.setUsername("user");
user.set('email', 'user@parse.com');
return user.signUp();
}).then(() => {
expect(sendEmailOptions).not.toBeUndefined();
request.get(sendEmailOptions.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);
Parse.User.logIn("user", "other-password")
.then(user => {
expect(typeof user).toBe('object');
expect(user.get('emailVerified')).toBe(true);
done();
}, error => {
fail('login should have succeeded');
done();
});
}, (err) => {
console.error(err);
fail("this should not fail");
done();
}).catch((err) =>
{
console.error(err);
fail(err);
done();
})
});
});
});
it_exclude_dbs(['postgres'])('allows user to login if email is not verified but preventLoginWithUnverifiedEmail is set to false', done => {
reconfigureServer({
appName: 'test',
publicServerURL: 'http://localhost:1337/1',
verifyUserEmails: true,
preventLoginWithUnverifiedEmail: 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.logIn("zxcv", "asdf"))
.then(user => {
expect(typeof user).toBe('object');
expect(user.get('emailVerified')).toBe(false);
done();
}, error => {
fail('login should have succeeded');
done();
});
})
.catch(error => {
fail(JSON.stringify(error));
done();
});
});
it_exclude_dbs(['postgres'])('fails if you include an emailAdapter, set a publicServerURL, but have no appName and send a password reset email', done => {
reconfigureServer({
appName: undefined,
publicServerURL: 'http://localhost:1337/1',
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();
});
});
2016-02-27 14:46:29 -05:00
it('does not send verification email if email verification is disabled', done => {
var emailAdapter = {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve()
}
reconfigureServer({
2016-02-27 14:46:29 -05:00
appName: 'unused',
publicServerURL: 'http://localhost:1337/1',
2016-02-27 14:46:29 -05:00
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');
2016-02-27 14:46:29 -05:00
done();
}
});
2016-02-27 14:46:29 -05:00
});
});
it_exclude_dbs(['postgres'])('receives the app name and user in the adapter', done => {
var emailSent = false;
2016-02-27 14:46:29 -05:00
var emailAdapter = {
sendVerificationEmail: options => {
expect(options.appName).toEqual('emailing app');
expect(options.user.get('email')).toEqual('user@parse.com');
emailSent = true;
2016-02-27 14:46:29 -05:00
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {}
}
reconfigureServer({
2016-02-27 14:46:29 -05:00
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: () => {
expect(emailSent).toBe(true);
done();
},
error: function(userAgain, error) {
fail('Failed to save user');
done();
}
});
2016-02-27 14:46:29 -05:00
});
})
it_exclude_dbs(['postgres'])('when you click the link in the email it sets emailVerified to true and redirects you', done => {
2016-02-27 14:46:29 -05:00
var user = new Parse.User();
var sendEmailOptions;
2016-02-27 14:46:29 -05:00
var emailAdapter = {
sendVerificationEmail: options => {
sendEmailOptions = options;
2016-02-27 14:46:29 -05:00
},
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => {}
}
reconfigureServer({
2016-02-27 14:46:29 -05:00
appName: 'emailing app',
verifyUserEmails: true,
emailAdapter: emailAdapter,
publicServerURL: "http://localhost:8378/1"
})
.then(() => {
user.setPassword("other-password");
user.setUsername("user");
user.set('email', 'user@parse.com');
return user.signUp();
}).then(() => {
expect(sendEmailOptions).not.toBeUndefined();
request.get(sendEmailOptions.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();
}).catch((err) =>
{
console.error(err);
fail(err);
done();
})
});
2016-02-27 14:46:29 -05:00
});
});
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()
});
2016-02-27 14:46:29 -05:00
});
});
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();
});
2016-02-27 14:46:29 -05:00
});
});
it_exclude_dbs(['postgres'])('does not update email verified if you use an invalid token', done => {
2016-02-27 14:46:29 -05:00
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({
2016-02-27 14:46:29 -05:00
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();
}
});
2016-02-27 14:46:29 -05:00
});
});
it_exclude_dbs(['postgres'])('should send a password reset link', done => {
2016-02-27 14:46:29 -05:00
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);
2016-03-13 18:22:56 -04:00
var re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=[a-zA-Z0-9]+\&id=test\&username=zxcv%2Bzxcv/;
2016-02-27 14:46:29 -05:00
expect(response.body.match(re)).not.toBe(null);
done();
});
},
sendMail: () => {}
}
reconfigureServer({
2016-02-27 14:46:29 -05:00
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();
}
});
2016-02-27 14:46:29 -05:00
});
});
});
2016-03-13 18:22:56 -04:00
2016-02-27 14:46:29 -05:00
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();
});
2016-02-27 14:46:29 -05:00
});
});
it_exclude_dbs(['postgres'])('should programatically reset password', done => {
2016-02-27 14:46:29 -05:00
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];
2016-03-13 18:22:56 -04:00
request.post({
2016-02-27 14:46:29 -05:00
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');
2016-03-13 18:22:56 -04:00
2016-02-27 14:46:29 -05:00
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();
});
2016-02-27 14:46:29 -05:00
}, (err) => {
console.error(err);
fail("should login with new password");
done();
});
2016-03-13 18:22:56 -04:00
2016-02-27 14:46:29 -05:00
});
});
},
sendMail: () => {}
}
reconfigureServer({
2016-02-27 14:46:29 -05:00
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();
}
});
2016-02-27 14:46:29 -05:00
});
});
});
2016-03-13 18:22:56 -04:00
})