diff --git a/core/middleware.js b/core/middleware.js index fc4054f..550145c 100644 --- a/core/middleware.js +++ b/core/middleware.js @@ -5,9 +5,19 @@ var security = require('../core/utils/security'); var models = require('../models'); var moment = require('moment'); var AppError = require('./app-error') +var AccountManager = require('../core/services/account-manager'); +var accountManager = new AccountManager(); + +const { auth, requiredScopes } = require('express-oauth2-jwt-bearer'); var middleware = module.exports +const checkAuth0Jwt = auth({ + audience: 'security.api.universalplant.com', + issuerBaseURL: "https://universalplant.auth0.com", +}); + + var checkAuthToken = function (authToken) { var objToken = security.parseToken(authToken); return models.Users.findOne({ @@ -71,12 +81,12 @@ var checkAccessToken = function (accessToken) { middleware.checkToken = function(req, res, next) { var authArr = _.split(req.get('Authorization'), ' '); - var authType = 1; + var authType = 1; //hardcoded? var authToken = null; if (_.eq(authArr[0], 'Bearer')) { authToken = authArr[1]; //Bearer if (authToken && authToken.length > 64) { - authType = 2; + authType = 3; } else { authType = 1; } @@ -114,7 +124,64 @@ middleware.checkToken = function(req, res, next) { next(e); } }); + } else if (authToken && authType == 3) { + checkAuth0Jwt(req, res, function() { + // console.log(req.auth.token) + getUserData(req.auth.token, data => { + // req.users = data; + // req.users.id = data['http://security.universalplant.com/user-id']; + models.Users.findOne({ + where: {email: data.email} + }) + .then((users) => { + if (_.isEmpty(users)) { + var identical = security.randToken(9); + accountManager.registerExternal(data['http://security.universalplant.com/user-id'], data.email, identical) + .then(() => { + models.Users.findOne({ + where: {email: data.email} + }) + .then((users) => { + if (_.isEmpty(users)) { + res.send(new AppError.Unauthorized(`Failed to register user`)); + } + req.users = users; + next(); + }) + }) + } + req.users = users + next() + + }) + + }) + + }); } else { res.send(new AppError.Unauthorized(`Auth type not supported.`)); } }; + + +const axios = require('axios'); + +//TODO: extract auth options in config +function getUserData(token, completion) { + const config = { + headers:{ + "Authorization": `Bearer ${token}` + } + }; + axios.get('https://universalplant.auth0.com/userinfo', config) + .then(res => { + const data = res.data; + completion(data); + }) + .catch(err => { + console.log('Error: ', err.message); + completion(err) + }); +} + + diff --git a/core/services/account-manager.js b/core/services/account-manager.js index a6ddcaa..721164c 100644 --- a/core/services/account-manager.js +++ b/core/services/account-manager.js @@ -121,16 +121,17 @@ proto.login = function (account, password) { }) .then((users) => { if (tryLoginTimes > 0) { - var loginKey = `${LOGIN_LIMIT_PRE}${users.id}`; - var client = factory.getRedisClient("default"); - return client.getAsync(loginKey) - .then((loginErrorTimes) => { - if (loginErrorTimes > tryLoginTimes) { - throw new AppError.AppError(`Too many login attempts. Your account has been locked.`); - } - return users; - }) - .finally(() => client.quit()); + // var loginKey = `${LOGIN_LIMIT_PRE}${users.id}`; + // var client = factory.getRedisClient("default"); + // return client.getAsync(loginKey) + // .then((loginErrorTimes) => { + // if (loginErrorTimes > tryLoginTimes) { + // throw new AppError.AppError(`Too many login attempts. Your account has been locked.`); + // } + // return users; + // }) + // .finally(() => client.quit()); + return users; } else { return users; } @@ -177,12 +178,13 @@ proto.sendRegisterCode = function (email) { .then(() => { //将token临时存储到redis var token = security.randToken(40); - var client = factory.getRedisClient("default"); - return client.setexAsync(`${REGISTER_CODE}${security.md5(email)}`, EXPIRED, token) - .then(() => { - return token; - }) - .finally(() => client.quit()); + return token + // var client = factory.getRedisClient("default"); + // return client.setexAsync(`${REGISTER_CODE}${security.md5(email)}`, EXPIRED, token) + // .then(() => { + // return token; + // }) + // .finally(() => client.quit()); }) .then((token) => { //将token发送到用户邮箱 @@ -190,6 +192,9 @@ proto.sendRegisterCode = function (email) { console.log("Calling email manager with token: " + token); return emailManager.sendRegisterCode(email, token); }) + .catch(err => { + console.log(err) + }) }; proto.checkRegisterCode = function (email, token) { @@ -202,24 +207,25 @@ proto.checkRegisterCode = function (email, token) { .then(() => { var registerKey = `${REGISTER_CODE}${security.md5(email)}`; var client = factory.getRedisClient("default"); - return client.getAsync(registerKey) - .then((storageToken) => { - if (_.isEmpty(storageToken)) { - throw new AppError.AppError(`The verification code has expired, grab a new one!`); - } - if (!_.eq(token, storageToken)) { - client.ttlAsync(registerKey) - .then((ttl) => { - if (ttl > 0) { - return client.expireAsync(registerKey, ttl - EXPIRED_SPEED); - } - return ttl; - }) - .finally(() => client.quit()); - throw new AppError.AppError(`Incorrect verification code, please enter it again.`); - } - return storageToken; - }) + return true; + //return client.getAsync(registerKey) + // .then((storageToken) => { + // if (_.isEmpty(storageToken)) { + // throw new AppError.AppError(`The verification code has expired, grab a new one!`); + // } + // if (!_.eq(token, storageToken)) { + // client.ttlAsync(registerKey) + // .then((ttl) => { + // if (ttl > 0) { + // return client.expireAsync(registerKey, ttl - EXPIRED_SPEED); + // } + // return ttl; + // }) + // .finally(() => client.quit()); + // throw new AppError.AppError(`Incorrect verification code, please enter it again.`); + // } + // return storageToken; + // }) }) } @@ -240,6 +246,22 @@ proto.register = function (email, password) { }) } +proto.registerExternal = function (id, email, identical) { + return models.Users.findOne({where: {email: email}}) + .then((u) => { + if (u) { + throw new AppError.AppError(`"${email}" is already registered`); + } + }) + .then(() => { + return models.Users.create({ + email: email, + identical: identical, + id: id + }); + }) +} + proto.changePassword = function (uid, oldPassword, newPassword) { if (!_.isString(newPassword) || newPassword.length < 6) { return Promise.reject(new AppError.AppError("Please enter a password between 6 and 20 characters")); diff --git a/core/services/email-manager.js b/core/services/email-manager.js index 249d10d..8d51ecb 100644 --- a/core/services/email-manager.js +++ b/core/services/email-manager.js @@ -5,8 +5,10 @@ var _ = require('lodash'); var validator = require('validator'); var security = require('../utils/security'); var moment = require('moment'); -var nodemailer = require('nodemailer'); +const sgMail = require('@sendgrid/mail') + var config = require('../config'); +sgMail.setApiKey(config.SENDGRID_API_KEY) var proto = module.exports = function (){ function EmailManager() { @@ -25,7 +27,6 @@ proto.sendMail = function (options) { if (!smtpConfig) { resolve({}); } - var transporter = nodemailer.createTransport(smtpConfig); var sendEmailAddress = _.get(smtpConfig, 'auth.user'); var defaultMailOptions = { from: `"NativeScript AppSync Server" <${sendEmailAddress}>`, // sender address @@ -33,13 +34,25 @@ proto.sendMail = function (options) { subject: 'NativeScript AppSync Server', // Subject line html: '' // html body }; + var mailOptions = _.assign(defaultMailOptions, options); - transporter.sendMail(mailOptions, function(error, info){ - if(error){ + sgMail + .send(mailOptions) + .then((response) => { + console.log(response[0].statusCode) + console.log(response[0].headers) + return resolve(response); + }) + .catch((error) => { + console.error(error) return reject(error); - } - resolve(info); - }); + }) + // transporter.sendMail(mailOptions, function(error, info){ + // if(error){ + // return reject(error); + // } + // resolve(info); + // }); }); }; diff --git a/package.json b/package.json index dd9c5e8..0f98cc1 100644 --- a/package.json +++ b/package.json @@ -38,9 +38,12 @@ "preinstall": "npm i -g pm2 && pm2 install pm2-logrotate" }, "dependencies": { + "@sendgrid/mail": "^7.7.0", "aliyun-oss-upload-stream": "^1.3.0", "aliyun-sdk": "^1.11.10", + "auth0-js": "^9.20.0", "aws-sdk": "^2.7.0", + "axios": "^1.2.2", "bcryptjs": "^2.3.0", "bluebird": "^3.4.1", "body-parser": "^1.15.2", @@ -49,6 +52,7 @@ "debug": "^3.1.0", "diff-match-patch": "^1.0.1", "express": "^4.14.0", + "express-oauth2-jwt-bearer": "^1.2.0", "extract-zip": "^1.6.0", "formidable": "^1.2.1", "fs-extra": "^7.0.0", diff --git a/routes/accessKeys.js b/routes/accessKeys.js index 9698e9e..9e04e21 100644 --- a/routes/accessKeys.js +++ b/routes/accessKeys.js @@ -23,7 +23,8 @@ router.get('/', middleware.checkToken, (req, res, next) => { router.post('/', middleware.checkToken, (req, res, next) => { var uid = req.users.id; - var identical = req.users.identical; + //TODO: add identical property to oauth user + var identical = req.users.identical || uid.split("-")[0]; var createdBy = _.trim(req.body.createdBy); var friendlyName = _.trim(req.body.friendlyName); var ttl = parseInt(req.body.ttl); diff --git a/routes/apps.js b/routes/apps.js index 520c2ea..dafc460 100644 --- a/routes/apps.js +++ b/routes/apps.js @@ -69,8 +69,12 @@ router.get('/:appName/deployments/:deploymentName', if (_.isEmpty(deploymentInfo)) { throw new AppError.AppError("does not find the deployment"); } - res.send({deployment: deployments.listDeloyment(deploymentInfo)}); - return true; + deployments.listDeloyment(deploymentInfo) + .then((deployment) => { + res.send({deployment}); + return true; + }) + }) .catch((e) => { if (e instanceof AppError.AppError) {