Skip to content

Commit

Permalink
Field validation updates (Closes #167) (Closes #26)
Browse files Browse the repository at this point in the history
* Added length checks to most string fields (Except in budgets)
* Cleaned up date validation to be much better and added a future date check
* Removed references to soon-to-be-former president 'Mitch Daniels' and replaced them with 'Purdue Pete'
  • Loading branch information
hadiahmed098 committed Jul 30, 2022
1 parent 9c5843d commit ce09f0b
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 19 deletions.
24 changes: 24 additions & 0 deletions api/src/routes/access.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
35 changes: 30 additions & 5 deletions api/src/routes/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions api/src/routes/income.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
75 changes: 68 additions & 7 deletions api/src/routes/purchase.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
14 changes: 7 additions & 7 deletions ui/src/views/LoginSignup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,33 +36,33 @@
<form class="row g-3" v-on:submit.prevent="newAccount()" name="new_form">
<div class="col-md-6">
<label for="new_fname" class="form-label">First name</label>
<input type="text" class="form-control" id="new_fname" v-model="new_fname" placeholder="Mitch" required>
<input type="text" class="form-control" id="new_fname" v-model="new_fname" placeholder="Purdue" required>
</div>
<div class="col-md-6">
<label for="new_lname" class="form-label">Last Name</label>
<input type="text" class="form-control" id="new_lname" v-model="new_lname" placeholder="Daniels" required>
<input type="text" class="form-control" id="new_lname" v-model="new_lname" placeholder="Pete" required>
</div>
<div class="col-md-6">
<label for="new_email" class="form-label">Email</label>
<input type="email" class="form-control" id="new_email" v-model="new_email" placeholder="president@purdue.edu" required>
<input type="email" class="form-control" id="new_email" v-model="new_email" placeholder="ppete@purdue.edu" required>
</div>
<div class="col-md-6">
<label for="new_uname" class="form-label">Username</label>
<input type="text" class="form-control" id="new_uname" v-model="new_uname" placeholder="mdaniels" required>
<input type="text" class="form-control" id="new_uname" v-model="new_uname" placeholder="ppete" required>
</div>
<div class="col-12">
<label for="new_address" class="form-label">Address</label>
<label for="new_address" class="form-label">US Mailing Address</label>
<input type="text" class="form-control" id="new_address" v-model="new_address" placeholder="610 Purdue Mall" required>
</div>
<div class="col-md-6">
<label for="new_city" class="form-label">City</label>
<input type="text" class="form-control" id="new_city" v-model="new_city" placeholder="West Lafayette" required>
</div>
<div class="col-md-4">
<div class="col-md-3">
<label for="new_state" class="form-label">State</label>
<input type="text" class="form-control" id="new_state" v-model="new_state" placeholder="IN" required>
</div>
<div class="col-md-2">
<div class="col-md-3">
<label for="new_zip" class="form-label">Zip</label>
<input type="text" class="form-control" id="new_zip" v-model="new_zip" placeholder="47907" required>
</div>
Expand Down

0 comments on commit ce09f0b

Please sign in to comment.