.
This commit is contained in:
parent
1f6d27f220
commit
a28814a420
@ -9,7 +9,7 @@ module.exports = {
|
|||||||
|
|
||||||
session: {
|
session: {
|
||||||
secret_token: process.env.SECRET_TOKEN || "B57J=7B`NQ$y98|~5;hc715bo09^5oz8NR+]n9r~215B91Nd9P%25_N6r!GHcOKp|18y5-73Dr5^@9k7n]5l<-41D1o",
|
secret_token: process.env.SECRET_TOKEN || "B57J=7B`NQ$y98|~5;hc715bo09^5oz8NR+]n9r~215B91Nd9P%25_N6r!GHcOKp|18y5-73Dr5^@9k7n]5l<-41D1o",
|
||||||
token_expires_in: 86400000
|
token_expires_in: '99d'
|
||||||
},
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ module.exports = {
|
|||||||
|
|
||||||
session: {
|
session: {
|
||||||
secret_token: process.env.SECRET_TOKEN || "B57J=7B`NQ$y98|~5;hc715bo09^5oz8NR+]n9r~215B91Nd9P%25_N6r!GHcOKp|18y5-73Dr5^@9k7n]5l<-41D1o",
|
secret_token: process.env.SECRET_TOKEN || "B57J=7B`NQ$y98|~5;hc715bo09^5oz8NR+]n9r~215B91Nd9P%25_N6r!GHcOKp|18y5-73Dr5^@9k7n]5l<-41D1o",
|
||||||
token_expires_in: 86400000
|
token_expires_in: '24h'
|
||||||
},
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
|
|||||||
@ -12,7 +12,7 @@ const passport = require('passport');
|
|||||||
|
|
||||||
const router = require('./router');
|
const router = require('./router');
|
||||||
const error = require('../middlewares/error');
|
const error = require('../middlewares/error');
|
||||||
const access = require('../middlewares/access');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Express instance
|
* Express instance
|
||||||
@ -42,12 +42,14 @@ app.use(methodOverride());
|
|||||||
// secure apps by setting various HTTP headers
|
// secure apps by setting various HTTP headers
|
||||||
app.use(helmet());
|
app.use(helmet());
|
||||||
|
|
||||||
|
|
||||||
// enable CORS - Cross Origin Resource Sharing
|
// enable CORS - Cross Origin Resource Sharing
|
||||||
app.use(cors({
|
app.use(cors({
|
||||||
exposeHeaders: [
|
exposeHeaders: [
|
||||||
"WWW-Authenticate",
|
"WWW-Authenticate",
|
||||||
"Server-Authorization"
|
"Server-Authorization",
|
||||||
|
"Content-Disposition",
|
||||||
|
"Content-Type",
|
||||||
|
"Content-Length"
|
||||||
],
|
],
|
||||||
maxAge: 31536000,
|
maxAge: 31536000,
|
||||||
credentials: true,
|
credentials: true,
|
||||||
@ -71,7 +73,7 @@ app.use(cors({
|
|||||||
|
|
||||||
// Access validator
|
// Access validator
|
||||||
app.use(passport.initialize());
|
app.use(passport.initialize());
|
||||||
passport.use('jwt', access.jwt);
|
require('./passport');
|
||||||
|
|
||||||
|
|
||||||
// Set routes
|
// Set routes
|
||||||
|
|||||||
@ -5,9 +5,7 @@ const Sequelize = require('sequelize');
|
|||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const log = require('./logger');
|
const log = require('./logger');
|
||||||
|
|
||||||
|
|
||||||
const modulesDir = path.resolve(__dirname + '/../modules/')
|
const modulesDir = path.resolve(__dirname + '/../modules/')
|
||||||
const basename = path.basename(__dirname);
|
|
||||||
const globOptions = {
|
const globOptions = {
|
||||||
cwd: modulesDir,
|
cwd: modulesDir,
|
||||||
nocase: true,
|
nocase: true,
|
||||||
|
|||||||
63
core/passport.js
Normal file
63
core/passport.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
const passport = require('passport');
|
||||||
|
const { Strategy: LocalStrategy } = require('passport-local');
|
||||||
|
const { Strategy: JWTStrategy} = require('passport-jwt');
|
||||||
|
|
||||||
|
const config = require('../config');
|
||||||
|
const models = require('./models');
|
||||||
|
const securityHelper = require('../helpers/security.helper');
|
||||||
|
|
||||||
|
|
||||||
|
passport.serializeUser((user, done) => {
|
||||||
|
done(null, user.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
passport.deserializeUser((id, done) => {
|
||||||
|
models.User.findById(id, (err, user) => {
|
||||||
|
done(err, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign in using Email and Password.
|
||||||
|
*/
|
||||||
|
const localOptions = {
|
||||||
|
usernameField: 'email',
|
||||||
|
passwordField: 'password'
|
||||||
|
}
|
||||||
|
|
||||||
|
passport.use('local', new LocalStrategy(localOptions, async (email, password, done) => {
|
||||||
|
try {
|
||||||
|
const user = await models.User.findOne({ where: { email } });
|
||||||
|
|
||||||
|
if (_.isNull(user)) {
|
||||||
|
return done(null, false, { message: 'User not found' })
|
||||||
|
} else {
|
||||||
|
const isPasswordValid = await user.comparePassword(password);
|
||||||
|
|
||||||
|
if (!isPasswordValid) {
|
||||||
|
return done(null, false, { message: 'Wrong Password' })
|
||||||
|
} else {
|
||||||
|
return done(null, user, { message: 'Logged in Successfully' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return done(error);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// JWT
|
||||||
|
passport.use('jwt', new JWTStrategy(securityHelper.jwtOptions, async (jwtPayload, done) => {
|
||||||
|
try {
|
||||||
|
const user = await models.User.findOne({ where: { id: jwtPayload.id } });
|
||||||
|
|
||||||
|
if (_.isNull(user)) {
|
||||||
|
return done(null, false, { message: 'User not found' })
|
||||||
|
} else {
|
||||||
|
return done(null, user, { message: 'User found' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return done(error);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
55
helpers/controller.helper.js
Normal file
55
helpers/controller.helper.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
|
const httpStatus = require('http-status');
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PRIVATE FUNCTIONS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function buildErrorLog(err) {
|
||||||
|
let errorLog;
|
||||||
|
if (_.isUndefined(err)) {
|
||||||
|
errorLog = 'Error not defined';
|
||||||
|
} else if (!_.isUndefined(err.message)) {
|
||||||
|
errorLog = err.message;
|
||||||
|
} else if (!_.isUndefined(err.stack)) {
|
||||||
|
errorLog = err.stack;
|
||||||
|
} else {
|
||||||
|
errorLog = JSON.stringify(err);
|
||||||
|
}
|
||||||
|
return errorLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildErrorResponse(nameController, nameMethod, error) {
|
||||||
|
|
||||||
|
const errorDescription = buildErrorLog(error);
|
||||||
|
|
||||||
|
const jsonResultFailed = {
|
||||||
|
code: httpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
message: 'Internal Server Error',
|
||||||
|
description: `Internal Application Error in ${nameController}:${nameMethod}. ${errorDescription}`
|
||||||
|
}
|
||||||
|
return jsonResultFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC FUNCTIONS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function handleErrorResponse(controllerName, methodName, error, res) {
|
||||||
|
|
||||||
|
const jsonResultFailed = buildErrorResponse(controllerName, methodName, error);
|
||||||
|
res.status(httpStatus.INTERNAL_SERVER_ERROR).send(jsonResultFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MODULE EXPORTS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
handleErrorResponse,
|
||||||
|
// for testing
|
||||||
|
buildErrorLog,
|
||||||
|
buildErrorResponse
|
||||||
|
};
|
||||||
37
helpers/message.helper.js
Normal file
37
helpers/message.helper.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CONSTANTS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const TITLE_ERROR = 'error';
|
||||||
|
const TITLE_MESSAGE = 'message';
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PRIVATE FUNCTIONS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function buildGenericMessage(nameMessage, textMessage) {
|
||||||
|
const jsonMessageResult = {};
|
||||||
|
jsonMessageResult[nameMessage] = textMessage;
|
||||||
|
return jsonMessageResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC FUNCTIONS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function buildErrorMessage(text) {
|
||||||
|
return buildGenericMessage(TITLE_ERROR, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildMessage(text) {
|
||||||
|
return buildGenericMessage(TITLE_MESSAGE, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
buildErrorMessage,
|
||||||
|
buildMessage,
|
||||||
|
//For testing
|
||||||
|
buildGenericMessage
|
||||||
|
}
|
||||||
111
helpers/security.helper.js
Normal file
111
helpers/security.helper.js
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const jwt = require('jsonwebtoken');
|
||||||
|
const bCrypt = require('bcrypt');
|
||||||
|
const config = require('../config');
|
||||||
|
|
||||||
|
const privateKEY = fs.readFileSync(path.join(__dirname, '..', 'private.key'), 'utf8');
|
||||||
|
const publicKEY = fs.readFileSync(path.join(__dirname, '..', 'public.key'), 'utf8');
|
||||||
|
|
||||||
|
const signOptions = {
|
||||||
|
issuer: 'Fundación LQDVI',
|
||||||
|
subject: 'info@loquedeverdadimporta.org',
|
||||||
|
audience: 'htts://www.loquedeverdadimporta.org',
|
||||||
|
};
|
||||||
|
|
||||||
|
const _genSalt = (rounds = 10) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
bCrypt.genSalt(rounds, function (err, salt) {
|
||||||
|
if (err) return reject(err);
|
||||||
|
return resolve(salt);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const _hashPassword = (password, salt) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
bCrypt.hash(password, salt, function (err, hash) {
|
||||||
|
if (err) return reject(err);
|
||||||
|
return resolve(hash);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// https://medium.com/@siddharthac6/json-web-token-jwt-the-right-way-of-implementing-with-node-js-65b8915d550e
|
||||||
|
|
||||||
|
const _sign = (payload, options) => {
|
||||||
|
/*
|
||||||
|
options = {
|
||||||
|
issuer: "Authorizaxtion/Resource/This server",
|
||||||
|
subject: "iam@user.me",
|
||||||
|
audience: "Client_Identity" // this should be provided by client
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Token signing options
|
||||||
|
const signOptions = {
|
||||||
|
issuer: options.issuer,
|
||||||
|
subject: options.subject,
|
||||||
|
audience: options.audience,
|
||||||
|
expiresIn: config.session.token_expires_in,
|
||||||
|
algorithm: "RS256"
|
||||||
|
};
|
||||||
|
|
||||||
|
return jwt.sign(payload, privateKEY, signOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
const _verify = (token, options) => {
|
||||||
|
/*
|
||||||
|
options = {
|
||||||
|
issuer: "Authorization/Resource/This server",
|
||||||
|
subject: "iam@user.me",
|
||||||
|
audience: "Client_Identity" // this should be provided by client
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const verifyOptions = {
|
||||||
|
issuer: options.issuer,
|
||||||
|
subject: options.subject,
|
||||||
|
audience: options.audience,
|
||||||
|
expiresIn: config.session.token_expires_in,
|
||||||
|
algorithm: ["RS256"]
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return jwt.verify(token, publicKEY, verifyOptions);
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const _decode = (token) => {
|
||||||
|
//returns null if token is invalid
|
||||||
|
return jwt.decode(token, { complete: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
jwtOptions: {
|
||||||
|
jwtFromRequest: (req) => ((req && req.headers && req.headers['x-access-token']) ? req.headers['x-access-token'] : null),
|
||||||
|
secretOrKey: publicKEY,
|
||||||
|
...signOptions,
|
||||||
|
},
|
||||||
|
|
||||||
|
generateHashPassword: async (password) => {
|
||||||
|
const salt = await _genSalt();
|
||||||
|
return _hashPassword(password, salt)
|
||||||
|
},
|
||||||
|
|
||||||
|
isValidPassword: async (password, candidate) => {
|
||||||
|
return await bCrypt.compareSync(candidate, password);
|
||||||
|
},
|
||||||
|
|
||||||
|
generateToken: (payload) => {
|
||||||
|
return _sign(payload, signOptions);
|
||||||
|
},
|
||||||
|
|
||||||
|
verify: (token) => {
|
||||||
|
return _verify(token, signOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,26 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
const { logger } = require('../core');
|
|
||||||
|
|
||||||
const JwtStrategy = require('passport-jwt').Strategy;
|
|
||||||
const { ExtractJwt } = require('passport-jwt');
|
|
||||||
//const User = this.models.User;
|
|
||||||
|
|
||||||
const jwtOptions = {
|
|
||||||
secretOrKey: config.session.secret_token,
|
|
||||||
jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const jwt = async (payload, done) => {
|
|
||||||
logger.info(payload);
|
|
||||||
try {
|
|
||||||
//const user = await User.findById(payload.sub);
|
|
||||||
//if (user) return done(null, user);
|
|
||||||
return done(null, false);
|
|
||||||
} catch (error) {
|
|
||||||
return done(error, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.jwt = new JwtStrategy(jwtOptions, jwt);
|
|
||||||
29
middlewares/accessValidator.js
Normal file
29
middlewares/accessValidator.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const passportJWT = require("passport-jwt");
|
||||||
|
const JWTStrategy = passportJWT.Strategy;
|
||||||
|
const ExtractJWT = passportJWT.ExtractJwt;
|
||||||
|
const config = require('../config');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login Required middleware.
|
||||||
|
*/
|
||||||
|
exports.isAuthenticated = (req, res, next) => {
|
||||||
|
if (req.isAuthenticated()) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
res.redirect('/login');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorization Required middleware.
|
||||||
|
*/
|
||||||
|
exports.isAuthorized = (req, res, next) => {
|
||||||
|
const provider = req.path.split('/').slice(-1)[0];
|
||||||
|
const token = req.user.tokens.find(token => token.kind === provider);
|
||||||
|
if (token) {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
res.redirect(`/auth/${provider}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,9 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const httpStatus = require('http-status');
|
const httpStatus = require('http-status');
|
||||||
const expressValidation = require('express-validation');
|
|
||||||
const APIError = require('./APIError');
|
const APIError = require('./APIError');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error handler. Send stacktrace only during development
|
* Error handler. Send stacktrace only during development
|
||||||
* @public
|
* @public
|
||||||
@ -28,14 +28,7 @@ exports.handler = handler;
|
|||||||
exports.converter = (err, req, res, next) => {
|
exports.converter = (err, req, res, next) => {
|
||||||
let convertedError = err;
|
let convertedError = err;
|
||||||
|
|
||||||
if (err instanceof expressValidation.ValidationError) {
|
if (!(err instanceof APIError)) {
|
||||||
convertedError = new APIError({
|
|
||||||
message: 'Error de validación',
|
|
||||||
errors: err.errors,
|
|
||||||
status: err.status,
|
|
||||||
stack: err.stack,
|
|
||||||
});
|
|
||||||
} else if (!(err instanceof APIError)) {
|
|
||||||
convertedError = new APIError({
|
convertedError = new APIError({
|
||||||
message: err.message,
|
message: err.message,
|
||||||
status: err.status,
|
status: err.status,
|
||||||
|
|||||||
73
middlewares/schemaValidator.js
Normal file
73
middlewares/schemaValidator.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
const Joi = require('joi');
|
||||||
|
|
||||||
|
module.exports = (schema, useJoiError = false) => {
|
||||||
|
// useJoiError determines if we should respond with the base Joi error
|
||||||
|
// boolean: defaults to false
|
||||||
|
const _useJoiError = _.isBoolean(useJoiError) && useJoiError;
|
||||||
|
|
||||||
|
// enabled HTTP methods for request data validation
|
||||||
|
const _supportedMethods = ['post', 'put'];
|
||||||
|
|
||||||
|
// Joi validation options
|
||||||
|
const _validationOptions = {
|
||||||
|
abortEarly: false, // abort after the last validation error
|
||||||
|
allowUnknown: true, // allow unknown keys that will be ignored
|
||||||
|
stripUnknown: true // remove unknown keys from the validated data
|
||||||
|
};
|
||||||
|
|
||||||
|
// return the validation middleware
|
||||||
|
return (req, res, next) => {
|
||||||
|
|
||||||
|
const route = req.route.path;
|
||||||
|
const method = req.method.toLowerCase();
|
||||||
|
|
||||||
|
if (_.includes(_supportedMethods, method)) {
|
||||||
|
|
||||||
|
// get schema for the current route
|
||||||
|
const _schema = schema
|
||||||
|
|
||||||
|
if (_schema) {
|
||||||
|
console.log(req.body);
|
||||||
|
// Validate req.body using the schema and validation options
|
||||||
|
return Joi.validate(req.body, _schema, _validationOptions, (err, data) => {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
|
||||||
|
// Joi Error
|
||||||
|
const JoiError = {
|
||||||
|
status: 'failed',
|
||||||
|
error: {
|
||||||
|
original: err._object,
|
||||||
|
|
||||||
|
// fetch only message and type from each error
|
||||||
|
details: _.map(err.details, ({ message, type }) => ({
|
||||||
|
message: message.replace(/['"]/g, ''),
|
||||||
|
type
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Custom Error
|
||||||
|
const CustomError = {
|
||||||
|
status: 'failed',
|
||||||
|
error: 'Invalid request data. Please review request and try again.'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send back the JSON error response
|
||||||
|
res.status(422).json(_useJoiError ? JoiError : CustomError);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Replace req.body with the data after Joi validation
|
||||||
|
req.body = data;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
72
modules/auth/auth.controller.js
Normal file
72
modules/auth/auth.controller.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
|
const httpStatus = require('http-status');
|
||||||
|
const passport = require('passport');
|
||||||
|
const controllerHelper = require('../../helpers/controller.helper');
|
||||||
|
const messageHelper = require('../../helpers/message.helper');
|
||||||
|
const securityHelper = require('../../helpers/security.helper');
|
||||||
|
const authService = require('./auth.service');
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CONSTANTS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Module Name
|
||||||
|
const MODULE_NAME = '[auth.controller]';
|
||||||
|
|
||||||
|
// Error Messages
|
||||||
|
const NOT_FOUND = 'Videogame not found';
|
||||||
|
|
||||||
|
// Success Messages
|
||||||
|
const VG_CT_VIDEOGAME_DELETED_SUCCESSFULLY = 'Videogame deleted successfully';
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC METHODS
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
async function login(req, res, next) {
|
||||||
|
try {
|
||||||
|
passport.authenticate('local', { session: false }, async (error, user, info) => {
|
||||||
|
try {
|
||||||
|
if (!user) {
|
||||||
|
return res.status(httpStatus.NOT_FOUND).json(messageHelper.buildMessage(NOT_FOUND));
|
||||||
|
}
|
||||||
|
|
||||||
|
req.login(user, { session: false }, async (error) => {
|
||||||
|
if (error) {
|
||||||
|
return controllerHelper.handleErrorResponse(MODULE_NAME, login.name, error, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
//We don't want to store the sensitive information such as the
|
||||||
|
//user password in the token so we pick only the email and id
|
||||||
|
const data = {
|
||||||
|
id: user.id,
|
||||||
|
email: user.email
|
||||||
|
};
|
||||||
|
|
||||||
|
//Send back the token to the user
|
||||||
|
return res.json({
|
||||||
|
token: securityHelper.generateToken({ user: data }),
|
||||||
|
user: {
|
||||||
|
id: data.id,
|
||||||
|
email: data.email
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return next(error);
|
||||||
|
}
|
||||||
|
})(req, res, next);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
controllerHelper.handleErrorResponse(MODULE_NAME, login.name, error, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
login,
|
||||||
|
MODULE_NAME
|
||||||
|
}
|
||||||
35
modules/auth/auth.routes.js
Normal file
35
modules/auth/auth.routes.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const routes = require('express').Router();
|
||||||
|
const passport = require('passport');
|
||||||
|
const authController = require('./auth.controller');
|
||||||
|
const authValidation = require('./auth.validations');
|
||||||
|
const securityHelper = require('../../helpers/security.helper');
|
||||||
|
const SchemaValidator = require('../../middlewares/schemaValidator');
|
||||||
|
|
||||||
|
//const postService = require('./post.service')(models.Post);
|
||||||
|
//const postController = require('./post.controller')(postService);
|
||||||
|
|
||||||
|
//const { ModelHandler } = require('sequelize-handlers');
|
||||||
|
//const postHandler = new ModelHandler(models.Post);
|
||||||
|
|
||||||
|
routes.post('/auth',
|
||||||
|
SchemaValidator(authValidation.login, true),
|
||||||
|
passport.authenticate('local'),
|
||||||
|
function (req, res, next) {
|
||||||
|
const data = {
|
||||||
|
id: req.user.id,
|
||||||
|
email: req.user.email
|
||||||
|
};
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
token: securityHelper.generateToken(data),
|
||||||
|
user: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//authController.login
|
||||||
|
);
|
||||||
|
|
||||||
|
routes.get('/pepepe', passport.authenticate('jwt', { session: false }), function (req, res, next) {
|
||||||
|
res.send(req.user.email);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = routes;
|
||||||
17
modules/auth/auth.service.js
Normal file
17
modules/auth/auth.service.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
'use strict';
|
||||||
|
//const JwtHelper = require('../../helpers/jwt.helper');
|
||||||
|
const models = require('../../core/models');
|
||||||
|
|
||||||
|
function findOne(params) {
|
||||||
|
return models.User.findOne({
|
||||||
|
where: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
findOne,
|
||||||
|
login: async (params) => {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
15
modules/auth/auth.validations.js
Normal file
15
modules/auth/auth.validations.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const Joi = require('joi');
|
||||||
|
|
||||||
|
const LoginInputType = Joi.object().keys({
|
||||||
|
email: Joi.string().email().required(),
|
||||||
|
password: Joi.string().required()
|
||||||
|
});
|
||||||
|
|
||||||
|
const LoginOutputType = Joi.object().keys({
|
||||||
|
token: Joi.string().required()
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
login: LoginInputType,
|
||||||
|
};
|
||||||
60
modules/auth/user.model.js
Normal file
60
modules/auth/user.model.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { isValidPassword, generateHashPassword } = require('../../helpers/security.helper');
|
||||||
|
|
||||||
|
module.exports = function (sequelize, DataTypes) {
|
||||||
|
const User = sequelize.define('User', {
|
||||||
|
id: {
|
||||||
|
type: DataTypes.UUID,
|
||||||
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
unique: true,
|
||||||
|
validate: { isEmail: true }
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
tableName: 'user',
|
||||||
|
freezeTableName: true,
|
||||||
|
timestamps: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
User.associate = function (models) {
|
||||||
|
/*User.Categories = User.belongsToMany(models.Category, {
|
||||||
|
through: models.UserCategory,
|
||||||
|
foreignKey: 'UserId'
|
||||||
|
});*/
|
||||||
|
//User.Comments = User.hasMany(models.UserComment, { foreignKey: 'UserId' });
|
||||||
|
//User.Reactions = User.hasMany(models.UserReaction, { foreignKey: 'UserId' });
|
||||||
|
//User.User = User.belongsTo(models.User, { foreignKey: 'userId' });
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
User.beforeCreate(async function (model, options) {
|
||||||
|
const encrypted = await generateHashPassword(model.password)
|
||||||
|
model.password = encrypted;
|
||||||
|
return model;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Instance Methods
|
||||||
|
// InventoryLevel.prototype.someMethod = function () {...}
|
||||||
|
|
||||||
|
User.prototype.comparePassword = async function (candidatePassword) {
|
||||||
|
|
||||||
|
const user = this;
|
||||||
|
|
||||||
|
if (user.password) {
|
||||||
|
return await isValidPassword(user.password, candidatePassword)
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return User;
|
||||||
|
};
|
||||||
@ -1,16 +1,35 @@
|
|||||||
const routes = require('express').Router();
|
const routes = require('express').Router();
|
||||||
const models = require('../../core/models');
|
const models = require('../../core/models');
|
||||||
const postService = require('./post.service')(models.Post);
|
//const postService = require('./post.service')(models.Post);
|
||||||
const postController = require('./post.controller')(postService);
|
//const postController = require('./post.controller')(postService);
|
||||||
|
|
||||||
|
const { ModelHandler } = require('sequelize-handlers');
|
||||||
|
const postHandler = new ModelHandler(models.Post);
|
||||||
|
|
||||||
routes.use((req, res, next) => {
|
routes.use((req, res, next) => {
|
||||||
// here we can access the req.params object and make auth checks
|
// here we can access the req.params object and make auth checks
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
routes.get('/posts', function (req, res) {
|
routes.get('/posts', postHandler.query());
|
||||||
data = postController.find(req)
|
|
||||||
res.status(200).json(data);
|
/*routes.get('/posts', function (req, res) {
|
||||||
|
postController.find(req).then(data => {
|
||||||
|
console.log(data);
|
||||||
|
res.status(200).json(data);
|
||||||
|
})
|
||||||
|
});*/
|
||||||
|
|
||||||
|
routes.get('/posts/count', function (req, res) {
|
||||||
|
//res.status(200).json(postController.count(req));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
routes.get('/posts/:id', function (req, res) {
|
||||||
|
//res.status(200).json(postController.findOne(req));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = routes;
|
module.exports = routes;
|
||||||
@ -9,8 +9,6 @@ module.exports = function (sequelize, DataTypes) {
|
|||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
sort: {
|
sort: {
|
||||||
// Se cambia el nombre del campo de 'order' a 'sort' porque 'order' es una palabra reservada SQL y da problemas al generar las consultas SQL.
|
|
||||||
field: 'order', // <- Chapuza!! El nombre del campo en MySQL es una palabra reservada en SQL.
|
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
|||||||
@ -7,13 +7,6 @@ module.exports = function (sequelize, DataTypes) {
|
|||||||
defaultValue: DataTypes.UUIDV4,
|
defaultValue: DataTypes.UUIDV4,
|
||||||
primaryKey: true,
|
primaryKey: true,
|
||||||
},
|
},
|
||||||
/*userId: {
|
|
||||||
type: DataTypes.UUID,
|
|
||||||
allowNull: true,
|
|
||||||
primaryKey: false,
|
|
||||||
unique: false,
|
|
||||||
foreignKey: true
|
|
||||||
},*/
|
|
||||||
date: {
|
date: {
|
||||||
type: DataTypes.DATE,
|
type: DataTypes.DATE,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
@ -35,7 +28,6 @@ module.exports = function (sequelize, DataTypes) {
|
|||||||
tableName: 'post',
|
tableName: 'post',
|
||||||
freezeTableName: true,
|
freezeTableName: true,
|
||||||
timestamps: true,
|
timestamps: true,
|
||||||
updatedAt: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Post.associate = function (models) {
|
Post.associate = function (models) {
|
||||||
|
|||||||
@ -19,7 +19,7 @@ module.exports = function (Post) {
|
|||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fetchAll: (params) => {
|
fetchAll: async (params) => {
|
||||||
// Convert `params` object to filters compatible with Bookshelf.
|
// Convert `params` object to filters compatible with Bookshelf.
|
||||||
const filters = []; //strapi.utils.models.convertParams('post', params);
|
const filters = []; //strapi.utils.models.convertParams('post', params);
|
||||||
// Select field to populate.
|
// Select field to populate.
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"args-list": "^0.3.3",
|
"args-list": "^0.3.3",
|
||||||
"async": "^2.6.2",
|
"async": "^2.6.2",
|
||||||
|
"bcrypt": "^3.0.6",
|
||||||
"body-parser": "^1.18.3",
|
"body-parser": "^1.18.3",
|
||||||
"buffer": "^5.2.1",
|
"buffer": "^5.2.1",
|
||||||
"cheerio": "^1.0.0-rc.3",
|
"cheerio": "^1.0.0-rc.3",
|
||||||
@ -35,6 +36,7 @@
|
|||||||
"helmet": "^3.16.0",
|
"helmet": "^3.16.0",
|
||||||
"http": "^0.0.0",
|
"http": "^0.0.0",
|
||||||
"http-status": "^1.3.2",
|
"http-status": "^1.3.2",
|
||||||
|
"joi": "^14.3.1",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"method-override": "^3.0.0",
|
"method-override": "^3.0.0",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
@ -42,10 +44,12 @@
|
|||||||
"os": "^0.1.1",
|
"os": "^0.1.1",
|
||||||
"passport": "^0.4.0",
|
"passport": "^0.4.0",
|
||||||
"passport-jwt": "^4.0.0",
|
"passport-jwt": "^4.0.0",
|
||||||
|
"passport-local": "^1.0.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"pino": "^4.7.1",
|
"pino": "^4.7.1",
|
||||||
"response-time": "^2.3.2",
|
"response-time": "^2.3.2",
|
||||||
"sequelize": "^5.3.5",
|
"sequelize": "^5.3.5",
|
||||||
|
"sequelize-handlers": "^1.0.7",
|
||||||
"vm": "^0.1.0",
|
"vm": "^0.1.0",
|
||||||
"winston": "^3.2.1"
|
"winston": "^3.2.1"
|
||||||
}
|
}
|
||||||
|
|||||||
9
private.key
Normal file
9
private.key
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOQIBAAJBANHIOJ5cQCp97Je11BqiyOrPauRnc26mHFMEua3a35vdNxpkJnLi
|
||||||
|
2/3JxhBRDGj0buvmQDO3Pc2BbfoV1lJRwF8CAwEAAQJAU7skziBoBA3K1yreA9uh
|
||||||
|
cgdj1NJtwmZOu9wQ+JF52s2Ryrz+CS7R1NNNa39ujJgVdNv/DbS6RIVmaM1KN69j
|
||||||
|
gQIhAPARxNtaVhB1d7EVVd9DZqxcjbGoDfnQXULDy9TO4Go/AiEA37PwsP48KZYC
|
||||||
|
ybGDlSjG8+8utbb6q+Q/SdKk4AON4eECIC42vXachUTV2By2xrkb+H/lsUEp4Mbe
|
||||||
|
XZWkq3BkAr9xAiA6iv2/ZBlcjLyYChO0cmJ2ri6cMZGycF47tJufYG6+IQIgPEx/
|
||||||
|
Un8VU2psMTSmRDFp5f3l9Rx39BAghBf7CTqyWSk=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
4
public.key
Normal file
4
public.key
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANHIOJ5cQCp97Je11BqiyOrPauRnc26m
|
||||||
|
HFMEua3a35vdNxpkJnLi2/3JxhBRDGj0buvmQDO3Pc2BbfoV1lJRwF8CAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
73
yarn.lock
73
yarn.lock
@ -203,6 +203,14 @@ base@^0.11.1:
|
|||||||
mixin-deep "^1.2.0"
|
mixin-deep "^1.2.0"
|
||||||
pascalcase "^0.1.1"
|
pascalcase "^0.1.1"
|
||||||
|
|
||||||
|
bcrypt@^3.0.6:
|
||||||
|
version "3.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-3.0.6.tgz#f607846df62d27e60d5e795612c4f67d70206eb2"
|
||||||
|
integrity sha512-taA5bCTfXe7FUjKroKky9EXpdhkVvhE5owfxfLYodbrAR1Ul3juLmIQmIQBK4L9a5BuUcE6cqmwT+Da20lF9tg==
|
||||||
|
dependencies:
|
||||||
|
nan "2.13.2"
|
||||||
|
node-pre-gyp "0.12.0"
|
||||||
|
|
||||||
binary-extensions@^1.0.0:
|
binary-extensions@^1.0.0:
|
||||||
version "1.13.1"
|
version "1.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
|
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
|
||||||
@ -1414,6 +1422,11 @@ hide-powered-by@1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b"
|
resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b"
|
||||||
integrity sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys=
|
integrity sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys=
|
||||||
|
|
||||||
|
hoek@6.x.x:
|
||||||
|
version "6.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/hoek/-/hoek-6.1.3.tgz#73b7d33952e01fe27a38b0457294b79dd8da242c"
|
||||||
|
integrity sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==
|
||||||
|
|
||||||
hpkp@2.0.0:
|
hpkp@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672"
|
resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672"
|
||||||
@ -1749,6 +1762,13 @@ isarray@1.0.0, isarray@~1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||||
|
|
||||||
|
isemail@3.x.x:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c"
|
||||||
|
integrity sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==
|
||||||
|
dependencies:
|
||||||
|
punycode "2.x.x"
|
||||||
|
|
||||||
isexe@^2.0.0:
|
isexe@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||||
@ -1766,6 +1786,15 @@ isobject@^3.0.0, isobject@^3.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||||
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
||||||
|
|
||||||
|
joi@^14.3.1:
|
||||||
|
version "14.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/joi/-/joi-14.3.1.tgz#164a262ec0b855466e0c35eea2a885ae8b6c703c"
|
||||||
|
integrity sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==
|
||||||
|
dependencies:
|
||||||
|
hoek "6.x.x"
|
||||||
|
isemail "3.x.x"
|
||||||
|
topo "3.x.x"
|
||||||
|
|
||||||
js-tokens@^3.0.2:
|
js-tokens@^3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
||||||
@ -2103,7 +2132,7 @@ mute-stream@0.0.7:
|
|||||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
||||||
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
|
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
|
||||||
|
|
||||||
nan@^2.9.2:
|
nan@2.13.2, nan@^2.9.2:
|
||||||
version "2.13.2"
|
version "2.13.2"
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
|
||||||
integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
|
integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
|
||||||
@ -2154,6 +2183,22 @@ node-fetch@^2.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5"
|
||||||
integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==
|
integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==
|
||||||
|
|
||||||
|
node-pre-gyp@0.12.0:
|
||||||
|
version "0.12.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
|
||||||
|
integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
|
||||||
|
dependencies:
|
||||||
|
detect-libc "^1.0.2"
|
||||||
|
mkdirp "^0.5.1"
|
||||||
|
needle "^2.2.1"
|
||||||
|
nopt "^4.0.1"
|
||||||
|
npm-packlist "^1.1.6"
|
||||||
|
npmlog "^4.0.2"
|
||||||
|
rc "^1.2.7"
|
||||||
|
rimraf "^2.6.1"
|
||||||
|
semver "^5.3.0"
|
||||||
|
tar "^4"
|
||||||
|
|
||||||
node-pre-gyp@^0.10.0:
|
node-pre-gyp@^0.10.0:
|
||||||
version "0.10.3"
|
version "0.10.3"
|
||||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
|
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
|
||||||
@ -2389,6 +2434,13 @@ passport-jwt@^4.0.0:
|
|||||||
jsonwebtoken "^8.2.0"
|
jsonwebtoken "^8.2.0"
|
||||||
passport-strategy "^1.0.0"
|
passport-strategy "^1.0.0"
|
||||||
|
|
||||||
|
passport-local@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee"
|
||||||
|
integrity sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=
|
||||||
|
dependencies:
|
||||||
|
passport-strategy "1.x.x"
|
||||||
|
|
||||||
passport-strategy@1.x.x, passport-strategy@^1.0.0:
|
passport-strategy@1.x.x, passport-strategy@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
|
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
|
||||||
@ -2530,6 +2582,11 @@ pump@^3.0.0:
|
|||||||
end-of-stream "^1.1.0"
|
end-of-stream "^1.1.0"
|
||||||
once "^1.3.1"
|
once "^1.3.1"
|
||||||
|
|
||||||
|
punycode@2.x.x:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||||
|
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||||
|
|
||||||
qs@6.5.2:
|
qs@6.5.2:
|
||||||
version "6.5.2"
|
version "6.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||||
@ -2771,6 +2828,13 @@ send@0.16.2:
|
|||||||
range-parser "~1.2.0"
|
range-parser "~1.2.0"
|
||||||
statuses "~1.4.0"
|
statuses "~1.4.0"
|
||||||
|
|
||||||
|
sequelize-handlers@^1.0.7:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/sequelize-handlers/-/sequelize-handlers-1.0.7.tgz#1ef1d81447bdcd608ae42f5855d7fc2d978bf57a"
|
||||||
|
integrity sha512-fyNPYLSF03mRwy/gyJJOxH7fN3R6os5Ptsj18Gezfpt/T6mLFwOvxHp+dWd6O1KDNBr0JZi4kIj8FuDq55upbw==
|
||||||
|
dependencies:
|
||||||
|
lodash "^4.17.11"
|
||||||
|
|
||||||
sequelize-pool@^1.0.2:
|
sequelize-pool@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-1.0.2.tgz#89c767882bbdb8a41dac66922ed9820939a5401e"
|
resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-1.0.2.tgz#89c767882bbdb8a41dac66922ed9820939a5401e"
|
||||||
@ -3127,6 +3191,13 @@ to-regex@^3.0.1, to-regex@^3.0.2:
|
|||||||
regex-not "^1.0.2"
|
regex-not "^1.0.2"
|
||||||
safe-regex "^1.1.0"
|
safe-regex "^1.1.0"
|
||||||
|
|
||||||
|
topo@3.x.x:
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/topo/-/topo-3.0.3.tgz#d5a67fb2e69307ebeeb08402ec2a2a6f5f7ad95c"
|
||||||
|
integrity sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==
|
||||||
|
dependencies:
|
||||||
|
hoek "6.x.x"
|
||||||
|
|
||||||
toposort-class@^1.0.1:
|
toposort-class@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988"
|
resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user