-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request from GHSA-h4mf-75hf-67w4
* Fix session token issue * verify email problem * Fix password reset problem * Change test file name * Split tests * Refetch user * Replaces lets to consts * Refactor unit test What you have is just finee, but wanted to show you what I meant with my comment Use jasmine's this to set stuff in beforeEach's Not that all functions need to be `function ()` instead of `() =>` so `this` is preserved. see: https://jasmine.github.io/tutorials/your_first_suite#section-The_%3Ccode%3Ethis%3C/code%3E_keyword Co-authored-by: Antonio Davi Macedo Coelho de Castro <[email protected]>
- Loading branch information
1 parent
bde8ab6
commit 3a3a5ee
Showing
3 changed files
with
212 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
const request = require('../lib/request'); | ||
|
||
const serverURL = 'http://localhost:8378/1'; | ||
const headers = { | ||
'Content-Type': 'application/json', | ||
}; | ||
const keys = { | ||
_ApplicationId: 'test', | ||
_JavaScriptKey: 'test', | ||
}; | ||
const emailAdapter = { | ||
sendVerificationEmail: () => Promise.resolve(), | ||
sendPasswordResetEmail: () => Promise.resolve(), | ||
sendMail: () => {}, | ||
}; | ||
const appName = 'test'; | ||
const publicServerURL = 'http://localhost:8378/1'; | ||
|
||
describe('Regex Vulnerabilities', function() { | ||
beforeEach(async function() { | ||
await reconfigureServer({ | ||
verifyUserEmails: true, | ||
emailAdapter, | ||
appName, | ||
publicServerURL, | ||
}); | ||
|
||
const signUpResponse = await request({ | ||
url: `${serverURL}/users`, | ||
method: 'POST', | ||
headers, | ||
body: JSON.stringify({ | ||
...keys, | ||
_method: 'POST', | ||
username: '[email protected]', | ||
password: 'somepassword', | ||
email: '[email protected]', | ||
}), | ||
}); | ||
this.objectId = signUpResponse.data.objectId; | ||
this.sessionToken = signUpResponse.data.sessionToken; | ||
this.partialSessionToken = this.sessionToken.slice(0, 3); | ||
}); | ||
|
||
describe('on session token', function() { | ||
it('should not work with regex', async function() { | ||
try { | ||
await request({ | ||
url: `${serverURL}/users/me`, | ||
method: 'POST', | ||
headers, | ||
body: JSON.stringify({ | ||
...keys, | ||
_SessionToken: { | ||
$regex: this.partialSessionToken, | ||
}, | ||
_method: 'GET', | ||
}), | ||
}); | ||
fail('should not work'); | ||
} catch (e) { | ||
expect(e.data.code).toEqual(209); | ||
expect(e.data.error).toEqual('Invalid session token'); | ||
} | ||
}); | ||
|
||
it('should work with plain token', async function() { | ||
const meResponse = await request({ | ||
url: `${serverURL}/users/me`, | ||
method: 'POST', | ||
headers, | ||
body: JSON.stringify({ | ||
...keys, | ||
_SessionToken: this.sessionToken, | ||
_method: 'GET', | ||
}), | ||
}); | ||
expect(meResponse.data.objectId).toEqual(this.objectId); | ||
expect(meResponse.data.sessionToken).toEqual(this.sessionToken); | ||
}); | ||
}); | ||
|
||
describe('on verify e-mail', function() { | ||
beforeEach(async function() { | ||
const userQuery = new Parse.Query(Parse.User); | ||
this.user = await userQuery.get(this.objectId, { useMasterKey: true }); | ||
}); | ||
|
||
it('should not work with regex', async function() { | ||
expect(this.user.get('emailVerified')).toEqual(false); | ||
await request({ | ||
url: `${serverURL}/apps/test/[email protected]&token[$regex]=`, | ||
method: 'GET', | ||
}); | ||
await this.user.fetch({ useMasterKey: true }); | ||
expect(this.user.get('emailVerified')).toEqual(false); | ||
}); | ||
|
||
it('should work with plain token', async function() { | ||
expect(this.user.get('emailVerified')).toEqual(false); | ||
// It should work | ||
await request({ | ||
url: `${serverURL}/apps/test/[email protected]&token=${this.user.get( | ||
'_email_verify_token' | ||
)}`, | ||
method: 'GET', | ||
}); | ||
await this.user.fetch({ useMasterKey: true }); | ||
expect(this.user.get('emailVerified')).toEqual(true); | ||
}); | ||
}); | ||
|
||
describe('on password reset', function() { | ||
beforeEach(async function() { | ||
this.user = await Parse.User.logIn( | ||
'[email protected]', | ||
'somepassword' | ||
); | ||
}); | ||
|
||
it('should not work with regex', async function() { | ||
expect(this.user.id).toEqual(this.objectId); | ||
await request({ | ||
url: `${serverURL}/requestPasswordReset`, | ||
method: 'POST', | ||
headers, | ||
body: JSON.stringify({ | ||
...keys, | ||
_method: 'POST', | ||
email: '[email protected]', | ||
}), | ||
}); | ||
await this.user.fetch({ useMasterKey: true }); | ||
const passwordResetResponse = await request({ | ||
url: `${serverURL}/apps/test/[email protected]&token[$regex]=`, | ||
method: 'GET', | ||
}); | ||
expect(passwordResetResponse.status).toEqual(302); | ||
expect(passwordResetResponse.headers.location).toMatch( | ||
`\\/invalid\\_link\\.html` | ||
); | ||
await request({ | ||
url: `${serverURL}/apps/test/request_password_reset`, | ||
method: 'POST', | ||
body: { | ||
token: { $regex: '' }, | ||
username: '[email protected]', | ||
new_password: 'newpassword', | ||
}, | ||
}); | ||
try { | ||
await Parse.User.logIn('[email protected]', 'newpassword'); | ||
fail('should not work'); | ||
} catch (e) { | ||
expect(e.code).toEqual(101); | ||
expect(e.message).toEqual('Invalid username/password.'); | ||
} | ||
}); | ||
|
||
it('should work with plain token', async function() { | ||
expect(this.user.id).toEqual(this.objectId); | ||
await request({ | ||
url: `${serverURL}/requestPasswordReset`, | ||
method: 'POST', | ||
headers, | ||
body: JSON.stringify({ | ||
...keys, | ||
_method: 'POST', | ||
email: '[email protected]', | ||
}), | ||
}); | ||
await this.user.fetch({ useMasterKey: true }); | ||
const token = this.user.get('_perishable_token'); | ||
const passwordResetResponse = await request({ | ||
url: `${serverURL}/apps/test/[email protected]&token=${token}`, | ||
method: 'GET', | ||
}); | ||
expect(passwordResetResponse.status).toEqual(302); | ||
expect(passwordResetResponse.headers.location).toMatch( | ||
`\\/choose\\_password\\?token\\=${token}\\&` | ||
); | ||
await request({ | ||
url: `${serverURL}/apps/test/request_password_reset`, | ||
method: 'POST', | ||
body: { | ||
token, | ||
username: '[email protected]', | ||
new_password: 'newpassword', | ||
}, | ||
}); | ||
const userAgain = await Parse.User.logIn( | ||
'[email protected]', | ||
'newpassword' | ||
); | ||
expect(userAgain.id).toEqual(this.objectId); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters