Skip to content

Commit

Permalink
Merge pull request #22 from Lavish883/lavishBranch
Browse files Browse the repository at this point in the history
fixed all vulnerabilities that were found from code scanning from github
  • Loading branch information
Lavish883 authored Aug 22, 2023
2 parents fd916ae + 3408849 commit 695472d
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 73 deletions.
50 changes: 26 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const pathFunctions = require('./mainJS/pathFunctions');
const createFormFuctions = require('./mainJS/creatingForms');
const saveForm = require('./mainJS/saveForm');
const downloadPDFisInBulk = require('./mainJS/downloadPDFisInBulk');
const rateLimiter = require('./mainJS/rateLimiter.js').databaseAccessLimiter;
const imageLimiter = require('./mainJS/rateLimiter.js').imageLimiter;

// conenct to the database
const dbURI = process.env.DB_URL;
Expand All @@ -24,59 +26,59 @@ require('dotenv').config();


// for users to sign up to the form - updated
app.get('/form/signup/:formName/:adminKey/:formId', pathFunctions.signUp);
app.get('/form/signup/:formName/:adminKey/:formId', rateLimiter, pathFunctions.signUp);
// used to genreate new link
// email needs to be verfied first
//app.post('/createNewLink', pathFunctions.generateLink);

// create a new verify link for the form - updated
app.post('/createVerifyLink', pathFunctions.generateVerficationLink);
app.post('/createVerifyLink', rateLimiter, pathFunctions.generateVerficationLink);

// verify email - updated to keep up with the database
app.get('/verifyEmail/:formName/:adminKey/:formId/:verifyLink', pathFunctions.verifyUserEmail);
app.get('/verifyEmail/:formName/:adminKey/:formId/:verifyLink', rateLimiter, pathFunctions.verifyUserEmail);

// display the form to the user, needs password so no one can else access it use jwt
// ?jwt=token, if the token is valid then the user can access the form
app.get('/form/:formName/:adminKey/:formId/:userId', pathFunctions.formPage);
app.post('/form/verifyFormAccess', pathFunctions.verifyFormAccess)
app.get('/form/:formName/:adminKey/:formId/:userId', rateLimiter, pathFunctions.formPage);
app.post('/form/verifyFormAccess', rateLimiter, pathFunctions.verifyFormAccess)

// serve all images - updated
app.get('/image/:formName/:adminKey/:formId/:userId', pathFunctions.serveImage);
app.get('/image/:formName/:adminKey/:formId/:userId', imageLimiter, pathFunctions.serveImage);

// save the form to the database - updated
app.post('/saveForm', saveForm);
app.post('/saveForm', rateLimiter, saveForm);

// filter data page - updated
app.get('/filterData/:formName/:adminKey/:formId', pathFunctions.filterDataPage)
app.get('/filterData/:formName/:adminKey/:formId', rateLimiter, pathFunctions.filterDataPage)

// filter data - updated
app.post('/search/:formName/:adminKey/:formId', filterData);
app.post('/search/:formName/:adminKey/:formId', rateLimiter, filterData);

// pdf page for sending it to the user, needs password so no one can else access it - updated
app.get('/pdf/:formName/:adminKey/:formId/:userId', pathFunctions.pdfPage);
app.get('/pdf/:formName/:adminKey/:formId/:userId', rateLimiter, pathFunctions.pdfPage);

// download the pdf- for the teachers
app.get('/download/pdf/:formName/:adminKey/:formId/:userId', pathFunctions.downloadPDF);
app.get('/download/pdf/:formName/:adminKey/:formId/:userId', rateLimiter, pathFunctions.downloadPDF);
// download all the pdfs that are requested
app.post('/downloadAllPDFs/:formName/:adminKey/:formId', downloadPDFisInBulk);
app.post('/downloadAllPDFs/:formName/:adminKey/:formId', rateLimiter, downloadPDFisInBulk);

// to edit the form
app.get('/editForm/:formName/:adminKey/:formId', pathFunctions.editFormPage);
app.get('/editForm/:formName/:adminKey/:formId', rateLimiter, pathFunctions.editFormPage);

// to save the edited form
app.post('/editForm/save', pathFunctions.saveEditedForm);
app.post('/editForm/save', rateLimiter, pathFunctions.saveEditedForm);

// tempory setup for creating new form page
app.post('/test/makeNewFormMakerUser', createFormFuctions.makeNewFormMakerUser);
app.post('/test/makeNewForm', createFormFuctions.makeNewForm);
app.delete('/test/deleteForm', createFormFuctions.deleteForm);
app.post('/test/giveUserFormDeatils', createFormFuctions.giveUserFormDeatils);
app.get('/previewForm/:formName/:adminKey/:formId', pathFunctions.previewForm);
app.get('/test/serveLogoImage/:formName/:formId', createFormFuctions.serveLogoImage);
app.post('/test/saveLogoImage', createFormFuctions.saveLogoImage);
app.post('/formMaker/sendCodeEmail', createFormFuctions.sendCodeEmail);
app.post('/formMaker/confirmEmailWithCode', createFormFuctions.confirmEmailWithCode);
app.post('/formMaker/passwordReset', createFormFuctions.passwordReset);
app.post('/test/makeNewFormMakerUser', rateLimiter, createFormFuctions.makeNewFormMakerUser);
app.post('/test/makeNewForm', rateLimiter, createFormFuctions.makeNewForm);
app.delete('/test/deleteForm', rateLimiter, createFormFuctions.deleteForm);
app.post('/test/giveUserFormDeatils', rateLimiter, createFormFuctions.giveUserFormDeatils);
app.get('/previewForm/:formName/:adminKey/:formId', rateLimiter, pathFunctions.previewForm);
app.get('/test/serveLogoImage/:formName/:formId', imageLimiter, createFormFuctions.serveLogoImage);
app.post('/test/saveLogoImage', rateLimiter, createFormFuctions.saveLogoImage);
app.post('/formMaker/sendCodeEmail', rateLimiter ,createFormFuctions.sendCodeEmail);
app.post('/formMaker/confirmEmailWithCode', rateLimiter, createFormFuctions.confirmEmailWithCode);
app.post('/formMaker/passwordReset', rateLimiter, createFormFuctions.passwordReset);

// Making the form maker page
app.get('/formMaker', createFormFuctions.formMakerLogin);
Expand Down
31 changes: 22 additions & 9 deletions mainJS/creatingForms.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ const mailFunctions = require('./mailFunctions');
const bcrpyt = require('bcrypt');

async function verifyUser(email, password) {
var user = await schemas.formMakerUsers.findOne({ 'email': email });
var user = await schemas.formMakerUsers.findOne({
'email': { $eq: email }
});

if (!user) return { 'send': 'User does not exist', 'status': 400 };

Expand Down Expand Up @@ -68,7 +70,9 @@ async function makeNewFormMakerUser(req, res) {
if (email == '' || password == '') return res.status(400).send('Email or password cannot be empty');

// find the user with that email, update the password
var user = await schemas.formMakerUsers.findOne({ 'email': email });
var user = await schemas.formMakerUsers.findOne({
'email': { $eq: email }
});

// hash the password
const hashedPassword = bcrpyt.hashSync(password, 10);
Expand Down Expand Up @@ -135,7 +139,10 @@ async function serveLogoImage(req, res) {

async function saveLogoImage(req, res) {
// find the user with that form
var formUser = await schemas.formMakerUsers.findOne({ 'forms.formId': req.body.formId, 'forms.formName': unescape(req.body.formName) });
var formUser = await schemas.formMakerUsers.findOne({
'forms.formId': { $eq: req.body.formId },
'forms.formName': { $eq: unescape(req.body.formName) }
});
if (!formUser) return res.status(400).send('Form does not exist');

// get the form from the user
Expand All @@ -158,12 +165,14 @@ async function confirmEmailWithCode(req, res) {
if (req.body.code == undefined || req.body.code == '') return res.status(400).send('Code cannot be empty');

// find the user with that email
var user = await schemas.formMakerUsers.findOne({ 'email': req.body.email });
var user = await schemas.formMakerUsers.findOne({
'email': { $eq: req.body.email }
});
if (!user) return res.status(400).send('That is weird, user with that email does not exist. Refresh the page and try again');

// check if the code is correct
if (user.verifyCode != req.body.code) return res.status(400).send('Code is incorrect');

// check if the code has expired
if (new Date() > user.expireDate) return res.status(400).send('Code has expired, please refresh the page and try to sign up again');

Expand All @@ -179,7 +188,9 @@ async function sendCodeEmail(req, res) {
if (email == undefined || email == '') return res.status(400).send('Email cannot be empty');

// check if the email is already in the database
var doesItExist = await schemas.formMakerUsers.findOne({ 'email': email });
var doesItExist = await schemas.formMakerUsers.findOne({
'email': { $eq: email }
});

// if verified let the user know
if (doesItExist.verified) return res.status(400).send('Account has already been made');
Expand Down Expand Up @@ -209,12 +220,14 @@ async function sendCodeEmail(req, res) {
return res.status(200).send('Email sent');
}

async function passwordReset(req, res){
async function passwordReset(req, res) {
// the way we structured sign up, all we can do is set verified to false and then they can use sign up to change the password
// find the user with that email
if (req.body.email == undefined || req.body.email == '') return res.status(400).send('Email cannot be empty');
var user = await schemas.formMakerUsers.findOne({ 'email': req.body.email });

var user = await schemas.formMakerUsers.findOne({
'email': { $eq: req.body.email }
});

user.verified = false;
await user.save();
return res.status(200).send('Done');
Expand Down
4 changes: 2 additions & 2 deletions mainJS/downloadPDFisInBulk.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async function downloadAllPDFs(req, res){
var fetchURLS = [];

for (var user of req.body.savedData){
fetchURLS.push(process.env.WEBSITELINK + `pdf/${req.params.formName}/${req.params.adminKey}/${req.params.formId}/` + user.userId);
fetchURLS.push(`pdf/${req.params.formName}/${req.params.adminKey}/${req.params.formId}/` + user.userId);
}
// create a zip file
const zip = new JSZip();
Expand All @@ -39,7 +39,7 @@ async function downloadAllPDFs(req, res){
await page.setViewport({ width: 1280, height: 720 });

for (var i = 0; i < fetchURLS.length; i++){
await page.goto(fetchURLS[i], {waitUntil: 'networkidle0'});
await page.goto(process.env.WEBSITELINK + fetchURLS[i], {waitUntil: 'networkidle0'});
const pdf = await page.pdf({ format: 'A4', margin: { top: '30px', bottom: '30px', left: '60px', right: '60px' }});
await zip.file(req.body.savedData[i].form.firstName + req.body.savedData[i].form.lastName + '.pdf', pdf);
}
Expand Down
2 changes: 0 additions & 2 deletions mainJS/filterThroughData.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ function filterCheckBoxesNegative(filterValues, remUsers) {
if (filter.type == 'checkBoxes' && filter.value.length > 0) {
var stringToCompare = makeComparingString(filter.value, 'negative');

console.log(filter.value, 'filter value')
if (stringToCompare.replace(/\s/g, '').length == 0) continue;

for (var i = remUsers.length - 1; i >= 0; i--) {
Expand All @@ -102,7 +101,6 @@ function filterCheckBoxesNegative(filterValues, remUsers) {
remUsers.splice(i, 1);
continue;
}
console.log(stringToCompare, 'string to compare');

// go through all the user checkboxes and see if they have all the values
var userCheckboxes = user.form[key];
Expand Down
46 changes: 27 additions & 19 deletions mainJS/pathFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function findForm(formUser, formId) {
}

async function signUp(req, res) {
var formUser = await schemas.formMakerUsers.findOne({ 'forms.formId': req.params.formId, 'forms.formName': req.params.formName });
var formUser = await schemas.formMakerUsers.findOne({ 'forms.formId': { $eq: req.params.formId }, 'forms.formName': { $eq: req.params.formName } });
if (formUser == null || formUser == undefined) return res.status(404).send('Form not found');
var formOptions = findForm(formUser, req.params.formId);
// another check to verify it is allowed
Expand All @@ -54,7 +54,10 @@ function testIfValidEmail(email) {
// genreate email verifaction link
async function generateVerficationLink(req, res) {
// see if the form is valid or not
var formUser = await schemas.formMakerUsers.findOne({ 'forms.formId': req.body.formId, 'forms.formName': unescape(req.body.formName) });
var formUser = await schemas.formMakerUsers.findOne({
'forms.formId': { $eq: req.body.formId },
'forms.formName': { $eq: unescape(req.body.formName) }
});
if (formUser == null || formUser == undefined) return res.status(404).send('Form not found');

var formOptions = findForm(formUser, req.body.formId);
Expand All @@ -65,7 +68,7 @@ async function generateVerficationLink(req, res) {
const collectionName = req.body.formId + '-' + formOptions.adminKeyForForm.slice(10);
const newCollection = mongoose.model(collectionName, schemas.userSchema, collectionName);

var user = await newCollection.findOne({ 'email': req.body.email });
var user = await newCollection.findOne({ 'email': { $eq: req.body.email } });
var token = crypto.randomBytes(16).toString('hex');
var email = req.body.email;
// does any other user have the same token
Expand Down Expand Up @@ -148,13 +151,13 @@ async function checkFormAuthToken(token, urlParams) {
console.log(decoded);
console.log(urlParams);
let found = await schemas.formAuthTokens.findOne({
'formName': urlParams.formName,
'formId': urlParams.formId,
'formAdminKey': urlParams.adminKey,
'userId': urlParams.userId,
'code': decoded.code
'formName': { $eq: urlParams.formName },
'formId': { $eq: urlParams.formId },
'formAdminKey': { $eq: urlParams.adminKey },
'userId': { $eq: urlParams.userId },
'code': { $eq: decoded.code }
})

if (found != null || found != undefined) return true;

} catch (err) {
Expand All @@ -166,11 +169,11 @@ async function checkFormAuthToken(token, urlParams) {
async function verifyFormAccess(req, res) {
// find the code from the database, and see if it matches
let found = await schemas.formAuthTokens.findOne({
'formName': req.body.formName,
'formId': req.body.formId,
'formAdminKey': req.body.formAdminKey,
'userId': req.body.userId,
'code': req.body.code
'formName': { $eq: req.body.formName },
'formId': { $eq: req.body.formId },
'formAdminKey': { $eq: req.body.formAdminKey },
'userId': { $eq: req.body.userId },
'code': { $eq: req.body.code }
})

if (found == null || found == undefined) return res.status(403).send('Code is not valid');
Expand Down Expand Up @@ -221,11 +224,11 @@ async function formPage(req, res) {
var formOptions = findForm(formUser, req.params.formId);
// another check to verify it is allowed
if (formOptions.adminKeyForForm.slice(-5) != req.params.adminKey) return res.status(403).send('Not authorized');
if (formOptions.formSettings.isFormClosed){

if (formOptions.formSettings.isFormClosed) {
return res.render('formClosed');
}

// find the user
var user = await accessCollectionOfUsers(req.params.formId + '-' + formOptions.adminKeyForForm.slice(10), req.params.userId);
if (user == null || user == undefined) return res.status(404).send('User not found');
Expand Down Expand Up @@ -352,7 +355,7 @@ async function pdfPage(req, res) {
if (formOptions.adminKeyForForm != req.params.adminKey) return res.status(403).send('Not authorized');

// find the user
console.log(req.params.formId + '-' + formOptions.adminKeyForForm.slice(10), req.params.userId);
console.log('showing pdf page');
var user = await accessCollectionOfUsers(req.params.formId + '-' + formOptions.adminKeyForForm.slice(10), req.params.userId);
if (user == null || user == undefined) return res.status(404).send('User not found');

Expand Down Expand Up @@ -397,7 +400,12 @@ async function editFormPage(req, res) {

async function saveEditedForm(req, res) {
// check if the user is authorized or not
var formUser = await schemas.formMakerUsers.findOne({ 'forms.formId': req.body.formId, 'forms.formName': unescape(req.body.formName), 'forms.adminKeyForForm': req.body.adminKey });
var formUser = await schemas.formMakerUsers.findOne({
'forms.formId': { $eq: req.body.formId },
'forms.formName': { $eq: unescape(req.body.formName) },
'forms.adminKeyForForm': { $eq: req.body.adminKey }
});

if (formUser == null || formUser == undefined) return res.status(403).send('Not Authorized !!! Check the password or contact the admin');

console.log(req.body);
Expand Down
18 changes: 18 additions & 0 deletions mainJS/rateLimiter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const rateLimiter = require("express-rate-limit");
// Here we are limiting the number of requests to the database to 5 every 10 seconds for each IP address
// This is to prevent the database from being overloaded
const databaseAccessLimiter = rateLimiter({
max: 5,
windowMS: 5000, // 5 seconds
message: "You can't make any more requests at the moment. Try again later",
});

const imageLimiter = rateLimiter({
max: 100,
windowMS: 5000, // 5 seconds
});

module.exports = {
databaseAccessLimiter,
imageLimiter
};
Loading

0 comments on commit 695472d

Please sign in to comment.