Skip to content

Commit 1429f98

Browse files
authored
Merge pull request #97 from HackRU/input_validation
Input validation
2 parents 04f4d92 + 127f001 commit 1429f98

File tree

7 files changed

+113
-1
lines changed

7 files changed

+113
-1
lines changed

src/functions/create/handler.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import schema from './schema';
77
import { MongoDB } from '../../util';
88
import * as config from '../../config';
99

10+
import { validateEmail } from '../../helper';
11+
1012
import * as path from 'path';
1113
import * as dotenv from 'dotenv';
1214
dotenv.config({ path: path.resolve(process.cwd(), '.env') });
@@ -25,6 +27,15 @@ const create: ValidatedEventAPIGatewayProxyEvent<typeof schema> = async (event)
2527
}
2628

2729
const uEmail = event.body.email.toLowerCase();
30+
if (!validateEmail(uEmail)) {
31+
return {
32+
statusCode: 403,
33+
body: JSON.stringify({
34+
statusCode: 403,
35+
message: 'Improper Email format',
36+
}),
37+
};
38+
}
2839
let password = event.body.password;
2940

3041
try {

src/functions/update-buy-ins/handler.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,32 @@ const updateBuyIns: ValidatedEventAPIGatewayProxyEvent<typeof schema> = async (e
7979
};
8080
}
8181

82+
//validate point update
83+
for (const userBuyIn of userBuyInsSorted) {
84+
const value = userBuyIn.buy_in;
85+
if (value === '') userBuyIn.buy_in = 0;
86+
87+
const numVal = parseInt(value, 10);
88+
if (Number.isNaN(numVal)) {
89+
return {
90+
statusCode: 403,
91+
body: JSON.stringify({
92+
statusCode: 403,
93+
message: 'Requested point change is not a valid integer input',
94+
}),
95+
};
96+
}
97+
if (numVal >= 1000 || numVal <= -1000) {
98+
return {
99+
statusCode: 403,
100+
body: JSON.stringify({
101+
statusCode: 403,
102+
message: 'Requested point change is not in a valid point range',
103+
}),
104+
};
105+
}
106+
}
107+
82108
//update the buy_ins array
83109
await pointCollection.updateOne({ email: event.body.email }, { $set: { buy_ins: event.body.buy_ins } });
84110
return {

src/functions/update/handler.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { middyfy } from '@libs/lambda';
44

55
import schema from './schema';
66

7+
import { validateEmail } from '../../helper';
8+
79
import { MongoDB, validateToken, ensureRoles } from '../../util';
810
import * as path from 'path';
911
import * as dotenv from 'dotenv';
@@ -214,6 +216,9 @@ function validateUpdates(updates: Updates, registrationStatus?: string, user?: W
214216
return 'Missing required fields';
215217
} else return true;
216218
}
219+
220+
if ('email' in setUpdates) if (!validateEmail(setUpdates.email)) return 'Improper Email format';
221+
217222
if (
218223
['_id', 'password', 'discord', 'created_at', 'registered_at', 'email_verified'].some(
219224
(lockedProp) => lockedProp in setUpdates

src/helper.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export function validateEmail(email) {
2+
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3+
return emailPattern.test(email);
4+
}

tests/create.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ describe('Create endpoint', () => {
4848
expect(res.statusCode).toBe(200);
4949
expect(JSON.parse(res.body).message).toBe('User created!');
5050
});
51+
it('Email entry is invalid', async () => {
52+
const mockEvent = createEvent({ email: 'notValidFormat', password: 'testPassword123' }, '/create', 'POST');
53+
54+
const mockCallback = jest.fn();
55+
56+
(bcrypt.hash as jest.Mock).mockResolvedValue('hashedPassword');
57+
const res = await main(mockEvent, mockContext, mockCallback);
58+
59+
expect(res.statusCode).toBe(403);
60+
expect(JSON.parse(res.body).message).toBe('Improper Email format');
61+
});
5162
it('Registration time has passed', async () => {
5263
jest.useFakeTimers();
5364
jest.setSystemTime(new Date('01/01/2100'));

tests/update-buy-ins.test.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,45 @@ describe('Update-Buy-Ins tests', () => {
9696
expect(result.statusCode).toBe(403);
9797
expect(JSON.parse(result.body).message).toBe('Points distributed exceed user point total.');
9898
});
99+
//case 5
100+
it('non-numeric value entered for input', async () => {
101+
findOneMock.mockReturnValueOnce({
102+
email: userData.email,
103+
total_points: 30,
104+
balance: 2,
105+
buy_ins: [
106+
{ prize_id: 'prize1', buy_in: 'random' },
107+
{ prize_id: 'prize2', buy_in: 20 },
108+
],
109+
});
99110

100-
// case 5
111+
const mockEvent = createEvent(userData, path, httpMethod);
112+
113+
const result = await main(mockEvent, mockContext, mockCallback);
114+
115+
expect(result.statusCode).toBe(403);
116+
expect(JSON.parse(result.body).message).toBe('Requested point change is not a valid integer input');
117+
});
118+
// case 6
119+
it('Buy-in points out of range', async () => {
120+
findOneMock.mockReturnValueOnce({
121+
email: userData.email,
122+
total_points: 30,
123+
balance: 2,
124+
buy_ins: [
125+
{ prize_id: 'prize1', buy_in: 1500 },
126+
{ prize_id: 'prize2', buy_in: 20 },
127+
],
128+
});
129+
130+
const mockEvent = createEvent(userData, path, httpMethod);
131+
132+
const result = await main(mockEvent, mockContext, mockCallback);
133+
134+
expect(result.statusCode).toBe(403);
135+
expect(JSON.parse(result.body).message).toBe('Requested point change is not in a valid point range');
136+
});
137+
// case 7
101138
it('successfully update user point balance', async () => {
102139
findOneMock.mockReturnValueOnce({
103140
email: userData.email,

tests/update.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ describe('/update endpoint', () => {
261261
},
262262
},
263263
};
264+
264265
jest.clearAllMocks();
265266
findOneMock.mockReturnValue({
266267
//successful update
@@ -298,4 +299,21 @@ describe('/update endpoint', () => {
298299
const res = await main(mockEvent, mockContext, mockCallback);
299300
expect(res.statusCode).toBe(200);
300301
});
302+
//case 9
303+
it('Invalid email format', async () => {
304+
const completeUserData = {
305+
user_email: 'test@test.org',
306+
auth_email: 'testAuth@test.org',
307+
auth_token: 'sampleAuthToken',
308+
updates: {
309+
$set: {
310+
email: 'randomVal',
311+
},
312+
},
313+
};
314+
const mockEvent = createEvent(completeUserData, '/update', 'POST');
315+
const res = await main(mockEvent, mockContext, mockCallback);
316+
expect(res.statusCode).toBe(400);
317+
expect(JSON.parse(res.body).message).toBe('Improper Email format');
318+
});
301319
});

0 commit comments

Comments
 (0)