diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..6d8c40f --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,17 @@ +## Description +Briefly describe the changes made in this pull request. + +## Fixes +Specify the related issues or tickets that this pull request fixes (e.g., Fixes #123). + +## Checklist + +- [ ] Code follows project's style guidelines. +- [ ] Changes are documented appropriately. + +## Notes +Add any additional notes or context that might be useful for reviewers. + + + +#### (PS → Make Sure Pull request title is meaningful.) \ No newline at end of file diff --git a/controller/auth.js b/controller/auth.js index a5281a2..3db5753 100644 --- a/controller/auth.js +++ b/controller/auth.js @@ -1,8 +1,7 @@ -import util, {logger} from "#util"; +import OTPStore from "#models/otpStore"; +import util, { logger } from "#util"; import { authenticateUser, userExists, updatePassword } from "#services/user"; -const otpStore = {}; - async function login(req, res) { const { id, password } = req.body; try { @@ -17,7 +16,7 @@ async function login(req, res) { userDetails.token = token; res.json({ res: "welcome", user: userDetails }); } catch (error) { - logger.error("Error while login", error) + logger.error("Error while login", error); if (error.name === "UserDoesNotExist") { res.status(403); res.json({ err: "Incorrect ID password" }); @@ -36,7 +35,7 @@ async function sendOTP(req, res) { const { uid, emailId } = req.body; if (await userExists(uid, emailId)) { const otp = Math.floor(1000 + Math.random() * 9000); - otpStore[uid] = otp; + await OTPStore.update({ uid }, { otp }); util.sendOTP(emailId, otp); res.json({ res: "otp sent to emailID" }); } else { @@ -46,12 +45,13 @@ async function sendOTP(req, res) { async function resetPassword(req, res) { const { uid, otp, password } = req.body; - if (otpStore[uid] === otp) { + const storedOtp = await OTPStore.read({ uid }); + if (storedOtp[0].otp === `${otp}`) { try { await updatePassword(uid, password); res.json({ res: "successfully updated password" }); } catch (error) { - logger.log("Error while updating", error) + logger.log("Error while updating", error); res.status(500); if (error.name === "UpdateError") res.json({ err: "Something went wrong while updating password" }); else res.json({ err: "something went wrong" }); diff --git a/controller/user.js b/controller/user.js index a3e94ac..20efc5c 100644 --- a/controller/user.js +++ b/controller/user.js @@ -9,8 +9,8 @@ async function addUser(req, res) { const newUser = await createUser(name, password, emailId, uid, userType); res.json({ res: `added user ${newUser.id}` }); } catch (error) { - logger.error("Error while inserting", error) - res.status(500) + logger.error("Error while inserting", error); + res.status(500); res.json({ err: "Error while inserting in DB" }); } } diff --git a/middleware/auth.js b/middleware/auth.js index 74418f0..016483d 100644 --- a/middleware/auth.js +++ b/middleware/auth.js @@ -1,5 +1,5 @@ import jwt from "jsonwebtoken"; -import util, {logger} from "#util"; +import util from "#util"; async function authenticateToken(req, res, next) { const authHeader = req.headers.authorization; @@ -9,15 +9,17 @@ async function authenticateToken(req, res, next) { const payload = jwt.verify(token, process.env.TOKEN_SECRET); const decryptedIP = util.decrypt(payload.ip); if (decryptedIP !== req.ip) { - res.status(403) - res.send({err:"Unauthorized"}); + res.status(403); + res.send({ err: "Unauthorized" }); } req.user = payload.data; next(); + return true; } catch (error) { - res.status(403) - res.send({err:"Unauthorized"}); + res.status(403); + res.send({ err: "Unauthorized" }); + return false; } } diff --git a/models/accreditation.js b/models/accreditation.js index cd75537..3bb137c 100644 --- a/models/accreditation.js +++ b/models/accreditation.js @@ -1,25 +1,23 @@ import connector from "#models/databaseUtil"; const accreditationSchema = { - uid: { type: String, unique: true, required: true }, accreditationName: { type: String, required: true }, agencyName: { type: String, required: true }, dateofAccreditation: { type: Date, required: true }, dateofExpiry: { type: Date, required: true }, }; -const Accreditation = new connector.model("Accreditation", accreditationSchema); +const Accreditation = connector.model("Accreditation", accreditationSchema); async function remove(filter) { const res = await Accreditation.findOneAndDelete(filter); return res; } -async function create(uid, accreditationName, agencyName, dateofAccreditation, dateofExpiry) { +async function create(accreditationName, agencyName, dateofAccreditation, dateofExpiry) { const accreditation = new Accreditation({ accreditationName, agencyName, - uid, dateofAccreditation, dateofExpiry, }); diff --git a/models/attendance.js b/models/attendance.js new file mode 100644 index 0000000..5b0a723 --- /dev/null +++ b/models/attendance.js @@ -0,0 +1,39 @@ +import connector from "./databaseUtil"; + +connector.set("debug", true); + +const attendanceSchema = { + date: { type: Date, required: true }, + time: { type: String, required: true }, + absentees: { type: Array }, +}; + +const Attendance = connector.model("Attendance", attendanceSchema); + +async function create(date, time, absentees) { + const attendance = new Attendance({ + date, + time, + absentees, + }); + const newAttendence = await attendance.save(); + return newAttendence; +} + +async function remove(filter) { + const res = await Attendance.findOneAndDelete(filter); + return res; +} + +async function grantAttendance(roll, date) { + const res = await Attendance.findOneAndUpdate( + date, + { $pull: { absentees: roll } }, + { new: true }, + ); + return res; +} + +export default { + create, remove, grantAttendance, +}; diff --git a/models/faculty.js b/models/faculty.js index 3e74312..54e6f72 100644 --- a/models/faculty.js +++ b/models/faculty.js @@ -1,13 +1,13 @@ -const { connector } = require('./databaseUtil'); +const { connector } = require("./databaseUtil"); -const facultySchema = new mongoose.Schema({ +const facultySchema = { name: { type: String, required: true, }, department: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Department', + type: connector.Schema.Types.ObjectId, + ref: "Department", required: true, }, empType: { @@ -19,7 +19,7 @@ const facultySchema = new mongoose.Schema({ required: true, }, preferredSubjects: { - type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Subject' }], + type: [{ type: connector.Schema.Types.ObjectId, ref: "Subject" }], required: true, }, profileLink: { @@ -87,8 +87,8 @@ const facultySchema = new mongoose.Schema({ type: Date, default: Date.now, }, -}); +}; -const Faculty = connector.model('Faculty', facultySchema); +const Faculty = connector.model("Faculty", facultySchema); module.exports = Faculty; diff --git a/models/group.js b/models/group.js index e705a1b..19118eb 100644 --- a/models/group.js +++ b/models/group.js @@ -1,8 +1,55 @@ import connector from "#models/databaseUtil"; const groupSchema = { - groupName: { type: String, required: true }, - studentIds: { type: [Number], required: true }, //array of number + groupName: { type: String, required: true }, + studentIds: { type: [Number], required: true }, +}; + +const groupModel = connector.model("group", groupSchema); + +async function createGroup(groupData) { + try { + const newGroup = await groupModel.create(groupData); + return newGroup; + } catch (error) { + console.error("Error creating group:", error); + return null; + } +} + +async function getGroupById(groupId) { + try { + const group = await groupModel.findById(groupId); + return group; + } catch (error) { + console.error("Error retrieving group:", error); + return null; + } +} + +async function updateGroup(groupId, updateData) { + try { + const updatedGroup = await groupModel.findByIdAndUpdate(groupId, updateData, { new: true }); + return updatedGroup; + } catch (error) { + console.error("Error updating group:", error); + return null; + } +} + +async function deleteGroup(groupId) { + try { + const deletedGroup = await groupModel.findByIdAndDelete(groupId); + return deletedGroup; + } catch (error) { + console.error("Error deleting group:", error); + return null; + } } -const groupModel = new connector.model('group', groupSchema); \ No newline at end of file +export default { + createGroup, + getGroupById, + updateGroup, + deleteGroup, +}; diff --git a/models/infra.js b/models/infra.js index ec2bac8..37c5c16 100644 --- a/models/infra.js +++ b/models/infra.js @@ -8,7 +8,7 @@ const infrastructureSchema = { capacity: { type: Number, required: true }, }; -const Infrastructure = new connector.model("Infrastructure", infrastructureSchema); +const Infrastructure = connector.model("Infrastructure", infrastructureSchema); async function remove(filter) { const res = await Infrastructure.findOneAndDelete(filter); diff --git a/models/module.js b/models/module.js index 3387f38..3ce94ee 100644 --- a/models/module.js +++ b/models/module.js @@ -1,4 +1,4 @@ -import connector from '#models/databaseUtil'; +import connector from "#models/databaseUtil"; const moduleSchema = { moduleNo: { type: Number, required: true }, @@ -9,7 +9,7 @@ const moduleSchema = { cognitiveLevels: [{ type: String, required: true }], }; -const Module = new connector.model('Module', moduleSchema); +const Module = connector.model("Module", moduleSchema); async function remove(filter) { const res = await Module.findOneAndDelete(filter); @@ -22,7 +22,7 @@ async function create( moduleOutcome, moduleContents, hrsPerModule, - cognitiveLevels + cognitiveLevels, ) { const module = new Module({ moduleNo, diff --git a/models/organization.js b/models/organization.js new file mode 100644 index 0000000..95ba478 --- /dev/null +++ b/models/organization.js @@ -0,0 +1,16 @@ +import connector from "./databaseUtil"; + +const organizationSchema = { + parent: { type: connector.Schema.Types.ObjectId, ref: "Organization", required: "true" }, + orgID: { type: String, required: true }, + orgName: { type: String, required: true }, + orgAddress: { type: String, required: true }, + orgInfra: [{ type: connector.Schema.Types.ObjectId, ref: "Infrastructure", required: "true" }], + accreditation: { type: connector.Schema.Types.ObjectId, ref: "Accrediation", required: "true" }, + department: [{ type: connector.Schema.Types.ObjectId, ref: "Department", required: "true" }], + employees: [{ type: connector.Schema.Types.ObjectId, ref: "Faculty", required: "true" }], + +}; + +// eslint-disable-next-line no-unused-vars +const Organization = connector.model("Organization", organizationSchema); diff --git a/models/otpStore.js b/models/otpStore.js new file mode 100644 index 0000000..6695e49 --- /dev/null +++ b/models/otpStore.js @@ -0,0 +1,36 @@ +import connector from "#models/databaseUtil"; + +const otpStoreSchema = { + uid: { type: String, unique: true, required: true }, + otp: { type: String, unique: true, required: true }, +}; + +const OTPStore = connector.model("OTPStore", otpStoreSchema); + +async function remove(filter) { + const res = await OTPStore.findOneAndDelete(filter); + return res; +} + +async function create(uid, otp) { + const otpStore = new OTPStore({ + uid, + otp, + }); + const otpDoc = await otpStore.save(); + return otpDoc; +} + +async function read(filter, limit = 1) { + const otpData = await OTPStore.find(filter).limit(limit); + return otpData; +} + +async function update(filter, updateObject) { + const otpDoc = await OTPStore.findOneAndUpdate(filter, updateObject, { upsert: true, new: true }); + return otpDoc; +} + +export default { + create, read, update, remove, +}; diff --git a/models/subject.js b/models/subject.js new file mode 100644 index 0000000..e014bcc --- /dev/null +++ b/models/subject.js @@ -0,0 +1,26 @@ +const { connector } = require("#models/databaseUtil"); + +const subjectcontentSchema = { + courseCode: { type: String, required: true }, + courseName: { type: String, required: true }, + totalCredit: { type: Number, required: true }, + duration: { type: Number, required: true }, + subID: { type: String, required: true }, + subName: { type: String, required: true }, + semester: { type: String, required: true }, + ltpCredDist: { type: [Number], required: true }, + subType: { type: String, enum: ["open", "professional", "core"], required: true }, // can be open, professional, or core + prerequisites: { type: String, required: true }, + courseObjective: { type: String, required: true }, + courseOutcomes: [{ + courseOutcome: { type: String }, + RBTLevel: { type: String }, + }], // this is the modules from syllabus + reccTextbooks: { type: [String], required: true }, + refBooks: { type: [String], required: true }, + evalScheme: { type: [Number], required: true }, + maxMarks: { type: Number, required: true }, +}; + +// eslint-disable-next-line no-unused-vars +const subjectcontentModel = connector.model("subjectcontent", subjectcontentSchema); diff --git a/models/user.js b/models/user.js index eb051db..17e63cd 100644 --- a/models/user.js +++ b/models/user.js @@ -1,5 +1,5 @@ import connector from "#models/databaseUtil"; -import { logger } from "#util"; +import { hashPassword } from "#util"; connector.set("debug", true); const userSchema = { @@ -17,7 +17,8 @@ async function remove(filter) { return res; } -async function create(name, password, emailId, uid, userType) { +async function create(name, pass, emailId, uid, userType) { + const password = await hashPassword(pass); const user = new User({ name, password, diff --git a/package-lock.json b/package-lock.json index 45bec43..4f104dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "api", "version": "0.0.0", "dependencies": { + "bcrypt": "^5.1.0", "cookie-parser": "~1.4.4", "cors": "^2.8.5", "debug": "~2.6.9", @@ -2366,6 +2367,39 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2584,8 +2618,7 @@ "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/accepts": { "version": "1.3.8", @@ -2620,6 +2653,38 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2667,7 +2732,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2700,6 +2764,23 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2900,8 +2981,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2933,6 +3013,19 @@ "node": ">= 0.8" } }, + "node_modules/bcrypt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.0.tgz", + "integrity": "sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.10", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2994,7 +3087,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3225,6 +3317,14 @@ "fsevents": "~2.3.2" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/ci-info": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", @@ -3311,6 +3411,14 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/color/node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -3352,8 +3460,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/confusing-browser-globals": { "version": "1.0.11", @@ -3361,6 +3468,11 @@ "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", "dev": true }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3514,6 +3626,11 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -3531,6 +3648,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -3612,8 +3737,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/enabled": { "version": "2.0.0", @@ -4481,11 +4605,32 @@ "node": ">= 0.6" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.2", @@ -4533,6 +4678,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -4605,7 +4769,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4766,6 +4929,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", @@ -4803,6 +4971,39 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -4905,7 +5106,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5055,7 +5255,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -6145,7 +6344,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, "dependencies": { "semver": "^6.0.0" }, @@ -6160,7 +6358,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -6263,7 +6460,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6280,6 +6476,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -6414,6 +6652,49 @@ "node": ">= 0.6" } }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -6522,6 +6803,17 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -6761,7 +7053,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7150,7 +7441,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -7303,6 +7593,11 @@ "node": ">= 0.8.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -7350,8 +7645,7 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/simple-swizzle": { "version": "0.2.2", @@ -7539,7 +7833,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7598,7 +7891,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -7730,6 +8022,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -8101,6 +8409,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/winston": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", diff --git a/package.json b/package.json index feef845..1f1d7d1 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,11 @@ "serverstartWin": "SET DEBUG=api:* && npm run devstart", "test": "NODE_OPTIONS=--experimental-vm-modules npx jest", "test:watch": "NODE_OPTIONS=--experimental-vm-modules npx jest --watch", - "test:openHandels": "NODE_OPTIONS=--experimental-vm-modules npx jest --detectOpenHandles" + "test:openHandels": "NODE_OPTIONS=--experimental-vm-modules npx jest --detectOpenHandles", + "eslint": "eslint '**/*.js'" }, "dependencies": { + "bcrypt": "^5.1.0", "cookie-parser": "~1.4.4", "cors": "^2.8.5", "debug": "~2.6.9", diff --git a/services/user.js b/services/user.js index c059717..b45fe34 100644 --- a/services/user.js +++ b/services/user.js @@ -1,9 +1,11 @@ import User from "#models/user"; import databaseError from "#error/database"; +import { comparePasswords, hashPassword } from "#util"; export async function authenticateUser(uid, password) { - const user = await User.read({ uid, password }, 1); - if (user[0]?.uid === uid) { + const user = await User.read({ uid }, 1); + const passwordMatched = await comparePasswords(password, user[0]?.password); + if (passwordMatched) { return user[0]; } throw new databaseError.UserDoesNotExistError(); @@ -16,7 +18,8 @@ export async function userExists(uid, email) { } export async function updatePassword(uid, password) { - const user = await User.update({ uid }, { password }); + const hashedPassword = await hashPassword(password); + const user = await User.update({ uid }, { password: hashedPassword }); if (user.uid === uid) return user; throw new databaseError.UpdateError("User"); } diff --git a/util.js b/util.js index 6f6d5b5..e7ff739 100644 --- a/util.js +++ b/util.js @@ -1,10 +1,11 @@ import jwt from "jsonwebtoken"; import nodemailer from "nodemailer"; import { logLevel } from "#constant"; -import crypto from "crypto" +import crypto from "crypto"; import "winston-daily-rotate-file"; import winston from "winston"; import dotenv from "dotenv"; +import bcrypt from "bcrypt"; const { combine, timestamp, align, printf, colorize, json, @@ -23,26 +24,26 @@ const transporter = nodemailer.createTransport({ const key = crypto.randomBytes(32); const iv = crypto.randomBytes(16); -const algorithm = 'aes-256-cbc'; +const algorithm = "aes-256-cbc"; const encrypt = (IP) => { - const cipher = crypto.createCipheriv(algorithm, key, iv); - let encrypted = cipher.update(IP, 'utf8', 'hex'); - encrypted += cipher.final('hex'); - return encrypted; -} + const cipher = crypto.createCipheriv(algorithm, key, iv); + let encrypted = cipher.update(IP, "utf8", "hex"); + encrypted += cipher.final("hex"); + return encrypted; +}; const decrypt = (IP) => { - const decipher = crypto.createDecipheriv(algorithm, key, iv); - let decrypted = decipher.update(IP, 'hex', 'utf8'); - decrypted += decipher.final('utf8'); - return decrypted; -} + const decipher = crypto.createDecipheriv(algorithm, key, iv); + let decrypted = decipher.update(IP, "hex", "utf8"); + decrypted += decipher.final("utf8"); + return decrypted; +}; -const generateToken = (data, IP)=>{ +const generateToken = (data, IP) => { const encryptedIP = encrypt(IP); - return jwt.sign({data: data, ip: encryptedIP}, process.env.TOKEN_SECRET); -} + return jwt.sign({ data, ip: encryptedIP }, process.env.TOKEN_SECRET); +}; const sendOTP = async (to, otp) => { await transporter.sendMail({ @@ -53,6 +54,25 @@ const sendOTP = async (to, otp) => { }); }; +export const hashPassword = async (password) => { + try { + const salt = await bcrypt.genSalt(10); + const hashedPassword = await bcrypt.hash(password, salt); + return hashedPassword; + } catch (error) { + return error.message; + } +}; + +export const comparePasswords = async (userPassword, storedPassword) => { + try { + const matched = await bcrypt.compare(userPassword, storedPassword); + return matched; + } catch (error) { + return error.message; + } +}; + /** * * @param {*} data any data that you want as return from the function after mentioned time @@ -123,5 +143,12 @@ logger.stream = { }; export default { - generateToken, encrypt, decrypt, sendOTP, asyncPlaceholders, logger + generateToken, + encrypt, + decrypt, + sendOTP, + asyncPlaceholders, + logger, + hashPassword, + comparePasswords, };