| @@ -12,6 +12,7 @@ | |||
| "bcryptjs": "^2.4.3", | |||
| "express": "^4.18.1", | |||
| "express-jwt": "^7.7.2", | |||
| "jsonwebtoken": "^8.5.1", | |||
| "mongodb": "^4.6.0", | |||
| "mongoose": "^6.3.4", | |||
| "nodemon": "^2.0.16", | |||
| @@ -1445,6 +1446,41 @@ | |||
| "node": ">=8" | |||
| } | |||
| }, | |||
| "node_modules/lodash.includes": { | |||
| "version": "4.3.0", | |||
| "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", | |||
| "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" | |||
| }, | |||
| "node_modules/lodash.isboolean": { | |||
| "version": "3.0.3", | |||
| "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", | |||
| "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" | |||
| }, | |||
| "node_modules/lodash.isinteger": { | |||
| "version": "4.0.4", | |||
| "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", | |||
| "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" | |||
| }, | |||
| "node_modules/lodash.isnumber": { | |||
| "version": "3.0.3", | |||
| "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", | |||
| "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" | |||
| }, | |||
| "node_modules/lodash.isplainobject": { | |||
| "version": "4.0.6", | |||
| "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", | |||
| "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" | |||
| }, | |||
| "node_modules/lodash.isstring": { | |||
| "version": "4.0.1", | |||
| "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", | |||
| "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" | |||
| }, | |||
| "node_modules/lodash.once": { | |||
| "version": "4.1.1", | |||
| "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", | |||
| "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" | |||
| }, | |||
| "node_modules/lowercase-keys": { | |||
| "version": "1.0.1", | |||
| "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", | |||
| @@ -3727,6 +3763,41 @@ | |||
| "package-json": "^6.3.0" | |||
| } | |||
| }, | |||
| "lodash.includes": { | |||
| "version": "4.3.0", | |||
| "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", | |||
| "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" | |||
| }, | |||
| "lodash.isboolean": { | |||
| "version": "3.0.3", | |||
| "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", | |||
| "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" | |||
| }, | |||
| "lodash.isinteger": { | |||
| "version": "4.0.4", | |||
| "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", | |||
| "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" | |||
| }, | |||
| "lodash.isnumber": { | |||
| "version": "3.0.3", | |||
| "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", | |||
| "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" | |||
| }, | |||
| "lodash.isplainobject": { | |||
| "version": "4.0.6", | |||
| "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", | |||
| "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" | |||
| }, | |||
| "lodash.isstring": { | |||
| "version": "4.0.1", | |||
| "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", | |||
| "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" | |||
| }, | |||
| "lodash.once": { | |||
| "version": "4.1.1", | |||
| "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", | |||
| "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" | |||
| }, | |||
| "lowercase-keys": { | |||
| "version": "1.0.1", | |||
| "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", | |||
| @@ -16,6 +16,7 @@ | |||
| "bcryptjs": "^2.4.3", | |||
| "express": "^4.18.1", | |||
| "express-jwt": "^7.7.2", | |||
| "jsonwebtoken": "^8.5.1", | |||
| "mongodb": "^4.6.0", | |||
| "mongoose": "^6.3.4", | |||
| "nodemon": "^2.0.16", | |||
| @@ -0,0 +1,33 @@ | |||
| const { Router } = require("express") | |||
| const User = require("../models/token") | |||
| const Token = require('../models/token') | |||
| const bcrypt = require('bcryptjs') | |||
| const loginUser = async (req, res) => { | |||
| 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('Password is incorrect!') | |||
| } | |||
| const token = await Token.generateAuthToken(findUser) | |||
| return res.send(findUser) | |||
| } catch (e) { | |||
| return res.status(500).send(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!') | |||
| } | |||
| module.exports = { loginUser, logout } | |||
| @@ -1,11 +1,14 @@ | |||
| const bcrypt = require("bcryptjs/dist/bcrypt") | |||
| const { Router } = require("express") | |||
| const User = require("../models/user") | |||
| const getAll = async (req, res) => { | |||
| try { | |||
| if (Object.entries(req.params).length === 0) { | |||
| // const usersList = userService.GetAllUsers() | |||
| // return res.Status(200).sendJson(usersList) | |||
| return res.status(200).send('getting all users') | |||
| const allUsers = await User.find({}) | |||
| return res.status(200).send(allUsers) | |||
| } else { | |||
| return res.status(400).send('unable to get all users, request was bad') | |||
| } | |||
| @@ -31,7 +34,11 @@ const create = async (req, res, userModel) => { | |||
| try { | |||
| if (Object.entries(userModel).length !== 0) { | |||
| //create user | |||
| return res.status(201).json(userModel) | |||
| const newUser = new User(req.body) | |||
| newUser.password = await bcrypt.hash(newUser.password, 8) | |||
| await newUser.save() | |||
| return res.status(201).json(newUser) | |||
| } else { | |||
| return res.status(400).send('bad request') | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| const jwt = require('jsonwebtoken') | |||
| const User = require('../models/user') | |||
| const auth = async (req, res, next) => { | |||
| try { | |||
| const token = req.header('Authorization').replace('Bearer ', '') | |||
| const decoded = jwt.verify(token, 'ovoJeSecret') | |||
| console.log(decoded) | |||
| } catch (e) { | |||
| return res.send(e) | |||
| } | |||
| console.log('auth middleware') | |||
| next() | |||
| } | |||
| module.exports = auth | |||
| @@ -0,0 +1,67 @@ | |||
| const validator = require('validator') | |||
| const mongoose = require('mongoose') | |||
| const bcrypt = require('bcryptjs') | |||
| const jwt = require('jsonwebtoken') | |||
| const User = require('../models/user') | |||
| const tokenSchema = new mongoose.Schema({ | |||
| token: { | |||
| type: String, | |||
| required: true | |||
| }, | |||
| userId: { | |||
| type: String, | |||
| required: true | |||
| } | |||
| }) | |||
| tokenSchema.statics.findByCredentials = async (email, password) => { | |||
| const user = await User.findOne({email}) | |||
| if(!user) { | |||
| return | |||
| } | |||
| const checkMatch = await bcrypt.compare(password, user.password) | |||
| if(checkMatch) { | |||
| return user | |||
| } | |||
| return null | |||
| } | |||
| tokenSchema.statics.generateAuthToken = async function(userArg) { | |||
| console.log('aaa') | |||
| const user = userArg | |||
| const token = jwt.sign({ _id: user._id.toString() }, 'ovoJeSecret', { expiresIn: 60 * 20 }) | |||
| console.log(token) | |||
| user.tokens = user.tokens.concat({ token }) | |||
| await user.save() | |||
| return token | |||
| } | |||
| tokenSchema.statics.refreshAuthToken = async function(token, refreshOptions) { | |||
| const payload = jwt.verify(token, 'ovoJeSecret', refreshOptions.verify) | |||
| delete payload.iat | |||
| delete payload.exp | |||
| delete payload.nbf | |||
| delete payload.jti | |||
| const jwtSignOptions = Object.assign({ }, this.options, { jwtid: refreshOptions.jwtid }) | |||
| return jwt.sign(payload, 'ovoJeSecret', jwtSignOptions) | |||
| } | |||
| tokenSchema.statics.destroyToken = async function(token) { | |||
| const findUser = await User.findOne({ 'tokens.token': token }) | |||
| if(!findUser) { | |||
| return null | |||
| } | |||
| findUser.tokens = findUser.tokens.filter((currToken) => { | |||
| return currToken.token !== token | |||
| }) | |||
| await findUser.save() | |||
| return true | |||
| } | |||
| const Token = mongoose.model('Token', tokenSchema) | |||
| module.exports = Token | |||
| @@ -1,8 +1,41 @@ | |||
| const validator = require('validator') | |||
| const mongoose = require('mongoose') | |||
| const bcrypt = require('bcryptjs') | |||
| const jwt = require('jsonwebtoken') | |||
| const ejwt = require('express-jwt') | |||
| const User = mongoose.model('User', { | |||
| const userSchema = new mongoose.Schema({ | |||
| name: { | |||
| type: String | |||
| }, | |||
| email: { | |||
| type: String, | |||
| required: true | |||
| }, | |||
| password: { | |||
| type: String, | |||
| required: true | |||
| }, | |||
| tokens: [{ | |||
| token: { | |||
| type: String, | |||
| required: true | |||
| } | |||
| }] | |||
| }) | |||
| // userSchema.pre('save', async function(next) { | |||
| // const user = this | |||
| // console.log('pre hash: ' + user.password) | |||
| // user.password = await bcrypt.hash(user.password, 8) | |||
| // console.log('posle hash: ' + user.password) | |||
| // console.log('Middleware before password hash') | |||
| // next() | |||
| // }) | |||
| const User = mongoose.model('User', userSchema) | |||
| module.exports = User | |||
| @@ -0,0 +1,19 @@ | |||
| const express = require('express') | |||
| const Token = require('../models/token') | |||
| const User = require('../models/user') | |||
| const jwt = require('jsonwebtoken') | |||
| const bcrypt = require('bcryptjs') | |||
| const router = new express.Router() | |||
| const auth = require('../middleware/auth') | |||
| const endpoints = require('../endpoints/token') | |||
| router.post('/login', async (req, res) => { | |||
| return await endpoints.loginUser(req, res) | |||
| }) | |||
| router.post('/logout/', async (req, res) => { | |||
| return await endpoints.logout(req, res) | |||
| }) | |||
| module.exports = router | |||
| @@ -3,6 +3,7 @@ const User = require('../models/user') | |||
| const endpoints = require('../endpoints/user') | |||
| const router = new express.Router() | |||
| const app = express() | |||
| const auth = require('../middleware/auth') | |||
| router.get('/users', async (req, res) => { | |||
| return await endpoints.getAll(req, res) | |||
| @@ -3,11 +3,13 @@ const app = express() | |||
| const path = require('path') | |||
| const port = process.env.PORT || 3000 | |||
| require('./database/mongoose') | |||
| const userRouter = require('./routers/user') | |||
| const userRouter = require('./routes/user') | |||
| const tokenRouter = require('./routes/token') | |||
| //const viewsPath = path.join(__dirname, '../templates/views') | |||
| app.use(express.json()) | |||
| app.use(userRouter) | |||
| app.use(tokenRouter) | |||
| app.get('/', (req, res) => { | |||
| try { | |||