diff --git a/Dockerfile b/Dockerfile index 92d19a5c2..91a5b43e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ -FROM node:12.7.0 +FROM node:12-alpine ENV WORKDIR /usr/src/app/ WORKDIR $WORKDIR COPY package*.json $WORKDIR RUN npm install --production --no-cache -FROM node:4-alpine +FROM node:12-alpine ENV USER node ENV WORKDIR /home/$USER/app WORKDIR $WORKDIR diff --git a/app/data/allocations-dao.js b/app/data/allocations-dao.js index 8d3940c03..26ecc387e 100644 --- a/app/data/allocations-dao.js +++ b/app/data/allocations-dao.js @@ -30,7 +30,7 @@ const AllocationsDAO = function(db){ userId: parsedUserId }, allocations, { upsert: true - }, (err, result) => { + }, err => { if (!err) { @@ -90,7 +90,7 @@ const AllocationsDAO = function(db){ let doneCounter = 0; const userAllocations = []; - allocations.forEach( (alloc) => { + allocations.forEach( alloc => { userDAO.getUserById(alloc.userId, (err, user) => { if (err) return callback(err, null); diff --git a/app/data/benefits-dao.js b/app/data/benefits-dao.js index 3839164e9..5e773e442 100644 --- a/app/data/benefits-dao.js +++ b/app/data/benefits-dao.js @@ -10,19 +10,17 @@ function BenefitsDAO(db) { return new BenefitsDAO(db); } - var usersCol = db.collection("users"); + const usersCol = db.collection("users"); - this.getAllNonAdminUsers = function(callback) { + this.getAllNonAdminUsers = callback => { usersCol.find({ "isAdmin": { $ne: true } - }).toArray(function(err, users) { - callback(null, users); - }); + }).toArray((err, users) => callback(null, users)); }; - this.updateBenefits = function(userId, startDate, callback) { + this.updateBenefits = (userId, startDate, callback) => { usersCol.update({ _id: parseInt(userId) }, { @@ -30,7 +28,7 @@ function BenefitsDAO(db) { benefitStartDate: startDate } }, - function(err, result) { + (err, result) => { if (!err) { console.log("Updated benefits"); return callback(null, result); @@ -42,4 +40,4 @@ function BenefitsDAO(db) { }; } -module.exports.BenefitsDAO = BenefitsDAO; +module.exports = { BenefitsDAO }; diff --git a/app/data/contributions-dao.js b/app/data/contributions-dao.js index 9aacaed77..00041dac6 100644 --- a/app/data/contributions-dao.js +++ b/app/data/contributions-dao.js @@ -1,4 +1,4 @@ -var UserDAO = require("./user-dao").UserDAO; +const UserDAO = require("./user-dao").UserDAO; /* The ContributionsDAO must be constructed with a connected database object */ function ContributionsDAO(db) { @@ -11,14 +11,14 @@ function ContributionsDAO(db) { return new ContributionsDAO(db); } - var contributionsDB = db.collection("contributions"); - var userDAO = new UserDAO(db); + const contributionsDB = db.collection("contributions"); + const userDAO = new UserDAO(db); - this.update = function(userId, preTax, afterTax, roth, callback) { - var parsedUserId = parseInt(userId); + this.update = (userId, preTax, afterTax, roth, callback) => { + const parsedUserId = parseInt(userId); // Create contributions document - var contributions = { + const contributions = { userId: parsedUserId, preTax: preTax, afterTax: afterTax, @@ -26,16 +26,16 @@ function ContributionsDAO(db) { }; contributionsDB.update({ - userId: userId + userId }, contributions, { upsert: true }, - function(err, result) { + err => { if (!err) { console.log("Updated contributions"); // add user details - userDAO.getUserById(parsedUserId, function(err, user) { + userDAO.getUserById(parsedUserId, (err, user) => { if (err) return callback(err, null); @@ -53,11 +53,11 @@ function ContributionsDAO(db) { ); }; - this.getByUserId = function(userId, callback) { + this.getByUserId = (userId, callback) => { contributionsDB.findOne({ userId: userId }, - function(err, contributions) { + (err, contributions) => { if (err) return callback(err, null); // Set defualt contributions if not set @@ -68,10 +68,9 @@ function ContributionsDAO(db) { }; // add user details - userDAO.getUserById(userId, function(err, user) { + userDAO.getUserById(userId, (err, user) => { if (err) return callback(err, null); - contributions.userName = user.userName; contributions.firstName = user.firstName; contributions.lastName = user.lastName; @@ -84,4 +83,4 @@ function ContributionsDAO(db) { }; } -module.exports.ContributionsDAO = ContributionsDAO; +module.exports = { ContributionsDAO }; diff --git a/app/data/memos-dao.js b/app/data/memos-dao.js index e5d1de47c..434c935c2 100644 --- a/app/data/memos-dao.js +++ b/app/data/memos-dao.js @@ -10,39 +10,30 @@ function MemosDAO(db) { return new MemosDAO(db); } - var memosCol = db.collection("memos"); + const memosCol = db.collection("memos"); - this.insert = function(memo, callback) { + this.insert = (memo, callback) => { // Create allocations document - var memos = { - memo: memo, + const memos = { + memo, timestamp: new Date() }; - memosCol.insert(memos, function(err, result) { - - if (!err) { - return callback(null, result); - } - - return callback(err, null); - }); + memosCol.insert(memos, (err, result) => !err ? callback(null, result) : callback(err, null)); }; - this.getAllMemos = function(callback) { + this.getAllMemos = (callback) => { memosCol.find({}).sort({ timestamp: -1 - }).toArray(function(err, memos) { + }).toArray((err, memos) => { if (err) return callback(err, null); if (!memos) return callback("ERROR: No memos found", null); - callback(null, memos); - }); }; } -module.exports.MemosDAO = MemosDAO; +module.exports = { MemosDAO }; diff --git a/app/data/profile-dao.js b/app/data/profile-dao.js index d388f5aff..552e5df38 100644 --- a/app/data/profile-dao.js +++ b/app/data/profile-dao.js @@ -10,39 +10,39 @@ function ProfileDAO(db) { return new ProfileDAO(db); } - var users = db.collection("users"); + const users = db.collection("users"); /* Fix for A6 - Sensitive Data Exposure // Use crypto module to save sensitive data such as ssn, dob in encrypted format - var crypto = require("crypto"); - var config = require("../../config/config"); + const crypto = require("crypto"); + const config = require("../../config/config"); /// Helper method create initialization vector // By default the initialization vector is not secure enough, so we create our own - var createIV = function() { + const createIV = () => { // create a random salt for the PBKDF2 function - 16 bytes is the minimum length according to NIST - var salt = crypto.randomBytes(16); + const salt = crypto.randomBytes(16); return crypto.pbkdf2Sync(config.cryptoKey, salt, 100000, 512, "sha512"); }; // Helper methods to encryt / decrypt - var encrypt = function(toEncrypt) { + const encrypt = (toEncrypt) => { config.iv = createIV(); - var cipher = crypto.createCipheriv(config.cryptoAlgo, config.cryptoKey, config.iv); - return cipher.update(toEncrypt, "utf8", "hex") + cipher.final("hex"); + const cipher = crypto.createCipheriv(config.cryptoAlgo, config.cryptoKey, config.iv); + return `${cipher.update(toEncrypt, "utf8", "hex")} ${cipher.final("hex")}`; }; - var decrypt = function(toDecrypt) { - var decipher = crypto.createDecipheriv(config.cryptoAlgo, config.cryptoKey, config.iv); - return decipher.update(toDecrypt, "hex", "utf8") + decipher.final("utf8"); + const decrypt = (toDecrypt) => { + const decipher = crypto.createDecipheriv(config.cryptoAlgo, config.cryptoKey, config.iv); + return `${decipher.update(toDecrypt, "hex", "utf8")} ${decipher.final("utf8")}`; }; */ - this.updateUser = function(userId, firstName, lastName, ssn, dob, address, bankAcc, bankRouting, callback) { + this.updateUser = (userId, firstName, lastName, ssn, dob, address, bankAcc, bankRouting, callback) => { // Create user document - var user = {}; + const user = {}; if (firstName) { user.firstName = firstName; } @@ -80,7 +80,7 @@ function ProfileDAO(db) { }, { $set: user }, - function(err, result) { + err => { if (!err) { console.log("Updated user profile"); return callback(null, user); @@ -91,11 +91,11 @@ function ProfileDAO(db) { ); }; - this.getByUserId = function(userId, callback) { + this.getByUserId = (userId, callback) => { users.findOne({ _id: parseInt(userId) }, - function(err, user) { + (err, user) => { if (err) return callback(err, null); /* // Fix for A6 - Sensitive Data Exposure @@ -110,4 +110,4 @@ function ProfileDAO(db) { }; } -module.exports.ProfileDAO = ProfileDAO; +module.exports = { ProfileDAO }; diff --git a/app/data/research-dao.js b/app/data/research-dao.js index 974c3551e..96e211fc4 100644 --- a/app/data/research-dao.js +++ b/app/data/research-dao.js @@ -10,9 +10,9 @@ function ResearchDAO(db) { return new ResearchDAO(db); } - this.getBySymbol= function(symbol, callback) { + this.getBySymbol = (symbol, callback) => { - function searchCriteria() { + const searchCriteria = () => { if (symbol) { console.log("in if symbol"); @@ -24,4 +24,4 @@ function ResearchDAO(db) { } } -module.exports.ResearchDAO = ResearchDAO; +module.exports = { ResearchDAO }; diff --git a/app/data/user-dao.js b/app/data/user-dao.js index 733e91a58..e88bdafb3 100644 --- a/app/data/user-dao.js +++ b/app/data/user-dao.js @@ -1,4 +1,4 @@ -var bcrypt = require("bcrypt-nodejs"); +const bcrypt = require("bcrypt-nodejs"); /* The UserDAO must be constructed with a connected database object */ function UserDAO(db) { @@ -12,17 +12,17 @@ function UserDAO(db) { return new UserDAO(db); } - var usersCol = db.collection("users"); + const usersCol = db.collection("users"); - this.addUser = function(userName, firstName, lastName, password, email, callback) { + this.addUser = (userName, firstName, lastName, password, email, callback) => { // Create user document - var user = { - userName: userName, - firstName: firstName, - lastName: lastName, + const user = { + userName, + firstName, + lastName, benefitStartDate: this.getRandomFutureDate(), - password: password //received from request param + password //received from request param /* // Fix for A2-1 - Broken Auth // Stores password in a safer way using one way encryption and salt hashing @@ -31,41 +31,33 @@ function UserDAO(db) { }; // Add email if set - if (email !== "") { + if (email) { user.email = email; } - this.getNextSequence("userId", function(err, id) { + this.getNextSequence("userId", (err, id) => { if (err) { return callback(err, null); } console.log(typeof(id)); user._id = id; - - usersCol.insert(user, function(err, result) { - - if (!err) { - return callback(null, result.ops[0]); - } - - return callback(err, null); - }); + usersCol.insert(user, (err, result) => !err ? callback(null, result.ops[0]) : callback(err, null)); }); }; - this.getRandomFutureDate = function() { - var today = new Date(); - var day = (Math.floor(Math.random() * 10) + today.getDay()) % 29; - var month = (Math.floor(Math.random() * 10) + today.getMonth()) % 12; - var year = Math.ceil(Math.random() * 30) + today.getFullYear(); - return year + "-" + ("0" + month).slice(-2) + "-" + ("0" + day).slice(-2); + this.getRandomFutureDate = () => { + const today = new Date(); + const day = (Math.floor(Math.random() * 10) + today.getDay()) % 29; + const month = (Math.floor(Math.random() * 10) + today.getMonth()) % 12; + const year = Math.ceil(Math.random() * 30) + today.getFullYear(); + return `${year}-${("0" + month).slice(-2)}-${("0" + day).slice(-2)}` }; - this.validateLogin = function(userName, password, callback) { + this.validateLogin = (userName, password, callback) => { // Helper function to compare passwords - function comparePassword(fromDB, fromUser) { + const comparePassword = (fromDB, fromUser) => { return fromDB === fromUser; /* // Fix for A2-Broken Auth @@ -75,7 +67,7 @@ function UserDAO(db) { } // Callback to pass to MongoDB that validates a user document - function validateUserDoc(err, user) { + const validateUserDoc = (err, user) => { if (err) return callback(err, null); @@ -83,13 +75,13 @@ function UserDAO(db) { if (comparePassword(password, user.password)) { callback(null, user); } else { - var invalidPasswordError = new Error("Invalid password"); + const invalidPasswordError = new Error("Invalid password"); // Set an extra field so we can distinguish this from a db error invalidPasswordError.invalidPassword = true; callback(invalidPasswordError, null); } } else { - var noSuchUserError = new Error("User: " + user + " does not exist"); + const noSuchUserError = new Error("User: " + user + " does not exist"); // Set an extra field so we can distinguish this from a db error noSuchUserError.noSuchUser = true; callback(noSuchUserError, null); @@ -102,19 +94,19 @@ function UserDAO(db) { }; // This is the good one, see the next function - this.getUserById = function(userId, callback) { + this.getUserById = (userId, callback) => { usersCol.findOne({ _id: parseInt(userId) }, callback); }; - this.getUserByUserName = function(userName, callback) { + this.getUserByUserName = (userName, callback) => { usersCol.findOne({ userName: userName }, callback); }; - this.getNextSequence = function(name, callback) { + this.getNextSequence = (name, callback) => { db.collection("counters").findAndModify({ _id: name }, [], { @@ -124,14 +116,8 @@ function UserDAO(db) { }, { new: true }, - function(err, data) { - if (err) { - return callback(err, null); - } - callback(null, data.value.seq); - } - ); + (err, data) => err ? callback(err, null) : callback(null, data.value.seq)); }; } -module.exports.UserDAO = UserDAO; +module.exports = { UserDAO }; diff --git a/app/routes/allocations.js b/app/routes/allocations.js index dca22a412..b45f1ab13 100644 --- a/app/routes/allocations.js +++ b/app/routes/allocations.js @@ -1,25 +1,21 @@ -var AllocationsDAO = require("../data/allocations-dao").AllocationsDAO; +const AllocationsDAO = require("../data/allocations-dao").AllocationsDAO; -function AllocationsHandler(db) { +function AllocationsHandler (db) { "use strict"; - var allocationsDAO = new AllocationsDAO(db); + const allocationsDAO = new AllocationsDAO(db); - - this.displayAllocations = function(req, res, next) { + this.displayAllocations = (req, res, next) => { /* // Fix for A4 Insecure DOR - take user id from session instead of from URL param - var userId = req.session.userId; + const { userId } = req.session; */ - var userId = req.params.userId; + const {userId} = req.params; + const { threshold } = req.query - allocationsDAO.getByUserIdAndThreshold(userId, req.query.threshold, function(err, allocations) { + allocationsDAO.getByUserIdAndThreshold(userId, threshold, (err, allocations) => { if (err) return next(err); - - return res.render("allocations", { - userId: userId, - allocations: allocations - }); + return res.render("allocations", { userId, allocations }); }); }; } diff --git a/app/routes/benefits.js b/app/routes/benefits.js index 5374e8c6e..1e8189501 100644 --- a/app/routes/benefits.js +++ b/app/routes/benefits.js @@ -1,18 +1,18 @@ -var BenefitsDAO = require("../data/benefits-dao").BenefitsDAO; +const { BenefitsDAO } = require("../data/benefits-dao"); -function BenefitsHandler(db) { +function BenefitsHandler (db) { "use strict"; - var benefitsDAO = new BenefitsDAO(db); + const benefitsDAO = new BenefitsDAO(db); - this.displayBenefits = function(req, res, next) { + this.displayBenefits = (req, res, next) => { - benefitsDAO.getAllNonAdminUsers(function(error, users) { + benefitsDAO.getAllNonAdminUsers((error, users) => { if (error) return next(error); return res.render("benefits", { - users: users, + users, user: { isAdmin: true } @@ -20,21 +20,18 @@ function BenefitsHandler(db) { }); }; - this.updateBenefits = function(req, res, next) { - var userId = req.body.userId; - var benefitStartDate = req.body.benefitStartDate; + this.updateBenefits = (req, res, next) => { + const { userId, benefitStartDate } = req.body; - benefitsDAO.updateBenefits(userId, benefitStartDate, function(error) { + benefitsDAO.updateBenefits(userId, benefitStartDate, (error) => { if (error) return next(error); - benefitsDAO.getAllNonAdminUsers(function(error, users) { - var data; - + benefitsDAO.getAllNonAdminUsers((error, users) => { if (error) return next(error); - data = { - users: users, + const data = { + users, user: { isAdmin: true }, diff --git a/app/routes/contributions.js b/app/routes/contributions.js index 939ac180a..14327c9ed 100644 --- a/app/routes/contributions.js +++ b/app/routes/contributions.js @@ -1,15 +1,15 @@ -var ContributionsDAO = require("../data/contributions-dao").ContributionsDAO; +const ContributionsDAO = require("../data/contributions-dao").ContributionsDAO; /* The ContributionsHandler must be constructed with a connected db */ -function ContributionsHandler(db) { +function ContributionsHandler (db) { "use strict"; - var contributionsDAO = new ContributionsDAO(db); + const contributionsDAO = new ContributionsDAO(db); - this.displayContributions = function(req, res, next) { - var userId = req.session.userId; + this.displayContributions = (req, res, next) => { + const { userId } = req.session; - contributionsDAO.getByUserId(userId, function(error, contrib) { + contributionsDAO.getByUserId(userId, (error, contrib) => { if (error) return next(error); contrib.userId = userId; //set for nav menu items @@ -17,38 +17,40 @@ function ContributionsHandler(db) { }); }; - this.handleContributionsUpdate = function(req, res, next) { + this.handleContributionsUpdate = (req, res, next) => { /*jslint evil: true */ // Insecure use of eval() to parse inputs - var preTax = eval(req.body.preTax); - var afterTax = eval(req.body.afterTax); - var roth = eval(req.body.roth); + const preTax = eval(req.body.preTax); + const afterTax = eval(req.body.afterTax); + const roth = eval(req.body.roth); /* //Fix for A1 -1 SSJS Injection attacks - uses alternate method to eval - var preTax = parseInt(req.body.preTax); - var afterTax = parseInt(req.body.afterTax); - var roth = parseInt(req.body.roth); + const preTax = parseInt(req.body.preTax); + const afterTax = parseInt(req.body.afterTax); + const roth = parseInt(req.body.roth); */ - var userId = req.session.userId; + const { userId } = req.session; //validate contributions - if (isNaN(preTax) || isNaN(afterTax) || isNaN(roth) || preTax < 0 || afterTax < 0 || roth < 0) { + const validations = [isNaN(preTax), isNaN(afterTax), isNaN(roth), preTax < 0, afterTax < 0, roth < 0] + const isInvalid = validations.some(validation => validation) + if (isInvalid) { return res.render("contributions", { updateError: "Invalid contribution percentages", - userId: userId + userId }); } // Prevent more than 30% contributions if (preTax + afterTax + roth > 30) { return res.render("contributions", { updateError: "Contribution percentages cannot exceed 30 %", - userId: userId + userId }); } - contributionsDAO.update(userId, preTax, afterTax, roth, function(err, contributions) { + contributionsDAO.update(userId, preTax, afterTax, roth, (err, contributions) => { if (err) return next(err); diff --git a/app/routes/error.js b/app/routes/error.js index 2dc4e1dbb..0df5fd867 100644 --- a/app/routes/error.js +++ b/app/routes/error.js @@ -1,6 +1,6 @@ // Error handling middleware -var errorHandler = function(err, req, res, next) { +const errorHandler = (err, req, res,next) => { "use strict"; @@ -12,4 +12,4 @@ var errorHandler = function(err, req, res, next) { }); }; -exports.errorHandler = errorHandler; +module.exports = { errorHandler }; diff --git a/app/routes/index.js b/app/routes/index.js index 9ab8b9b72..62ca639a8 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -1,30 +1,30 @@ -var SessionHandler = require("./session"); -var ProfileHandler = require("./profile"); -var BenefitsHandler = require("./benefits"); -var ContributionsHandler = require("./contributions"); -var AllocationsHandler = require("./allocations"); -var MemosHandler = require("./memos"); -var ResearchHandler = require("./research"); +const SessionHandler = require("./session"); +const ProfileHandler = require("./profile"); +const BenefitsHandler = require("./benefits"); +const ContributionsHandler = require("./contributions"); +const AllocationsHandler = require("./allocations"); +const MemosHandler = require("./memos"); +const ResearchHandler = require("./research"); -var ErrorHandler = require("./error").errorHandler; +const ErrorHandler = require("./error").errorHandler; -var exports = function(app, db) { +const index = (app, db) => { "use strict"; - var sessionHandler = new SessionHandler(db); - var profileHandler = new ProfileHandler(db); - var benefitsHandler = new BenefitsHandler(db); - var contributionsHandler = new ContributionsHandler(db); - var allocationsHandler = new AllocationsHandler(db); - var memosHandler = new MemosHandler(db); - var researchHandler = new ResearchHandler(db); + const sessionHandler = new SessionHandler(db); + const profileHandler = new ProfileHandler(db); + const benefitsHandler = new BenefitsHandler(db); + const contributionsHandler = new ContributionsHandler(db); + const allocationsHandler = new AllocationsHandler(db); + const memosHandler = new MemosHandler(db); + const researchHandler = new ResearchHandler(db); // Middleware to check if a user is logged in - var isLoggedIn = sessionHandler.isLoggedInMiddleware; + const isLoggedIn = sessionHandler.isLoggedInMiddleware; //Middleware to check if user has admin rights - var isAdmin = sessionHandler.isAdminUserMiddleware; + const isAdmin = sessionHandler.isAdminUserMiddleware; // The main page of the app app.get("/", sessionHandler.displayWelcomePage); @@ -67,17 +67,19 @@ var exports = function(app, db) { app.post("/memos", isLoggedIn, memosHandler.addMemos); // Handle redirect for learning resources link - app.get("/learn", isLoggedIn, function(req, res, next) { + app.get("/learn", isLoggedIn, (req, res) => { // Insecure way to handle redirects by taking redirect url from query string return res.redirect(req.query.url); }); // Handle redirect for learning resources link - app.get("/tutorial", function(req, res, next) { + app.get("/tutorial", (req, res) => { return res.render("tutorial/a1"); }); - app.get("/tutorial/:page", function(req, res, next) { - return res.render("tutorial/" + req.params.page); + + app.get("/tutorial/:page", (req, res) => { + const { page } = req.params + return res.render(`tutorial/${page}`); }); // Research Page @@ -87,4 +89,4 @@ var exports = function(app, db) { app.use(ErrorHandler); }; -module.exports = exports; +module.exports = index; diff --git a/app/routes/memos.js b/app/routes/memos.js index 019000eef..c70af0beb 100644 --- a/app/routes/memos.js +++ b/app/routes/memos.js @@ -1,26 +1,23 @@ -var MemosDAO = require("../data/memos-dao").MemosDAO; +const MemosDAO = require("../data/memos-dao").MemosDAO; -function MemosHandler(db) { +function MemosHandler (db) { "use strict"; - var memosDAO = new MemosDAO(db); + const memosDAO = new MemosDAO(db); - var self = this; - this.addMemos = function(req, res, next) { + this.addMemos = (req, res, next) => { - memosDAO.insert(req.body.memo, function(err, docs) { + memosDAO.insert(req.body.memo, (err, docs) => { if (err) return next(err); - - self.displayMemos(req, res, next); - + this.displayMemos(req, res, next); }); }; - this.displayMemos = function(req, res, next) { + this.displayMemos = (req, res, next) => { - var userId = req.session.userId; + const { userId } = req.session; - memosDAO.getAllMemos(function(err, docs) { + memosDAO.getAllMemos((err, docs) => { if (err) return next(err); return res.render("memos", { memosList: docs, diff --git a/app/routes/profile.js b/app/routes/profile.js index a9033483e..4282d55cb 100644 --- a/app/routes/profile.js +++ b/app/routes/profile.js @@ -1,18 +1,18 @@ -var ProfileDAO = require("../data/profile-dao").ProfileDAO; -var ESAPI = require('node-esapi') +const ProfileDAO = require("../data/profile-dao").ProfileDAO; +const ESAPI = require('node-esapi') /* The ProfileHandler must be constructed with a connected db */ -function ProfileHandler(db) { +function ProfileHandler (db) { "use strict"; - var profile = new ProfileDAO(db); + const profile = new ProfileDAO(db); - this.displayProfile = function (req, res, next) { - var userId = req.session.userId; + this.displayProfile = (req, res, next) => { + const { userId } = req.session; - profile.getByUserId(parseInt(userId), function (err, doc) { + profile.getByUserId(parseInt(userId), (err, doc) => { if (err) return next(err); doc.userId = userId; @@ -29,15 +29,9 @@ function ProfileHandler(db) { }); }; - this.handleProfileUpdate = function (req, res, next) { + this.handleProfileUpdate = (req, res, next) => { - var firstName = req.body.firstName; - var lastName = req.body.lastName; - var ssn = req.body.ssn; - var dob = req.body.dob; - var address = req.body.address; - var bankAcc = req.body.bankAcc; - var bankRouting = req.body.bankRouting; + const {firstName, lastName, ssn, dob, address, bankAcc, bankRouting} = req.body; // Fix for Section: ReDoS attack // The following regexPattern that is used to validate the bankRouting number is insecure and vulnerable to @@ -45,10 +39,10 @@ function ProfileHandler(db) { // with an exponential time until it completes // -- // The Fix: Instead of using greedy quantifiers the same regex will work if we omit the second quantifier + - // var regexPattern = /([0-9]+)\#/; - var regexPattern = /([0-9]+)+\#/; + // const regexPattern = /([0-9]+)\#/; + const regexPattern = /([0-9]+)+\#/; // Allow only numbers with a suffix of the letter #, for example: 'XXXXXX#' - var testComplyWithRequirements = regexPattern.test(bankRouting); + const testComplyWithRequirements = regexPattern.test(bankRouting); // if the regex test fails we do not allow saving if (testComplyWithRequirements !== true) { const firstNameSafeString = firstName @@ -64,7 +58,7 @@ function ProfileHandler(db) { }); } - var userId = req.session.userId; + const { userId } = req.session; profile.updateUser( parseInt(userId), @@ -75,7 +69,7 @@ function ProfileHandler(db) { address, bankAcc, bankRouting, - function (err, user) { + (err, user) => { if (err) return next(err); diff --git a/app/routes/research.js b/app/routes/research.js index 9bd820b5f..6923256cd 100644 --- a/app/routes/research.js +++ b/app/routes/research.js @@ -1,16 +1,16 @@ -var ResearchDAO = require("../data/research-dao").ResearchDAO; -var needle = require('needle'); +const ResearchDAO = require("../data/research-dao").ResearchDAO; +const needle = require('needle'); -function ResearchHandler(db) { +function ResearchHandler (db) { "use strict"; - var researchDAO = new ResearchDAO(db); + const researchDAO = new ResearchDAO(db); - this.displayResearch = function(req, res, next) { + this.displayResearch = (req, res) => { if (req.query.symbol) { - var url = req.query.url+req.query.symbol; - needle.get(url, function(error, newResponse) { + const url = req.query.url+req.query.symbol; + return needle.get(url, (error, newResponse) => { if (!error && newResponse.statusCode == 200) res.writeHead(200, {'Content-Type': 'text/html'}); res.write('

The following is the stock information you requested.

\n\n'); @@ -18,7 +18,9 @@ function ResearchHandler(db) { res.write(newResponse.body); return res.end(); }); - } else return res.render("research"); + } + + return res.render("research"); }; } diff --git a/app/routes/session.js b/app/routes/session.js index f3d38bfc7..64a4e2a61 100644 --- a/app/routes/session.js +++ b/app/routes/session.js @@ -1,49 +1,42 @@ -var UserDAO = require("../data/user-dao").UserDAO; -var AllocationsDAO = require("../data/allocations-dao").AllocationsDAO; +const UserDAO = require("../data/user-dao").UserDAO; +const AllocationsDAO = require("../data/allocations-dao").AllocationsDAO; /* The SessionHandler must be constructed with a connected db */ -function SessionHandler(db) { +function SessionHandler (db) { "use strict"; - var userDAO = new UserDAO(db); - var allocationsDAO = new AllocationsDAO(db); + const userDAO = new UserDAO(db); + const allocationsDAO = new AllocationsDAO(db); - var prepareUserData = function(user, next) { + const prepareUserData = (user, next) => { // Generate random allocations - var stocks = Math.floor((Math.random() * 40) + 1); - var funds = Math.floor((Math.random() * 40) + 1); - var bonds = 100 - (stocks + funds); + const stocks = Math.floor((Math.random() * 40) + 1); + const funds = Math.floor((Math.random() * 40) + 1); + const bonds = 100 - (stocks + funds); - allocationsDAO.update(user._id, stocks, funds, bonds, function(err) { + allocationsDAO.update(user._id, stocks, funds, bonds, (err) => { if (err) return next(err); }); }; - this.isAdminUserMiddleware = function(req, res, next) { + this.isAdminUserMiddleware = (req, res, next) => { if (req.session.userId) { - userDAO.getUserById(req.session.userId, function(err, user) { - if (user && user.isAdmin) { - next(); - } else { - return res.redirect("/login"); - } - }); - } else { - console.log("redirecting to login"); - return res.redirect("/login"); - } + return userDAO.getUserById(req.session.userId, (err, user) => user && user.isAdmin ? next() : res.redirect("/login")); + } + console.log("redirecting to login"); + return res.redirect("/login"); + }; - this.isLoggedInMiddleware = function(req, res, next) { + this.isLoggedInMiddleware = (req, res, next) => { if (req.session.userId) { - next(); - } else { - console.log("redirecting to login"); - return res.redirect("/login"); - } + return next(); + } + console.log("redirecting to login"); + return res.redirect("/login"); }; - this.displayLoginPage = function(req, res, next) { + this.displayLoginPage = (req, res, next) => { return res.render("login", { userName: "", password: "", @@ -51,14 +44,12 @@ function SessionHandler(db) { }); }; - this.handleLoginRequest = function(req, res, next) { - var userName = req.body.userName; - var password = req.body.password; - - userDAO.validateLogin(userName, password, function(err, user) { - var errorMessage = "Invalid username and/or password"; - var invalidUserNameErrorMessage = "Invalid username"; - var invalidPasswordErrorMessage = "Invalid password"; + this.handleLoginRequest = (req, res, next) => { + const { userName, password } = req.body + userDAO.validateLogin(userName, password, (err, user) => { + const errorMessage = "Invalid username and/or password"; + const invalidUserNameErrorMessage = "Invalid username"; + const invalidPasswordErrorMessage = "Invalid password"; if (err) { if (err.noSuchUser) { console.log('Error: attempt to login with invalid user: ', userName); @@ -66,7 +57,7 @@ function SessionHandler(db) { // Fix for A1 - 3 Log Injection - encode/sanitize input for CRLF Injection // that could result in log forging: // - Step 1: Require a module that supports encoding - // var ESAPI = require('node-esapi'); + // const ESAPI = require('node-esapi'); // - Step 2: Encode the user input that will be logged in the correct context // following are a few examples: // console.log('Error: attempt to login with invalid user: %s', ESAPI.encoder().encodeForHTML(userName)); @@ -107,23 +98,17 @@ function SessionHandler(db) { // Fix the problem by regenerating a session in each login // by wrapping the below code as a function callback for the method req.session.regenerate() // i.e: - // `req.session.regenerate(function() {})` + // `req.session.regenerate(() => {})` req.session.userId = user._id; - if (user.isAdmin) { - return res.redirect("/benefits"); - } else { - return res.redirect("/dashboard"); - } + return res.redirect(user.isAdmin ? "/benefits" : "/dashboard") }); }; - this.displayLogoutPage = function(req, res, next) { - req.session.destroy(function() { - res.redirect("/"); - }); + this.displayLogoutPage = (req, res) => { + req.session.destroy(() => res.redirect("/")); }; - this.displaySignupPage = function(req, res, next) { + this.displaySignupPage = (req, res) => { res.render("signup", { userName: "", password: "", @@ -135,17 +120,17 @@ function SessionHandler(db) { }); }; - function validateSignup(userName, firstName, lastName, password, verify, email, errors) { + const validateSignup = (userName, firstName, lastName, password, verify, email, errors) => { - var USER_RE = /^.{1,20}$/; - var FNAME_RE = /^.{1,100}$/; - var LNAME_RE = /^.{1,100}$/; - var EMAIL_RE = /^[\S]+@[\S]+\.[\S]+$/; - var PASS_RE = /^.{1,20}$/; + const USER_RE = /^.{1,20}$/; + const FNAME_RE = /^.{1,100}$/; + const LNAME_RE = /^.{1,100}$/; + const EMAIL_RE = /^[\S]+@[\S]+\.[\S]+$/; + const PASS_RE = /^.{1,20}$/; /* //Fix for A2-2 - Broken Authentication - requires stronger password //(at least 8 characters with numbers and both lowercase and uppercase letters.) - var PASS_RE =/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/; + const PASS_RE =/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/; */ errors.userNameError = ""; @@ -186,24 +171,19 @@ function SessionHandler(db) { return true; } - this.handleSignup = function(req, res, next) { + this.handleSignup = (req, res, next) => { - var email = req.body.email; - var userName = req.body.userName; - var firstName = req.body.firstName; - var lastName = req.body.lastName; - var password = req.body.password; - var verify = req.body.verify; + const { email, userName, firstName, lastName, password, verify } = req.body; // set these up in case we have an error case - var errors = { + const errors = { "userName": userName, "email": email }; if (validateSignup(userName, firstName, lastName, password, verify, email, errors)) { - userDAO.getUserByUserName(userName, function(err, user) { + userDAO.getUserByUserName(userName, (err, user) => { if (err) return next(err); @@ -212,23 +192,21 @@ function SessionHandler(db) { return res.render("signup", errors); } - userDAO.addUser(userName, firstName, lastName, password, email, function(err, user) { + userDAO.addUser(userName, firstName, lastName, password, email, (err, user) => { if (err) return next(err); //prepare data for the user prepareUserData(user, next); /* - sessionDAO.startSession(user._id, function(err, sessionId) { - + sessionDAO.startSession(user._id, (err, sessionId) => { if (err) return next(err); - res.cookie("session", sessionId); req.session.userId = user._id; return res.render("dashboard", user); }); */ - req.session.regenerate(function() { + req.session.regenerate(() => { req.session.userId = user._id; // Set userId property. Required for left nav menu links user.userId = user._id; @@ -244,25 +222,21 @@ function SessionHandler(db) { } }; - this.displayWelcomePage = function(req, res, next) { - var userId; + this.displayWelcomePage = (req, res, next) => { + let userId; if (!req.session.userId) { console.log("welcome: Unable to identify user...redirecting to login"); - return res.redirect("/login"); } userId = req.session.userId; - userDAO.getUserById(userId, function(err, doc) { + userDAO.getUserById(userId, (err, doc) => { if (err) return next(err); - doc.userId = userId; - return res.render("dashboard", doc); }); - }; } diff --git a/artifacts/db-reset.js b/artifacts/db-reset.js index f24523d09..7e7dacc2b 100644 --- a/artifacts/db-reset.js +++ b/artifacts/db-reset.js @@ -6,10 +6,11 @@ // before running it (default: development). ie: // NODE_ENV=production node artifacts/db-reset.js -var _ = require("underscore"); -var MongoClient = require("mongodb").MongoClient; +const _ = require("underscore"); +const { MongoClient } = require("mongodb"); +const { db } = require("../config/config"); -var USERS_TO_INSERT = [ +const USERS_TO_INSERT = [ { "_id": 1, "userName": "admin", @@ -25,7 +26,7 @@ var USERS_TO_INSERT = [ "lastName": "Doe", "benefitStartDate": "2030-01-10", "password": "User1_123" - // "password" : "$2a$10$RNFhiNmt2TTpVO9cqZElb.LQM9e1mzDoggEHufLjAnAKImc6FNE86",// User1_123 + // "password" : "$2a$10$RNFhiNmt2TTpVO9cqZElb.LQM9e1mzDoggEHufLjAnAKImc6FNE86",// User1_123 }, { "_id": 3, "userName": "user2", @@ -33,13 +34,12 @@ var USERS_TO_INSERT = [ "lastName": "Smith", "benefitStartDate": "2025-11-30", "password": "User2_123" - //"password" : "$2a$10$Tlx2cNv15M0Aia7wyItjsepeA8Y6PyBYaNdQqvpxkIUlcONf1ZHyq", // User2_123 + //"password" : "$2a$10$Tlx2cNv15M0Aia7wyItjsepeA8Y6PyBYaNdQqvpxkIUlcONf1ZHyq", // User2_123 }]; // Getting the global config taking in account he environment (proc) -var config = require("../config/config"); -function parseResponse(err, res, comm) { +const parseResponse = (err, res, comm) => { if (err) { console.log("ERROR:"); console.log(comm); @@ -52,15 +52,13 @@ function parseResponse(err, res, comm) { // Starting here -MongoClient.connect(config.db, function(err, db) { - var usersCol, allocationsCol, countersCol; - +MongoClient.connect(db, (err, db) => { if (err) { console.log("ERROR: connect"); console.log(JSON.stringify(err)); process.exit(1); } - console.log("Connected to the database: " + config.db); + console.log("Connected to the database: " + db); // remove existing data (if any), we don't want to look for errors here db.dropCollection("users"); @@ -69,9 +67,9 @@ MongoClient.connect(config.db, function(err, db) { db.dropCollection("memos"); db.dropCollection("counters"); - usersCol = db.collection("users"); - allocationsCol = db.collection("allocations"); - countersCol = db.collection("counters"); + const usersCol = db.collection("users"); + const allocationsCol = db.collection("allocations"); + const countersCol = db.collection("counters"); // reset unique id counter countersCol.insert({ @@ -81,13 +79,10 @@ MongoClient.connect(config.db, function(err, db) { // insert admin and test users console.log("Users to insert:"); - USERS_TO_INSERT.forEach(function(user) { - console.log(JSON.stringify(user)); - }); + USERS_TO_INSERT.forEach((user) => console.log(JSON.stringify(user))); - usersCol.insertMany(USERS_TO_INSERT, function(err, data) { - var finalAllocations = []; - var ids; + usersCol.insertMany(USERS_TO_INSERT, (err, data) => { + const finalAllocations = []; // We can't continue if error here if (err) { @@ -97,9 +92,9 @@ MongoClient.connect(config.db, function(err, db) { } parseResponse(err, data, "users.insertMany"); - data.ops.forEach(function(user) { - var stocks = Math.floor((Math.random() * 40) + 1); - var funds = Math.floor((Math.random() * 40) + 1); + data.ops.forEach((user) => { + const stocks = Math.floor((Math.random() * 40) + 1); + const funds = Math.floor((Math.random() * 40) + 1); finalAllocations.push({ userId: user._id, @@ -110,11 +105,9 @@ MongoClient.connect(config.db, function(err, db) { }); console.log("Allocations to insert:"); - finalAllocations.forEach(function(allocation) { - console.log(JSON.stringify(allocation)); - }); + finalAllocations.forEach(allocation => console.log(JSON.stringify(allocation))); - allocationsCol.insertMany(finalAllocations, function(err, data) { + allocationsCol.insertMany(finalAllocations, (err, data) => { parseResponse(err, data, "allocations.insertMany"); console.log("Database reset performed successfully") process.exit(0); diff --git a/config/config.js b/config/config.js index e50338c21..5b1d511d6 100644 --- a/config/config.js +++ b/config/config.js @@ -1,13 +1,13 @@ -var _ = require("underscore"); -var path = require("path"); +const _ = require("underscore"); +const path = require("path"); -var finalEnv = process.env.NODE_ENV || "development"; +const finalEnv = process.env.NODE_ENV || "development"; -var config = _.extend( - require(path.resolve(__dirname + "/../config/env/all.js")), - require(path.resolve(__dirname + "/../config/env/" + finalEnv.toLowerCase() + ".js") || {}) -); +const allConf = require(path.resolve(__dirname + "/../config/env/all.js")) +const envConf = require(path.resolve(__dirname + "/../config/env/" + finalEnv.toLowerCase() + ".js")) || {} -console.log("Current Config:", config) +const config = { ...allConf, ...envConf } + +console.log(`Current Config: ${config}`) module.exports = config; diff --git a/config/env/all.js b/config/env/all.js index 8c7fce7e8..70641ec73 100755 --- a/config/env/all.js +++ b/config/env/all.js @@ -1,15 +1,15 @@ // default app configuration -var port = process.env.PORT || 4000; -var db = process.env.MONGOLAB_URI || process.env.MONGODB_URI; +const port = process.env.PORT || 4000; +let db = process.env.MONGOLAB_URI || process.env.MONGODB_URI; if (!db) { db = process.env.NODE_ENV === 'test' ? "mongodb://localhost:27017/nodegoat" : "mongodb://nodegoat:owasp@ds159217.mlab.com:59217/nodegoat"; } module.exports = { - port: port, - db: db, + port, + db, cookieSecret: "session_cookie_secret_key_here", cryptoKey: "a_secure_key_for_crypto_here", cryptoAlgo: "aes256", diff --git a/server.js b/server.js index d46b52e03..a0147579f 100644 --- a/server.js +++ b/server.js @@ -1,41 +1,39 @@ "use strict"; -var express = require("express"); -var favicon = require("serve-favicon"); -var bodyParser = require("body-parser"); -var session = require("express-session"); -// var csrf = require('csurf'); -var consolidate = require("consolidate"); // Templating library adapter for Express -var swig = require("swig"); -// var helmet = require("helmet"); -var MongoClient = require("mongodb").MongoClient; // Driver for connecting to MongoDB -var http = require("http"); -var marked = require("marked"); -//var helmet = require("helmet"); -//var nosniff = require('dont-sniff-mimetype'); -var app = express(); // Web framework to handle routing requests -var routes = require("./app/routes"); -var config = require("./config/config"); // Application config properties +const express = require("express"); +const favicon = require("serve-favicon"); +const bodyParser = require("body-parser"); +const session = require("express-session"); +// const csrf = require('csurf'); +const consolidate = require("consolidate"); // Templating library adapter for Express +const swig = require("swig"); +// const helmet = require("helmet"); +const MongoClient = require("mongodb").MongoClient; // Driver for connecting to MongoDB +const http = require("http"); +const marked = require("marked"); +//const nosniff = require('dont-sniff-mimetype'); +const app = express(); // Web framework to handle routing requests +const routes = require("./app/routes"); +const { port, db, cookieSecret } = require("./config/config"); // Application config properties /* // Fix for A6-Sensitive Data Exposure // Load keys for establishing secure HTTPS connection -var fs = require("fs"); -var https = require("https"); -var path = require("path"); -var httpsOptions = { +const fs = require("fs"); +const https = require("https"); +const path = require("path"); +const httpsOptions = { key: fs.readFileSync(path.resolve(__dirname, "./artifacts/cert/server.key")), cert: fs.readFileSync(path.resolve(__dirname, "./artifacts/cert/server.crt")) }; */ -MongoClient.connect(config.db, function(err, db) { +MongoClient.connect(db, (err, db) => { if (err) { console.log("Error: DB: connect"); console.log(err); - process.exit(1); } - console.log("Connected to the database: " + config.db); + console.log(`Connected to the database: ${db}`); /* // Fix for A5 - Security MisConfig @@ -78,10 +76,10 @@ MongoClient.connect(config.db, function(err, db) { // Enable session management using express middleware app.use(session({ - // genid: function(req) { + // genid: (req) => { // return genuuid() // use UUIDs for session IDs //}, - secret: config.cookieSecret, + secret: cookieSecret, // Both mandatory in Express v4 saveUninitialized: true, resave: true @@ -108,7 +106,7 @@ MongoClient.connect(config.db, function(err, db) { // Enable Express csrf protection app.use(csrf()); // Make csrf token available in templates - app.use(function(req, res, next) { + app.use((req, res, next) => { res.locals.csrftoken = req.csrfToken(); next(); }); @@ -117,8 +115,8 @@ MongoClient.connect(config.db, function(err, db) { // Register templating engine app.engine(".html", consolidate.swig); app.set("view engine", "html"); - app.set("views", __dirname + "/app/views"); - app.use(express.static(__dirname + "/app/assets")); + app.set("views", `${__dirname}/app/views`); + app.use(express.static(`${__dirname}/app/assets`)); // Initializing marked library @@ -142,15 +140,15 @@ MongoClient.connect(config.db, function(err, db) { }); // Insecure HTTP connection - http.createServer(app).listen(config.port, function() { - console.log("Express http server listening on port " + config.port); + http.createServer(app).listen(port, () => { + console.log(`Express http server listening on port ${port}`); }); /* // Fix for A6-Sensitive Data Exposure // Use secure HTTPS protocol - https.createServer(httpsOptions, app).listen(config.port, function() { - console.log("Express https server listening on port " + config.port); + https.createServer(httpsOptions, app).listen(port, () => { + console.log(`Express http server listening on port ${port}`); }); */