Files
kami-parse-server/spec/RegexVulnerabilities.spec.js
2024-07-18 15:41:04 +02:00

211 lines
6.7 KiB
JavaScript

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({
maintenanceKey: 'test2',
verifyUserEmails: true,
emailAdapter,
appName,
publicServerURL,
});
const signUpResponse = await request({
url: `${serverURL}/users`,
method: 'POST',
headers,
body: JSON.stringify({
...keys,
_method: 'POST',
username: 'someemail@somedomain.com',
password: 'somepassword',
email: 'someemail@somedomain.com',
}),
});
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/verify_email?username=someemail@somedomain.com&token[$regex]=`,
method: 'GET',
});
await this.user.fetch({ useMasterKey: true });
expect(this.user.get('emailVerified')).toEqual(false);
});
it_id('92bbb86d-bcda-49fa-8d79-aa0501078044')('should work with plain token', async function () {
expect(this.user.get('emailVerified')).toEqual(false);
const current = await request({
method: 'GET',
url: `http://localhost:8378/1/classes/_User/${this.user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'test',
'X-Parse-Maintenance-Key': 'test2',
'Content-Type': 'application/json',
},
}).then(res => res.data);
// It should work
await request({
url: `${serverURL}/apps/test/verify_email?username=someemail@somedomain.com&token=${current._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('someemail@somedomain.com', '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: 'someemail@somedomain.com',
}),
});
await this.user.fetch({ useMasterKey: true });
const passwordResetResponse = await request({
url: `${serverURL}/apps/test/request_password_reset?username=someemail@somedomain.com&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: 'someemail@somedomain.com',
new_password: 'newpassword',
},
});
try {
await Parse.User.logIn('someemail@somedomain.com', 'newpassword');
fail('should not work');
} catch (e) {
expect(e.code).toEqual(Parse.Error.OBJECT_NOT_FOUND);
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: 'someemail@somedomain.com',
}),
});
const current = await request({
method: 'GET',
url: `http://localhost:8378/1/classes/_User/${this.user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'test',
'X-Parse-Maintenance-Key': 'test2',
'Content-Type': 'application/json',
},
}).then(res => res.data);
const token = current._perishable_token;
const passwordResetResponse = await request({
url: `${serverURL}/apps/test/request_password_reset?username=someemail@somedomain.com&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: 'someemail@somedomain.com',
new_password: 'newpassword',
},
});
const userAgain = await Parse.User.logIn('someemail@somedomain.com', 'newpassword');
expect(userAgain.id).toEqual(this.objectId);
});
});
});