Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ import dotenv from 'dotenv';

dotenv.config();

export const env = {
API_URI_PREFIX: '/api',
JWT_SECRET: 'e18a33b0-9866-4867-800a-d6ffcd8f1cbd',
TOKEN_LIFETIME: 1,
MONGODB_CONNECTION: 'mongodb://localhost/recetar'
};

export const httpCodes = {
UNAUTHORIZED: 401,
FORBIDDEN: 403,
Expand All @@ -19,4 +12,4 @@ export const httpCodes = {
INTERNAL_SERVER_ERROR: 500,
OK: 200,
NOT_FOUND: 404,
};
};
13 changes: 7 additions & 6 deletions src/controllers/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Request, Response } from 'express';
import * as JWT from 'jsonwebtoken';
import { env, httpCodes } from '../config/config';
import { httpCodes } from '../config/config';
import { v4 as uuidv4 } from 'uuid';
import IUser from '../interfaces/user.interface';
import User from '../models/user.model';
Expand Down Expand Up @@ -309,8 +309,9 @@ class AuthController {
usrn: user.username,
bsname: user.businessName,
rl: roles,
iat: new Date().getTime()
}, (process.env.JWT_SECRET || env.JWT_SECRET), {
iat: moment().unix(),
exp: moment().add((process.env.TOKEN_LIFETIME || 12), 'hours').unix()
}, (process.env.JWT_SECRET || ''), {
algorithm: 'HS256'
});
return res.status(200).json({ jwt: token });
Expand All @@ -328,9 +329,9 @@ class AuthController {
usrn: username,
bsname: businessName,
rl: role,
iat: new Date().getTime(),
exp: new Date().setDate(new Date().getDate() + env.TOKEN_LIFETIME)
}, (process.env.JWT_SECRET || env.JWT_SECRET), {
iat: moment().unix(),
exp: moment().add((process.env.TOKEN_LIFETIME || 12), 'hours').unix()
}, (process.env.JWT_SECRET || ''), {
algorithm: 'HS256'
});
return token;
Expand Down
3 changes: 1 addition & 2 deletions src/database/dbconfig.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import mongoose from 'mongoose';
import { env } from '../config/config';

export const initializeMongo = async (): Promise<void> => {
const MONGO_URI = `${(process.env.MONGODB_URI || env.MONGODB_CONNECTION)}`;
const MONGO_URI = `${(process.env.MONGODB_URI)}`;
try {
await mongoose.connect(MONGO_URI, {
useNewUrlParser: true,
Expand Down
49 changes: 30 additions & 19 deletions src/middlewares/passport-config-andes.middleware.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,71 @@
import {Request, Response, NextFunction} from 'express';
import { Request, Response, NextFunction } from 'express';
import passport from 'passport';
import passportJwt from 'passport-jwt';
import { env, httpCodes } from '../config/config';
import { httpCodes } from '../config/config';
import User from '../models/user.model';
import IUser from '../interfaces/user.interface';

const JwtStrategy = passportJwt.Strategy;
const ExtractJwt = passportJwt.ExtractJwt;
const IAT_FUTURE_SKEW_SECONDS = 60;

// Config passport JWT strategy
// We will use Bearer token to authenticate
// This configuration checks:
// -token expiration
// -user exists
// -token iat is not in the future
passport.use(new JwtStrategy({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: (process.env.JWT_SECRET || env.JWT_SECRET)
}, async (payload, done: (err?: any, user?: IUser | boolean, info?: {code: number, message: string}) => any | Response) => {
try{
secretOrKey: (process.env.JWT_SECRET)
}, async (payload, done: (err?: any, user?: IUser | boolean, info?: { code: number; message: string }) => any | Response) => {
try {
// find the user specified in token
const user = await User.findOne({ _id: payload.sub }).select('_id');

// if user doesn't exists, handle it
if(!user){
return done(null, false, {code: httpCodes.EXPECTATION_FAILED, message: 'Debe iniciar sesión'});
if (!user) {
return done(null, false, { code: httpCodes.EXPECTATION_FAILED, message: 'Debe iniciar sesión' });
}
const nowUnix = Math.floor(Date.now() / 1000);
if (typeof payload.exp === 'number' && payload.exp < nowUnix) {
return done(null, false, { code: httpCodes.EXPIRED_TOKEN, message: 'El token ha expirado' });
}

if (typeof payload.iat === 'number' && payload.iat > nowUnix + IAT_FUTURE_SKEW_SECONDS) {
if (payload.sub) {
await User.updateOne({ _id: payload.sub }, { refreshToken: '' });
}
return done(null, false, { code: httpCodes.UNAUTHORIZED, message: 'Sesión inválida, debe volver a iniciar sesión' });
}

// otherwise, return the user
done(null, user);
}catch(err){
} catch (err) {
// eslint-disable-next-line no-console
console.log('in error');
done(err, false);
}
}));



const authenticationMiddleware = (req: Request, res: Response, next: NextFunction, authenticationType: string) => {
passport.authenticate(authenticationType, {session: false}, (err, user: IUser | boolean, info?: {code: number, message: string}): any | Response => {
try{
passport.authenticate(authenticationType, { session: false }, (err, user: IUser | boolean, info?: { code: number; message: string }): any | Response => {
try {

if (err) return next(err)
if (err) { return next(err); }

if(typeof(info) !== 'undefined') return res.status(info.code).json({message: info.message});
if (typeof (info) !== 'undefined') { return res.status(info.code).json({ message: info.message }); }

req.user = user;
next();
}catch(error){
if(error.code == 'ERR_HTTP_INVALID_STATUS_CODE') return res.status(httpCodes.EXPECTATION_FAILED).json({message: 'Debe iniciar sesión'});

return res.status(500).json('Server Error')
} catch (error) {
if (error.code === 'ERR_HTTP_INVALID_STATUS_CODE') {return res.status(httpCodes.EXPECTATION_FAILED).json({ message: 'Debe iniciar sesión' });}
return res.status(500).json('Server Error');
}
})(req, res, next);

};

export const checkAuthAndes = (req: Request, res: Response, next: NextFunction) => {
authenticationMiddleware(req, res, next, 'jwt');
}
};
66 changes: 38 additions & 28 deletions src/middlewares/passport-config.middleware.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,50 @@
import {Request, Response, NextFunction} from 'express';
import { Request, Response, NextFunction } from 'express';
import passport from 'passport';
import passportJwt from 'passport-jwt';
import passportLocal from 'passport-local';
import { env, httpCodes } from '../config/config';
import { httpCodes } from '../config/config';
import User from '../models/user.model';
import IUser from '../interfaces/user.interface';

const JwtStrategy = passportJwt.Strategy;
const LocalStrategy = passportLocal.Strategy;
const ExtractJwt = passportJwt.ExtractJwt;
const IAT_FUTURE_SKEW_SECONDS = 60;

// Config passport JWT strategy
// We will use Bearer token to authenticate
// This configuration checks:
// -token expiration
// -user exists
passport.use(new JwtStrategy({
passport.use('jwt', new JwtStrategy({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: (process.env.JWT_SECRET || env.JWT_SECRET)
}, async (payload, done: (err?: any, user?: IUser | boolean, info?: {code: number, message: string}) => any | Response) => {
try{
const expirationDate = new Date(payload.exp);
if(expirationDate < new Date()) {
return done(null, false, {code: httpCodes.EXPIRED_TOKEN, message: 'El token ha expirado'});
secretOrKey: (process.env.JWT_SECRET)
}, async (payload, done: (err?: any, user?: IUser | boolean, info?: { code: number; message: string }) => any | Response) => {
try {
const nowUnix = Math.floor(Date.now() / 1000);
if (typeof payload.exp === 'number' && payload.exp < nowUnix) {
return done(null, false, { code: httpCodes.EXPIRED_TOKEN, message: 'El token ha expirado' });
}

if (typeof payload.iat === 'number' && payload.iat > nowUnix + IAT_FUTURE_SKEW_SECONDS) {
if (payload.sub) {
await User.updateOne({ _id: payload.sub }, { refreshToken: '' });
}
return done(null, false, { code: httpCodes.UNAUTHORIZED, message: 'Sesión inválida, debe volver a iniciar sesión' });
}

// find the user specified in token
const user = await User.findOne({ _id: payload.sub }).select('_id');

// if user doesn't exists, handle it
if(!user){
return done(null, false, {code: httpCodes.EXPECTATION_FAILED, message: 'Debe iniciar sesión'});
if (!user) {
return done(null, false, { code: httpCodes.EXPECTATION_FAILED, message: 'Debe iniciar sesión' });
}

// otherwise, return the user
done(null, user);
}catch(err){
} catch (err) {
// eslint-disable-next-line no-console
console.log('in error');
done(err, false);
}
Expand All @@ -47,47 +57,47 @@ passport.use(new JwtStrategy({
passport.use(new LocalStrategy({
usernameField: 'identifier',
passwordField: 'password'
}, async (identifier, password, done: (err?: any, user?: IUser | boolean, info?: {code: number, message: string}) => any | Response ) => {
try{
}, async (identifier, password, done: (err?: any, user?: IUser | boolean, info?: { code: number; message: string }) => any | Response) => {
try {
// find the user given the identifier
let user = await User.findOne({ email: identifier });

// if not, handle it
if(!user){
if (!user) {
user = await User.findOne({ username: identifier });
if(!user){
return done(null, false, {code: httpCodes.UNAUTHORIZED, message: 'El usuario o contraseña que has ingresado es incorrecto. Por favor intenta de nuevo.'});
if (!user) {
return done(null, false, { code: httpCodes.UNAUTHORIZED, message: 'El usuario o contraseña que has ingresado es incorrecto. Por favor intenta de nuevo.' });
}
}

// check if the password is correct
const isMatch = await user.schema.methods.isValidPassword(user, password);

// if not, handle it
if(!isMatch){
return done(null, false, {code: httpCodes.UNAUTHORIZED, message: 'El usuario o contraseña que has ingresado es incorrecto. Por favor intenta de nuevo.'});
if (!isMatch) {
return done(null, false, { code: httpCodes.UNAUTHORIZED, message: 'El usuario o contraseña que has ingresado es incorrecto. Por favor intenta de nuevo.' });
}
// otherwise, return the user
done(null, user);
}catch(err){
} catch (err) {
done(err, false);
}
}));

const authenticationMiddleware = (req: Request, res: Response, next: NextFunction, authenticationType: string) => {
passport.authenticate(authenticationType, {session: false}, (err, user: IUser | boolean, info?: {code: number, message: string}): any | Response => {
try{
passport.authenticate(authenticationType, { session: false }, (err, user: IUser | boolean, info?: { code: number; message: string }): any | Response => {
try {

if (err) return next(err)
if (err) { return next(err); }

if(typeof(info) !== 'undefined') return res.status(info.code).json({message: info.message});
if (typeof (info) !== 'undefined') { return res.status(info.code).json({ message: info.message }); }

req.user = user;
next();
}catch(error){
if(error.code == 'ERR_HTTP_INVALID_STATUS_CODE') return res.status(httpCodes.EXPECTATION_FAILED).json({message: 'Debe iniciar sesión'});
} catch (error) {
if (error.code == 'ERR_HTTP_INVALID_STATUS_CODE') return res.status(httpCodes.EXPECTATION_FAILED).json({ message: 'Debe iniciar sesión' });

return res.status(500).json('Server Error')
return res.status(500).json({ message: 'Server Error' });
}
})(req, res, next);

Expand All @@ -100,4 +110,4 @@ export const passportMiddlewareLocal = (req: Request, res: Response, next: NextF

export const checkAuth = (req: Request, res: Response, next: NextFunction) => {
authenticationMiddleware(req, res, next, 'jwt');
}
};
6 changes: 2 additions & 4 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import compression from 'compression';
import { errorHandler } from './middlewares/error.middleware';
import { notFoundHandler } from './middlewares/notFound.middleware';
import * as db from './database/dbconfig';
// config
import { env } from './config/config';
// services

import routes from './routes/routes';
Expand Down Expand Up @@ -41,7 +39,7 @@ class Server {
}

routes() {
this.app.use(`${(process.env.API_URI_PRFIX || env.API_URI_PREFIX)}`, routes);
this.app.use(`${(process.env.API_URI_PREFIX)}`, routes);
}

async start() {
Expand All @@ -50,7 +48,7 @@ class Server {
// eslint-disable-next-line no-console
console.log(`🚀 API Server running on port ${this.app.get('port')}`);
// eslint-disable-next-line no-console
console.log(`📋 API disponible en: http://localhost:${this.app.get('port')}${env.API_URI_PREFIX}`);
console.log(`📋 API disponible en: http://localhost:${this.app.get('port')}${process.env.API_URI_PREFIX}`);
});
}

Expand Down
Loading