Skip to content

Commit

Permalink
fix #310: wrap ObjectId creation in try-catch
Browse files Browse the repository at this point in the history
  • Loading branch information
geoffrey-wu committed Sep 9, 2024
1 parent a7fe83b commit 928ebd9
Show file tree
Hide file tree
Showing 21 changed files with 78 additions and 77 deletions.
9 changes: 7 additions & 2 deletions database/account-info/question-stats/record-bonus-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ async function recordBonusData (username, data) {
}
}

newData.bonus_id = new ObjectId(bonus._id);
newData.set_id = new ObjectId(bonus.set._id);
try {
newData.bonus_id = new ObjectId(bonus._id);
newData.set_id = new ObjectId(bonus.set._id);
} catch (e) {
return false;
}

newData.user_id = userId;
return await bonusData.insertOne(newData);
}
Expand Down
8 changes: 6 additions & 2 deletions database/account-info/question-stats/record-tossup-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ async function recordTossupData (username, data) {
}
}

newData.tossup_id = new ObjectId(tossup._id);
newData.set_id = new ObjectId(tossup.set._id);
try {
newData.tossup_id = new ObjectId(tossup._id);
newData.set_id = new ObjectId(tossup.set._id);
} catch (e) {
return false;
}
newData.user_id = userId;
return await tossupData.insertOne(newData);
}
Expand Down
6 changes: 2 additions & 4 deletions database/account-info/verify-email.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { users } from './collections.js';

import { ObjectId } from 'mongodb';

/**
*
* @param {String} userId
* @param {ObjectId} userId
* @returns {Promise<Result>}
*/
async function verifyEmail (userId) {
return await users.updateOne(
{ _id: new ObjectId(userId) },
{ _id: userId },
{ $set: { verifiedEmail: true } }
);
}
Expand Down
28 changes: 9 additions & 19 deletions database/qbreader/report-question.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
import { bonuses, tossups } from './collections.js';

import { ObjectId } from 'mongodb';

/**
* Report question with given id to the database.
* @param {string} _id - the id of the question to report
* @param {ObjectId} _id - the id of the question to report
* @param {'wrong-category' | 'text-error' | 'answer-checking' | 'other'} reason - the reason for reporting
* @param {string} description - a description of the problem
* @param {boolean} [verbose=true] - whether to log the result to the console
* @returns {Promise<boolean>} true if successful, false otherwise.
*/
async function reportQuestion (_id, reason, description, verbose = true) {
await tossups.updateOne({ _id: new ObjectId(_id) }, {
$push: {
reports: {
reason,
description
}
}
});
await tossups.updateOne(
{ _id },
{ $push: { reports: { reason, description } } }
);

await bonuses.updateOne({ _id: new ObjectId(_id) }, {
$push: {
reports: {
reason,
description
}
}
});
await bonuses.updateOne(
{ _id },
{ $push: { reports: { reason, description } } }
);

if (verbose) {
console.log('Reported question with id ' + _id);
Expand Down
5 changes: 3 additions & 2 deletions routes/api/admin/geoword.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ router.get('/protests', async (req, res) => {
});

router.post('/resolve-protest', async (req, res) => {
const { buzz_id: buzzId, decision, reason } = req.body;
const result = await resolveProtest(new ObjectId(buzzId), decision, reason);
let { buzz_id: buzzId, decision, reason } = req.body;
try { buzzId = new ObjectId(buzzId); } catch (e) { return res.status(400).send('Invalid buzz ID'); }
const result = await resolveProtest(buzzId, decision, reason);

if (result) {
res.sendStatus(200);
Expand Down
5 changes: 3 additions & 2 deletions routes/api/admin/update-subcategory.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { ObjectId } from 'mongodb';
const router = Router();

router.put('/', async (req, res) => {
const { _id, type, subcategory, alternate_subcategory: alternateSubcategory } = req.body;
const result = await updateSubcategory(new ObjectId(_id), type, subcategory, alternateSubcategory);
let { _id, type, subcategory, alternate_subcategory: alternateSubcategory } = req.body;
try { _id = new ObjectId(_id); } catch (e) { return res.status(400).send('Invalid ID'); }
const result = await updateSubcategory(_id, type, subcategory, alternateSubcategory);

if (result) {
res.sendStatus(200);
Expand Down
17 changes: 5 additions & 12 deletions routes/api/bonus-by-id.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,13 @@ const router = Router();

router.get('/', async (req, res) => {
if (!req.query.id) {
res.status(400).send('Bonus ID not specified');
return;
return res.status(400).send('Bonus ID not specified');
}
let oid;
try {
oid = ObjectId(req.query.id);
} catch (b) {
res.status(400).send('Invalid Bonus ID');
return;
}
const bonus = await getBonus(oid);
let _id;
try { _id = new ObjectId(req.query.id); } catch (b) { return res.status(400).send('Invalid Bonus ID'); }
const bonus = await getBonus(_id);
if (bonus === null) {
res.status(404).send(`Bonus with ID ${req.query.id} was not found`);
return;
return res.status(404).send(`Bonus with ID ${req.query.id} was not found`);
}

res.header('Access-Control-Allow-Origin', '*');
Expand Down
12 changes: 9 additions & 3 deletions routes/api/report-question.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { ObjectId } from 'mongodb';
import reportQuestion from '../../database/qbreader/report-question.js';

import { Router } from 'express';

const router = Router();

router.post('/', async (req, res) => {
const _id = req.body._id;
let _id;
try { _id = new ObjectId(req.body._id); } catch (e) {
res.header('Access-Control-Allow-Origin', '*');
return res.status(400).send('Invalid ID');
}

const reason = req.body.reason ?? '';
const description = req.body.description ?? '';
const successful = await reportQuestion(_id, reason, description);
if (successful) {
res.header('Access-Control-Allow-Origin', '*');
res.sendStatus(200);
return res.sendStatus(200);
} else {
res.header('Access-Control-Allow-Origin', '*');
res.sendStatus(500);
return res.sendStatus(500);
}
});

Expand Down
11 changes: 3 additions & 8 deletions routes/api/tossup-by-id.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,9 @@ router.get('/', async (req, res) => {
res.status(400).send('Tossup ID not specified');
return;
}
let oid;
try {
oid = ObjectId(req.query.id);
} catch (b) {
res.status(400).send('Invalid Tossup ID');
return;
}
const tossup = await getTossup(oid);
let _id;
try { _id = new ObjectId(req.query.id); } catch (b) { return res.status(400).send('Invalid Tossup ID'); }
const tossup = await getTossup(_id);
if (tossup === null) {
res.status(404).send(`Tossup with ID ${req.query.id} was not found`);
return;
Expand Down
5 changes: 3 additions & 2 deletions routes/api/webhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ router.post('/', (req, res) => {
case 'payment_intent.succeeded': {
const paymentIntentSucceeded = event.data.object;
// Then define and call a function to handle the event payment_intent.succeeded
const { user_id: userId, packetName } = paymentIntentSucceeded.metadata;
recordPayment(packetName, new ObjectId(userId));
let { user_id: userId, packetName } = paymentIntentSucceeded.metadata;
try { userId = new ObjectId(userId); } catch (e) { return res.status(400).send('Invalid user ID'); }
recordPayment(packetName, userId);
break;
}

Expand Down
4 changes: 3 additions & 1 deletion routes/auth/question-stats/single-bonus.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { ObjectId } from 'mongodb';
const router = Router();

router.get('/', async (req, res) => {
const stats = await getSingleBonusStats(new ObjectId(req.query.bonus_id));
let _id;
try { _id = new ObjectId(req.query.bonus_id); } catch (e) { return res.status(400).send('Invalid Bonus ID'); }
const stats = await getSingleBonusStats(_id);
res.json({ stats });
});

Expand Down
4 changes: 3 additions & 1 deletion routes/auth/question-stats/single-tossup.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { ObjectId } from 'mongodb';
const router = Router();

router.get('/', async (req, res) => {
const stats = await getSingleTossupStats(new ObjectId(req.query.tossup_id));
let _id;
try { _id = new ObjectId(req.query.tossup_id); } catch (e) { return res.status(400).send('Invalid Tossup ID'); }
const stats = await getSingleTossupStats(_id);
res.json({ stats });
});

Expand Down
5 changes: 3 additions & 2 deletions routes/auth/reset-password.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import { ObjectId } from 'mongodb';
const router = Router();

router.post('/', async (req, res) => {
const { user_id: userId, verifyResetPassword } = req.session;
let { user_id: userId, verifyResetPassword } = req.session;
try { userId = new ObjectId(userId); } catch (e) { return res.sendStatus(400); }
if (!verifyResetPassword) {
res.sendStatus(401);
return;
}

const username = await getUsername(new ObjectId(userId));
const username = await getUsername(userId);
const password = req.body.password;
await updatePassword(username, password);
req.session = null;
Expand Down
9 changes: 3 additions & 6 deletions routes/auth/stars/is-starred-bonus.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ const router = Router();
router.get('/', async (req, res) => {
const username = req.session.username;
const userId = await getUserId(username);
try {
const bonusId = new ObjectId(req.query.bonus_id);
res.json({ isStarred: await isStarredBonus(userId, bonusId) });
} catch { // Invalid ObjectID
res.json({ isStarred: false });
}
let bonusId;
try { bonusId = new ObjectId(req.query.bonus_id); } catch { return res.status(400).send('Invalid Bonus ID'); }
res.json({ isStarred: await isStarredBonus(userId, bonusId) });
});

export default router;
9 changes: 3 additions & 6 deletions routes/auth/stars/is-starred-tossup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ const router = Router();
router.get('/', async (req, res) => {
const username = req.session.username;
const userId = await getUserId(username);
try {
const tossupId = new ObjectId(req.query.tossup_id);
res.json({ isStarred: await isStarredTossup(userId, tossupId) });
} catch { // Invalid ObjectID
res.json({ isStarred: false });
}
let tossupId;
try { tossupId = new ObjectId(req.query.tossup_id); } catch { return res.status(400).send('Invalid Tossup ID'); }
res.json({ isStarred: await isStarredTossup(userId, tossupId) });
});

export default router;
3 changes: 2 additions & 1 deletion routes/auth/stars/star-bonus.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const router = Router();
router.put('/', async (req, res) => {
const username = req.session.username;
const userId = await getUserId(username);
const bonusId = new ObjectId(req.body.bonus_id);
let bonusId;
try { bonusId = new ObjectId(req.body.bonus_id); } catch { return res.status(400).send('Invalid Bonus ID'); }
await starBonus(userId, bonusId);
res.sendStatus(200);
});
Expand Down
3 changes: 2 additions & 1 deletion routes/auth/stars/star-tossup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const router = Router();
router.put('/', async (req, res) => {
const username = req.session.username;
const userId = await getUserId(username);
const tossupId = new ObjectId(req.body.tossup_id);
let tossupId;
try { tossupId = new ObjectId(req.body.tossup_id); } catch { return res.status(400).send('Invalid Tossup ID'); }
await starTossup(userId, tossupId);
res.sendStatus(200);
});
Expand Down
3 changes: 2 additions & 1 deletion routes/auth/stars/unstar-bonus.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const router = Router();
router.put('/', async (req, res) => {
const username = req.session.username;
const userId = await getUserId(username);
const bonusId = new ObjectId(req.body.bonus_id);
let bonusId;
try { bonusId = new ObjectId(req.body.bonus_id); } catch { return res.status(400).send('Invalid Bonus ID'); }
await unstarBonus(userId, bonusId);
res.sendStatus(200);
});
Expand Down
3 changes: 2 additions & 1 deletion routes/auth/stars/unstar-tossup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const router = Router();
router.put('/', async (req, res) => {
const username = req.session.username;
const userId = await getUserId(username);
const tossupId = new ObjectId(req.body.tossup_id);
let tossupId;
try { tossupId = new ObjectId(req.body.tossup_id); } catch { return res.status(400).send('Invalid Tossup ID'); }
await unstarTossup(userId, tossupId);
res.sendStatus(200);
});
Expand Down
3 changes: 3 additions & 0 deletions server/authentication.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import verifyEmail from '../database/account-info/verify-email.js';

import { createHash } from 'crypto';
import jsonwebtoken from 'jsonwebtoken';
import { ObjectId } from 'mongodb';
const { sign, verify } = jsonwebtoken;

const baseURL = process.env.BASE_URL ?? (process.env.NODE_ENV === 'production' ? 'https://www.qbreader.org' : 'http://localhost:3000');
Expand Down Expand Up @@ -181,6 +182,8 @@ function verifyEmailLink (userId, token) {
return false;
}

try { userId = new ObjectId(userId); } catch (e) { return false; }

verifyEmail(userId);
return true;
});
Expand Down
3 changes: 2 additions & 1 deletion test/database.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import reportQuestion from '../database/qbreader/report-question.js';

import { assert } from 'chai';
import mocha from 'mocha';
import { ObjectId } from 'mongodb';

const packetNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24];

Expand Down Expand Up @@ -57,7 +58,7 @@ async function testTiming (count) {
mocha.it('reportQuestion', async () => {
const results = [];
for (let i = 0; i < count; i++) {
results.push(reportQuestion('630020e3cab8fa6d1490b8ea', 'other', 'test'));
results.push(reportQuestion(new ObjectId('630020e3cab8fa6d1490b8ea'), 'other', 'test'));
}
await Promise.all(results);
});
Expand Down

0 comments on commit 928ebd9

Please sign in to comment.