diff --git a/bin/db b/bin/db index 005b8810..b819e440 100755 --- a/bin/db +++ b/bin/db @@ -3,81 +3,96 @@ /** * Module dependencies. */ -var fs = require('fs'); -var path = require('path'); -var _ = require('lodash'); -var mysql = require('mysql2'); +var fs = require("fs"); +var path = require("path"); +var _ = require("lodash"); +var mysql = require("mysql2"); var Promise = require("bluebird"); -var common = require("../core/utils/common"); -var constConfig = require('../core/const'); -var yargs = require('yargs') - .usage('Usage: $0 [options]') - .command('init', '初始化数据库', { - dbpassword: { - alias: 'dbpassword', - type: 'string' - } +var constConfig = require("../core/const"); +var yargs = require("yargs") + .usage("Usage: $0 [options]") + .command("init", "初始化数据库", { + dbpassword: { + alias: "dbpassword", + type: "string", + }, }) - .command('upgrade', '升级数据库', { - dbpassword: { - alias: 'dbpassword', - type: 'string' - } + .command("upgrade", "升级数据库", { + dbpassword: { + alias: "dbpassword", + type: "string", + }, }) - .example('$0 init --dbname codepush --dbhost localhost --dbuser root --dbpassword 123456 --dbport 3306 --force', '初始化code-push-server数据库') - .example('$0 upgrade --dbname codepush --dbhost localhost --dbuser root --dbpassword 123456 --dbport 3306', '升级code-push-server数据库') - .default({dbname: 'codepush', dbhost: 'localhost', dbuser: 'root', dbpassword: null}) - .help('h') - .alias('h', 'help'); + .example( + "$0 init --dbname codepush --dbhost localhost --dbuser root --dbpassword 123456 --dbport 3306 --force", + "初始化code-push-server数据库" + ) + .example( + "$0 upgrade --dbname codepush --dbhost localhost --dbuser root --dbpassword 123456 --dbport 3306", + "升级code-push-server数据库" + ) + .default({ + dbname: "codepush", + dbhost: "localhost", + dbuser: "root", + dbpassword: null, + }) + .help("h") + .alias("h", "help"); var argv = yargs.argv; var command = argv._[0]; -var dbname = argv.dbname ? argv.dbname : 'codepush'; -var dbhost = argv.dbhost ? argv.dbhost : 'localhost'; -var dbuser = argv.dbuser ? argv.dbuser : 'root'; +var dbname = argv.dbname ? argv.dbname : "codepush"; +var dbhost = argv.dbhost ? argv.dbhost : "localhost"; +var dbuser = argv.dbuser ? argv.dbuser : "root"; var dbport = argv.dbport ? argv.dbport : 3306; var dbpassword = argv.dbpassword; -if (command === 'init') { +if (command === "init") { var connection2; var connection = mysql.createConnection({ host: dbhost, user: dbuser, password: dbpassword, - port: dbport + port: dbport, }); - var createDatabaseSql = argv.force ? `CREATE DATABASE IF NOT EXISTS ${dbname}` : - `CREATE DATABASE ${dbname}`; + var createDatabaseSql = argv.force + ? `CREATE DATABASE IF NOT EXISTS ${dbname}` + : `CREATE DATABASE ${dbname}`; Promise.promisifyAll(connection); connection.connect(); - connection.queryAsync(createDatabaseSql) - .then(function(){ - connection2 = mysql.createConnection({ - host: dbhost, - user: dbuser, - password: dbpassword, - database: dbname, - multipleStatements: true, - port: dbport + connection + .queryAsync(createDatabaseSql) + .then(function () { + connection2 = mysql.createConnection({ + host: dbhost, + user: dbuser, + password: dbpassword, + database: dbname, + multipleStatements: true, + port: dbport, + }); + connection2.connect(); + Promise.promisifyAll(connection2); + return connection2; + }) + .then(function (connection2) { + var sql = fs.readFileSync( + path.resolve(__dirname, "../sql/codepush-all.sql"), + "utf-8" + ); + return connection2.queryAsync(sql); + }) + .then(function () { + console.log("success."); + }) + .catch(function (e) { + console.log(e); + }) + .finally(function () { + if (connection) connection.end(); + if (connection2) connection2.end(); }); - connection2.connect(); - Promise.promisifyAll(connection2); - return connection2; - }) - .then(function(connection2){ - var sql = fs.readFileSync(path.resolve(__dirname, '../sql/codepush-all.sql'), 'utf-8'); - return connection2.queryAsync(sql); - }) - .then(function(){ - console.log('success.'); - }) - .catch(function(e){ - console.log(e); - }) - .finally(function(){ - if(connection) connection.end(); - if(connection2) connection2.end() - }); -} else if (command == 'upgrade'){ +} else if (command == "upgrade") { try { var connection = mysql.createConnection({ host: dbhost, @@ -85,54 +100,86 @@ if (command === 'init') { password: dbpassword, database: dbname, multipleStatements: true, - port: dbport + port: dbport, }); Promise.promisifyAll(connection); - connection.connect() - } catch(e) { - console.error('connect mysql error, check params',e); + connection.connect(); + } catch (e) { + console.error("connect mysql error, check params", e); return; } - return Promise.coroutine(function*(val){ - var version_no = '0.0.1'; - var rs = yield connection.queryAsync('select `version` from `versions` where `type`=1 limit 1'); - version_no = _.get(rs,'0.version', '0.0.1'); + return Promise.coroutine(function* (val) { + var version_no = "0.0.1"; + var rs = yield connection.queryAsync( + "select `version` from `versions` where `type`=1 limit 1" + ); + version_no = _.get(rs, "0.version", "0.0.1"); if (version_no == constConfig.CURRENT_DB_VERSION) { - console.log('Everything up-to-date.'); + console.log("Everything up-to-date."); process.exit(0); } var allSqlFile = [ - {version:'0.2.14', 'path':path.resolve(__dirname, '../sql/codepush-v0.2.14-patch.sql')}, - {version:'0.2.15', 'path':path.resolve(__dirname, '../sql/codepush-v0.2.15-patch.sql')}, - {version:'0.3.0', 'path':path.resolve(__dirname, '../sql/codepush-v0.3.0-patch.sql')}, - {version:'0.4.0', 'path':path.resolve(__dirname, '../sql/codepush-v0.4.0-patch.sql')}, - {version:'0.5.0', 'path':path.resolve(__dirname, '../sql/codepush-v0.5.0-patch.sql')} + { + version: "0.2.14", + path: path.resolve( + __dirname, + "../sql/codepush-v0.2.14-patch.sql" + ), + }, + { + version: "0.2.15", + path: path.resolve( + __dirname, + "../sql/codepush-v0.2.15-patch.sql" + ), + }, + { + version: "0.3.0", + path: path.resolve( + __dirname, + "../sql/codepush-v0.3.0-patch.sql" + ), + }, + { + version: "0.4.0", + path: path.resolve( + __dirname, + "../sql/codepush-v0.4.0-patch.sql" + ), + }, + { + version: "0.5.0", + path: path.resolve( + __dirname, + "../sql/codepush-v0.5.0-patch.sql" + ), + }, ]; for (var i = 0; i < allSqlFile.length; i++) { - if(!_.gt(allSqlFile[i]['version'], version_no)) { + if (!_.gt(allSqlFile[i]["version"], version_no)) { continue; } try { - var sql = fs.readFileSync(allSqlFile[i]['path'], 'utf-8'); - console.log('exec sql file:' + allSqlFile[i]['path']); + var sql = fs.readFileSync(allSqlFile[i]["path"], "utf-8"); + console.log("exec sql file:" + allSqlFile[i]["path"]); yield connection.queryAsync(sql); - console.log('success exec sql file:' + allSqlFile[i]['path']); + console.log("success exec sql file:" + allSqlFile[i]["path"]); } catch (e) { - console.error('error exec sql file:' + allSqlFile[i]['path']); + console.error("error exec sql file:" + allSqlFile[i]["path"]); throw e; } } })() - .then(function(){ - console.log('Upgrade success.'); - }) - .catch(function(e){ - console.error(e); - }) - .finally(function(){ - if(connection) connection.end(); - }); + .then(function () { + console.log("Upgrade success."); + }) + .catch(function (e) { + console.error(e); + }) + .finally(function () { + if (connection) connection.end(); + }); } else { yargs.showHelp(); } diff --git a/core/middleware.js b/core/middleware.js index fc4054f2..848ced0e 100644 --- a/core/middleware.js +++ b/core/middleware.js @@ -1,119 +1,124 @@ -'use strict'; -var _ = require('lodash'); -var Promise = require('bluebird'); -var security = require('../core/utils/security'); -var models = require('../models'); -var moment = require('moment'); -var AppError = require('./app-error') +"use strict"; +var _ = require("lodash"); +var security = require("../core/utils/security"); +var models = require("../models"); +var moment = require("moment"); +var AppError = require("./app-error"); -var middleware = module.exports +var middleware = module.exports; var checkAuthToken = function (authToken) { var objToken = security.parseToken(authToken); return models.Users.findOne({ - where: {identical: objToken.identical} + where: { identical: objToken.identical }, }) - .then((users) => { - if (_.isEmpty(users)) { - throw new AppError.Unauthorized(); - } - var Sequelize = require('sequelize'); - return models.UserTokens.findOne({ - where: {tokens: authToken, uid: users.id, expires_at: { [Sequelize.Op.gt]: moment().format('YYYY-MM-DD HH:mm:ss') }} - }) - .then((tokenInfo) => { - if (_.isEmpty(tokenInfo)){ - throw new AppError.Unauthorized() + .then((users) => { + if (_.isEmpty(users)) { + throw new AppError.Unauthorized(); } - return users; + var Sequelize = require("sequelize"); + return models.UserTokens.findOne({ + where: { + tokens: authToken, + uid: users.id, + expires_at: { + [Sequelize.Op.gt]: moment().format("YYYY-MM-DD HH:mm:ss"), + }, + }, + }).then((tokenInfo) => { + if (_.isEmpty(tokenInfo)) { + throw new AppError.Unauthorized(); + } + return users; + }); }) - }).then((users) => { - return users; - }) -} + .then((users) => { + return users; + }); +}; var checkAccessToken = function (accessToken) { return new Promise((resolve, reject) => { if (_.isEmpty(accessToken)) { return reject(new AppError.Unauthorized()); } - var config = require('../core/config'); - var tokenSecret = _.get(config, 'jwt.tokenSecret'); - var jwt = require('jsonwebtoken'); + var config = require("../core/config"); + var tokenSecret = _.get(config, "jwt.tokenSecret"); + var jwt = require("jsonwebtoken"); try { var authData = jwt.verify(accessToken, tokenSecret); } catch (e) { return reject(new AppError.Unauthorized()); } - var uid = _.get(authData, 'uid', null); - var hash = _.get(authData, 'hash', null); + var uid = _.get(authData, "uid", null); + var hash = _.get(authData, "hash", null); if (parseInt(uid) > 0) { return models.Users.findOne({ - where: {id: uid} - }) - .then((users) => { - if (_.isEmpty(users)) { - throw new AppError.Unauthorized(); - } - if (!_.eq(hash, security.md5(users.get('ack_code')))){ - throw new AppError.Unauthorized(); - } - resolve(users); + where: { id: uid }, }) - .catch((e) => { - reject(e); - }); + .then((users) => { + if (_.isEmpty(users)) { + throw new AppError.Unauthorized(); + } + if (!_.eq(hash, security.md5(users.get("ack_code")))) { + throw new AppError.Unauthorized(); + } + resolve(users); + }) + .catch((e) => { + reject(e); + }); } else { reject(new AppError.Unauthorized()); } }); -} +}; -middleware.checkToken = function(req, res, next) { - var authArr = _.split(req.get('Authorization'), ' '); +middleware.checkToken = function (req, res, next) { + var authArr = _.split(req.get("Authorization"), " "); var authType = 1; var authToken = null; - if (_.eq(authArr[0], 'Bearer')) { + if (_.eq(authArr[0], "Bearer")) { authToken = authArr[1]; //Bearer if (authToken && authToken.length > 64) { authType = 2; } else { authType = 1; } - } else if(_.eq(authArr[0], 'Basic')) { + } else if (_.eq(authArr[0], "Basic")) { authType = 2; - var b = new Buffer(authArr[1], 'base64'); - var user = _.split(b.toString(), ':'); - authToken = _.get(user, '1'); + var b = new Buffer(authArr[1], "base64"); + var user = _.split(b.toString(), ":"); + authToken = _.get(user, "1"); } if (authToken && authType == 1) { checkAuthToken(authToken) - .then((users) => { - req.users = users; - next(); - return users; - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(e.status || 404).send(e.message); - } else { - next(e); - } - }); + .then((users) => { + req.users = users; + next(); + return users; + }) + .catch((e) => { + if (e instanceof AppError.AppError) { + res.status(e.status || 404).send(e.message); + } else { + next(e); + } + }); } else if (authToken && authType == 2) { checkAccessToken(authToken) - .then((users) => { - req.users = users; - next(); - return users; - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(e.status || 404).send(e.message); - } else { - next(e); - } - }); + .then((users) => { + req.users = users; + next(); + return users; + }) + .catch((e) => { + if (e instanceof AppError.AppError) { + res.status(e.status || 404).send(e.message); + } else { + next(e); + } + }); } else { res.send(new AppError.Unauthorized(`Auth type not supported.`)); } diff --git a/core/services/account-manager.js b/core/services/account-manager.js index 0eae4a9e..e8b6613c 100644 --- a/core/services/account-manager.js +++ b/core/services/account-manager.js @@ -1,45 +1,40 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var _ = require('lodash'); -var validator = require('validator'); -var security = require('../utils/security'); -var factory = require('../utils/factory'); -var moment = require('moment'); -var EmailManager = require('./email-manager'); -var config = require('../config'); -var AppError = require('../app-error'); -var log4js = require('log4js'); +"use strict"; +var models = require("../../models"); +var _ = require("lodash"); +var validator = require("validator"); +var security = require("../utils/security"); +var factory = require("../utils/factory"); +var moment = require("moment"); +var EmailManager = require("./email-manager"); +var config = require("../config"); +var AppError = require("../app-error"); +var log4js = require("log4js"); var log = log4js.getLogger("cps:AccountManager"); -var proto = module.exports = function (){ - function AccountManager() { - - } +var proto = (module.exports = function () { + function AccountManager() {} AccountManager.__proto__ = proto; return AccountManager; -}; +}); -proto.collaboratorCan = function(uid, appName) { - return this.getCollaborator(uid, appName) - .then((data) => { +proto.collaboratorCan = function (uid, appName) { + return this.getCollaborator(uid, appName).then((data) => { if (!data) { log.debug(`collaboratorCan App ${appName} not exists.`); throw new AppError.AppError(`App ${appName} not exists.`); } - log.debug('collaboratorCan yes'); + log.debug("collaboratorCan yes"); return data; }); }; -proto.ownerCan = function(uid, appName) { - return this.getCollaborator(uid, appName) - .then((data) => { +proto.ownerCan = function (uid, appName) { + return this.getCollaborator(uid, appName).then((data) => { if (!data) { log.debug(`ownerCan App ${appName} not exists.`); throw new AppError.AppError(`App ${appName} not exists.`); } - if (!_.eq(_.get(data,'roles'), 'Owner') ) { + if (!_.eq(_.get(data, "roles"), "Owner")) { log.debug(`ownerCan Permission Deny, You are not owner!`); throw new AppError.AppError("Permission Deny, You are not owner!"); } @@ -52,8 +47,7 @@ proto.getCollaborator = function (uid, appName) { }; proto.findUserByEmail = function (email) { - return models.Users.findOne({where: {email: email}}) - .then((data) => { + return models.Users.findOne({ where: { email: email } }).then((data) => { if (_.isEmpty(data)) { throw new AppError.AppError(email + " does not exist."); } else { @@ -63,14 +57,16 @@ proto.findUserByEmail = function (email) { }; proto.getAllAccessKeyByUid = function (uid) { - return models.UserTokens.findAll({where: {uid: uid}, order:[['id', 'DESC']]}) - .then((tokens) => { - return _.map(tokens, function(v){ + return models.UserTokens.findAll({ + where: { uid: uid }, + order: [["id", "DESC"]], + }).then((tokens) => { + return _.map(tokens, function (v) { return { - name: '(hidden)', - createdTime: parseInt(moment(v.created_at).format('x')), + name: "(hidden)", + createdTime: parseInt(moment(v.created_at).format("x")), createdBy: v.created_by, - expires: parseInt(moment(v.expires_at).format('x')), + expires: parseInt(moment(v.expires_at).format("x")), friendlyName: v.name, description: v.description, }; @@ -80,84 +76,98 @@ proto.getAllAccessKeyByUid = function (uid) { proto.isExsitAccessKeyName = function (uid, friendlyName) { return models.UserTokens.findOne({ - where: {uid: uid, name: friendlyName} + where: { uid: uid, name: friendlyName }, }); }; -proto.createAccessKey = function (uid, newAccessKey, ttl, friendlyName, createdBy, description) { +proto.createAccessKey = function ( + uid, + newAccessKey, + ttl, + friendlyName, + createdBy, + description +) { return models.UserTokens.create({ uid: uid, name: friendlyName, tokens: newAccessKey, description: description, created_by: createdBy, - expires_at: moment().add(ttl/1000, 'seconds').format('YYYY-MM-DD HH:mm:ss'), - created_at: moment().format('YYYY-MM-DD HH:mm:ss'), + expires_at: moment() + .add(ttl / 1000, "seconds") + .format("YYYY-MM-DD HH:mm:ss"), + created_at: moment().format("YYYY-MM-DD HH:mm:ss"), }); }; -const LOGIN_LIMIT_PRE = 'LOGIN_LIMIT_PRE_'; +const LOGIN_LIMIT_PRE = "LOGIN_LIMIT_PRE_"; proto.login = function (account, password) { if (_.isEmpty(account)) { - return Promise.reject(new AppError.AppError("请您输入邮箱地址")) + return Promise.reject(new AppError.AppError("请您输入邮箱地址")); } if (_.isEmpty(password)) { - return Promise.reject(new AppError.AppError("请您输入密码")) + return Promise.reject(new AppError.AppError("请您输入密码")); } var where = {}; if (validator.isEmail(account)) { - where = {email: account}; - }else { - where = {username: account}; + where = { email: account }; + } else { + where = { username: account }; } - var tryLoginTimes = _.get(config, 'common.tryLoginTimes', 0); - return models.Users.findOne({where: where}) - .then((users) => { - if (_.isEmpty(users)) { - throw new AppError.AppError("您输入的邮箱或密码有误"); - } - return users; - }) - .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(`您输入密码错误次数超过限制,帐户已经锁定`); - } - return users; - }) - .finally(() => client.quit()); - } else { + var tryLoginTimes = _.get(config, "common.tryLoginTimes", 0); + return models.Users.findOne({ where: where }) + .then((users) => { + if (_.isEmpty(users)) { + throw new AppError.AppError("您输入的邮箱或密码有误"); + } return users; - } - }) - .then((users) => { - if (!security.passwordVerifySync(password, users.password)) { + }) + .then((users) => { if (tryLoginTimes > 0) { var loginKey = `${LOGIN_LIMIT_PRE}${users.id}`; var client = factory.getRedisClient("default"); - client.existsAsync(loginKey) - .then((isExists) => { - if (!isExists) { - var expires = moment().endOf('day').format('X') - moment().format('X'); - return client.setexAsync(loginKey, expires, 0); - } - return isExists; - }) - .then(() => { - return client.incrAsync(loginKey); - }) - .finally(() => client.quit()); + return client + .getAsync(loginKey) + .then((loginErrorTimes) => { + if (loginErrorTimes > tryLoginTimes) { + throw new AppError.AppError( + `您输入密码错误次数超过限制,帐户已经锁定` + ); + } + return users; + }) + .finally(() => client.quit()); + } else { + return users; } - throw new AppError.AppError("您输入的邮箱或密码有误"); - } else { - return users; - } - }); + }) + .then((users) => { + if (!security.passwordVerifySync(password, users.password)) { + if (tryLoginTimes > 0) { + var loginKey = `${LOGIN_LIMIT_PRE}${users.id}`; + var client = factory.getRedisClient("default"); + client + .existsAsync(loginKey) + .then((isExists) => { + if (!isExists) { + var expires = + moment().endOf("day").format("X") - moment().format("X"); + return client.setexAsync(loginKey, expires, 0); + } + return isExists; + }) + .then(() => { + return client.incrAsync(loginKey); + }) + .finally(() => client.quit()); + } + throw new AppError.AppError("您输入的邮箱或密码有误"); + } else { + return users; + } + }); }; const REGISTER_CODE = "REGISTER_CODE_"; @@ -168,96 +178,96 @@ proto.sendRegisterCode = function (email) { if (_.isEmpty(email)) { return Promise.reject(new AppError.AppError("请您输入邮箱地址")); } - return models.Users.findOne({where: {email: email}}) - .then((u) => { - if (u) { - throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); - } - }) - .then(() => { - //将token临时存储到redis - var token = security.randToken(40); - var client = factory.getRedisClient("default"); - return client.setexAsync(`${REGISTER_CODE}${security.md5(email)}`, EXPIRED, token) + return models.Users.findOne({ where: { email: email } }) + .then((u) => { + if (u) { + throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); + } + }) .then(() => { - return token; + //将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()); }) - .finally(() => client.quit()); - }) - .then((token) => { - //将token发送到用户邮箱 - var emailManager = new EmailManager(); - return emailManager.sendRegisterCode(email, token); - }) + .then((token) => { + //将token发送到用户邮箱 + var emailManager = new EmailManager(); + return emailManager.sendRegisterCode(email, token); + }); }; proto.checkRegisterCode = function (email, token) { - return models.Users.findOne({where: {email: email}}) - .then((u) => { - if (u) { - throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); - } - }) - .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(`验证码已经失效,请您重新获取`); - } - 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(`您输入的验证码不正确,请重新输入`); + return models.Users.findOne({ where: { email: email } }) + .then((u) => { + if (u) { + throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); } - return storageToken; }) - }) -} + .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(`验证码已经失效,请您重新获取`); + } + 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(`您输入的验证码不正确,请重新输入`); + } + return storageToken; + }); + }); +}; proto.register = function (email, password) { - return models.Users.findOne({where: {email: email}}) - .then((u) => { - if (u) { - throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); - } - }) - .then(() => { - var identical = security.randToken(9); - return models.Users.create({ - email: email, - password: security.passwordHashSync(password), - identical: identical + return models.Users.findOne({ where: { email: email } }) + .then((u) => { + if (u) { + throw new AppError.AppError(`"${email}" 已经注册过,请更换邮箱注册`); + } + }) + .then(() => { + var identical = security.randToken(9); + return models.Users.create({ + email: email, + password: security.passwordHashSync(password), + identical: identical, + }); }); - }) -} +}; proto.changePassword = function (uid, oldPassword, newPassword) { if (!_.isString(newPassword) || newPassword.length < 6) { return Promise.reject(new AppError.AppError("请您输入6~20位长度的新密码")); } - return models.Users.findOne({where: {id: uid}}) - .then((u) => { - if (!u) { - throw new AppError.AppError(`未找到用户信息`); - } - return u; - }) - .then((u) => { - var isEq = security.passwordVerifySync(oldPassword, u.get('password')); - if (!isEq) { - throw new AppError.AppError(`您输入的旧密码不正确,请重新输入`); - } - u.set('password', security.passwordHashSync(newPassword)); - u.set('ack_code', security.randToken(5)); - return u.save(); - }); + return models.Users.findOne({ where: { id: uid } }) + .then((u) => { + if (!u) { + throw new AppError.AppError(`未找到用户信息`); + } + return u; + }) + .then((u) => { + var isEq = security.passwordVerifySync(oldPassword, u.get("password")); + if (!isEq) { + throw new AppError.AppError(`您输入的旧密码不正确,请重新输入`); + } + u.set("password", security.passwordHashSync(newPassword)); + u.set("ack_code", security.randToken(5)); + return u.save(); + }); }; - diff --git a/core/services/datacenter-manager.js b/core/services/datacenter-manager.js index c59d29ff..7ea5dfe0 100644 --- a/core/services/datacenter-manager.js +++ b/core/services/datacenter-manager.js @@ -1,33 +1,29 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var _ = require('lodash'); -var fs = require('fs'); -var os = require('os'); -var security = require('../utils/security'); -var common = require('../utils/common'); -const MANIFEST_FILE_NAME = 'manifest.json'; -const CONTENTS_NAME = 'contents'; -var AppError = require('../app-error'); -var log4js = require('log4js'); +"use strict"; +var _ = require("lodash"); +var fs = require("fs"); +var os = require("os"); +var security = require("../utils/security"); +var common = require("../utils/common"); +const MANIFEST_FILE_NAME = "manifest.json"; +const CONTENTS_NAME = "contents"; +var AppError = require("../app-error"); +var log4js = require("log4js"); var log = log4js.getLogger("cps:DataCenterManager"); -var path = require('path'); +var path = require("path"); -var proto = module.exports = function (){ - function DataCenterManager() { - - } +var proto = (module.exports = function () { + function DataCenterManager() {} DataCenterManager.__proto__ = proto; return DataCenterManager; -}; +}); proto.getDataDir = function () { - var dataDir = _.get(require('../config'), 'common.dataDir', {}); + var dataDir = _.get(require("../config"), "common.dataDir", {}); if (_.isEmpty(dataDir)) { dataDir = os.tmpdir(); } return dataDir; -} +}; proto.hasPackageStoreSync = function (packageHash) { var dataDir = this.getDataDir(); @@ -35,28 +31,38 @@ proto.hasPackageStoreSync = function (packageHash) { var manifestFile = path.join(packageHashPath, MANIFEST_FILE_NAME); var contentPath = path.join(packageHashPath, CONTENTS_NAME); return fs.existsSync(manifestFile) && fs.existsSync(contentPath); -} +}; proto.getPackageInfo = function (packageHash) { - if (this.hasPackageStoreSync(packageHash)){ + if (this.hasPackageStoreSync(packageHash)) { var dataDir = this.getDataDir(); var packageHashPath = path.join(dataDir, packageHash); var manifestFile = path.join(packageHashPath, MANIFEST_FILE_NAME); var contentPath = path.join(packageHashPath, CONTENTS_NAME); - return this.buildPackageInfo(packageHash, packageHashPath, contentPath, manifestFile); + return this.buildPackageInfo( + packageHash, + packageHashPath, + contentPath, + manifestFile + ); } else { - throw new AppError.AppError('can\'t get PackageInfo'); + throw new AppError.AppError("can't get PackageInfo"); } -} +}; -proto.buildPackageInfo = function (packageHash, packageHashPath, contentPath, manifestFile) { +proto.buildPackageInfo = function ( + packageHash, + packageHashPath, + contentPath, + manifestFile +) { return { packageHash: packageHash, path: packageHashPath, contentPath: contentPath, - manifestFilePath:manifestFile - } -} + manifestFilePath: manifestFile, + }; +}; proto.validateStore = function (providePackageHash) { var dataDir = this.getDataDir(); @@ -67,57 +73,65 @@ proto.validateStore = function (providePackageHash) { log.debug(`validateStore providePackageHash not exist`); return Promise.resolve(false); } - return security.calcAllFileSha256(contentPath) - .then((manifestJson) => { + return security.calcAllFileSha256(contentPath).then((manifestJson) => { var packageHash = security.packageHashSync(manifestJson); log.debug(`validateStore packageHash:`, packageHash); try { var manifestJsonLocal = JSON.parse(fs.readFileSync(manifestFile)); - }catch(e) { + } catch (e) { log.debug(`validateStore manifestFile contents invilad`); return false; } var packageHashLocal = security.packageHashSync(manifestJsonLocal); log.debug(`validateStore packageHashLocal:`, packageHashLocal); - if (_.eq(providePackageHash, packageHash) && _.eq(providePackageHash, packageHashLocal)) { + if ( + _.eq(providePackageHash, packageHash) && + _.eq(providePackageHash, packageHashLocal) + ) { log.debug(`validateStore store files is ok`); return true; } log.debug(`validateStore store files broken`); return false; }); -} +}; proto.storePackage = function (sourceDst, force) { log.debug(`storePackage sourceDst:`, sourceDst); - if (_.isEmpty(force)){ + if (_.isEmpty(force)) { force = false; } var self = this; - return security.calcAllFileSha256(sourceDst) - .then((manifestJson) => { + return security.calcAllFileSha256(sourceDst).then((manifestJson) => { var packageHash = security.packageHashSync(manifestJson); - log.debug('storePackage manifestJson packageHash:', packageHash); + log.debug("storePackage manifestJson packageHash:", packageHash); var dataDir = self.getDataDir(); var packageHashPath = path.join(dataDir, packageHash); var manifestFile = path.join(packageHashPath, MANIFEST_FILE_NAME); var contentPath = path.join(packageHashPath, CONTENTS_NAME); - return self.validateStore(packageHash) - .then((isValidate) => { + return self.validateStore(packageHash).then((isValidate) => { if (!force && isValidate) { - return self.buildPackageInfo(packageHash, packageHashPath, contentPath, manifestFile); + return self.buildPackageInfo( + packageHash, + packageHashPath, + contentPath, + manifestFile + ); } else { log.debug(`storePackage cover from sourceDst:`, sourceDst); - return common.createEmptyFolder(packageHashPath) - .then(() => { - return common.copy(sourceDst, contentPath) - .then(() => { + return common.createEmptyFolder(packageHashPath).then(() => { + return common.copy(sourceDst, contentPath).then(() => { var manifestString = JSON.stringify(manifestJson); fs.writeFileSync(manifestFile, manifestString); - return self.buildPackageInfo(packageHash, packageHashPath, contentPath, manifestFile); + return self.buildPackageInfo( + packageHash, + packageHashPath, + contentPath, + manifestFile + ); }); }); } }); }); -} +}; diff --git a/core/services/deployments.js b/core/services/deployments.js index 6e0b19ea..dd06d956 100644 --- a/core/services/deployments.js +++ b/core/services/deployments.js @@ -1,32 +1,30 @@ -'use strict'; -var Promise = require('bluebird'); -var models = require('../../models'); -var security = require('../../core/utils/security'); -var common = require('../../core/utils/common'); -var PackageManager = require('./package-manager'); -var _ = require('lodash'); -var moment = require('moment'); -var AppError = require('../app-error'); -var log4js = require('log4js'); +"use strict"; +var Promise = require("bluebird"); +var models = require("../../models"); +var security = require("../../core/utils/security"); +var common = require("../../core/utils/common"); +var _ = require("lodash"); +var moment = require("moment"); +var AppError = require("../app-error"); +var log4js = require("log4js"); var log = log4js.getLogger("cps:deployments"); -var proto = module.exports = function (){ - function Deployments() { - - } +var proto = (module.exports = function () { + function Deployments() {} Deployments.__proto__ = proto; return Deployments; -}; +}); -proto.getAllPackageIdsByDeploymentsId = function(deploymentsId) { - return models.Packages.findAll({where: {deployment_id: deploymentsId}}); +proto.getAllPackageIdsByDeploymentsId = function (deploymentsId) { + return models.Packages.findAll({ where: { deployment_id: deploymentsId } }); }; proto.existDeloymentName = function (appId, name) { - return models.Deployments.findOne({where: {appid: appId, name: name}}) - .then((data) => { - if (!_.isEmpty(data)){ - throw new AppError.AppError(name + " name does Exist!") + return models.Deployments.findOne({ + where: { appid: appId, name: name }, + }).then((data) => { + if (!_.isEmpty(data)) { + throw new AppError.AppError(name + " name does Exist!"); } else { return data; } @@ -35,13 +33,11 @@ proto.existDeloymentName = function (appId, name) { proto.addDeloyment = function (name, appId, uid) { var self = this; - return models.Users.findById(uid) - .then((user) => { + return models.Users.findById(uid).then((user) => { if (_.isEmpty(user)) { - throw new AppError.AppError('can\'t find user'); + throw new AppError.AppError("can't find user"); } - return self.existDeloymentName(appId, name) - .then(() => { + return self.existDeloymentName(appId, name).then(() => { var identical = user.identical; var deploymentKey = security.randToken(28) + identical; return models.Deployments.create({ @@ -49,24 +45,24 @@ proto.addDeloyment = function (name, appId, uid) { name: name, deployment_key: deploymentKey, last_deployment_version_id: 0, - label_id: 0 + label_id: 0, }); }); }); }; proto.renameDeloymentByName = function (deploymentName, appId, newName) { - return this.existDeloymentName(appId, newName) - .then(() => { + return this.existDeloymentName(appId, newName).then(() => { return models.Deployments.update( - {name: newName}, - {where: {name: deploymentName,appid: appId}} - ) - .spread((affectedCount, affectedRow) => { + { name: newName }, + { where: { name: deploymentName, appid: appId } } + ).spread((affectedCount, affectedRow) => { if (_.gt(affectedCount, 0)) { - return {name: newName}; + return { name: newName }; } else { - throw new AppError.AppError(`does not find the deployment "${deploymentName}"`); + throw new AppError.AppError( + `does not find the deployment "${deploymentName}"` + ); } }); }); @@ -74,13 +70,14 @@ proto.renameDeloymentByName = function (deploymentName, appId, newName) { proto.deleteDeloymentByName = function (deploymentName, appId) { return models.Deployments.destroy({ - where: {name: deploymentName, appid: appId} - }) - .then((rowNum) => { + where: { name: deploymentName, appid: appId }, + }).then((rowNum) => { if (_.gt(rowNum, 0)) { - return {name: `${deploymentName}`}; + return { name: `${deploymentName}` }; } else { - throw new AppError.AppError(`does not find the deployment "${deploymentName}"`); + throw new AppError.AppError( + `does not find the deployment "${deploymentName}"` + ); } }); }; @@ -88,69 +85,90 @@ proto.deleteDeloymentByName = function (deploymentName, appId) { proto.findDeloymentByName = function (deploymentName, appId) { log.debug(`findDeloymentByName name:${deploymentName},appId: ${appId}`); return models.Deployments.findOne({ - where: {name: deploymentName, appid: appId} + where: { name: deploymentName, appid: appId }, }); }; proto.findPackagesAndOtherInfos = function (packageId) { return models.Packages.findOne({ - where: {id: packageId} - }) - .then((packageInfo) => { + where: { id: packageId }, + }).then((packageInfo) => { if (!packageInfo) { return null; } return Promise.props({ packageInfo: packageInfo, - packageDiffMap: models.PackagesDiff.findAll({where: {package_id: packageId}}) - .then((diffs) => { + packageDiffMap: models.PackagesDiff.findAll({ + where: { package_id: packageId }, + }).then((diffs) => { if (diffs.length > 0) { - return _.reduce(diffs, (result, v) => { - result[_.get(v, 'diff_against_package_hash')] = { - size: _.get(v, 'diff_size'), - url: common.getBlobDownloadUrl(_.get(v, 'diff_blob_url')), - }; - return result; - }, {}); + return _.reduce( + diffs, + (result, v) => { + result[_.get(v, "diff_against_package_hash")] = { + size: _.get(v, "diff_size"), + url: common.getBlobDownloadUrl(_.get(v, "diff_blob_url")), + }; + return result; + }, + {} + ); } return null; }), - userInfo: models.Users.findOne({where: {id: packageInfo.released_by}}), - deploymentsVersions: models.DeploymentsVersions.findById(packageInfo.deployment_version_id) + userInfo: models.Users.findOne({ + where: { id: packageInfo.released_by }, + }), + deploymentsVersions: models.DeploymentsVersions.findById( + packageInfo.deployment_version_id + ), }); }); }; proto.findDeloymentsPackages = function (deploymentsVersionsId) { var self = this; - return models.DeploymentsVersions.findOne({where: {id: deploymentsVersionsId}}) - .then((deploymentsVersionsInfo) => { + return models.DeploymentsVersions.findOne({ + where: { id: deploymentsVersionsId }, + }).then((deploymentsVersionsInfo) => { if (deploymentsVersionsInfo) { - return self.findPackagesAndOtherInfos(deploymentsVersionsInfo.current_package_id); + return self.findPackagesAndOtherInfos( + deploymentsVersionsInfo.current_package_id + ); } return null; }); }; -proto.formatPackage = function(packageVersion) { +proto.formatPackage = function (packageVersion) { if (!packageVersion) { return null; } return { description: _.get(packageVersion, "packageInfo.description"), isDisabled: false, - isMandatory: _.get(packageVersion, "packageInfo.is_mandatory") == 1 ? true : false, + isMandatory: + _.get(packageVersion, "packageInfo.is_mandatory") == 1 ? true : false, rollout: 100, appVersion: _.get(packageVersion, "deploymentsVersions.app_version"), packageHash: _.get(packageVersion, "packageInfo.package_hash"), - blobUrl: common.getBlobDownloadUrl(_.get(packageVersion, "packageInfo.blob_url")), + blobUrl: common.getBlobDownloadUrl( + _.get(packageVersion, "packageInfo.blob_url") + ), size: _.get(packageVersion, "packageInfo.size"), - manifestBlobUrl: common.getBlobDownloadUrl(_.get(packageVersion, "packageInfo.manifest_blob_url")), - diffPackageMap: _.get(packageVersion, 'packageDiffMap'), + manifestBlobUrl: common.getBlobDownloadUrl( + _.get(packageVersion, "packageInfo.manifest_blob_url") + ), + diffPackageMap: _.get(packageVersion, "packageDiffMap"), releaseMethod: _.get(packageVersion, "packageInfo.release_method"), - uploadTime: parseInt(moment(_.get(packageVersion, "packageInfo.updated_at")).format('x')), + uploadTime: parseInt( + moment(_.get(packageVersion, "packageInfo.updated_at")).format("x") + ), originalLabel: _.get(packageVersion, "packageInfo.original_label"), - originalDeployment: _.get(packageVersion, "packageInfo.original_deployment"), + originalDeployment: _.get( + packageVersion, + "packageInfo.original_deployment" + ), label: _.get(packageVersion, "packageInfo.label"), releasedBy: _.get(packageVersion, "userInfo.email"), }; @@ -158,74 +176,95 @@ proto.formatPackage = function(packageVersion) { proto.listDeloyments = function (appId) { var self = this; - return models.Deployments.findAll({where: {appid: appId}}) - .then((deploymentsInfos) => { - if (_.isEmpty(deploymentsInfos)) { - return []; + return models.Deployments.findAll({ where: { appid: appId } }).then( + (deploymentsInfos) => { + if (_.isEmpty(deploymentsInfos)) { + return []; + } + return Promise.map(deploymentsInfos, (v) => { + return self.listDeloyment(v); + }); } - return Promise.map(deploymentsInfos, (v) => { - return self.listDeloyment(v); - }) - }); + ); }; proto.listDeloyment = function (deploymentInfo) { const self = this; return Promise.props({ - createdTime: parseInt(moment(deploymentInfo.created_at).format('x')), + createdTime: parseInt(moment(deploymentInfo.created_at).format("x")), id: `${deploymentInfo.id}`, key: deploymentInfo.deployment_key, name: deploymentInfo.name, - package: self.findDeloymentsPackages([deploymentInfo.last_deployment_version_id]).then(self.formatPackage) + package: self + .findDeloymentsPackages([deploymentInfo.last_deployment_version_id]) + .then(self.formatPackage), }); -} +}; proto.getDeploymentHistory = function (deploymentId) { var self = this; - return models.DeploymentsHistory.findAll({where: {deployment_id: deploymentId}, order: [['id','desc']], limit: 15}) - .then((history) => { - return _.map(history, (v) => { return v.package_id}); + return models.DeploymentsHistory.findAll({ + where: { deployment_id: deploymentId }, + order: [["id", "desc"]], + limit: 15, }) - .then((packageIds) => { - return Promise.map(packageIds, (v) => { - return self.findPackagesAndOtherInfos(v).then(self.formatPackage); + .then((history) => { + return _.map(history, (v) => { + return v.package_id; + }); + }) + .then((packageIds) => { + return Promise.map(packageIds, (v) => { + return self.findPackagesAndOtherInfos(v).then(self.formatPackage); + }); }); - }); }; -proto.deleteDeploymentHistory = function(deploymentId) { +proto.deleteDeploymentHistory = function (deploymentId) { return models.sequelize.transaction((t) => { return Promise.all([ models.Deployments.update( - {last_deployment_version_id:0,label_id:0}, - {where: {id: deploymentId},transaction: t} + { last_deployment_version_id: 0, label_id: 0 }, + { where: { id: deploymentId }, transaction: t } ), - models.DeploymentsHistory.findAll({where: {deployment_id: deploymentId}, order: [['id','desc']], limit: 1000}) - .then((rs) => { + models.DeploymentsHistory.findAll({ + where: { deployment_id: deploymentId }, + order: [["id", "desc"]], + limit: 1000, + }).then((rs) => { return Promise.map(rs, (v) => { - return v.destroy({transaction: t}); + return v.destroy({ transaction: t }); }); }), - models.DeploymentsVersions.findAll({where: {deployment_id: deploymentId}, order: [['id','desc']], limit: 1000}) - .then((rs) => { + models.DeploymentsVersions.findAll({ + where: { deployment_id: deploymentId }, + order: [["id", "desc"]], + limit: 1000, + }).then((rs) => { return Promise.map(rs, (v) => { - return v.destroy({transaction: t}); + return v.destroy({ transaction: t }); }); }), - models.Packages.findAll({where: {deployment_id: deploymentId}, order: [['id','desc']], limit: 1000}) - .then((rs) => { + models.Packages.findAll({ + where: { deployment_id: deploymentId }, + order: [["id", "desc"]], + limit: 1000, + }).then((rs) => { return Promise.map(rs, (v) => { - return v.destroy({transaction: t}) - .then(() => { + return v.destroy({ transaction: t }).then(() => { return Promise.all([ - models.PackagesMetrics.destroy({where: {package_id: v.get('id')},transaction: t}), - models.PackagesDiff.destroy({where: {package_id: v.get('id')},transaction: t}) + models.PackagesMetrics.destroy({ + where: { package_id: v.get("id") }, + transaction: t, + }), + models.PackagesDiff.destroy({ + where: { package_id: v.get("id") }, + transaction: t, + }), ]); }); }); - }) + }), ]); }); -} - - +}; diff --git a/core/services/email-manager.js b/core/services/email-manager.js index 30aa69f5..613b61ba 100644 --- a/core/services/email-manager.js +++ b/core/services/email-manager.js @@ -1,10 +1,5 @@ "use strict"; -var Promise = require("bluebird"); -var models = require("../../models"); var _ = require("lodash"); -var validator = require("validator"); -var security = require("../utils/security"); -var moment = require("moment"); var nodemailer = require("nodemailer"); var config = require("../config"); diff --git a/core/utils/common.js b/core/utils/common.js index 6d221535..aa26398c 100644 --- a/core/utils/common.js +++ b/core/utils/common.js @@ -1,85 +1,116 @@ -'use strict'; -var Promise = require('bluebird'); +"use strict"; var fs = require("fs"); var fsextra = require("fs-extra"); -var extract = require('extract-zip') -var config = require('../config'); -var _ = require('lodash'); -var validator = require('validator'); +var extract = require("extract-zip"); +var config = require("../config"); +var _ = require("lodash"); +var validator = require("validator"); var qiniu = require("qiniu"); -var upyun = require('upyun'); +var upyun = require("upyun"); var common = {}; -var AppError = require('../app-error'); +var AppError = require("../app-error"); var jschardet = require("jschardet"); -var log4js = require('log4js'); -var path = require('path'); +var log4js = require("log4js"); +var path = require("path"); var log = log4js.getLogger("cps:utils:common"); module.exports = common; -common.detectIsTextFile = function(filePath) { - var fd = fs.openSync(filePath, 'r'); +common.detectIsTextFile = function (filePath) { + var fd = fs.openSync(filePath, "r"); var buffer = new Buffer(4096); fs.readSync(fd, buffer, 0, 4096, 0); fs.closeSync(fd); var rs = jschardet.detect(buffer); - log.debug('detectIsTextFile:', filePath, rs); + log.debug("detectIsTextFile:", filePath, rs); if (rs.confidence == 1) { return true; } return false; -} +}; common.parseVersion = function (versionNo) { - var version = '0'; + var version = "0"; var data = null; - if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { + if ((data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/))) { // "1.2.3" - version = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - } else if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5})$/)) { + version = + data[1] + _.padStart(data[2], 5, "0") + _.padStart(data[3], 10, "0"); + } else if ((data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5})$/))) { // "1.2" - version = data[1] + _.padStart(data[2], 5, '0') + _.padStart('0', 10, '0'); + version = data[1] + _.padStart(data[2], 5, "0") + _.padStart("0", 10, "0"); } return version; }; common.validatorVersion = function (versionNo) { var flag = false; - var min = '0'; - var max = '9999999999999999999'; + var min = "0"; + var max = "9999999999999999999"; var data = null; if (versionNo == "*") { // "*" flag = true; - } else if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { + } else if ( + (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) + ) { // "1.2.3" flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = data[1] + _.padStart(data[2], 5, '0') + _.padStart((parseInt(data[3])+1), 10, '0'); - } else if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5})(\.\*){0,1}$/)) { + min = data[1] + _.padStart(data[2], 5, "0") + _.padStart(data[3], 10, "0"); + max = + data[1] + + _.padStart(data[2], 5, "0") + + _.padStart(parseInt(data[3]) + 1, 10, "0"); + } else if ( + (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5})(\.\*){0,1}$/)) + ) { // "1.2" "1.2.*" flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart('0', 10, '0'); - max = data[1] + _.padStart((parseInt(data[2])+1), 5, '0') + _.padStart('0', 10, '0'); - } else if (data = versionNo.match(/^\~([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { + min = data[1] + _.padStart(data[2], 5, "0") + _.padStart("0", 10, "0"); + max = + data[1] + + _.padStart(parseInt(data[2]) + 1, 5, "0") + + _.padStart("0", 10, "0"); + } else if ( + (data = versionNo.match(/^\~([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) + ) { //"~1.2.3" flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = data[1] + _.padStart((parseInt(data[2])+1), 5, '0') + _.padStart('0', 10, '0'); - } else if (data = versionNo.match(/^\^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { + min = data[1] + _.padStart(data[2], 5, "0") + _.padStart(data[3], 10, "0"); + max = + data[1] + + _.padStart(parseInt(data[2]) + 1, 5, "0") + + _.padStart("0", 10, "0"); + } else if ( + (data = versionNo.match(/^\^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) + ) { //"^1.2.3" flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = _.toString((parseInt(data[1])+1)) + _.padStart(0, 5, '0') + _.padStart('0', 10, '0'); - } else if (data = versionNo.match(/^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})\s?-\s?([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { + min = data[1] + _.padStart(data[2], 5, "0") + _.padStart(data[3], 10, "0"); + max = + _.toString(parseInt(data[1]) + 1) + + _.padStart(0, 5, "0") + + _.padStart("0", 10, "0"); + } else if ( + (data = versionNo.match( + /^([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})\s?-\s?([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/ + )) + ) { // "1.2.3 - 1.2.7" flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = data[4] + _.padStart(data[5], 5, '0') + _.padStart((parseInt(data[6])+1), 10, '0'); - } else if (data = versionNo.match(/^>=([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})\s?<([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/)) { + min = data[1] + _.padStart(data[2], 5, "0") + _.padStart(data[3], 10, "0"); + max = + data[4] + + _.padStart(data[5], 5, "0") + + _.padStart(parseInt(data[6]) + 1, 10, "0"); + } else if ( + (data = versionNo.match( + /^>=([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})\s?<([0-9]{1,3}).([0-9]{1,5}).([0-9]{1,10})$/ + )) + ) { // ">=1.2.3 <1.2.7" flag = true; - min = data[1] + _.padStart(data[2], 5, '0') + _.padStart(data[3], 10, '0'); - max = data[4] + _.padStart(data[5], 5, '0') + _.padStart(data[6], 10, '0'); + min = data[1] + _.padStart(data[2], 5, "0") + _.padStart(data[3], 10, "0"); + max = data[4] + _.padStart(data[5], 5, "0") + _.padStart(data[6], 10, "0"); } return [flag, min, max]; }; @@ -88,26 +119,27 @@ common.createFileFromRequest = function (url, filePath) { return new Promise((resolve, reject) => { fs.exists(filePath, function (exists) { if (!exists) { - var request = require('request'); - log.debug(`createFileFromRequest url:${url}`) - request(url).on('error', function (error) { - reject(error); - }) - .on('response', function (response) { - if (response.statusCode == 200) { - let stream = fs.createWriteStream(filePath); - response.pipe(stream); - stream.on('close',function(){ - resolve(null); - }); - stream.on('error', function (error) { - reject(error) - }) - } else { - reject({message:'request fail'}) - } - }); - }else { + var request = require("request"); + log.debug(`createFileFromRequest url:${url}`); + request(url) + .on("error", function (error) { + reject(error); + }) + .on("response", function (response) { + if (response.statusCode == 200) { + let stream = fs.createWriteStream(filePath); + response.pipe(stream); + stream.on("close", function () { + resolve(null); + }); + stream.on("error", function (error) { + reject(error); + }); + } else { + reject({ message: "request fail" }); + } + }); + } else { resolve(null); } }); @@ -115,17 +147,19 @@ common.createFileFromRequest = function (url, filePath) { }; common.copySync = function (sourceDst, targertDst) { - return fsextra.copySync(sourceDst, targertDst, {overwrite: true}); + return fsextra.copySync(sourceDst, targertDst, { overwrite: true }); }; common.copy = function (sourceDst, targertDst) { return new Promise((resolve, reject) => { - fsextra.copy(sourceDst, targertDst, {overwrite: true}, function (err) { + fsextra.copy(sourceDst, targertDst, { overwrite: true }, function (err) { if (err) { log.error(err); reject(err); } else { - log.debug(`copy success sourceDst:${sourceDst} targertDst:${targertDst}`); + log.debug( + `copy success sourceDst:${sourceDst} targertDst:${targertDst}` + ); resolve(); } }); @@ -134,12 +168,14 @@ common.copy = function (sourceDst, targertDst) { common.move = function (sourceDst, targertDst) { return new Promise((resolve, reject) => { - fsextra.move(sourceDst, targertDst, {overwrite: true}, function (err) { + fsextra.move(sourceDst, targertDst, { overwrite: true }, function (err) { if (err) { log.error(err); reject(err); } else { - log.debug(`move success sourceDst:${sourceDst} targertDst:${targertDst}`); + log.debug( + `move success sourceDst:${sourceDst} targertDst:${targertDst}` + ); resolve(); } }); @@ -152,7 +188,7 @@ common.deleteFolder = function (folderPath) { if (err) { log.error(err); reject(err); - }else { + } else { log.debug(`deleteFolder delete ${folderPath} success.`); resolve(null); } @@ -167,8 +203,7 @@ common.deleteFolderSync = function (folderPath) { common.createEmptyFolder = function (folderPath) { return new Promise((resolve, reject) => { log.debug(`createEmptyFolder Create dir ${folderPath}`); - return common.deleteFolder(folderPath) - .then((data) => { + return common.deleteFolder(folderPath).then((data) => { fsextra.mkdirs(folderPath, (err) => { if (err) { log.error(err); @@ -194,12 +229,12 @@ common.unzipFile = function (zipFile, outputPath) { log.debug(`Pass unzipFile file ${zipFile}`); } catch (e) { log.error(e); - return reject(new AppError.AppError(e.message)) + return reject(new AppError.AppError(e.message)); } - extract(zipFile, {dir: outputPath}, function(err){ + extract(zipFile, { dir: outputPath }, function (err) { if (err) { log.error(err); - reject(new AppError.AppError(`it's not a zipFile`)) + reject(new AppError.AppError(`it's not a zipFile`)); } else { log.debug(`unzipFile success`); resolve(outputPath); @@ -210,25 +245,25 @@ common.unzipFile = function (zipFile, outputPath) { common.getUploadTokenQiniu = function (mac, bucket, key) { var options = { - scope: bucket + ":" + key - } + scope: bucket + ":" + key, + }; var putPolicy = new qiniu.rs.PutPolicy(options); return putPolicy.uploadToken(mac); }; common.uploadFileToStorage = function (key, filePath) { - var storageType = _.get(config, 'common.storageType'); - if ( storageType === 'local') { + var storageType = _.get(config, "common.storageType"); + if (storageType === "local") { return common.uploadFileToLocal(key, filePath); - } else if (storageType === 's3') { + } else if (storageType === "s3") { return common.uploadFileToS3(key, filePath); - } else if (storageType === 'oss') { + } else if (storageType === "oss") { return common.uploadFileToOSS(key, filePath); - } else if (storageType === 'qiniu') { + } else if (storageType === "qiniu") { return common.uploadFileToQiniu(key, filePath); - } else if (storageType === 'upyun') { + } else if (storageType === "upyun") { return common.uploadFileToUpyun(key, filePath); - } else if (storageType === 'tencentcloud') { + } else if (storageType === "tencentcloud") { return common.uploadFileToTencentCloud(key, filePath); } throw new AppError.AppError(`${storageType} storageType does not support.`); @@ -236,13 +271,13 @@ common.uploadFileToStorage = function (key, filePath) { common.uploadFileToLocal = function (key, filePath) { return new Promise((resolve, reject) => { - var storageDir = _.get(config, 'local.storageDir'); + var storageDir = _.get(config, "local.storageDir"); if (!storageDir) { - throw new AppError.AppError('please set config local storageDir'); + throw new AppError.AppError("please set config local storageDir"); } if (key.length < 3) { log.error(`generate key is too short, key value:${key}`); - throw new AppError.AppError('generate key is too short.'); + throw new AppError.AppError("generate key is too short."); } try { log.debug(`uploadFileToLocal check directory ${storageDir} fs.R_OK`); @@ -269,7 +304,7 @@ common.uploadFileToLocal = function (key, filePath) { log.debug(`uploadFileToLocal mkdir:${finalDir}`); } try { - fs.accessSync(filePath, fs.R_OK); + fs.accessSync(filePath, fs.R_OK); } catch (e) { log.error(e); throw new AppError.AppError(e.message); @@ -280,7 +315,7 @@ common.uploadFileToLocal = function (key, filePath) { log.error(e); throw e; } - fsextra.copy(filePath, fileName,(err) => { + fsextra.copy(filePath, fileName, (err) => { if (err) { log.error(new AppError.AppError(err.message)); return reject(new AppError.AppError(err.message)); @@ -293,20 +328,21 @@ common.uploadFileToLocal = function (key, filePath) { common.getBlobDownloadUrl = function (blobUrl) { var fileName = blobUrl; - var storageType = _.get(config, 'common.storageType'); + var storageType = _.get(config, "common.storageType"); var downloadUrl = _.get(config, `${storageType}.downloadUrl`); - if ( storageType === 'local') { - fileName = blobUrl.substr(0, 2).toLowerCase() + '/' + blobUrl; + if (storageType === "local") { + fileName = blobUrl.substr(0, 2).toLowerCase() + "/" + blobUrl; } if (!validator.isURL(downloadUrl)) { - var e = new AppError.AppError(`Please config ${storageType}.downloadUrl in config.js`); + var e = new AppError.AppError( + `Please config ${storageType}.downloadUrl in config.js` + ); log.error(e); throw e; } - return `${downloadUrl}/${fileName}` + return `${downloadUrl}/${fileName}`; }; - common.uploadFileToQiniu = function (key, filePath) { return new Promise((resolve, reject) => { var accessKey = _.get(config, "qiniu.accessKey"); @@ -317,11 +353,11 @@ common.uploadFileToQiniu = function (key, filePath) { var bucketManager = new qiniu.rs.BucketManager(mac, conf); bucketManager.stat(bucket, key, (respErr, respBody, respInfo) => { if (respErr) { - log.debug('uploadFileToQiniu file stat:', respErr); + log.debug("uploadFileToQiniu file stat:", respErr); return reject(new AppError.AppError(respErr.message)); } - log.debug('uploadFileToQiniu file stat respBody:', respBody); - log.debug('uploadFileToQiniu file stat respInfo:', respInfo); + log.debug("uploadFileToQiniu file stat respBody:", respBody); + log.debug("uploadFileToQiniu file stat respInfo:", respInfo); if (respInfo.statusCode == 200) { resolve(respBody.hash); } else { @@ -332,22 +368,28 @@ common.uploadFileToQiniu = function (key, filePath) { } var formUploader = new qiniu.form_up.FormUploader(conf); var putExtra = new qiniu.form_up.PutExtra(); - formUploader.putFile(uploadToken, key, filePath, putExtra, (respErr, respBody, respInfo) => { - if(respErr) { - log.error('uploadFileToQiniu putFile:', respErr); - // 上传失败, 处理返回代码 - return reject(new AppError.AppError(JSON.stringify(respErr))); - } else { - log.debug('uploadFileToQiniu putFile respBody:', respBody); - log.debug('uploadFileToQiniu putFile respInfo:', respInfo); - // 上传成功, 处理返回值 - if (respInfo.statusCode == 200) { - return resolve(respBody.hash); + formUploader.putFile( + uploadToken, + key, + filePath, + putExtra, + (respErr, respBody, respInfo) => { + if (respErr) { + log.error("uploadFileToQiniu putFile:", respErr); + // 上传失败, 处理返回代码 + return reject(new AppError.AppError(JSON.stringify(respErr))); } else { - return reject(new AppError.AppError(respBody.error)); + log.debug("uploadFileToQiniu putFile respBody:", respBody); + log.debug("uploadFileToQiniu putFile respInfo:", respInfo); + // 上传成功, 处理返回值 + if (respInfo.statusCode == 200) { + return resolve(respBody.hash); + } else { + return reject(new AppError.AppError(respBody.error)); + } } } - }); + ); } }); }); @@ -360,89 +402,96 @@ common.uploadFileToUpyun = function (key, filePath) { var storageDir = _.get(config, "upyun.storageDir", ""); var service = new upyun.Service(serviceName, operatorName, operatorPass); var client = new upyun.Client(service); - return ( - new Promise((resolve, reject) => { - client.makeDir(storageDir).then(result => { - if(!storageDir) { - reject(new AppError.AppError('Please config the upyun remoteDir!')); + return new Promise((resolve, reject) => { + client + .makeDir(storageDir) + .then((result) => { + if (!storageDir) { + reject(new AppError.AppError("Please config the upyun remoteDir!")); return; } - let remotePath = storageDir + '/' + key; - log.debug('uploadFileToUpyun remotePath:', remotePath); - log.debug('uploadFileToUpyun mkDir result:', result); - client.putFile(remotePath, fs.createReadStream(filePath)).then(data => { - log.debug('uploadFileToUpyun putFile response:', data); - if(data) { - resolve(key) - } else { - log.debug('uploadFileToUpyun putFile failed!', data); - reject(new AppError.AppError('Upload file to upyun failed!')); - } - }).catch(e1 => { - log.debug('uploadFileToUpyun putFile exception e1:', e1); - reject(new AppError.AppError(JSON.stringify(e1))); - }) - }).catch(e => { - log.debug('uploadFileToUpyun putFile exception e:', e); + let remotePath = storageDir + "/" + key; + log.debug("uploadFileToUpyun remotePath:", remotePath); + log.debug("uploadFileToUpyun mkDir result:", result); + client + .putFile(remotePath, fs.createReadStream(filePath)) + .then((data) => { + log.debug("uploadFileToUpyun putFile response:", data); + if (data) { + resolve(key); + } else { + log.debug("uploadFileToUpyun putFile failed!", data); + reject(new AppError.AppError("Upload file to upyun failed!")); + } + }) + .catch((e1) => { + log.debug("uploadFileToUpyun putFile exception e1:", e1); + reject(new AppError.AppError(JSON.stringify(e1))); + }); + }) + .catch((e) => { + log.debug("uploadFileToUpyun putFile exception e:", e); reject(new AppError.AppError(JSON.stringify(e))); }); - }) - ); + }); }; common.uploadFileToS3 = function (key, filePath) { - var AWS = require('aws-sdk'); - return ( - new Promise((resolve, reject) => { - AWS.config.update({ - accessKeyId: _.get(config, 's3.accessKeyId'), - secretAccessKey: _.get(config, 's3.secretAccessKey'), - sessionToken: _.get(config, 's3.sessionToken'), - region: _.get(config, 's3.region') - }); - var s3 = new AWS.S3({ - params: {Bucket: _.get(config, 's3.bucketName')} - }); - fs.readFile(filePath, (err, data) => { - s3.upload({ + var AWS = require("aws-sdk"); + return new Promise((resolve, reject) => { + AWS.config.update({ + accessKeyId: _.get(config, "s3.accessKeyId"), + secretAccessKey: _.get(config, "s3.secretAccessKey"), + sessionToken: _.get(config, "s3.sessionToken"), + region: _.get(config, "s3.region"), + }); + var s3 = new AWS.S3({ + params: { Bucket: _.get(config, "s3.bucketName") }, + }); + fs.readFile(filePath, (err, data) => { + s3.upload( + { Key: key, Body: data, - ACL:'public-read', - }, (err, response) => { - if(err) { + ACL: "public-read", + }, + (err, response) => { + if (err) { reject(new AppError.AppError(JSON.stringify(err))); } else { - resolve(response.ETag) + resolve(response.ETag); } - }) - }); - }) - ); + } + ); + }); + }); }; common.uploadFileToOSS = function (key, filePath) { - var ALY = require('aliyun-sdk'); - var ossStream = require('aliyun-oss-upload-stream')(new ALY.OSS({ - accessKeyId: _.get(config, 'oss.accessKeyId'), - secretAccessKey: _.get(config, 'oss.secretAccessKey'), - endpoint: _.get(config, 'oss.endpoint'), - apiVersion: '2013-10-15', - })); - if (!_.isEmpty(_.get(config, 'oss.prefix', ""))) { - key = `${_.get(config, 'oss.prefix')}/${key}`; + var ALY = require("aliyun-sdk"); + var ossStream = require("aliyun-oss-upload-stream")( + new ALY.OSS({ + accessKeyId: _.get(config, "oss.accessKeyId"), + secretAccessKey: _.get(config, "oss.secretAccessKey"), + endpoint: _.get(config, "oss.endpoint"), + apiVersion: "2013-10-15", + }) + ); + if (!_.isEmpty(_.get(config, "oss.prefix", ""))) { + key = `${_.get(config, "oss.prefix")}/${key}`; } var upload = ossStream.upload({ - Bucket: _.get(config, 'oss.bucketName'), + Bucket: _.get(config, "oss.bucketName"), Key: key, }); return new Promise((resolve, reject) => { - upload.on('error', (error) => { + upload.on("error", (error) => { log.debug("uploadFileToOSS", error); reject(error); }); - upload.on('uploaded', (details) => { + upload.on("uploaded", (details) => { log.debug("uploadFileToOSS", details); resolve(details.ETag); }); @@ -452,33 +501,36 @@ common.uploadFileToOSS = function (key, filePath) { common.uploadFileToTencentCloud = function (key, filePath) { return new Promise((resolve, reject) => { - var COS = require('cos-nodejs-sdk-v5'); + var COS = require("cos-nodejs-sdk-v5"); var cosIn = new COS({ - SecretId: _.get(config, 'tencentcloud.accessKeyId'), - SecretKey: _.get(config, 'tencentcloud.secretAccessKey') + SecretId: _.get(config, "tencentcloud.accessKeyId"), + SecretKey: _.get(config, "tencentcloud.secretAccessKey"), }); - cosIn.sliceUploadFile({ - Bucket: _.get(config, 'tencentcloud.bucketName'), - Region: _.get(config, 'tencentcloud.region'), + cosIn.sliceUploadFile( + { + Bucket: _.get(config, "tencentcloud.bucketName"), + Region: _.get(config, "tencentcloud.region"), Key: key, - FilePath: filePath - }, function (err, data) { - log.debug("uploadFileToTencentCloud", err, data); - if (err) { - reject(new AppError.AppError(JSON.stringify(err))); - }else { - resolve(data.Key); + FilePath: filePath, + }, + function (err, data) { + log.debug("uploadFileToTencentCloud", err, data); + if (err) { + reject(new AppError.AppError(JSON.stringify(err))); + } else { + resolve(data.Key); + } } - }); + ); }); -} +}; common.diffCollectionsSync = function (collection1, collection2) { var diffFiles = []; var collection1Only = []; var newCollection2 = Object.assign({}, collection2); if (collection1 instanceof Object) { - for(var key of Object.keys(collection1)) { + for (var key of Object.keys(collection1)) { if (_.isEmpty(newCollection2[key])) { collection1Only.push(key); } else { @@ -489,5 +541,9 @@ common.diffCollectionsSync = function (collection1, collection2) { } } } - return {diff:diffFiles, collection1Only: collection1Only, collection2Only: Object.keys(newCollection2)} + return { + diff: diffFiles, + collection1Only: collection1Only, + collection2Only: Object.keys(newCollection2), + }; }; diff --git a/core/utils/security.js b/core/utils/security.js index a4054acd..dd8e2f63 100644 --- a/core/utils/security.js +++ b/core/utils/security.js @@ -1,98 +1,97 @@ -'use strict'; -var bcrypt = require('bcryptjs'); -var crypto = require('crypto'); -var fs = require('fs'); -var Promise = require('bluebird'); -var qetag = require('../utils/qetag'); -var _ = require('lodash'); -var log4js = require('log4js'); +"use strict"; +var bcrypt = require("bcryptjs"); +var crypto = require("crypto"); +var fs = require("fs"); +var qetag = require("../utils/qetag"); +var _ = require("lodash"); +var log4js = require("log4js"); var log = log4js.getLogger("cps:utils:security"); -var AppError = require('../app-error'); +var AppError = require("../app-error"); -var randToken = require('rand-token').generator({ - chars: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', - source: crypto.randomBytes +var randToken = require("rand-token").generator({ + chars: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + source: crypto.randomBytes, }); var security = {}; module.exports = security; security.md5 = function (str) { - var md5sum = crypto.createHash('md5'); + var md5sum = crypto.createHash("md5"); md5sum.update(str); - str = md5sum.digest('hex'); + str = md5sum.digest("hex"); return str; -} +}; -security.passwordHashSync = function(password){ +security.passwordHashSync = function (password) { return bcrypt.hashSync(password, bcrypt.genSaltSync(12)); -} +}; -security.passwordVerifySync = function(password, hash){ - return bcrypt.compareSync(password, hash) -} +security.passwordVerifySync = function (password, hash) { + return bcrypt.compareSync(password, hash); +}; -security.randToken = function(num) { +security.randToken = function (num) { return randToken.generate(num); -} +}; -security.parseToken = function(token) { - return {identical: token.substr(-9,9), token:token.substr(0,28)} -} +security.parseToken = function (token) { + return { identical: token.substr(-9, 9), token: token.substr(0, 28) }; +}; security.fileSha256 = function (file) { return new Promise((resolve, reject) => { var rs = fs.createReadStream(file); - var hash = crypto.createHash('sha256'); - rs.on('data', hash.update.bind(hash)); - rs.on('error', (e) => { + var hash = crypto.createHash("sha256"); + rs.on("data", hash.update.bind(hash)); + rs.on("error", (e) => { reject(e); }); - rs.on('end', () => { - resolve(hash.digest('hex')); + rs.on("end", () => { + resolve(hash.digest("hex")); }); }); -} +}; security.stringSha256Sync = function (contents) { - var sha256 = crypto.createHash('sha256'); + var sha256 = crypto.createHash("sha256"); sha256.update(contents); - return sha256.digest('hex'); -} + return sha256.digest("hex"); +}; security.packageHashSync = function (jsonData) { var sortedArr = security.sortJsonToArr(jsonData); var manifestData = _.filter(sortedArr, (v) => { return !security.isPackageHashIgnored(v.path); }).map((v) => { - return v.path + ':' + v.hash; + return v.path + ":" + v.hash; }); - log.debug('packageHashSync manifestData:', manifestData); + log.debug("packageHashSync manifestData:", manifestData); var manifestString = JSON.stringify(manifestData.sort()); - manifestString = _.replace(manifestString, /\\\//g, '/'); - log.debug('packageHashSync manifestString:', manifestString); + manifestString = _.replace(manifestString, /\\\//g, "/"); + log.debug("packageHashSync manifestString:", manifestString); return security.stringSha256Sync(manifestString); -} +}; //参数为buffer或者readableStream或者文件路径 security.qetag = function (buffer) { - if (typeof buffer === 'string') { + if (typeof buffer === "string") { try { log.debug(`Check upload file ${buffer} fs.R_OK`); fs.accessSync(buffer, fs.R_OK); log.debug(`Pass upload file ${buffer}`); } catch (e) { log.error(e); - return Promise.reject(new AppError.AppError(e.message)) + return Promise.reject(new AppError.AppError(e.message)); } } - log.debug(`generate file identical`) + log.debug(`generate file identical`); return new Promise((resolve, reject) => { - qetag(buffer, (data)=>{ - log.debug('identical:', data); - resolve(data) + qetag(buffer, (data) => { + log.debug("identical:", data); + resolve(data); }); }); -} +}; security.sha256AllFiles = function (files) { return new Promise((resolve, reject) => { @@ -100,8 +99,7 @@ security.sha256AllFiles = function (files) { var length = files.length; var count = 0; files.forEach((file) => { - security.fileSha256(file) - .then((hash) => { + security.fileSha256(file).then((hash) => { results[file] = hash; count++; if (count == length) { @@ -110,12 +108,12 @@ security.sha256AllFiles = function (files) { }); }); }); -} +}; security.uploadPackageType = function (directoryPath) { return new Promise((resolve, reject) => { var recursive = require("recursive-readdir"); - var path = require('path'); + var path = require("path"); var slash = require("slash"); recursive(directoryPath, (err, files) => { if (err) { @@ -126,9 +124,9 @@ security.uploadPackageType = function (directoryPath) { log.debug(`uploadPackageType empty files`); reject(new AppError.AppError("empty files")); } else { - var constName = require('../const'); - const AREGEX=/android\.bundle/ - const AREGEX_IOS=/main\.jsbundle/ + var constName = require("../const"); + const AREGEX = /android\.bundle/; + const AREGEX_IOS = /main\.jsbundle/; var packageType = 0; _.forIn(files, function (value) { if (AREGEX.test(value)) { @@ -146,7 +144,7 @@ security.uploadPackageType = function (directoryPath) { } }); }); -} +}; // some files are ignored in calc hash in client sdk // https://github.com/Microsoft/react-native-code-push/pull/974/files#diff-21b650f88429c071b217d46243875987R15 @@ -155,13 +153,15 @@ security.isHashIgnored = function (relativePath) { return true; } - const IgnoreMacOSX = '__MACOSX/'; - const IgnoreDSStore = '.DS_Store'; + const IgnoreMacOSX = "__MACOSX/"; + const IgnoreDSStore = ".DS_Store"; - return relativePath.startsWith(IgnoreMacOSX) - || relativePath === IgnoreDSStore - || relativePath.endsWith(IgnoreDSStore); -} + return ( + relativePath.startsWith(IgnoreMacOSX) || + relativePath === IgnoreDSStore || + relativePath.endsWith(IgnoreDSStore) + ); +}; security.isPackageHashIgnored = function (relativePath) { if (!relativePath) { @@ -170,17 +170,18 @@ security.isPackageHashIgnored = function (relativePath) { // .codepushrelease contains code sign JWT // it should be ignored in package hash but need to be included in package manifest - const IgnoreCodePushMetadata = '.codepushrelease'; - return relativePath === IgnoreCodePushMetadata - || relativePath.endsWith(IgnoreCodePushMetadata) - || security.isHashIgnored(relativePath); -} - + const IgnoreCodePushMetadata = ".codepushrelease"; + return ( + relativePath === IgnoreCodePushMetadata || + relativePath.endsWith(IgnoreCodePushMetadata) || + security.isHashIgnored(relativePath) + ); +}; security.calcAllFileSha256 = function (directoryPath) { return new Promise((resolve, reject) => { var recursive = require("recursive-readdir"); - var path = require('path'); + var path = require("path"); var slash = require("slash"); recursive(directoryPath, (error, files) => { if (error) { @@ -194,17 +195,19 @@ security.calcAllFileSha256 = function (directoryPath) { }); if (files.length == 0) { - log.debug(`calcAllFileSha256 empty files in directoryPath:`, directoryPath); + log.debug( + `calcAllFileSha256 empty files in directoryPath:`, + directoryPath + ); reject(new AppError.AppError("empty files")); - }else { - security.sha256AllFiles(files) - .then((results) => { + } else { + security.sha256AllFiles(files).then((results) => { var data = {}; _.forIn(results, (value, key) => { var relativePath = path.relative(directoryPath, key); var matchresult = relativePath.match(/(\/|\\).*/); if (matchresult) { - relativePath = path.join('CodePush', matchresult[0]); + relativePath = path.join("CodePush", matchresult[0]); } relativePath = slash(relativePath); data[relativePath] = value; @@ -216,12 +219,12 @@ security.calcAllFileSha256 = function (directoryPath) { } }); }); -} +}; security.sortJsonToArr = function (json) { var rs = []; _.forIn(json, (value, key) => { - rs.push({path:key, hash: value}) + rs.push({ path: key, hash: value }); }); return _.sortBy(rs, (o) => o.path); -} +}; diff --git a/routes/accessKeys.js b/routes/accessKeys.js index b7239b41..34ddd81c 100644 --- a/routes/accessKeys.js +++ b/routes/accessKeys.js @@ -1,84 +1,94 @@ -var express = require('express'); +var express = require("express"); var router = express.Router(); -var _ = require('lodash'); -var Promise = require('bluebird'); -var security = require('../core/utils/security'); -var models = require('../models'); -var middleware = require('../core/middleware'); -var accountManager = require('../core/services/account-manager')(); -var AppError = require('../core/app-error') -var log4js = require('log4js'); +var _ = require("lodash"); +var security = require("../core/utils/security"); +var models = require("../models"); +var middleware = require("../core/middleware"); +var accountManager = require("../core/services/account-manager")(); +var AppError = require("../core/app-error"); +var log4js = require("log4js"); var log = log4js.getLogger("cps:accessKey"); -router.get('/', middleware.checkToken, (req, res, next) => { - log.debug('request get acceesKeys') +router.get("/", middleware.checkToken, (req, res, next) => { + log.debug("request get acceesKeys"); var uid = req.users.id; - accountManager.getAllAccessKeyByUid(uid) - .then((accessKeys) => { - log.debug('acceesKeys:', accessKeys) - res.send({accessKeys: accessKeys}); - }) - .catch((e) => { - next(e); - }); + accountManager + .getAllAccessKeyByUid(uid) + .then((accessKeys) => { + log.debug("acceesKeys:", accessKeys); + res.send({ accessKeys: accessKeys }); + }) + .catch((e) => { + next(e); + }); }); -router.post('/', middleware.checkToken, (req, res, next) => { +router.post("/", middleware.checkToken, (req, res, next) => { var uid = req.users.id; var identical = req.users.identical; var createdBy = _.trim(req.body.createdBy); var friendlyName = _.trim(req.body.friendlyName); var ttl = parseInt(req.body.ttl); var description = _.trim(req.body.description); - log.debug(req.body) + log.debug(req.body); var newAccessKey = security.randToken(28).concat(identical); - return accountManager.isExsitAccessKeyName(uid, friendlyName) - .then((data) => { - if (!_.isEmpty(data)) { - throw new AppError.AppError(`The access key "${friendlyName}" already exists.`); - } - }) - .then(() => { - return accountManager.createAccessKey(uid, newAccessKey, ttl, friendlyName, createdBy, description); - }) - .then((newToken) => { - var moment = require("moment"); - var info = { - name : newToken.tokens, - createdTime : parseInt(moment(newToken.created_at).format('x')), - createdBy : newToken.created_by, - expires : parseInt(moment(newToken.expires_at).format('x')), - description : newToken.description, - friendlyName: newToken.name, - }; - log.debug(info); - res.send({accessKey:info}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - log.debug(e) - res.status(406).send(e.message); - } else { - next(e); - } - }); + return accountManager + .isExsitAccessKeyName(uid, friendlyName) + .then((data) => { + if (!_.isEmpty(data)) { + throw new AppError.AppError( + `The access key "${friendlyName}" already exists.` + ); + } + }) + .then(() => { + return accountManager.createAccessKey( + uid, + newAccessKey, + ttl, + friendlyName, + createdBy, + description + ); + }) + .then((newToken) => { + var moment = require("moment"); + var info = { + name: newToken.tokens, + createdTime: parseInt(moment(newToken.created_at).format("x")), + createdBy: newToken.created_by, + expires: parseInt(moment(newToken.expires_at).format("x")), + description: newToken.description, + friendlyName: newToken.name, + }; + log.debug(info); + res.send({ accessKey: info }); + }) + .catch((e) => { + if (e instanceof AppError.AppError) { + log.debug(e); + res.status(406).send(e.message); + } else { + next(e); + } + }); }); -router.delete('/:name', middleware.checkToken, (req, res, next) => { +router.delete("/:name", middleware.checkToken, (req, res, next) => { var name = _.trim(decodeURI(req.params.name)); var uid = req.users.id; - return models.UserTokens.destroy({where: {name:name, uid: uid}}) - .then((rowNum) => { - log.debug('delete acceesKey:', name) - res.send({friendlyName:name}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - log.debug(e) - res.status(406).send(e.message); - } else { - next(e); - } - }); + return models.UserTokens.destroy({ where: { name: name, uid: uid } }) + .then((rowNum) => { + log.debug("delete acceesKey:", name); + res.send({ friendlyName: name }); + }) + .catch((e) => { + if (e instanceof AppError.AppError) { + log.debug(e); + res.status(406).send(e.message); + } else { + next(e); + } + }); }); module.exports = router; diff --git a/routes/indexV1.js b/routes/indexV1.js index 498517b4..bf965e2c 100644 --- a/routes/indexV1.js +++ b/routes/indexV1.js @@ -1,42 +1,48 @@ -var express = require('express'); +var express = require("express"); var router = express.Router(); -var Promise = require('bluebird'); -var AppError = require('../core/app-error'); -var middleware = require('../core/middleware'); -var ClientManager = require('../core/services/client-manager'); -var _ = require('lodash'); -var log4js = require('log4js'); +var AppError = require("../core/app-error"); +var ClientManager = require("../core/services/client-manager"); +var _ = require("lodash"); +var log4js = require("log4js"); var log = log4js.getLogger("cps:indexV1"); -router.get('/update_check', (req, res, next) => { +router.get("/update_check", (req, res, next) => { var deploymentKey = _.get(req, "query.deployment_key"); var appVersion = _.get(req, "query.app_version"); var label = _.get(req, "query.label"); - var packageHash = _.get(req, "query.package_hash") - var isCompanion = _.get(req, "query.is_companion") - var clientUniqueId = _.get(req, "query.client_unique_id") + var packageHash = _.get(req, "query.package_hash"); + var isCompanion = _.get(req, "query.is_companion"); + var clientUniqueId = _.get(req, "query.client_unique_id"); var clientManager = new ClientManager(); - log.debug('req.query', req.query); - clientManager.updateCheckFromCache(deploymentKey, appVersion, label, packageHash, clientUniqueId) - .then((rs) => { - //灰度检测 - return clientManager.chosenMan(rs.packageId, rs.rollout, clientUniqueId) - .then((data)=>{ - if (!data) { - rs.isAvailable = false; - return rs; - } - return rs; - }); - }) - .then((rs) => { - delete rs.packageId; - delete rs.rollout; - var update_info = { - download_url : rs.downloadUrl, - description : rs.description, - is_available : rs.isAvailable, - is_disabled : rs.isDisabled, + log.debug("req.query", req.query); + clientManager + .updateCheckFromCache( + deploymentKey, + appVersion, + label, + packageHash, + clientUniqueId + ) + .then((rs) => { + //灰度检测 + return clientManager + .chosenMan(rs.packageId, rs.rollout, clientUniqueId) + .then((data) => { + if (!data) { + rs.isAvailable = false; + return rs; + } + return rs; + }); + }) + .then((rs) => { + delete rs.packageId; + delete rs.rollout; + var update_info = { + download_url: rs.downloadUrl, + description: rs.description, + is_available: rs.isAvailable, + is_disabled: rs.isDisabled, // Note: need to use appVersion here to get it compatible with client side change... // https://github.com/microsoft/code-push/commit/7d2ffff395cc54db98aefba7c67889f509e8c249#diff-a937c637a47cbd31cbb52c89bef7d197R138 target_binary_range: rs.appVersion, @@ -46,46 +52,48 @@ router.get('/update_check', (req, res, next) => { should_run_binary_version: rs.shouldRunBinaryVersion, update_app_version: rs.updateAppVersion, is_mandatory: rs.isMandatory, - }; - res.send({"update_info": update_info}); - }) - .catch((e) => { - if (e instanceof AppError.AppError) { - res.status(404).send(e.message); - } else { - next(e); - } - }); + }; + res.send({ update_info: update_info }); + }) + .catch((e) => { + if (e instanceof AppError.AppError) { + res.status(404).send(e.message); + } else { + next(e); + } + }); }); -router.post('/report_status/download', (req, res) => { - log.debug('req.body', req.body); +router.post("/report_status/download", (req, res) => { + log.debug("req.body", req.body); var clientUniqueId = _.get(req, "body.client_unique_id"); var label = _.get(req, "body.label"); var deploymentKey = _.get(req, "body.deployment_key"); var clientManager = new ClientManager(); - clientManager.reportStatusDownload(deploymentKey, label, clientUniqueId) - .catch((err) => { - if (!err instanceof AppError.AppError) { - console.error(err.stack) - } - }); - res.send('OK'); + clientManager + .reportStatusDownload(deploymentKey, label, clientUniqueId) + .catch((err) => { + if (!err instanceof AppError.AppError) { + console.error(err.stack); + } + }); + res.send("OK"); }); -router.post('/report_status/deploy', (req, res) => { - log.debug('req.body', req.body); +router.post("/report_status/deploy", (req, res) => { + log.debug("req.body", req.body); var clientUniqueId = _.get(req, "body.client_unique_id"); var label = _.get(req, "body.label"); var deploymentKey = _.get(req, "body.deployment_key"); var clientManager = new ClientManager(); - clientManager.reportStatusDeploy(deploymentKey, label, clientUniqueId, req.body) - .catch((err) => { - if (!err instanceof AppError.AppError) { - console.error(err.stack) - } - }); - res.send('OK'); + clientManager + .reportStatusDeploy(deploymentKey, label, clientUniqueId, req.body) + .catch((err) => { + if (!err instanceof AppError.AppError) { + console.error(err.stack); + } + }); + res.send("OK"); }); module.exports = router; diff --git a/test/api/index/index.test.js b/test/api/index/index.test.js index 51f51289..c21bfbab 100644 --- a/test/api/index/index.test.js +++ b/test/api/index/index.test.js @@ -1,216 +1,248 @@ -var app = require('../../../app'); -var request = require('supertest')(app); +var app = require("../../../app"); +var request = require("supertest")(app); var should = require("should"); -var _ = require('lodash'); +var _ = require("lodash"); -describe('api/index/index.test.js', function() { - var account = '522539441@qq.com'; - var password = '123456'; +describe("api/index/index.test.js", function () { + var account = "522539441@qq.com"; + var password = "123456"; var authToken; - var appName = 'Demo-ios'; + var appName = "Demo-ios"; var deploymentKey; var packageHash; var label; - before(function(done){ - request.post('/auth/login') - .send({ - account: account, - password: password - }) - .end(function(err, res) { - should.not.exist(err); - var rs = JSON.parse(res.text); - rs.should.containEql({status:"OK"}); - authToken = (new Buffer(`auth:${_.get(rs, 'results.tokens')}`)).toString('base64'); - done(); - }); - }); - - describe('list apps all deployments', function(done) { - it('should list apps all deployments successful', function(done) { - request.get(`/apps/${appName}/deployments`) - .set('Authorization', `Basic ${authToken}`) - .send() - .end(function(err, res) { + before(function (done) { + request + .post("/auth/login") + .send({ + account: account, + password: password, + }) + .end(function (err, res) { should.not.exist(err); - res.status.should.equal(200); var rs = JSON.parse(res.text); - rs.should.have.properties('deployments'); - rs.deployments.should.be.an.instanceOf(Array); - rs.deployments.should.matchEach(function(it) { - if (_.get(it, 'name') == 'Production') { - deploymentKey = _.get(it, 'key'); - packageHash = _.get(it, 'package.packageHash'); - label = _.get(it, 'package.label'); - } - return it.should.have.properties(['createdTime', 'id', 'key', 'name', 'package']); - }); + rs.should.containEql({ status: "OK" }); + authToken = new Buffer(`auth:${_.get(rs, "results.tokens")}`).toString( + "base64" + ); done(); }); - }); }); - describe('render index views', function(done) { - it('should render index views successful', function(done) { - request.get(`/`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); + describe("list apps all deployments", function (done) { + it("should list apps all deployments successful", function (done) { + request + .get(`/apps/${appName}/deployments`) + .set("Authorization", `Basic ${authToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties("deployments"); + rs.deployments.should.be.an.instanceOf(Array); + rs.deployments.should.matchEach(function (it) { + if (_.get(it, "name") == "Production") { + deploymentKey = _.get(it, "key"); + packageHash = _.get(it, "package.packageHash"); + label = _.get(it, "package.label"); + } + return it.should.have.properties([ + "createdTime", + "id", + "key", + "name", + "package", + ]); + }); + done(); + }); }); }); - describe('render README.md views', function(done) { - it('should render README.md views successful', function(done) { - request.get(`/README.md`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); + describe("render index views", function (done) { + it("should render index views successful", function (done) { + request + .get(`/`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); }); }); - describe('render tokens views', function(done) { - it('should render tokens views successful', function(done) { - request.get(`/tokens`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); + describe("render tokens views", function (done) { + it("should render tokens views successful", function (done) { + request + .get(`/tokens`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); }); }); - describe('authenticated', function(done) { - it('should authenticated successful', function(done) { - request.get(`/authenticated`) - .set('Authorization', `Basic ${authToken}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - done(); - }); + describe("authenticated", function (done) { + it("should authenticated successful", function (done) { + request + .get(`/authenticated`) + .set("Authorization", `Basic ${authToken}`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + done(); + }); }); }); - describe('updateCheck', function(done) { - it('should not updateCheck successful where deploymentKey is empty', function(done) { - request.get(`/updateCheck?deploymentKey=&appVersion=1.0.0&label=&packageHash=`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(404); - res.text.should.equal(`please input deploymentKey and appVersion`); - done(); - }); + describe("updateCheck", function (done) { + it("should not updateCheck successful where deploymentKey is empty", function (done) { + request + .get(`/updateCheck?deploymentKey=&appVersion=1.0.0&label=&packageHash=`) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(404); + res.text.should.equal(`please input deploymentKey and appVersion`); + done(); + }); }); - it('should not updateCheck successful where deploymentKey does not exist', function(done) { - request.get(`/updateCheck?deploymentKey=123&appVersion=1.0.0&label=&packageHash=`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(404); - res.text.should.equal(`Not found deployment, check deployment key is right.`); - done(); - }); + it("should not updateCheck successful where deploymentKey does not exist", function (done) { + request + .get( + `/updateCheck?deploymentKey=123&appVersion=1.0.0&label=&packageHash=` + ) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(404); + res.text.should.equal( + `Not found deployment, check deployment key is right.` + ); + done(); + }); }); - it('should updateCheck successful', function(done) { - request.get(`/updateCheck?deploymentKey=${deploymentKey}&appVersion=1.0.0&label=&packageHash=`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('updateInfo'); - rs.updateInfo.should.have.properties([ - 'downloadURL','description','isAvailable','isMandatory','appVersion', - 'packageHash','label','packageSize','updateAppVersion','shouldRunBinaryVersion' - ]); - rs.updateInfo.isAvailable.should.be.true; - done(); - }); + it("should updateCheck successful", function (done) { + request + .get( + `/updateCheck?deploymentKey=${deploymentKey}&appVersion=1.0.0&label=&packageHash=` + ) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties("updateInfo"); + rs.updateInfo.should.have.properties([ + "downloadURL", + "description", + "isAvailable", + "isMandatory", + "appVersion", + "packageHash", + "label", + "packageSize", + "updateAppVersion", + "shouldRunBinaryVersion", + ]); + rs.updateInfo.isAvailable.should.be.true; + done(); + }); }); - it('should updateCheck successful when packageHash is newer', function(done) { - request.get(`/updateCheck?deploymentKey=${deploymentKey}&appVersion=1.0.0&label=&packageHash=${packageHash}`) - .send() - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - var rs = JSON.parse(res.text); - rs.should.have.properties('updateInfo'); - rs.updateInfo.should.have.properties([ - 'downloadURL','description','isAvailable','isMandatory','appVersion', - 'packageHash','label','packageSize','updateAppVersion','shouldRunBinaryVersion' - ]); - rs.updateInfo.isAvailable.should.be.false; - done(); - }); + it("should updateCheck successful when packageHash is newer", function (done) { + request + .get( + `/updateCheck?deploymentKey=${deploymentKey}&appVersion=1.0.0&label=&packageHash=${packageHash}` + ) + .send() + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + var rs = JSON.parse(res.text); + rs.should.have.properties("updateInfo"); + rs.updateInfo.should.have.properties([ + "downloadURL", + "description", + "isAvailable", + "isMandatory", + "appVersion", + "packageHash", + "label", + "packageSize", + "updateAppVersion", + "shouldRunBinaryVersion", + ]); + rs.updateInfo.isAvailable.should.be.false; + done(); + }); }); }); - describe('reportStatus download', function(done) { - it('should reportStatus download successful', function(done) { - request.post(`/reportStatus/download`) - .send({ - clientUniqueId: Math.random(), - label: label, - deploymentKey:deploymentKey - }) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`OK`); - setTimeout(function(){ - done(); - }, 1000) - }); + describe("reportStatus download", function (done) { + it("should reportStatus download successful", function (done) { + request + .post(`/reportStatus/download`) + .send({ + clientUniqueId: Math.random(), + label: label, + deploymentKey: deploymentKey, + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`OK`); + setTimeout(function () { + done(); + }, 1000); + }); }); }); - describe('reportStatus deploy', function(done) { - it('should reportStatus deploy successful', function(done) { - request.post(`/reportStatus/deploy`) - .send({ - clientUniqueId: Math.random(), - label: label, - deploymentKey: deploymentKey, - status: 'DeploymentSucceeded' - }) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`OK`); - setTimeout(function(){ - done(); - }, 1000) - }); + describe("reportStatus deploy", function (done) { + it("should reportStatus deploy successful", function (done) { + request + .post(`/reportStatus/deploy`) + .send({ + clientUniqueId: Math.random(), + label: label, + deploymentKey: deploymentKey, + status: "DeploymentSucceeded", + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`OK`); + setTimeout(function () { + done(); + }, 1000); + }); }); - it('should reportStatus deploy successful', function(done) { - request.post(`/reportStatus/deploy`) - .send({ - clientUniqueId: Math.random(), - label: label, - deploymentKey: deploymentKey, - status: 'DeploymentFailed' - }) - .end(function(err, res) { - should.not.exist(err); - res.status.should.equal(200); - res.text.should.equal(`OK`); - setTimeout(function(){ - done(); - }, 1000) - }); + it("should reportStatus deploy successful", function (done) { + request + .post(`/reportStatus/deploy`) + .send({ + clientUniqueId: Math.random(), + label: label, + deploymentKey: deploymentKey, + status: "DeploymentFailed", + }) + .end(function (err, res) { + should.not.exist(err); + res.status.should.equal(200); + res.text.should.equal(`OK`); + setTimeout(function () { + done(); + }, 1000); + }); }); }); });