diff --git a/src/controllers/auth.ts b/src/controllers/auth.ts index 2c6fbcb..f49eed3 100644 --- a/src/controllers/auth.ts +++ b/src/controllers/auth.ts @@ -1,6 +1,5 @@ import { Security, Route, Tags, Example, Post, Body, Query, Hidden } from 'tsoa' import jwt from 'jsonwebtoken' -import bcrypt from 'bcryptjs' import User from '../model/User' import { InfoJWT } from '../types' import { removeTokensInDB, saveTokensInDB } from '../utils' @@ -80,7 +79,7 @@ const authorize = async (data: any): Promise => { const user = await User.findOne({ username }) if (!user) throw new Error('Username is not found.') - const validPass = await bcrypt.compare(password, user.password) + const validPass = user.comparePassword(password) if (!validPass) throw new Error('Invalid password.') // generate authorization code against clientId diff --git a/src/controllers/group.ts b/src/controllers/group.ts index 7cd7aa2..98a9467 100644 --- a/src/controllers/group.ts +++ b/src/controllers/group.ts @@ -163,7 +163,10 @@ const createGroup = async ({ } const getGroup = async (groupId: number): Promise => { - const group = (await Group.findOne({ groupId }).populate( + const group = (await Group.findOne( + { groupId }, + 'groupId name description isActive users -_id' + ).populate( 'users', 'id username displayName -_id' )) as unknown as GroupDetailsResponse @@ -193,7 +196,13 @@ const addUserToGroup = async ( )) as unknown as GroupDetailsResponse if (!updatedGroup) throw new Error('Unable to update group') - return updatedGroup + return { + groupId: updatedGroup.groupId, + name: updatedGroup.name, + description: updatedGroup.description, + isActive: updatedGroup.isActive, + users: updatedGroup.users + } } const removeUserFromGroup = async ( @@ -211,5 +220,11 @@ const removeUserFromGroup = async ( )) as unknown as GroupDetailsResponse if (!updatedGroup) throw new Error('Unable to update group') - return updatedGroup + return { + groupId: updatedGroup.groupId, + name: updatedGroup.name, + description: updatedGroup.description, + isActive: updatedGroup.isActive, + users: updatedGroup.users + } } diff --git a/src/controllers/user.ts b/src/controllers/user.ts index 5e4573c..b47d666 100644 --- a/src/controllers/user.ts +++ b/src/controllers/user.ts @@ -12,7 +12,6 @@ import { Body, Hidden } from 'tsoa' -import bcrypt from 'bcryptjs' import User, { UserPayload } from '../model/User' @@ -131,8 +130,7 @@ const createUser = async (data: UserPayload): Promise => { if (usernameExist) throw new Error('Username already exists.') // Hash passwords - const salt = await bcrypt.genSalt(10) - const hashPassword = await bcrypt.hash(password, salt) + const hashPassword = User.hashPassword(password) // Create a new user const user = new User({ @@ -180,8 +178,7 @@ const updateUser = async ( if (password) { // Hash passwords - const salt = await bcrypt.genSalt(10) - params.password = await bcrypt.hash(password, salt) + params.password = User.hashPassword(password) } const updatedUser = await User.findOneAndUpdate({ id }, params, { new: true }) @@ -208,7 +205,7 @@ const deleteUser = async ( if (!user) throw new Error('User is not found.') if (!isAdmin) { - const validPass = await bcrypt.compare(password!, user.password) + const validPass = user.comparePassword(password!) if (!validPass) throw new Error('Invalid password.') } diff --git a/src/model/Group.ts b/src/model/Group.ts index c081894..8ff04ff 100644 --- a/src/model/Group.ts +++ b/src/model/Group.ts @@ -31,7 +31,7 @@ interface IGroup extends IGroupDocument { } interface IGroupModel extends Model {} -const groupSchema = new Schema({ +const groupSchema = new Schema({ name: { type: String, required: true diff --git a/src/model/User.ts b/src/model/User.ts index 589f4f5..61521b5 100644 --- a/src/model/User.ts +++ b/src/model/User.ts @@ -1,5 +1,6 @@ -import mongoose, { Schema, model } from 'mongoose' +import mongoose, { Schema, model, Document, Model } from 'mongoose' const AutoIncrement = require('mongoose-sequence')(mongoose) +import bcrypt from 'bcryptjs' export interface UserPayload { /** @@ -28,7 +29,7 @@ export interface UserPayload { isActive?: boolean } -interface User extends UserPayload { +interface IUserDocument extends UserPayload, Document { id: number isAdmin: boolean isActive: boolean @@ -36,7 +37,14 @@ interface User extends UserPayload { tokens: [{ [key: string]: string }] } -const UserSchema = new Schema({ +interface IUser extends IUserDocument { + comparePassword(password: string): boolean +} +interface IUserModel extends Model { + hashPassword(password: string): string +} + +const userSchema = new Schema({ displayName: { type: String, required: true @@ -76,6 +84,20 @@ const UserSchema = new Schema({ } ] }) -UserSchema.plugin(AutoIncrement, { inc_field: 'id' }) +userSchema.plugin(AutoIncrement, { inc_field: 'id' }) -export default model('User', UserSchema) +// Static Methods +userSchema.static('hashPassword', (password: string): string => { + const salt = bcrypt.genSaltSync(10) + return bcrypt.hashSync(password, salt) +}) + +// Instance Methods +userSchema.method('comparePassword', function (password: string): boolean { + if (bcrypt.compareSync(password, this.password)) return true + return false +}) + +export const User: IUserModel = model('User', userSchema) + +export default User diff --git a/src/routes/api/auth.ts b/src/routes/api/auth.ts index 8aedd32..b16e302 100644 --- a/src/routes/api/auth.ts +++ b/src/routes/api/auth.ts @@ -1,6 +1,5 @@ import express from 'express' import mongoose from 'mongoose' -import jwt from 'jsonwebtoken' import AuthController from '../../controllers/auth' import Client from '../../model/Client' @@ -10,12 +9,7 @@ import { authenticateRefreshToken } from '../../middlewares' -import { - authorizeValidation, - removeTokensInDB, - saveTokensInDB, - tokenValidation -} from '../../utils' +import { authorizeValidation, tokenValidation } from '../../utils' import { InfoJWT } from '../../types' const authRouter = express.Router()