diff --git a/api/src/routes/access.js b/api/src/routes/access.js index 3b0c8ccc..9fd8f3c3 100644 --- a/api/src/routes/access.js +++ b/api/src/routes/access.js @@ -92,6 +92,14 @@ router.post("/treasurers", async(req, res, next) => { return next(); } + if (req.body.username.length > 50) { + res.status(400).send("Username field too long"); + return next(); + } + if (req.body.username.role > 50) { + res.status(400).send("Role field too long"); + } + try { // first make sure user is actually a treasurer const [results] = await req.context.models.account.getUserTreasurer(req.context.request_user_id); @@ -151,6 +159,14 @@ router.post("/officers", async(req, res, next) => { return next(); } + if (req.body.username.length > 50) { + res.status(400).send("Username field too long"); + return next(); + } + if (req.body.username.role > 50) { + res.status(400).send("Role field too long"); + } + try { // first make sure user is actually a treasurer const [results] = await req.context.models.account.getUserTreasurer(req.context.request_user_id); @@ -202,6 +218,14 @@ router.post("/internals", async(req, res, next) => { return next(); } + if (req.body.username.length > 50) { + res.status(400).send("Username field too long"); + return next(); + } + if (req.body.username.role > 50) { + res.status(400).send("Role field too long"); + } + try { // first make sure user is actually a treasurer const [results] = await req.context.models.account.getUserTreasurer(req.context.request_user_id); diff --git a/api/src/routes/account.js b/api/src/routes/account.js index 2cc6f035..9db8f51d 100644 --- a/api/src/routes/account.js +++ b/api/src/routes/account.js @@ -61,6 +61,36 @@ router.post("/", async(req, res, next) => { return next(); } + if (req.body.fname.length > 100) { + res.status(400).send("First Name is too long"); + return next(); + } + if (req.body.lname.length > 100) { + res.status(400).send("Last Name is too long"); + return next(); + } + if (req.body.email.length > 200) { + res.status(400).send("Email is too long"); + return next(); + } + if (req.body.address.length > 200) { + res.status(400).send("Address is too long"); + return next(); + } + if (req.body.city.length > 100) { + res.status(400).send("City is too long"); + return next(); + } + + if (req.body.state.length !== 2) { + res.status(400).send("State must be a 2 letter abbreviation"); + return next(); + } + + if (req.body.uname.length > 50) { + res.status(400).send("Username is too long"); + } + // eslint-disable-next-line if (req.body.uname.match(/[$&+,/:;=?@ "<>#%{}|\\^~\[\]`]/)) { res.status(400).send("Username cannot contain any special characters"); @@ -82,11 +112,6 @@ router.post("/", async(req, res, next) => { return next(); } - if (req.body.state.length !== 2) { - res.status(400).send("State must be a 2 letter abbreviation"); - return next(); - } - bcrypt.hash(req.body.pass1, bcrypt_rounds, async(error, hash) => { if (error) { logger.error(error); diff --git a/api/src/routes/income.js b/api/src/routes/income.js index c3fa8fd5..5267c8e0 100644 --- a/api/src/routes/income.js +++ b/api/src/routes/income.js @@ -45,6 +45,19 @@ router.post("/", async(req, res, next) => { return next(); } + if (req.body.source.length > 50) { + res.status(400).send("Source field too long"); + return next(); + } + if (req.body.item.length > 50) { + res.status(400).send("Item field too long"); + return next(); + } + if (req.body.comments.length > 10000) { + res.status(400).send("Comments field too long"); + return next(); + } + // can't escape committee so check committee name first if (committee_name_swap[req.body.committee] === undefined) { res.status(400).send("Committee must be proper value"); diff --git a/api/src/routes/purchase.js b/api/src/routes/purchase.js index 98c21875..b3cdbab5 100644 --- a/api/src/routes/purchase.js +++ b/api/src/routes/purchase.js @@ -97,6 +97,23 @@ router.post("/", async(req, res, next) => { return next(); } + if (req.body.item.length > 50) { + res.status(400).send("Item field too long"); + return next(); + } + if (req.body.reason.length > 50) { + res.status(400).send("Reason field too long"); + return next(); + } + if (req.body.vendor.length > 50) { + res.status(400).send("Vendor field too long"); + return next(); + } + if (req.body.comments.length > 500) { + res.status(400).send("Comments field too long"); + return next(); + } + // can't escape committe so check for committee name first if (committee_name_swap[req.body.committee] === undefined) { res.status(400).send("Committee must be proper value"); @@ -413,6 +430,23 @@ router.post("/:purchaseID/approve", async(req, res, next) => { return next(); } + if (req.body.item.length > 50) { + res.status(400).send("Item field too long"); + return next(); + } + if (req.body.reason.length > 50) { + res.status(400).send("Reason field too long"); + return next(); + } + if (req.body.vendor.length > 50) { + res.status(400).send("Vendor field too long"); + return next(); + } + if (req.body.comments.length > 500) { + res.status(400).send("Comments field too long"); + return next(); + } + if (!approve_status.includes(req.body.status)) { res.status(400).send("Purchase status must be 'Approved' or 'Denied'"); return next(); @@ -527,6 +561,40 @@ router.post("/:purchaseID/complete", fileHandler.single("receipt"), async(req, r return next(); } + if (req.body.comments.length > 500) { + fs.unlink(req.file.path); + res.status(400).send("Comments field too long"); + return next(); + } + + // can't escape the purchasedate, so check format instead + if ((req.body.purchasedate.match(/^\d{4}-\d{2}-\d{2}$/)).length === 0) { + fs.unlink(req.file.path); + res.status(400).send("Purchase Date must be in the form YYYY-MM-DD"); + return next(); + } + + // The format is good, so check the actual validity of the date + // @see https://stackoverflow.com/a/62517465 + const parts = req.body.purchasedate.split('-').map((p) => parseInt(p, 10)); + parts[1] -= 1; + const date_check = new Date(parts[0], parts[1], parts[2]); + const date_good = (date_check.getFullYear() === parts[0]) && (date_check.getMonth() === parts[1]) && (date_check.getDate() === parts[2]); + if (!date_good) { + fs.unlink(req.file.path); + res.status(400).send("Purchase Date is invalid"); + return next(); + } + + // Now that the format and validity of the date is good, make sure it's in the past + const today = new Date() + const today_string = `${today.getFullYear()}-${(today.getMonth()+1).toString().padStart(2,'0')}-${(today.getDate()).toString().padStart(2,'0')}`; + if (req.body.purchasedate > today_string) { + fs.unlink(req.file.path); + res.status(400).send("Purchase Date cannot be in the future"); + return next(); + } + try { const [results] = await req.context.models.purchase.getFullPurchaseByID(req.params.purchaseID); if (results.length === 0) { @@ -546,13 +614,6 @@ router.post("/:purchaseID/complete", fileHandler.single("receipt"), async(req, r return next(); } - // can't escape the purchasedate, so check format instead - if ((req.body.purchasedate.match(/^\d{4}-\d{2}-\d{2}$/)).length === 0) { - fs.unlink(req.file.path); - res.status(400).send("Purchase Date must be in the form YYYY-MM-DD"); - return next(); - } - /** get the basic params to check access control **/ try { const [results] = await req.context.models.purchase.getFullPurchaseByID(req.params.purchaseID); diff --git a/ui/src/views/LoginSignup.vue b/ui/src/views/LoginSignup.vue index 0a170084..ebab5f42 100644 --- a/ui/src/views/LoginSignup.vue +++ b/ui/src/views/LoginSignup.vue @@ -36,33 +36,33 @@
- +
- +
- +
- +
- +
-
+
-
+