2018-09-01 13:58:06 -04:00
'use strict' ;
2016-02-27 14:46:29 -05:00
2021-03-15 02:04:09 -05:00
const MockEmailAdapterWithOptions = require ( './support/MockEmailAdapterWithOptions' ) ;
2018-09-24 17:07:51 -04:00
const request = require ( '../lib/request' ) ;
2018-09-01 13:58:06 -04:00
const Config = require ( '../lib/Config' ) ;
2025-03-02 12:32:43 +11:00
const Auth = require ( '../lib/Auth' ) ;
2016-05-25 16:48:18 -07:00
2018-09-01 13:58:06 -04:00
describe ( 'Custom Pages, Email Verification, Password Reset' , ( ) => {
it ( 'should set the custom pages' , done => {
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 15:24:45 -05:00
appName : 'unused' ,
customPages : {
2018-09-01 13:58:06 -04:00
invalidLink : 'myInvalidLink' ,
verifyEmailSuccess : 'myVerifyEmailSuccess' ,
choosePassword : 'myChoosePassword' ,
passwordResetSuccess : 'myPasswordResetSuccess' ,
parseFrameURL : 'http://example.com/handle-parse-iframe' ,
2016-02-27 15:24:45 -05:00
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'https://my.public.server.com/1' ,
} ) . then ( ( ) => {
const config = Config . get ( 'test' ) ;
expect ( config . invalidLinkURL ) . toEqual ( 'myInvalidLink' ) ;
expect ( config . verifyEmailSuccessURL ) . toEqual ( 'myVerifyEmailSuccess' ) ;
expect ( config . choosePasswordURL ) . toEqual ( 'myChoosePassword' ) ;
expect ( config . passwordResetSuccessURL ) . toEqual ( 'myPasswordResetSuccess' ) ;
2020-10-25 15:06:58 -05:00
expect ( config . parseFrameURL ) . toEqual ( 'http://example.com/handle-parse-iframe' ) ;
2018-09-01 13:58:06 -04:00
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 15:24:45 -05:00
} ) ;
2016-02-27 14:46:29 -05:00
2024-08-13 22:13:19 +02:00
it _id ( '5e558687-40f3-496c-9e4f-af6100bd1b2f' ) ( it ) ( 'sends verification email if email verification is enabled' , done => {
2018-02-17 09:55:30 -05:00
const emailAdapter = {
2016-02-27 14:46:29 -05:00
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => Promise . resolve ( ) ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 14:46:29 -05:00
appName : 'unused' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( async ( ) => {
spyOn ( emailAdapter , 'sendVerificationEmail' ) ;
const user = new Parse . User ( ) ;
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . setEmail ( 'testIfEnabled@parse.com' ) ;
await user . signUp ( ) ;
2024-01-15 15:44:49 +01:00
await jasmine . timeout ( ) ;
2018-09-01 13:58:06 -04:00
expect ( emailAdapter . sendVerificationEmail ) . toHaveBeenCalled ( ) ;
user . fetch ( ) . then ( ( ) => {
expect ( user . get ( 'emailVerified' ) ) . toEqual ( false ) ;
done ( ) ;
2016-06-10 20:27:21 -07:00
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2016-03-13 18:22:56 -04:00
2016-02-27 15:24:45 -05:00
it ( 'does not send verification email when verification is enabled and email is not set' , done => {
2018-02-17 09:55:30 -05:00
const emailAdapter = {
2016-02-27 15:24:45 -05:00
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => Promise . resolve ( ) ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 15:24:45 -05:00
appName : 'unused' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( async ( ) => {
spyOn ( emailAdapter , 'sendVerificationEmail' ) ;
const user = new Parse . User ( ) ;
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
await user . signUp ( ) ;
expect ( emailAdapter . sendVerificationEmail ) . not . toHaveBeenCalled ( ) ;
user . fetch ( ) . then ( ( ) => {
expect ( user . get ( 'emailVerified' ) ) . toEqual ( undefined ) ;
done ( ) ;
2016-06-10 20:27:21 -07:00
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-02-27 15:24:45 -05:00
} ) ;
2016-03-13 18:22:56 -04:00
2016-08-15 16:48:39 -04:00
it ( 'does send a validation email when updating the email' , done => {
2018-02-17 09:55:30 -05:00
const emailAdapter = {
2016-02-27 15:24:45 -05:00
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => Promise . resolve ( ) ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 15:24:45 -05:00
appName : 'unused' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2018-08-05 13:58:07 -04:00
} ) . then ( async ( ) => {
spyOn ( emailAdapter , 'sendVerificationEmail' ) ;
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
2018-08-05 13:58:07 -04:00
await user . signUp ( ) ;
expect ( emailAdapter . sendVerificationEmail ) . not . toHaveBeenCalled ( ) ;
2018-09-01 13:58:06 -04:00
user
. fetch ( )
. then ( user => {
user . set ( 'email' , 'testWhenUpdating@parse.com' ) ;
2018-08-05 13:58:07 -04:00
return user . save ( ) ;
2018-09-01 13:58:06 -04:00
} )
. then ( user => {
2018-08-05 13:58:07 -04:00
return user . fetch ( ) ;
2018-09-01 13:58:06 -04:00
} )
. then ( ( ) => {
2018-08-05 13:58:07 -04:00
expect ( user . get ( 'emailVerified' ) ) . toEqual ( false ) ;
// Wait as on update email, we need to fetch the username
2020-10-25 15:06:58 -05:00
setTimeout ( function ( ) {
2018-08-05 13:58:07 -04:00
expect ( emailAdapter . sendVerificationEmail ) . toHaveBeenCalled ( ) ;
2017-06-20 09:15:26 -07:00
done ( ) ;
2018-08-05 13:58:07 -04:00
} , 200 ) ;
2017-06-20 09:15:26 -07:00
} ) ;
2018-08-05 13:58:07 -04:00
} ) ;
2016-03-29 17:48:54 +02:00
} ) ;
2018-08-05 13:58:07 -04:00
it ( 'does send a validation email with valid verification link when updating the email' , async done => {
2018-02-17 09:55:30 -05:00
const emailAdapter = {
2016-03-29 17:48:54 +02:00
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => Promise . resolve ( ) ,
} ;
2018-08-05 13:58:07 -04:00
await reconfigureServer ( {
2016-03-29 17:48:54 +02:00
appName : 'unused' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) ;
spyOn ( emailAdapter , 'sendVerificationEmail' ) . and . callFake ( options => {
2018-08-05 13:58:07 -04:00
expect ( options . link ) . not . toBeNull ( ) ;
expect ( options . link ) . not . toMatch ( /token=undefined/ ) ;
2024-01-15 00:47:03 +01:00
expect ( options . link ) . not . toMatch ( /username=undefined/ ) ;
2018-08-05 13:58:07 -04:00
Promise . resolve ( ) ;
} ) ;
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
2018-08-05 13:58:07 -04:00
await user . signUp ( ) ;
expect ( emailAdapter . sendVerificationEmail ) . not . toHaveBeenCalled ( ) ;
2018-09-01 13:58:06 -04:00
await user . fetch ( ) ;
user . set ( 'email' , 'testValidLinkWhenUpdating@parse.com' ) ;
2018-08-05 13:58:07 -04:00
await user . save ( ) ;
await user . fetch ( ) ;
expect ( user . get ( 'emailVerified' ) ) . toEqual ( false ) ;
// Wait as on update email, we need to fetch the username
2020-10-25 15:06:58 -05:00
setTimeout ( function ( ) {
2018-08-05 13:58:07 -04:00
expect ( emailAdapter . sendVerificationEmail ) . toHaveBeenCalled ( ) ;
done ( ) ;
} , 200 ) ;
2016-02-27 20:01:12 -05:00
} ) ;
2016-03-13 18:22:56 -04:00
2024-08-13 22:13:19 +02:00
it _id ( '33d31119-c724-4f5d-83ec-f56815d23df3' ) ( it ) ( 'does send with a simple adapter' , done => {
2018-02-17 09:55:30 -05:00
let calls = 0 ;
const emailAdapter = {
2020-10-25 15:06:58 -05:00
sendMail : function ( options ) {
2016-05-25 16:48:18 -07:00
expect ( options . to ) . toBe ( 'testSendSimpleAdapter@parse.com' ) ;
2016-02-27 20:01:12 -05:00
if ( calls == 0 ) {
2020-10-25 15:06:58 -05:00
expect ( options . subject ) . toEqual ( 'Please verify your e-mail for My Cool App' ) ;
2016-02-27 20:01:12 -05:00
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 ( ) ;
2018-09-01 13:58:06 -04:00
} ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 20:01:12 -05:00
appName : 'My Cool App' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( async ( ) => {
const user = new Parse . User ( ) ;
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'testSendSimpleAdapter@parse.com' ) ;
await user . signUp ( ) ;
2024-01-15 15:44:49 +01:00
await jasmine . timeout ( ) ;
2018-09-01 13:58:06 -04:00
expect ( calls ) . toBe ( 1 ) ;
user
. fetch ( )
. then ( user => {
return user . save ( ) ;
} )
. then ( ( ) => {
2020-10-25 15:06:58 -05:00
return Parse . User . requestPasswordReset ( 'testSendSimpleAdapter@parse.com' ) . catch ( ( ) => {
2018-09-01 13:58:06 -04:00
fail ( 'Should not fail requesting a password' ) ;
2016-04-14 19:24:56 -04:00
done ( ) ;
2018-08-05 13:58:07 -04:00
} ) ;
2018-09-01 13:58:06 -04:00
} )
. then ( ( ) => {
expect ( calls ) . toBe ( 2 ) ;
done ( ) ;
} ) ;
} ) ;
2016-02-27 15:24:45 -05:00
} ) ;
2016-02-27 14:46:29 -05:00
2016-08-15 16:48:39 -04:00
it ( 'prevents user from login if email is not verified but preventLoginWithUnverifiedEmail is set to true' , done => {
2016-07-04 12:56:35 -05:00
reconfigureServer ( {
appName : 'test' ,
publicServerURL : 'http://localhost:1337/1' ,
verifyUserEmails : true ,
preventLoginWithUnverifiedEmail : true ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
} )
2016-11-24 15:47:41 -05:00
. then ( ( ) => {
2017-06-20 09:15:26 -07:00
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'testInvalidConfig@parse.com' ) ;
user
. signUp ( null )
. then ( user => {
2017-09-11 11:07:39 -04:00
expect ( user . getSessionToken ( ) ) . toBe ( undefined ) ;
2018-09-01 13:58:06 -04:00
return Parse . User . logIn ( 'zxcv' , 'asdf' ) ;
2017-09-11 11:07:39 -04:00
} )
2018-09-01 13:58:06 -04:00
. then (
( ) => {
fail ( 'login should have failed' ) ;
done ( ) ;
} ,
error => {
expect ( error . message ) . toEqual ( 'User email is not verified.' ) ;
done ( ) ;
}
) ;
2017-06-20 09:15:26 -07:00
} )
. catch ( error => {
fail ( JSON . stringify ( error ) ) ;
2016-07-04 12:56:35 -05:00
done ( ) ;
} ) ;
} ) ;
2023-12-26 21:01:27 +01:00
it ( 'prevents user from signup and login if email is not verified and preventLoginWithUnverifiedEmail is set to function returning true' , async ( ) => {
await reconfigureServer ( {
appName : 'test' ,
publicServerURL : 'http://localhost:1337/1' ,
verifyUserEmails : async ( ) => true ,
preventLoginWithUnverifiedEmail : async ( ) => true ,
preventSignupWithUnverifiedEmail : true ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
} ) ;
const user = new Parse . User ( ) ;
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'testInvalidConfig@parse.com' ) ;
const signupRes = await user . signUp ( null ) . catch ( e => e ) ;
expect ( signupRes . message ) . toEqual ( 'User email is not verified.' ) ;
const loginRes = await Parse . User . logIn ( 'zxcv' , 'asdf' ) . catch ( e => e ) ;
expect ( loginRes . message ) . toEqual ( 'User email is not verified.' ) ;
} ) ;
2023-12-28 00:34:58 +01:00
it ( 'provides function arguments in verifyUserEmails on login' , async ( ) => {
const user = new Parse . User ( ) ;
user . setUsername ( 'user' ) ;
user . setPassword ( 'pass' ) ;
user . set ( 'email' , 'test@example.com' ) ;
await user . signUp ( ) ;
const verifyUserEmails = {
method : async ( params ) => {
expect ( params . object ) . toBeInstanceOf ( Parse . User ) ;
expect ( params . ip ) . toBeDefined ( ) ;
expect ( params . master ) . toBeDefined ( ) ;
expect ( params . installationId ) . toBeDefined ( ) ;
return true ;
} ,
} ;
const verifyUserEmailsSpy = spyOn ( verifyUserEmails , 'method' ) . and . callThrough ( ) ;
await reconfigureServer ( {
appName : 'test' ,
publicServerURL : 'http://localhost:1337/1' ,
verifyUserEmails : verifyUserEmails . method ,
preventLoginWithUnverifiedEmail : verifyUserEmails . method ,
preventSignupWithUnverifiedEmail : true ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
} ) ;
const res = await Parse . User . logIn ( 'user' , 'pass' ) . catch ( e => e ) ;
expect ( res . code ) . toBe ( 205 ) ;
expect ( verifyUserEmailsSpy ) . toHaveBeenCalledTimes ( 2 ) ;
} ) ;
2024-08-13 22:13:19 +02:00
it _id ( '2a5d24be-2ca5-4385-b580-1423bd392e43' ) ( it ) ( 'allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true' , async ( ) => {
2018-02-17 09:55:30 -05:00
let sendEmailOptions ;
const emailAdapter = {
2016-07-04 12:56:35 -05:00
sendVerificationEmail : options => {
sendEmailOptions = options ;
} ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
} ;
2023-06-08 05:51:53 +10:00
await reconfigureServer ( {
2016-07-04 12:56:35 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
preventLoginWithUnverifiedEmail : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2023-06-08 05:51:53 +10:00
} ) ;
let user = new Parse . User ( ) ;
user . setPassword ( 'other-password' ) ;
user . setUsername ( 'user' ) ;
user . set ( 'email' , 'user@example.com' ) ;
await user . signUp ( ) ;
2024-01-15 15:44:49 +01:00
await jasmine . timeout ( ) ;
2023-06-08 05:51:53 +10:00
expect ( sendEmailOptions ) . not . toBeUndefined ( ) ;
const response = await request ( {
url : sendEmailOptions . link ,
followRedirects : false ,
} ) ;
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
expect ( response . text ) . toContain ( 'Email verified!' ) ;
2023-06-08 05:51:53 +10:00
user = await new Parse . Query ( Parse . User ) . first ( { useMasterKey : true } ) ;
expect ( user . get ( 'emailVerified' ) ) . toEqual ( true ) ;
user = await Parse . User . logIn ( 'user' , 'other-password' ) ;
expect ( typeof user ) . toBe ( 'object' ) ;
expect ( user . get ( 'emailVerified' ) ) . toBe ( true ) ;
2016-07-04 12:56:35 -05:00
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'allows user to login if email is not verified but preventLoginWithUnverifiedEmail is set to false' , done => {
2016-07-04 12:56:35 -05:00
reconfigureServer ( {
appName : 'test' ,
publicServerURL : 'http://localhost:1337/1' ,
verifyUserEmails : true ,
preventLoginWithUnverifiedEmail : false ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
} )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'testInvalidConfig@parse.com' ) ;
user
. signUp ( null )
. then ( ( ) => Parse . User . logIn ( 'zxcv' , 'asdf' ) )
. then (
user => {
expect ( typeof user ) . toBe ( 'object' ) ;
expect ( user . get ( 'emailVerified' ) ) . toBe ( false ) ;
done ( ) ;
} ,
( ) => {
fail ( 'login should have succeeded' ) ;
done ( ) ;
}
) ;
2017-06-20 09:15:26 -07:00
} )
. catch ( error => {
fail ( JSON . stringify ( error ) ) ;
2016-07-04 12:56:35 -05:00
done ( ) ;
} ) ;
} ) ;
2024-08-13 22:13:19 +02:00
it _id ( 'a18a07af-0319-4f15-8237-28070c5948fa' ) ( it ) ( 'does not allow signup with preventSignupWithUnverified' , async ( ) => {
2023-06-08 05:51:53 +10:00
let sendEmailOptions ;
const emailAdapter = {
sendVerificationEmail : options => {
sendEmailOptions = options ;
} ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
sendMail : ( ) => { } ,
} ;
await reconfigureServer ( {
appName : 'test' ,
publicServerURL : 'http://localhost:1337/1' ,
verifyUserEmails : true ,
preventLoginWithUnverifiedEmail : true ,
preventSignupWithUnverifiedEmail : true ,
emailAdapter ,
} ) ;
const newUser = new Parse . User ( ) ;
newUser . setPassword ( 'asdf' ) ;
newUser . setUsername ( 'zxcv' ) ;
newUser . set ( 'email' , 'test@example.com' ) ;
await expectAsync ( newUser . signUp ( ) ) . toBeRejectedWith (
new Parse . Error ( Parse . Error . EMAIL _NOT _FOUND , 'User email is not verified.' )
) ;
const user = await new Parse . Query ( Parse . User ) . first ( { useMasterKey : true } ) ;
expect ( user ) . toBeDefined ( ) ;
expect ( sendEmailOptions ) . toBeDefined ( ) ;
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'fails if you include an emailAdapter, set a publicServerURL, but have no appName and send a password reset email' , done => {
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-06-28 19:25:44 -07:00
appName : undefined ,
publicServerURL : 'http://localhost:1337/1' ,
2016-05-25 16:48:18 -07:00
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
} )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'testInvalidConfig@parse.com' ) ;
user
. signUp ( null )
2020-10-25 15:06:58 -05:00
. then ( ( ) => Parse . User . requestPasswordReset ( 'testInvalidConfig@parse.com' ) )
2018-09-01 13:58:06 -04:00
. then (
2018-09-24 17:07:51 -04:00
( ) => {
2018-09-01 13:58:06 -04:00
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 and email verification functionality.'
) ;
done ( ) ;
}
) ;
2017-06-20 09:15:26 -07:00
} )
. catch ( error => {
fail ( JSON . stringify ( error ) ) ;
2016-06-10 20:27:21 -07:00
done ( ) ;
} ) ;
2016-05-25 16:48:18 -07:00
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'fails if you include an emailAdapter, have an appName, but have no publicServerURL and send a password reset email' , done => {
2016-07-05 12:08:46 -07:00
reconfigureServer ( {
appName : undefined ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
} )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'testInvalidConfig@parse.com' ) ;
user
. signUp ( null )
2020-10-25 15:06:58 -05:00
. then ( ( ) => Parse . User . requestPasswordReset ( 'testInvalidConfig@parse.com' ) )
2018-09-01 13:58:06 -04:00
. then (
2018-09-24 17:07:51 -04:00
( ) => {
2018-09-01 13:58:06 -04:00
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 and email verification functionality.'
) ;
done ( ) ;
}
) ;
2017-06-20 09:15:26 -07:00
} )
. catch ( error => {
fail ( JSON . stringify ( error ) ) ;
2016-07-05 12:08:46 -07:00
done ( ) ;
} ) ;
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'fails if you set a publicServerURL, have an appName, but no emailAdapter and send a password reset email' , done => {
2016-07-05 12:08:46 -07:00
reconfigureServer ( {
appName : 'unused' ,
publicServerURL : 'http://localhost:1337/1' ,
emailAdapter : undefined ,
} )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'testInvalidConfig@parse.com' ) ;
user
. signUp ( null )
2020-10-25 15:06:58 -05:00
. then ( ( ) => Parse . User . requestPasswordReset ( 'testInvalidConfig@parse.com' ) )
2018-09-01 13:58:06 -04:00
. then (
2018-09-24 17:07:51 -04:00
( ) => {
2018-09-01 13:58:06 -04:00
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 and email verification functionality.'
) ;
done ( ) ;
}
) ;
2017-06-20 09:15:26 -07:00
} )
. catch ( error => {
fail ( JSON . stringify ( error ) ) ;
2016-07-05 12:08:46 -07:00
done ( ) ;
} ) ;
} ) ;
2019-12-17 03:15:29 +01:00
it ( 'succeeds sending a password reset email if appName, publicServerURL, and email adapter are provided' , done => {
2016-07-05 12:08:46 -07:00
reconfigureServer ( {
appName : 'coolapp' ,
publicServerURL : 'http://localhost:1337/1' ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
} )
2016-11-24 15:47:41 -05:00
. then ( ( ) => {
2017-06-20 09:15:26 -07:00
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'testInvalidConfig@parse.com' ) ;
user
. signUp ( null )
2020-10-25 15:06:58 -05:00
. then ( ( ) => Parse . User . requestPasswordReset ( 'testInvalidConfig@parse.com' ) )
2018-09-01 13:58:06 -04:00
. then (
( ) => {
done ( ) ;
} ,
error => {
done ( error ) ;
}
) ;
2017-06-20 09:15:26 -07:00
} )
. catch ( error => {
fail ( JSON . stringify ( error ) ) ;
2016-07-05 12:08:46 -07:00
done ( ) ;
2016-09-18 18:32:34 -04:00
} ) ;
} ) ;
2018-10-02 14:41:22 -07:00
it ( 'succeeds sending a password reset username if appName, publicServerURL, and email adapter are provided' , done => {
2016-12-07 15:17:05 -08:00
const adapter = MockEmailAdapterWithOptions ( {
2016-09-18 18:32:34 -04:00
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
2020-10-25 15:06:58 -05:00
sendMail : function ( options ) {
2016-09-18 18:32:34 -04:00
expect ( options . to ) . toEqual ( 'testValidConfig@parse.com' ) ;
return Promise . resolve ( ) ;
2018-09-01 13:58:06 -04:00
} ,
2016-09-18 18:32:34 -04:00
} ) ;
// delete that handler to force using the default
delete adapter . sendPasswordResetEmail ;
spyOn ( adapter , 'sendMail' ) . and . callThrough ( ) ;
reconfigureServer ( {
appName : 'coolapp' ,
publicServerURL : 'http://localhost:1337/1' ,
2018-09-01 13:58:06 -04:00
emailAdapter : adapter ,
2016-09-18 18:32:34 -04:00
} )
2016-11-24 15:47:41 -05:00
. then ( ( ) => {
2017-06-20 09:15:26 -07:00
const user = new Parse . User ( ) ;
2018-09-01 13:58:06 -04:00
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'testValidConfig@parse.com' ) ;
user
. signUp ( null )
2020-10-25 15:06:58 -05:00
. then ( ( ) => Parse . User . requestPasswordReset ( 'testValidConfig@parse.com' ) )
2018-09-01 13:58:06 -04:00
. then (
( ) => {
expect ( adapter . sendMail ) . toHaveBeenCalled ( ) ;
done ( ) ;
} ,
error => {
done ( error ) ;
}
) ;
2017-06-20 09:15:26 -07:00
} )
. catch ( error => {
fail ( JSON . stringify ( error ) ) ;
2016-09-18 18:32:34 -04:00
done ( ) ;
2016-07-05 12:08:46 -07:00
} ) ;
} ) ;
2016-02-27 14:46:29 -05:00
it ( 'does not send verification email if email verification is disabled' , done => {
2018-02-17 09:55:30 -05:00
const emailAdapter = {
2016-02-27 14:46:29 -05:00
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => Promise . resolve ( ) ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 14:46:29 -05:00
appName : 'unused' ,
2016-06-28 19:25:44 -07:00
publicServerURL : 'http://localhost:1337/1' ,
2016-02-27 14:46:29 -05:00
verifyUserEmails : false ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
} ) . then ( async ( ) => {
spyOn ( emailAdapter , 'sendVerificationEmail' ) ;
const user = new Parse . User ( ) ;
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
await user . signUp ( ) ;
await user . fetch ( ) ;
expect ( emailAdapter . sendVerificationEmail . calls . count ( ) ) . toEqual ( 0 ) ;
expect ( user . get ( 'emailVerified' ) ) . toEqual ( undefined ) ;
done ( ) ;
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2024-08-13 22:13:19 +02:00
it _id ( '45f550a2-a2b2-4b2b-b533-ccbf96139cc9' ) ( it ) ( 'receives the app name and user in the adapter' , done => {
2018-02-17 09:55:30 -05:00
let emailSent = false ;
const emailAdapter = {
2016-02-27 14:46:29 -05:00
sendVerificationEmail : options => {
expect ( options . appName ) . toEqual ( 'emailing app' ) ;
expect ( options . user . get ( 'email' ) ) . toEqual ( 'user@parse.com' ) ;
2016-06-26 23:20:02 -04:00
emailSent = true ;
2016-02-27 14:46:29 -05:00
} ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 14:46:29 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( async ( ) => {
const user = new Parse . User ( ) ;
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'user@parse.com' ) ;
await user . signUp ( ) ;
2024-01-15 15:44:49 +01:00
await jasmine . timeout ( ) ;
2018-09-01 13:58:06 -04:00
expect ( emailSent ) . toBe ( true ) ;
done ( ) ;
} ) ;
} ) ;
2016-02-27 14:46:29 -05:00
2024-08-13 22:13:19 +02:00
it _id ( 'ea37ef62-aad8-4a17-8dfe-35e5b2986f0f' ) ( it ) ( 'when you click the link in the email it sets emailVerified to true and redirects you' , done => {
2018-02-17 09:55:30 -05:00
const user = new Parse . User ( ) ;
let sendEmailOptions ;
const emailAdapter = {
2016-02-27 14:46:29 -05:00
sendVerificationEmail : options => {
2016-06-26 23:20:02 -04:00
sendEmailOptions = options ;
2016-02-27 14:46:29 -05:00
} ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 14:46:29 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-06-10 20:27:21 -07:00
} )
2017-06-20 09:15:26 -07:00
. then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setPassword ( 'other-password' ) ;
user . setUsername ( 'user' ) ;
2017-06-20 09:15:26 -07:00
user . set ( 'email' , 'user@parse.com' ) ;
return user . signUp ( ) ;
2018-09-01 13:58:06 -04:00
} )
2024-01-15 15:44:49 +01:00
. then ( ( ) => jasmine . timeout ( ) )
2018-09-01 13:58:06 -04:00
. then ( ( ) => {
2017-06-20 09:15:26 -07:00
expect ( sendEmailOptions ) . not . toBeUndefined ( ) ;
2018-09-24 17:07:51 -04:00
request ( {
url : sendEmailOptions . link ,
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
expect ( response . text ) . toContain ( 'Email verified!' ) ;
2018-09-24 17:07:51 -04:00
user
. fetch ( )
. then (
( ) => {
expect ( user . get ( 'emailVerified' ) ) . toEqual ( true ) ;
done ( ) ;
} ,
err => {
2018-09-01 13:58:06 -04:00
jfail ( err ) ;
2018-09-24 17:07:51 -04:00
fail ( 'this should not fail' ) ;
2018-09-01 13:58:06 -04:00
done ( ) ;
2018-09-24 17:07:51 -04:00
}
)
. catch ( err => {
jfail ( err ) ;
done ( ) ;
} ) ;
} ) ;
2016-06-26 23:20:02 -04:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2018-10-02 14:41:22 -07:00
it ( 'redirects you to invalid link if you try to verify email incorrectly' , done => {
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-29 20:51:13 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-02-29 20:51:13 -05:00
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( ( ) => {
2018-09-24 17:07:51 -04:00
request ( {
url : 'http://localhost:8378/1/apps/test/verify_email' ,
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
expect ( response . text ) . toContain ( 'Invalid verification link!' ) ;
2018-09-24 17:07:51 -04:00
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2017-05-10 14:02:16 +01:00
it ( 'redirects you to invalid verification link page if you try to validate a nonexistant users email' , done => {
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-29 20:51:13 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-02-29 20:51:13 -05:00
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( ( ) => {
2018-09-24 17:07:51 -04:00
request ( {
2025-03-02 12:32:43 +11:00
url : 'http://localhost:8378/1/apps/test/verify_email?token=asdfasdf' ,
2018-09-24 17:07:51 -04:00
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
expect ( response . text ) . toContain ( 'Invalid verification link!' ) ;
2018-09-24 17:07:51 -04:00
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2017-05-10 14:02:16 +01:00
} ) ;
it ( 'redirects you to link send fail page if you try to resend a link for a nonexistant user' , done => {
reconfigureServer ( {
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2017-05-10 14:02:16 +01:00
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( ( ) => {
2018-09-24 17:07:51 -04:00
request ( {
url : 'http://localhost:8378/1/apps/test/resend_verification_email' ,
method : 'POST' ,
followRedirects : false ,
body : {
username : 'sadfasga' ,
2018-09-01 13:58:06 -04:00
} ,
2018-09-24 17:07:51 -04:00
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 303 ) ;
expect ( response . text ) . toContain ( 'email_verification_send_fail.html' ) ;
2018-09-24 17:07:51 -04:00
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2016-08-15 16:48:39 -04:00
it ( 'does not update email verified if you use an invalid token' , done => {
2018-02-17 09:55:30 -05:00
const user = new Parse . User ( ) ;
const emailAdapter = {
2016-11-24 15:47:41 -05:00
sendVerificationEmail : ( ) => {
2018-09-24 17:07:51 -04:00
request ( {
2025-03-02 12:32:43 +11:00
url : 'http://localhost:8378/1/apps/test/verify_email?token=invalid' ,
2018-09-24 17:07:51 -04:00
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
expect ( response . text ) . toContain ( 'Invalid verification link!' ) ;
2018-09-24 17:07:51 -04:00
user . fetch ( ) . then ( ( ) => {
expect ( user . get ( 'emailVerified' ) ) . toEqual ( false ) ;
done ( ) ;
} ) ;
} ) ;
2016-02-27 14:46:29 -05:00
} ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 14:46:29 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( ( ) => {
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'user@parse.com' ) ;
user . signUp ( null , {
success : ( ) => { } ,
2020-10-25 15:06:58 -05:00
error : function ( ) {
2018-09-01 13:58:06 -04:00
fail ( 'Failed to save user' ) ;
done ( ) ;
} ,
2016-06-10 20:27:21 -07:00
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2016-08-18 18:05:26 -04:00
it ( 'should send a password reset link' , done => {
2018-02-17 09:55:30 -05:00
const user = new Parse . User ( ) ;
const emailAdapter = {
2016-02-27 14:46:29 -05:00
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
2018-09-24 17:07:51 -04:00
request ( {
url : options . link ,
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
const re = /name="token"[^>]*value="([^"]+)"/ ;
2018-09-24 17:07:51 -04:00
expect ( response . text . match ( re ) ) . not . toBe ( null ) ;
done ( ) ;
} ) ;
2016-02-27 14:46:29 -05:00
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 14:46:29 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
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 => {
jfail ( err ) ;
fail ( 'Should not fail requesting a password' ) ;
done ( ) ;
} ,
2016-06-10 20:27:21 -07:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
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 => {
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-29 20:51:13 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-02-29 20:51:13 -05:00
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( ( ) => {
2018-09-24 17:07:51 -04:00
request ( {
2025-03-02 12:32:43 +11:00
url : 'http://localhost:8378/1/apps/test/request_password_reset?token=asdfasdf' ,
2018-09-24 17:07:51 -04:00
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
expect ( response . text ) . toContain ( 'Invalid password reset link!' ) ;
2018-09-24 17:07:51 -04:00
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2018-10-02 14:41:22 -07:00
it ( 'should programmatically reset password' , done => {
2018-02-17 09:55:30 -05:00
const user = new Parse . User ( ) ;
const emailAdapter = {
2016-02-27 14:46:29 -05:00
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
2018-09-24 17:07:51 -04:00
request ( {
url : options . link ,
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
const re = /name="token"[^>]*value="([^"]+)"/ ;
2018-09-24 17:07:51 -04:00
const match = response . text . match ( re ) ;
if ( ! match ) {
fail ( 'should have a token' ) ;
done ( ) ;
return ;
}
const token = match [ 1 ] ;
2018-09-01 13:58:06 -04:00
2018-09-24 17:07:51 -04:00
request ( {
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
method : 'POST' ,
body : { new _password : 'hello' , token , username : 'zxcv' } ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
} ,
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
expect ( response . text ) . toContain ( 'Success!' ) ;
2018-09-01 13:58:06 -04:00
2018-09-24 17:07:51 -04:00
Parse . User . logIn ( 'zxcv' , 'hello' ) . then (
2020-10-25 15:06:58 -05:00
function ( ) {
2018-09-24 17:07:51 -04:00
const config = Config . get ( 'test' ) ;
config . database . adapter
2020-10-25 15:06:58 -05:00
. find ( '_User' , { fields : { } } , { username : 'zxcv' } , { limit : 1 } )
2018-09-24 17:07:51 -04:00
. then ( results => {
// _perishable_token should be unset after reset password
expect ( results . length ) . toEqual ( 1 ) ;
expect ( results [ 0 ] [ '_perishable_token' ] ) . toEqual ( undefined ) ;
2018-09-01 13:58:06 -04:00
done ( ) ;
2018-09-24 17:07:51 -04:00
} ) ;
} ,
err => {
jfail ( err ) ;
fail ( 'should login with new password' ) ;
done ( ) ;
2018-09-01 13:58:06 -04:00
}
) ;
2018-09-24 17:07:51 -04:00
} ) ;
} ) ;
2016-02-27 14:46:29 -05:00
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
} ;
2016-06-10 20:27:21 -07:00
reconfigureServer ( {
2016-02-27 14:46:29 -05:00
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
2018-09-01 13:58:06 -04:00
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 => {
jfail ( err ) ;
fail ( 'Should not fail' ) ;
done ( ) ;
} ,
2016-06-10 20:27:21 -07:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-02-27 14:46:29 -05:00
} ) ;
2018-10-02 15:01:50 -07:00
2019-12-17 03:15:29 +01:00
it ( 'should redirect with username encoded on success page' , done => {
const user = new Parse . User ( ) ;
const emailAdapter = {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
request ( {
url : options . link ,
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
const re = /name="token"[^>]*value="([^"]+)"/ ;
2019-12-17 03:15:29 +01:00
const match = response . text . match ( re ) ;
if ( ! match ) {
fail ( 'should have a token' ) ;
done ( ) ;
return ;
}
const token = match [ 1 ] ;
request ( {
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
method : 'POST' ,
body : { new _password : 'hello' , token , username : 'zxcv+1' } ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
} ,
followRedirects : false ,
} ) . then ( response => {
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
expect ( response . text ) . toContain ( 'Success!' ) ;
2019-12-17 03:15:29 +01:00
done ( ) ;
} ) ;
} ) ;
} ,
sendMail : ( ) => { } ,
} ;
reconfigureServer ( {
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( ( ) => {
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv+1' ) ;
user . set ( 'email' , 'user@parse.com' ) ;
user . signUp ( ) . then ( ( ) => {
Parse . User . requestPasswordReset ( 'user@parse.com' , {
error : err => {
jfail ( err ) ;
fail ( 'Should not fail' ) ;
done ( ) ;
} ,
} ) ;
} ) ;
} ) ;
} ) ;
2019-03-14 23:06:18 +02:00
it ( 'should programmatically reset password on ajax request' , async done => {
const user = new Parse . User ( ) ;
const emailAdapter = {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : async options => {
const response = await request ( {
url : options . link ,
followRedirects : false ,
} ) ;
2025-12-12 20:55:39 +01:00
expect ( response . status ) . toEqual ( 200 ) ;
const re = /name="token"[^>]*value="([^"]+)"/ ;
2019-03-14 23:06:18 +02:00
const match = response . text . match ( re ) ;
if ( ! match ) {
fail ( 'should have a token' ) ;
return ;
}
const token = match [ 1 ] ;
const resetResponse = await request ( {
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
method : 'POST' ,
body : { new _password : 'hello' , token , username : 'zxcv' } ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
'X-Requested-With' : 'XMLHttpRequest' ,
} ,
followRedirects : false ,
} ) ;
expect ( resetResponse . status ) . toEqual ( 200 ) ;
expect ( resetResponse . text ) . toEqual ( '"Password successfully reset"' ) ;
await Parse . User . logIn ( 'zxcv' , 'hello' ) ;
const config = Config . get ( 'test' ) ;
const results = await config . database . adapter . find (
'_User' ,
{ fields : { } } ,
{ username : 'zxcv' } ,
{ limit : 1 }
) ;
// _perishable_token should be unset after reset password
expect ( results . length ) . toEqual ( 1 ) ;
expect ( results [ 0 ] [ '_perishable_token' ] ) . toEqual ( undefined ) ;
done ( ) ;
} ,
sendMail : ( ) => { } ,
} ;
await reconfigureServer ( {
appName : 'emailing app' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
publicServerURL : 'http://localhost:8378/1' ,
} ) ;
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'user@parse.com' ) ;
await user . signUp ( ) ;
await Parse . User . requestPasswordReset ( 'user@parse.com' ) ;
} ) ;
it ( 'should return ajax failure error on ajax request with wrong data provided' , async ( ) => {
await reconfigureServer ( {
publicServerURL : 'http://localhost:8378/1' ,
} ) ;
try {
await request ( {
method : 'POST' ,
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
2025-03-02 12:32:43 +11:00
body : ` new_password=user1&token=12345 ` ,
2019-03-14 23:06:18 +02:00
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
'X-Requested-With' : 'XMLHttpRequest' ,
} ,
followRedirects : false ,
} ) ;
} catch ( error ) {
expect ( error . status ) . not . toBe ( 302 ) ;
expect ( error . text ) . toEqual (
'{"code":-1,"error":"Failed to reset password: username / email / token is invalid"}'
) ;
}
} ) ;
2018-10-09 17:34:04 -07:00
it ( 'deletes password reset token on email address change' , done => {
2018-10-02 15:01:50 -07:00
reconfigureServer ( {
appName : 'coolapp' ,
publicServerURL : 'http://localhost:1337/1' ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
} )
. then ( ( ) => {
const config = Config . get ( 'test' ) ;
const user = new Parse . User ( ) ;
user . setPassword ( 'asdf' ) ;
user . setUsername ( 'zxcv' ) ;
user . set ( 'email' , 'test@parse.com' ) ;
return user
. signUp ( null )
. then ( ( ) => Parse . User . requestPasswordReset ( 'test@parse.com' ) )
2018-10-09 17:34:04 -07:00
. then ( ( ) =>
config . database . adapter . find (
2018-10-02 15:01:50 -07:00
'_User' ,
{ fields : { } } ,
{ username : 'zxcv' } ,
{ limit : 1 }
2018-10-09 17:34:04 -07:00
)
)
2018-10-02 15:01:50 -07:00
. then ( results => {
// validate that there is a token
expect ( results . length ) . toEqual ( 1 ) ;
expect ( results [ 0 ] [ '_perishable_token' ] ) . not . toBeNull ( ) ;
user . set ( 'email' , 'test2@parse.com' ) ;
return user . save ( ) ;
} )
2018-10-09 17:34:04 -07:00
. then ( ( ) =>
config . database . adapter . find (
2018-10-02 15:01:50 -07:00
'_User' ,
{ fields : { } } ,
{ username : 'zxcv' } ,
2018-10-09 17:34:04 -07:00
{ limit : 1 }
)
2018-10-02 15:01:50 -07:00
)
. then ( results => {
expect ( results . length ) . toEqual ( 1 ) ;
2018-10-04 10:26:54 -07:00
expect ( results [ 0 ] [ '_perishable_token' ] ) . toBeUndefined ( ) ;
2018-10-02 15:01:50 -07:00
done ( ) ;
2018-10-09 17:34:04 -07:00
} ) ;
2018-10-02 15:01:50 -07:00
} )
. catch ( error => {
fail ( JSON . stringify ( error ) ) ;
done ( ) ;
} ) ;
} ) ;
2023-02-25 06:30:48 +11:00
2025-03-02 12:32:43 +11:00
it ( 'can resend email using an expired reset password token' , async ( ) => {
const user = new Parse . User ( ) ;
const emailAdapter = {
sendVerificationEmail : ( ) => { } ,
sendPasswordResetEmail : ( ) => Promise . resolve ( ) ,
sendMail : ( ) => { } ,
} ;
await reconfigureServer ( {
appName : 'emailVerifyToken' ,
verifyUserEmails : true ,
emailAdapter : emailAdapter ,
emailVerifyTokenValidityDuration : 5 , // 5 seconds
publicServerURL : 'http://localhost:8378/1' ,
passwordPolicy : {
resetTokenValidityDuration : 5 * 60 , // 5 minutes
} ,
silent : false ,
} ) ;
user . setUsername ( 'test' ) ;
user . setPassword ( 'password' ) ;
user . set ( 'email' , 'user@example.com' ) ;
await user . signUp ( ) ;
await Parse . User . requestPasswordReset ( 'user@example.com' ) ;
await Parse . Server . database . update (
'_User' ,
{ objectId : user . id } ,
{
_perishable _token _expires _at : Parse . _encode ( new Date ( '2000' ) ) ,
}
) ;
let obj = await Parse . Server . database . find (
'_User' ,
{ objectId : user . id } ,
{ } ,
Auth . maintenance ( Parse . Server )
) ;
const token = obj [ 0 ] . _perishable _token ;
const res = await request ( {
url : ` http://localhost:8378/1/apps/test/request_password_reset ` ,
method : 'POST' ,
body : {
token ,
new _password : 'newpassword' ,
} ,
} ) ;
2025-12-12 20:55:39 +01:00
expect ( res . text ) . toContain ( 'The password reset link has expired' ) ;
2025-03-02 12:32:43 +11:00
await request ( {
url : ` http://localhost:8378/1/requestPasswordReset ` ,
method : 'POST' ,
body : {
token : token ,
} ,
headers : {
'X-Parse-Application-Id' : 'test' ,
'X-Parse-REST-API-Key' : 'rest' ,
'Content-Type' : 'application/json' ,
} ,
} ) ;
obj = await Parse . Server . database . find (
'_User' ,
{ objectId : user . id } ,
{ } ,
Auth . maintenance ( Parse . Server )
) ;
expect ( obj . _perishable _token ) . not . toBe ( token ) ;
} ) ;
2023-02-25 06:30:48 +11:00
it ( 'should throw on an invalid reset password' , async ( ) => {
await reconfigureServer ( {
appName : 'coolapp' ,
publicServerURL : 'http://localhost:1337/1' ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
passwordPolicy : {
resetPasswordSuccessOnInvalidEmail : false ,
} ,
} ) ;
await expectAsync ( Parse . User . requestPasswordReset ( 'test@example.com' ) ) . toBeRejectedWith (
new Parse . Error ( Parse . Error . OBJECT _NOT _FOUND , 'A user with that email does not exist.' )
) ;
} ) ;
it ( 'validate resetPasswordSuccessonInvalidEmail' , async ( ) => {
const invalidValues = [ [ ] , { } , 1 , 'string' ] ;
for ( const value of invalidValues ) {
await expectAsync (
reconfigureServer ( {
appName : 'coolapp' ,
publicServerURL : 'http://localhost:1337/1' ,
emailAdapter : MockEmailAdapterWithOptions ( {
fromAddress : 'parse@example.com' ,
apiKey : 'k' ,
domain : 'd' ,
} ) ,
passwordPolicy : {
resetPasswordSuccessOnInvalidEmail : value ,
} ,
} )
) . toBeRejectedWith ( 'resetPasswordSuccessOnInvalidEmail must be a boolean value' ) ;
}
} ) ;
2018-08-05 13:58:07 -04:00
} ) ;