| @@ -16,6 +16,7 @@ | |||
| "express-jwt": "^7.7.2", | |||
| "helmet": "^5.1.0", | |||
| "joi": "^17.6.0", | |||
| "joi-objectid": "^4.0.2", | |||
| "jsonwebtoken": "^8.5.1", | |||
| "migrate-mongo": "^9.0.0", | |||
| "mongodb": "^4.6.0", | |||
| @@ -1681,6 +1682,11 @@ | |||
| "@sideway/pinpoint": "^2.0.0" | |||
| } | |||
| }, | |||
| "node_modules/joi-objectid": { | |||
| "version": "4.0.2", | |||
| "resolved": "https://registry.npmjs.org/joi-objectid/-/joi-objectid-4.0.2.tgz", | |||
| "integrity": "sha512-OjYM+wK/JGo2bSb9ADEyzxxROJPZYtrqIwBbywpJ2a98oKlbLtWTKvpzmrnXzou69Ey9EsjHsFvZYzpjeCdKuA==" | |||
| }, | |||
| "node_modules/js-yaml": { | |||
| "version": "4.1.0", | |||
| "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", | |||
| @@ -4614,6 +4620,11 @@ | |||
| "@sideway/pinpoint": "^2.0.0" | |||
| } | |||
| }, | |||
| "joi-objectid": { | |||
| "version": "4.0.2", | |||
| "resolved": "https://registry.npmjs.org/joi-objectid/-/joi-objectid-4.0.2.tgz", | |||
| "integrity": "sha512-OjYM+wK/JGo2bSb9ADEyzxxROJPZYtrqIwBbywpJ2a98oKlbLtWTKvpzmrnXzou69Ey9EsjHsFvZYzpjeCdKuA==" | |||
| }, | |||
| "js-yaml": { | |||
| "version": "4.1.0", | |||
| "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", | |||
| @@ -20,6 +20,7 @@ | |||
| "express-jwt": "^7.7.2", | |||
| "helmet": "^5.1.0", | |||
| "joi": "^17.6.0", | |||
| "joi-objectid": "^4.0.2", | |||
| "jsonwebtoken": "^8.5.1", | |||
| "migrate-mongo": "^9.0.0", | |||
| "mongodb": "^4.6.0", | |||
| @@ -12,7 +12,7 @@ const userSchema = new mongoose.Schema({ | |||
| type: String, | |||
| required: true | |||
| }, | |||
| role: { | |||
| roles: { | |||
| type: String | |||
| }, | |||
| tokens: [{ | |||
| @@ -0,0 +1,41 @@ | |||
| const Auth = require('../database/models/token') | |||
| const authMediator = require('../mediator/authMediator') | |||
| const token = async (req, res, next) => { | |||
| try { | |||
| if (!req.body.email || !req.body.password){ | |||
| return res.status(400).send('Pass credentials') | |||
| } | |||
| const result = await authMediator.token() | |||
| if(!result.succeeded){ | |||
| res.status(401).send(result.error) | |||
| } | |||
| return res.status(200).send(result.value) | |||
| } catch (e) { | |||
| next(e) | |||
| } | |||
| } | |||
| const logout = async (req, res) => { | |||
| const result = await Auth.destroyToken(req.body.token) | |||
| if (!result) { | |||
| return res.status(404).send('No user has the token provided!') | |||
| } | |||
| return res.send('Auth ' + req.body.token + ' invalidated!') | |||
| } | |||
| const refreshUserToken = async (req, res) => { | |||
| const form = { | |||
| token: req.body.token | |||
| } | |||
| const result = await Auth.refreshAuthToken(form.token) | |||
| if (!result) { | |||
| return res.status(404).send('Auth not valid!') | |||
| } | |||
| return res.status(201).send('Auth ' + result + ' refreshed successfully!') | |||
| } | |||
| module.exports = { loginUser: token, logout, refreshUserToken } | |||
| @@ -1,43 +0,0 @@ | |||
| const Token = require('../database/models/token') | |||
| const bcrypt = require('bcryptjs') | |||
| const loginUser = async (req, res, next) => { | |||
| try { | |||
| const findUser = await Token.findByCredentials(req.body.email, req.body.password) | |||
| if (!findUser) { | |||
| return res.status(400).send('Wrong credentials!') | |||
| } | |||
| const isValidPassword = await bcrypt.compare(req.body.password, findUser.password) | |||
| if (!isValidPassword) { | |||
| return res.status(400).send('Wrong credentials!') | |||
| } | |||
| const token = await Token.generateAuthToken(findUser) | |||
| return res.status(201).send(findUser) | |||
| } catch (e) { | |||
| next(e) | |||
| } | |||
| } | |||
| const logout = async (req, res) => { | |||
| const result = await Token.destroyToken(req.body.token) | |||
| if (!result) { | |||
| return res.status(404).send('No user has the token provided!') | |||
| } | |||
| return res.send('Token ' + req.body.token + ' invalidated!') | |||
| } | |||
| const refreshUserToken = async (req, res) => { | |||
| const form = { | |||
| token: req.body.token | |||
| } | |||
| const result = await Token.refreshAuthToken(form.token) | |||
| if (!result) { | |||
| return res.status(404).send('Token not valid!') | |||
| } | |||
| return res.status(201).send('Token ' + result + ' refreshed successfully!') | |||
| } | |||
| module.exports = { loginUser, logout, refreshUserToken } | |||
| @@ -1,6 +1,6 @@ | |||
| const bcrypt = require("bcryptjs/dist/bcrypt") | |||
| const User = require("../database/models/user") | |||
| const { getUserValidator } = require("../validators/users") | |||
| const { getUserValidator, getIdValidator, getUpdatedUserValidator } = require("../validators/users") | |||
| const mediator = require('../mediator/userMediator') | |||
| const getUsers = async (req, res, next) => { | |||
| const allUsers = await User.find({}) | |||
| @@ -8,19 +8,18 @@ const getUsers = async (req, res, next) => { | |||
| } | |||
| const getUser = async (req, res, next) => { | |||
| const result = getUserValidator.validate(req.body) | |||
| console.log(result) | |||
| try { | |||
| const id = req.params.id | |||
| if (!id) { | |||
| return res.status(400).send('Bad request') | |||
| } | |||
| const user = await User.findById(id) | |||
| if (!user) { | |||
| return res.status(404).send("User with the id of: " + id + " doesnt exist") | |||
| const errId = getIdValidator.validate(id).error | |||
| if (errId) { | |||
| return res.status(404).send(errId.message) | |||
| } | |||
| const result = await mediator.getUser(id) | |||
| return res.json(user) | |||
| if (!result.succeeded) { | |||
| return res.status(400).send(result.error) | |||
| } | |||
| return res.status(200).json(result.value) | |||
| } catch (e) { | |||
| next(e) | |||
| } | |||
| @@ -29,20 +28,17 @@ const getUser = async (req, res, next) => { | |||
| const createUser = async (req, res, next) => { | |||
| try { | |||
| const userModel = req.body | |||
| if (Object.entries(userModel).length === 0) { | |||
| return res.status(400).send('Object cant be empty') | |||
| } | |||
| const err = getUserValidator.validate(userModel).error | |||
| if (err) { | |||
| return res.status(401).send(err.message) | |||
| return res.status(404).send(err.message) | |||
| } | |||
| const result = await mediator.createUser(userModel) | |||
| if (!result.succeeded) { | |||
| return res.status(400).send(result.error) | |||
| } | |||
| const newUser = new User(userModel) | |||
| newUser.password = await bcrypt.hash(newUser.password, 8) | |||
| await newUser.save() | |||
| return res.status(201).json(newUser) | |||
| return res.status(201).json(result.value) | |||
| } catch (e) { | |||
| next(e) | |||
| } | |||
| @@ -51,31 +47,40 @@ const createUser = async (req, res, next) => { | |||
| const updateUser = async (req, res, next) => { | |||
| try { | |||
| const id = req.params.id | |||
| const objBody = req.body | |||
| if (Object.entries(objBody).length == 0) { | |||
| return res.status(400).send('Invalid input parameters') | |||
| const errId = getIdValidator.validate(id).error | |||
| if (errId) { | |||
| return res.status(400).send(errId.message) | |||
| } | |||
| const err = getUserValidator.validate(objBody).error | |||
| const objBody = req.body | |||
| const err = getUpdatedUserValidator.validate(objBody).error | |||
| if (err) { | |||
| return res.status(400).send(err.message) | |||
| } | |||
| let user = await User.findById(id); | |||
| if (!user) { | |||
| return res.status(404).send("User with the id of: " + id + " doesnt exist") | |||
| const result = await mediator.updateUser(id, objBody) | |||
| if (!result.succeeded) { | |||
| return res.status(400).send(result.error) | |||
| } | |||
| return res.status(200).send(result.value) | |||
| } catch (e) { | |||
| next(e) | |||
| } | |||
| } | |||
| const updatedUser = { | |||
| name: objBody.name, | |||
| password: objBody.password, | |||
| email: objBody.email | |||
| const deleteUser = async (req, res, next) => { | |||
| try { | |||
| const id = req.params.id | |||
| const errId = getIdValidator.validate(id).error | |||
| if (errId) { | |||
| return res.status(400).send(errId.message) | |||
| } | |||
| await User.updateOne({ _id: req.params.id }, updatedUser) | |||
| return res.status(200).send('User updated successfully') | |||
| const result = await mediator.deleteUser(id) | |||
| if (!result.succeeded) { | |||
| return res.status(400).send(result.error) | |||
| } | |||
| return res.status(204).send(result.value) | |||
| } catch (e) { | |||
| next(e) | |||
| } | |||
| @@ -83,11 +88,11 @@ const updateUser = async (req, res, next) => { | |||
| const updateUserContacts = async (req, res, next) => { | |||
| try { | |||
| userFound = true | |||
| const userFound = true | |||
| if (!userFound) { | |||
| return res.status(404).send('user not found') | |||
| } | |||
| if (Object.entries(req.body).length == 0) { | |||
| if (!req.body) { | |||
| return res.status(400).send('invalid input parameters') | |||
| } | |||
| return res.status(200).send('user contacts updated successfully') | |||
| @@ -96,24 +101,5 @@ const updateUserContacts = async (req, res, next) => { | |||
| } | |||
| } | |||
| const deleteUser = async (req, res, next) => { | |||
| try { | |||
| const id = req.params.id | |||
| if (!id) { | |||
| return res.status(400).send('You need to provide valid Id') | |||
| } | |||
| const user = await User.findById(id) | |||
| if (!user) { | |||
| return res.status(404).send("User with the id of: " + id + " doesnt exist") | |||
| } | |||
| await User.deleteOne(user) | |||
| return res.status(204).send('Deleting user with id of ' + id) | |||
| } catch (e) { | |||
| next(e) | |||
| } | |||
| } | |||
| module.exports = { getUsers, getUser, createUser, updateUserContacts, updateUser, deleteUser } | |||
| module.exports = { getUsers, getUser, createUser, updateUser, updateUserContacts, deleteUser } | |||
| @@ -0,0 +1,31 @@ | |||
| const Auth = require("../database/models/token"); | |||
| const bcrypt = require("bcryptjs"); | |||
| const token = async (email, password) => { | |||
| const foundUser = await Auth.findByCredentials(email, password) | |||
| if (!foundUser) { | |||
| return { | |||
| succeeded: false, | |||
| value: null, | |||
| error: 'Wrong credentials!' | |||
| } | |||
| } | |||
| const isValidPassword = await bcrypt.compare(password, foundUser.password) | |||
| if (!isValidPassword) { | |||
| return { | |||
| succeeded: false, | |||
| value: null, | |||
| error: 'Wrong credentials!' | |||
| } | |||
| } | |||
| const token = await Auth.generateAuthToken(foundUser) | |||
| return { | |||
| succeeded: true, | |||
| value: token, | |||
| error: null | |||
| } | |||
| } | |||
| module.exports = {token} | |||
| @@ -0,0 +1,80 @@ | |||
| const bcrypt = require("bcryptjs/dist/bcrypt") | |||
| const User = require("../database/models/user") | |||
| const { getUserValidator } = require("../validators/users") | |||
| const getUser = async (id) => { | |||
| const user = await User.findById(id) | |||
| if (!user) { | |||
| return { | |||
| succeeded: false, | |||
| value: null, | |||
| error: 'User not found!' | |||
| } | |||
| } | |||
| return { | |||
| succeeded: true, | |||
| value: user, | |||
| error: null | |||
| } | |||
| } | |||
| const createUser = async (user) => { | |||
| const foundMail = await User.find({ email: user.email }) | |||
| if (foundMail.length) { | |||
| return { | |||
| succeeded: false, | |||
| value: null, | |||
| error: 'User with email already exists!' | |||
| } | |||
| } | |||
| const newUser = new User(user) | |||
| newUser.password = await bcrypt.hash(newUser.password, 8) | |||
| await User.create(newUser) | |||
| return { | |||
| succeeded: true, | |||
| value: newUser, | |||
| error: null | |||
| } | |||
| } | |||
| const updateUser = async (id, body) => { | |||
| let user = await User.findById(id); | |||
| if (!user) { | |||
| return { | |||
| succeeded: false, | |||
| value: null, | |||
| error: 'User with id ' + id + ' does not exist!' | |||
| } | |||
| } | |||
| const updatedUser = { | |||
| name: body.name, | |||
| roles: body.roles | |||
| } | |||
| await User.updateOne({ _id: id }, updatedUser) | |||
| return { | |||
| succeeded: true, | |||
| value: 'User updated successfully!', | |||
| error: null | |||
| } | |||
| } | |||
| const deleteUser = async (id) => { | |||
| let user = await User.findById(id) | |||
| if (!user) { | |||
| return { | |||
| succeeded: false, | |||
| value: null, | |||
| error: 'User with id ' + id + ' does not exist!' | |||
| } | |||
| } | |||
| await User.deleteOne(user) | |||
| return { | |||
| succeeded: true, | |||
| value: null, | |||
| error: null | |||
| } | |||
| } | |||
| module.exports = {getUser, createUser, updateUser, deleteUser} | |||
| @@ -2,8 +2,6 @@ const logger = require('../logging/logger') | |||
| const config = require('config') | |||
| const errorLogger = (err, req, res, next) => { | |||
| //console.error(err) | |||
| if (config.util.getEnv('NODE_ENV') === 'development') | |||
| logger.error(err) | |||
| @@ -1,6 +1,6 @@ | |||
| const express = require('express') | |||
| const router = new express.Router() | |||
| const endpoints = require('../endpoints/token') | |||
| const endpoints = require('../endpoints/auth') | |||
| router.post('/auth/token', endpoints.loginUser) | |||
| @@ -3,7 +3,7 @@ const express = require('express') | |||
| const app = express() | |||
| const port = process.env.NODE_ENV === 'production' ? 80 : 3001 | |||
| require('./database/mongoose') | |||
| const docs = require('./swagger.js'); | |||
| const docs = require('./swagger.js') | |||
| const swaggerUI = require('swagger-ui-express') | |||
| const { errorLogger, errorResponder } = require('./middleware/errorHandling.js') | |||
| const requestLogging = require('./middleware/requestLogging.js') | |||
| @@ -17,7 +17,7 @@ const routesDirectory = path.resolve(__dirname) + '/routes/' | |||
| app.use(errorLogger); | |||
| app.use(errorResponder); | |||
| app.use(express.json()) | |||
| app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(docs)) | |||
| app.use('/swagger', swaggerUI.serve, swaggerUI.setup(docs)) | |||
| app.use(requestLogging) | |||
| app.use(cors()) | |||
| app.use(helmet()) | |||
| @@ -1,12 +1,19 @@ | |||
| const Joi = require("joi"); | |||
| Joi.objectId = require('joi-objectid')(Joi) | |||
| const schema = { | |||
| getUserValidator: Joi.object({ | |||
| name: Joi.string().min(2).required(), | |||
| password: Joi.string().min(8).regex(/[a-zA-Z0-9]{3,30}/).required(), | |||
| email: Joi.string().email().required(), | |||
| role: Joi.string() | |||
| }) | |||
| } | |||
| module.exports = schema | |||
| const getIdValidator = Joi.objectId().required(); | |||
| const getUserValidator = Joi.object({ | |||
| name: Joi.string().min(2).required(), | |||
| password: Joi.string().min(8).regex(/[a-zA-Z0-9]{3,30}/).required(), | |||
| email: Joi.string().email().required(), | |||
| roles: Joi.string() | |||
| }) | |||
| const getUpdatedUserValidator = Joi.object({ | |||
| name: Joi.string().min(2).required(), | |||
| roles: Joi.string() | |||
| }) | |||
| module.exports = {getUserValidator, getIdValidator, getUpdatedUserValidator} | |||