This commit is contained in:
Kaushik Narayan R 2023-05-12 23:40:39 +05:30
parent af932c038d
commit ed306c119e
11 changed files with 357 additions and 108 deletions

34
middleware/admin.js Normal file
View File

@ -0,0 +1,34 @@
const typedefs = require("../typedefs");
const logger = require("../utils/logger")(module);
const creds = JSON.parse(process.env.ADMIN_CREDS);
/**
* Middleware to validate admin access
* @param {typedefs.Req} req
* @param {typedefs.Res} res
* @param {typedefs.Next} next
*/
const adminQueryCreds = async (req, res, next) => {
try {
/** @type {JSON} */
const { user, access } = req.query;
if (creds[user] === access) {
logger.info("Admin access - " + user);
next();
}
else {
// we do a bit of trolling here
const unauthIP = req.headers['x-real-ip'] || req.ip
logger.warn("Intruder alert.", { ip: unauthIP });
return res.status(401).send("Intruder alert. IP address: " + unauthIP);
}
} catch (error) {
logger.error("adminQueryCreds", { error });
return res.status(500).send({ message: "Server Error. Try again." });
}
}
module.exports = {
adminQueryCreds,
}

189
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "backend-template", "name": "backend-template",
"version": "1.3.0", "version": "1.3.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "backend-template", "name": "backend-template",
"version": "1.3.0", "version": "1.3.1",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"cors": "^2.8.5", "cors": "^2.8.5",
@ -16,7 +16,7 @@
"express-validator": "^6.14.2", "express-validator": "^6.14.2",
"fast-csv": "^4.3.6", "fast-csv": "^4.3.6",
"helmet": "^6.0.0", "helmet": "^6.0.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^9.0.0",
"nodemailer": "^6.8.0", "nodemailer": "^6.8.0",
"pg": "^8.8.0", "pg": "^8.8.0",
"sequelize": "^6.24.0", "sequelize": "^6.24.0",
@ -1160,24 +1160,29 @@
} }
}, },
"node_modules/jsonwebtoken": { "node_modules/jsonwebtoken": {
"version": "8.5.1", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
"dependencies": { "dependencies": {
"jws": "^3.2.2", "jws": "^3.2.2",
"lodash.includes": "^4.3.0", "lodash": "^4.17.21",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1", "ms": "^2.1.1",
"semver": "^5.6.0" "semver": "^7.3.8"
}, },
"engines": { "engines": {
"node": ">=4", "node": ">=12",
"npm": ">=1.4.28" "npm": ">=6"
}
},
"node_modules/jsonwebtoken/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
} }
}, },
"node_modules/jsonwebtoken/node_modules/ms": { "node_modules/jsonwebtoken/node_modules/ms": {
@ -1185,6 +1190,25 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}, },
"node_modules/jsonwebtoken/node_modules/semver": {
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz",
"integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jsonwebtoken/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/jwa": { "node_modules/jwa": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
@ -1224,11 +1248,6 @@
"resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
"integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==" "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw=="
}, },
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
},
"node_modules/lodash.isboolean": { "node_modules/lodash.isboolean": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
@ -1244,41 +1263,16 @@
"resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
"integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw=="
}, },
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
},
"node_modules/lodash.isnil": { "node_modules/lodash.isnil": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz",
"integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==" "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng=="
}, },
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
},
"node_modules/lodash.isundefined": { "node_modules/lodash.isundefined": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz",
"integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==" "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA=="
}, },
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
},
"node_modules/lodash.uniq": { "node_modules/lodash.uniq": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@ -1847,9 +1841,9 @@
} }
}, },
"node_modules/retry-as-promised": { "node_modules/retry-as-promised": {
"version": "6.1.0", "version": "7.0.4",
"resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-6.1.0.tgz", "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.0.4.tgz",
"integrity": "sha512-Hj/jY+wFC+SB9SDlIIFWiGOHnNG0swYbGYsOj2BJ8u2HKUaobNKab0OIC0zOLYzDy0mb7A4xA5BMo4LMz5YtEA==" "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA=="
}, },
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
@ -1887,6 +1881,7 @@
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true,
"bin": { "bin": {
"semver": "bin/semver" "semver": "bin/semver"
} }
@ -1920,9 +1915,9 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}, },
"node_modules/sequelize": { "node_modules/sequelize": {
"version": "6.25.4", "version": "6.31.1",
"resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.25.4.tgz", "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.31.1.tgz",
"integrity": "sha512-gD6RoEVlTKxQh9GC6Qd+pW2A9uhmqeuwBHGMGcZtDg2CchXQhrwS+k6ZnWZ1ggYZ3tUkk4q8fkFL3/XmXnMFFQ==", "integrity": "sha512-cahWtRrYLjqoZP/aurGBoaxn29qQCF4bxkAUPEQ/ozjJjt6mtL4Q113S3N39mQRmX5fgxRbli+bzZARP/N51eg==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -1937,9 +1932,9 @@
"inflection": "^1.13.2", "inflection": "^1.13.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.29.1", "moment": "^2.29.1",
"moment-timezone": "^0.5.34", "moment-timezone": "^0.5.35",
"pg-connection-string": "^2.5.0", "pg-connection-string": "^2.5.0",
"retry-as-promised": "^6.1.0", "retry-as-promised": "^7.0.3",
"semver": "^7.3.5", "semver": "^7.3.5",
"sequelize-pool": "^7.1.0", "sequelize-pool": "^7.1.0",
"toposort-class": "^1.0.1", "toposort-class": "^1.0.1",
@ -3462,26 +3457,41 @@
} }
}, },
"jsonwebtoken": { "jsonwebtoken": {
"version": "8.5.1", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
"requires": { "requires": {
"jws": "^3.2.2", "jws": "^3.2.2",
"lodash.includes": "^4.3.0", "lodash": "^4.17.21",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1", "ms": "^2.1.1",
"semver": "^5.6.0" "semver": "^7.3.8"
}, },
"dependencies": { "dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"ms": { "ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"semver": {
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz",
"integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
} }
} }
}, },
@ -3524,11 +3534,6 @@
"resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
"integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==" "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw=="
}, },
"lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
},
"lodash.isboolean": { "lodash.isboolean": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
@ -3544,41 +3549,16 @@
"resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
"integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw=="
}, },
"lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
},
"lodash.isnil": { "lodash.isnil": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz",
"integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==" "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng=="
}, },
"lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
},
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
},
"lodash.isundefined": { "lodash.isundefined": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz",
"integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==" "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA=="
}, },
"lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
},
"lodash.uniq": { "lodash.uniq": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@ -4006,9 +3986,9 @@
} }
}, },
"retry-as-promised": { "retry-as-promised": {
"version": "6.1.0", "version": "7.0.4",
"resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-6.1.0.tgz", "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.0.4.tgz",
"integrity": "sha512-Hj/jY+wFC+SB9SDlIIFWiGOHnNG0swYbGYsOj2BJ8u2HKUaobNKab0OIC0zOLYzDy0mb7A4xA5BMo4LMz5YtEA==" "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA=="
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
@ -4028,7 +4008,8 @@
"semver": { "semver": {
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
}, },
"send": { "send": {
"version": "0.18.0", "version": "0.18.0",
@ -4058,9 +4039,9 @@
} }
}, },
"sequelize": { "sequelize": {
"version": "6.25.4", "version": "6.31.1",
"resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.25.4.tgz", "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.31.1.tgz",
"integrity": "sha512-gD6RoEVlTKxQh9GC6Qd+pW2A9uhmqeuwBHGMGcZtDg2CchXQhrwS+k6ZnWZ1ggYZ3tUkk4q8fkFL3/XmXnMFFQ==", "integrity": "sha512-cahWtRrYLjqoZP/aurGBoaxn29qQCF4bxkAUPEQ/ozjJjt6mtL4Q113S3N39mQRmX5fgxRbli+bzZARP/N51eg==",
"requires": { "requires": {
"@types/debug": "^4.1.7", "@types/debug": "^4.1.7",
"@types/validator": "^13.7.1", "@types/validator": "^13.7.1",
@ -4069,9 +4050,9 @@
"inflection": "^1.13.2", "inflection": "^1.13.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.29.1", "moment": "^2.29.1",
"moment-timezone": "^0.5.34", "moment-timezone": "^0.5.35",
"pg-connection-string": "^2.5.0", "pg-connection-string": "^2.5.0",
"retry-as-promised": "^6.1.0", "retry-as-promised": "^7.0.3",
"semver": "^7.3.5", "semver": "^7.3.5",
"sequelize-pool": "^7.1.0", "sequelize-pool": "^7.1.0",
"toposort-class": "^1.0.1", "toposort-class": "^1.0.1",

View File

@ -27,7 +27,7 @@
"express-validator": "^6.14.2", "express-validator": "^6.14.2",
"fast-csv": "^4.3.6", "fast-csv": "^4.3.6",
"helmet": "^6.0.0", "helmet": "^6.0.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^9.0.0",
"nodemailer": "^6.8.0", "nodemailer": "^6.8.0",
"pg": "^8.8.0", "pg": "^8.8.0",
"sequelize": "^6.24.0", "sequelize": "^6.24.0",

View File

@ -7,9 +7,9 @@
* @typedef {import("express").Response} Res * @typedef {import("express").Response} Res
* @typedef {import("express").NextFunction} Next * @typedef {import("express").NextFunction} Next
* *
* @typedef {import("sequelize") Sequelize} * @typedef {import("sequelize")} Sequelize
* @typedef {import("sequelize").Model Model} * @typedef {import("sequelize").Model} Model
* @typedef {import("sequelize").QueryInterface QueryInterface} * @typedef {import("sequelize").QueryInterface} QueryInterface
* *
* @typedef {import("winston").Logger} Logger * @typedef {import("winston").Logger} Logger
*/ */

27
utils/archiver.js Normal file
View File

@ -0,0 +1,27 @@
const fs = require("fs");
const archiver = require('archiver');
/**
* @param {String} sourceDir: /some/folder/to/compress
* @param {String} outPath: /path/to/created.zip
* @returns {Promise}
*/
function zipDirectory(sourceDir, outPath) {
const archive = archiver('zip', { zlib: { level: 9 } });
const stream = fs.createWriteStream(outPath);
return new Promise((resolve, reject) => {
archive
.directory(sourceDir, false)
.on('error', err => reject(err))
.pipe(stream)
;
stream.on('close', () => resolve());
archive.finalize();
});
}
module.exports = {
zipDirectory,
}

12
utils/dateFormatter.js Normal file
View File

@ -0,0 +1,12 @@
/**
* Returns a timestamp string to use for timestamped files
* @returns {string} String of current datetime in YYYY.MM.DD-HH:MM:SS format
*/
const dateForFilename = () => {
const dt = new Date();
return `${dt.getFullYear()}-${dt.getMonth() + 1}-${dt.getDate()}-${dt.getHours()}-${dt.getMinutes()}-${dt.getSeconds()}`;
}
module.exports = {
dateForFilename,
}

24
utils/formData.js Normal file
View File

@ -0,0 +1,24 @@
function buildFormData(formData, data, parentKey) {
if (data && typeof data === 'object' && !(data instanceof Date)) {
Object.keys(data).forEach(key => {
buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key);
});
} else {
const value = data == null ? '' : data;
formData.append(parentKey, value);
}
}
function jsonToFormData(data) {
const formData = new FormData();
buildFormData(formData, data);
return formData;
}
module.exports = {
jsonToFormData,
buildFormData,
}

58
utils/qrGenerator.js Normal file
View File

@ -0,0 +1,58 @@
const pathLib = require("path");
const qr = require("qrcode");
const logger = require("./logger")(module);
const { getSignedJWT } = require("./token");
/**
* Generates QR code from data and writes to file in tmp folder.
* To avoid race conditions, use email or other unique attributes for id.
* @param {string|any} data String or JSON object
*/
const qrPNGFile = (id, data) => {
qr.toFile(
path = pathLib.join(__dirname, "../tmp/tmpQR-" + id + ".png"),
text = (typeof data === "object" ? JSON.stringify(data) : data),
options = { type: 'png' },
(err) => {
if (err) {
logger.error("qrPNGFile", err);
throw err;
}
}
);
}
/**
* Generates QR code from data after signing and writes to file in tmp or k-qrs folder.
*
* To avoid race conditions, use email or other unique attributes for ID.
* @param {string|any} data String or JSON object
*/
const qrSignedPNGFile = (id, data, tmp = true) => {
const signedData = getSignedJWT(data);
const qrFilename = `${tmp ? 'tmpEncQR' : 'K-QR'}-${id}.png`;
const targetPath = pathLib.join(
__dirname, "..",
tmp ? "tmp" : pathLib.join("uploads", "2023", "k-qrs"),
qrFilename,
);
qr.toFile(
path = targetPath,
text = (typeof data === "object" ? JSON.stringify(signedData) : signedData),
options = { type: 'png' },
(err) => {
if (err) {
logger.error("qrSignedPNGFile", err);
throw err;
}
}
)
return qrFilename;
}
module.exports = {
qrPNGFile,
qrSignedPNGFile,
}

23
utils/quickEncrypt.js Normal file
View File

@ -0,0 +1,23 @@
/* Taken from quick-encrypt package, which is not maintained anymore */
const crypto = require('crypto')
const acceptableBitSizes = [1024, 2048];
exports.generate = (sizeInBits) => {
if (!acceptableBitSizes.includes(sizeInBits))
throw Error('Error generating public and private key. Key size can only be 1024 or 2048. Example usage: ` let keys = QuickEncrypt.generate(2048); `')
return keypair({ bits: sizeInBits })
}
exports.encrypt = (payloadString, publicKey) => {
if (typeof payloadString !== 'string' || typeof publicKey !== 'string')
throw Error("Error encrypting. Payload and Public Key should be in text format. Example usage: ` let encryptedText = QuickEncrypt.encrypt('Some secret text here!', 'the public RSA key in text format here'); ` ")
return crypto.publicEncrypt(publicKey, Buffer.from(payloadString, 'utf8')).toString('hex')
}
exports.decrypt = (encryptedString, privateKey) => {
if (typeof encryptedString !== 'string' || typeof privateKey !== 'string')
throw Error("Error decrypting. Decrypted Text and Private Key should be in text format. Example usage: ` let decryptedText = QuickEncrypt.decrypt('asddd213d19jenacanscasn', 'the private RSA key in text format here'); ` ")
return crypto.privateDecrypt({ key: privateKey }, Buffer.from(encryptedString, 'hex')).toString()
}

30
utils/sendAttachment.js Normal file
View File

@ -0,0 +1,30 @@
const typedefs = require("../typedefs");
const fastCSV = require("fast-csv");
const stream = require("stream");
/**
* Sends object data from Sequelize after formatting into CSV
*
* @param {typedefs.Res} res Express response object
* @param {string} filename Filename for attachment. Prefer timestamped names
* @param {any[]} data Data from database queries, without metadata
* @returns
*/
const sendCSV = async (res, filename, data) => {
const csvData = await fastCSV.writeToBuffer(data, { headers: true });
// refer https://stackoverflow.com/a/45922316/
const fileStream = new stream.PassThrough();
fileStream.end(csvData);
res.attachment(filename + ".csv");
res.type("text/csv");
fileStream.pipe(res);
return;
}
module.exports = {
sendCSV,
}

60
utils/token.js Normal file
View File

@ -0,0 +1,60 @@
const fs = require("fs");
const jwt = require("jsonwebtoken");
const privateKey = fs.readFileSync(process.env.PRIVKEY);
const publicKey = fs.readFileSync(process.env.PUBKEY);
/**
* Sign data into JWT with JWT env secret
* @param {string|any} data
* @returns {jwt.JwtPayload}
*/
const getJWT = (data) => {
return jwt.sign({ id: data }, process.env.JWTSECRET, { algorithm: "HS256" }); // symmetric encryption, so simple secret with SHA
};
/**
* Sign data into JWT with private key.
* @param {string|any} data
* @returns {jwt.JwtPayload}
*/
const getSignedJWT = (data) => {
return jwt.sign(
{ id: data },
privateKey,
{
algorithm: "RS256", // asymmetric signing, so private key with RSA
}
)
}
/**
* Verify a JWT with JWT env secret
* @param {jwt.JwtPayload} data
* @returns {string|any}
*/
const verifyJWT = (data) => {
return jwt.verify(data, process.env.JWTSECRET, { algorithms: ["HS256"] });
}
/**
* Verify a signed JWT with public key.
* @param {jwt.JwtPayload} signedString
* @returns {string|any}
*/
const verifySignedJWT = (signedString) => {
return jwt.verify(
signedString,
publicKey,
{
algorithms: ["RS256"]
}
);
}
module.exports = {
getJWT,
verifyJWT,
getSignedJWT,
verifySignedJWT,
};