├── .gitignore ├── LICENSE ├── README.md ├── step0 ├── .gitignore ├── README.md ├── app │ ├── api │ │ ├── service │ │ │ ├── connect.service.js │ │ │ └── user.service.js │ │ ├── util │ │ │ ├── authorize.checker.js │ │ │ ├── error.handler.js │ │ │ ├── hash.creator.js │ │ │ ├── param.checker.js │ │ │ ├── return.msg.js │ │ │ └── test │ │ │ │ └── hash.creator.spec.js │ │ └── v1 │ │ │ ├── connect │ │ │ ├── connect.controller.js │ │ │ └── connect.router.js │ │ │ └── user │ │ │ ├── user.controller.js │ │ │ └── user.router.js │ ├── config │ │ └── environment.js │ ├── index.js │ ├── model │ │ ├── mysql.connection.js │ │ ├── userConnectInfo.js │ │ └── userInfo.js │ └── models.js ├── bin │ ├── sync-database.js │ └── www.js ├── package-lock.json └── package.json ├── step0_1 ├── .eslintrc.js ├── .gitignore ├── .lintgnore ├── app │ ├── index.js │ ├── middleware │ │ ├── acao.js │ │ ├── bodyparser.js │ │ ├── bodyparser.urlencoded.js │ │ ├── cookiparser.js │ │ ├── defauleRoute.middleware.js │ │ └── index.js │ └── routes │ │ ├── api │ │ └── v1 │ │ │ ├── connection │ │ │ ├── controller │ │ │ │ ├── createConnection.js │ │ │ │ ├── deleteConnection.js │ │ │ │ ├── getClientSalt.js │ │ │ │ └── updateConnection.js │ │ │ ├── index.js │ │ │ ├── middleware │ │ │ │ └── loginValidation.js │ │ │ └── validate │ │ │ │ ├── index.js │ │ │ │ └── rules.js │ │ │ └── user │ │ │ ├── controller │ │ │ ├── createUser.js │ │ │ ├── createUserInit.js │ │ │ └── showUser.js │ │ │ ├── index.js │ │ │ ├── middleware │ │ │ └── duplicationCheckByUser.js │ │ │ └── validate │ │ │ ├── index.js │ │ │ └── rules.js │ │ ├── index.js │ │ ├── routeLib │ │ ├── hash │ │ │ └── hash.creator.js │ │ ├── index.js │ │ ├── response │ │ │ ├── error.handler.js │ │ │ ├── error.js │ │ │ ├── responseCode.js │ │ │ └── responseMessage.js │ │ └── validate │ │ │ ├── rules.js │ │ │ └── validateFunc.js │ │ └── routeMiddleware │ │ ├── authorize.checker.js │ │ └── index.js ├── config │ └── db.config.json ├── db │ ├── index.js │ ├── model │ │ ├── index.js │ │ ├── user.js │ │ └── userConnection.js │ └── service │ │ ├── index.js │ │ ├── user.service.js │ │ └── userConnection.service.js ├── index.js ├── package-lock.json └── package.json ├── step1-express ├── README.md ├── app │ └── index.js ├── bin │ └── www.js └── package.json └── step2-https ├── README.md ├── app └── index.js ├── bin └── www.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | .idea 40 | 41 | sam-node-study-* 42 | 43 | config.json 44 | key -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 rosd89 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sam-node-study 2 | 3 | ### 회원가입 4 | 5 | * id: 유저 ID - pk 6 | * serverSalt: 2차 Hash를 만들기 위한 salt 값 7 | * clientSalt: 1차 Hash를 만들기 위한 salt 값 8 | * hashToken: 2차 Hash 9 | * userName: 유저이름 10 | * userAge: 유저나이 11 | * userEmail: 유저 이메일 주소 12 | * createdAt: 생성일 13 | * updatedAt: 업데이트날짜 14 | 15 | ``` 16 | 회원가입 시작 17 | # client --------------------------------------------------------------------------- # server 18 | 19 | step 1: init api 호출 -- param - userId ----------------------------------------------------> middleware - id중복체크 20 | 21 | <- http status code 400, return body: {"errorCode": -3, "data": 'userId'}-- 중복이라면 22 | 23 | 24 | 중복이 아니라면 clientSalt 생성, serverSalt생성 25 | 생성된 값을 유저DB에 저장 26 | <- http status code 200, return body: {"salt": "salt value" --------------- client에 clientSalt 전달 27 | 28 | 29 | step 2: 비밀번호와 clientSalt를 바탕으로 1차HASH를 생성 30 | create api 호출 -- param - 유저정보, 1차HASH -------------------------------------------> 1차HASH와 serverSalt를 바탕으로 2차HASH를 생성 31 | 2차HASH와 유저정보를 업데이트 32 | <- http status code 201 ---------------------------------------------------- 33 | 34 | 회원 가입 완료 35 | ``` 36 | 37 | ### 로그인 38 | 39 | * userId: 유저 ID 40 | * accesToken: 인증키 41 | * expiredTime: 만료시간 42 | 43 | ``` 44 | 로그인 시작 45 | # client --------------------------------------------------------------------------- # server 46 | step 1: getSalt api 호출 -- param - userId --------------------------------------------------> 47 | 48 | <- http status code 200, return body: {"salt": "salt value" --------------- 유저DB를 조회해서 clientSalt값 전달 49 | 50 | step 2: 비밀번호와 clientSalt를 바탕으로 1차HASH를 생성 51 | 로그인 api 호출 -- param - userID, 1차HASH --------------------------------------------- 1차HASH와 serverSalt를 바탕으로 2차HASH를 생성 hash 값을 비교 52 | 53 | <- 54 | -------------------------------------------------------------------------------- /step0/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /step0/README.md: -------------------------------------------------------------------------------- 1 | 출처) [http://blog.saltfactory.net/implements-nodejs-based-https-server/](http://blog.saltfactory.net/implements-nodejs-based-https-server/) -------------------------------------------------------------------------------- /step0/app/api/service/connect.service.js: -------------------------------------------------------------------------------- 1 | const {sequelize, UserConnectInfo} = require('../../models'); 2 | 3 | /** 4 | * 유저 접속 기록 조회 Service 5 | * 6 | * @param where 7 | */ 8 | exports.findOneConnection = where => UserConnectInfo.findOne({where}); 9 | 10 | /** 11 | * 유저 접속 기록 추가 Service 12 | * 13 | * @param connect 14 | */ 15 | exports.createConnection = connect => UserConnectInfo.create(connect); 16 | 17 | /** 18 | * 유저 접속 기록 삭제 Service 19 | * 20 | * @param where 21 | */ 22 | exports.destroyConnection = where => UserConnectInfo.destroy({where}); -------------------------------------------------------------------------------- /step0/app/api/service/user.service.js: -------------------------------------------------------------------------------- 1 | const {UserInfo} = require('../../models'); 2 | 3 | /** 4 | * 유저 정보 조회 Service 5 | * 6 | * @param where 7 | */ 8 | exports.findOneUser = (attributes, where) => UserInfo.findOne({attributes, where}); 9 | 10 | /** 11 | * 유저 정보 추가 Service 12 | * 13 | * @param user 14 | */ 15 | exports.createUser = user => UserInfo.create(user); -------------------------------------------------------------------------------- /step0/app/api/util/authorize.checker.js: -------------------------------------------------------------------------------- 1 | const {getExpiredTime} = require('../util/hash.creator'); 2 | const {tpcm, tpci, pcc, f} = require('./param.checker'); 3 | 4 | const {findOneConnection} = require('../service/connect.service'); 5 | 6 | /** 7 | * 인증키 체크 Middleware 8 | * 9 | * @param req 10 | * @param res 11 | * @param next 12 | */ 13 | module.exports = (req, res, next) => { 14 | let accessToken = req.body.accessToken || req.query.accessToken || tpcm('accessToken'); 15 | if (accessToken.length !== 64) tpci('accessToken'); 16 | 17 | findOneConnection({accessToken}).then(connection => { 18 | if (!connection) return next(pcc()); 19 | 20 | const timeNum = connection.expiredTime.getTime() - new Date().getTime(); 21 | if (timeNum < 0) return next(f()); 22 | 23 | //인증시간 갱신 24 | connection.expiredTime = getExpiredTime(); 25 | connection.save().then(connection => { 26 | //console.log('expired time refresh = ' + connection.dataValues.expiredTime); 27 | }); 28 | 29 | req.body.connectUserId = connection.userId; 30 | 31 | next(); 32 | }); 33 | }; -------------------------------------------------------------------------------- /step0/app/api/util/error.handler.js: -------------------------------------------------------------------------------- 1 | const errorCodeMap = { 2 | // Client ErrorCode 3 | ERROR_UNKNOWN: 0, 4 | ERROR_MISSING_PARAM: -1, 5 | ERROR_INVALID_PARAM: -2, 6 | ERROR_DUPLICATE: -3, 7 | ERROR_INVALID_ACCESS_TOKEN: -6, 8 | ERROR_NO_CONNECTION: -7, 9 | }; 10 | 11 | // 400 - 인자값 누락 12 | exports.error400InvalidCall = (res, errorCode, data) => { 13 | const resBody = { 14 | errorCode: errorCodeMap[errorCode], 15 | data: data 16 | }; 17 | 18 | res.body = JSON.stringify(resBody); 19 | return res.status(400).json(resBody); 20 | }; 21 | 22 | // 401 - 리소스 접근권한 없음 23 | exports.error401Unauthorized = res => res.status(401).json({}); 24 | 25 | // 403 - 리소스 접근권한 만료 26 | exports.error403Expired = res => res.status(403).json({}); 27 | 28 | // 404 - 리로스 없음 29 | exports.error404NotFound = res => res.status(404).json({}); 30 | 31 | module.exports = (err, req, res, next) => { 32 | const {statusCode, errorCode, data} = err; 33 | if (statusCode === 400) { 34 | return this.error400InvalidCall(res, errorCode, data); 35 | } 36 | else if (statusCode === 401) { 37 | return this.error401Unauthorized(res); 38 | } 39 | else if (statusCode === 403) { 40 | return this.error403Expired(res); 41 | } 42 | else if (statusCode === 404) { 43 | return this.error404NotFound(res); 44 | } 45 | else{ 46 | console.log(err); 47 | return this.error404NotFound(res); 48 | } 49 | }; -------------------------------------------------------------------------------- /step0/app/api/util/hash.creator.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const uuid = require('node-uuid'); 3 | 4 | const iv = new Buffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 5 | 6 | /** 7 | * salt값 생성 8 | * 9 | * @param _ 10 | */ 11 | exports.getSalt = _ => crypto.createHash('sha256').update(uuid.v1()).digest('hex'); 12 | 13 | /** 14 | * hash값 생성 15 | * 16 | * @param hash 17 | * @param salt 18 | */ 19 | exports.getHash = (hash, salt) => crypto.pbkdf2Sync(hash, salt, 10000, 32, 'sha256').toString('hex'); 20 | 21 | /** 22 | * 인증만료시간 생성 23 | * 24 | * @param _ 25 | */ 26 | exports.getExpiredTime = _ => { 27 | const expiredTime = new Date(); 28 | return expiredTime.setMinutes(expiredTime.getMinutes() + 120); 29 | }; -------------------------------------------------------------------------------- /step0/app/api/util/param.checker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Parameter Checker - Missing 3 | * 4 | * @param v 5 | */ 6 | exports.pcm = v => ({statusCode: 400, errorCode: 'ERROR_MISSING_PARAM', data: v}); 7 | 8 | /** 9 | * throw Parameter Checker - Missing 10 | * 11 | * @param v 12 | */ 13 | exports.tpcm = v => { 14 | throw this.pcm(v); 15 | }; 16 | 17 | /** 18 | * Parameter Checker - Invalid 19 | * 20 | * @param v 21 | */ 22 | exports.pci = v => ({statusCode: 400, errorCode: 'ERROR_INVALID_PARAM', data: v}); 23 | 24 | /** 25 | * throw Parameter Checker - Invalid 26 | * 27 | * @param v 28 | */ 29 | exports.tpci = v => { 30 | throw this.pci(v); 31 | }; 32 | 33 | /** 34 | * Parameter Checker - Duplicate 35 | * 36 | * @param v 37 | */ 38 | exports.pcd = v => ({statusCode: 400, errorCode: 'ERROR_DUPLICATE', data: v}); 39 | 40 | /** 41 | * throw Parameter Checker - Duplicate 42 | * 43 | * @param v 44 | */ 45 | exports.tpcd = v => { 46 | throw this.pcd(v); 47 | }; 48 | 49 | /** 50 | * Parameter Checker - No Connection 51 | * 52 | * @param _ 53 | */ 54 | exports.pcc = _ => ({statusCode: 400, errorCode: 'ERROR_NO_CONNECTION'}); 55 | 56 | /** 57 | * throw Parameter Checker - No Connection 58 | * 59 | * @param _ 60 | */ 61 | exports.tpcc = _ => { 62 | throw this.pcc(); 63 | }; 64 | 65 | /** 66 | * Parameter Checker 67 | * 68 | * @param errorCode 69 | * @param data 70 | */ 71 | exports.pc = (errorCode, data) => ({statusCode: 400, errorCode, data}); 72 | 73 | /** 74 | * throw Parameter Checker 75 | * 76 | * @param errorCode 77 | * @param data 78 | */ 79 | exports.tpc = (errorCode, data) => { 80 | throw this.pc(errorCode, data); 81 | }; 82 | 83 | /** 84 | * 401 Unauthorized 85 | * 86 | * @param _ 87 | */ 88 | exports.u = _ => ({statusCode: 401}); 89 | 90 | /** 91 | * throw 401 Unauthorized 92 | * 93 | * @param _ 94 | */ 95 | exports.tu = _ => { 96 | throw this.u(); 97 | }; 98 | 99 | /** 100 | * 403 Forbidden 101 | * 102 | * @param _ 103 | */ 104 | exports.f = _ => ({statusCode: 403}); 105 | 106 | /** 107 | * throw 403 Forbidden 108 | * 109 | * @param _ 110 | */ 111 | exports.tf = _ => { 112 | throw this.f(); 113 | }; 114 | 115 | /** 116 | * 404 Not Found 117 | * 118 | * @param _ 119 | */ 120 | exports.nf = _ => ({statusCode: 404}); 121 | 122 | /** 123 | * throw 404 Not Found 124 | * 125 | * @param _ 126 | */ 127 | exports.tnf = _ => { 128 | throw this.nf(); 129 | }; 130 | 131 | /** 132 | * json validation 133 | * 134 | * @param v 135 | * @returns {boolean} 136 | */ 137 | exports.jsonValidation = v => { 138 | try { 139 | return JSON.parse(v); 140 | } 141 | catch (e) { 142 | return false; 143 | } 144 | }; 145 | 146 | /** 147 | * undefined 체크 148 | * 149 | * @param v 150 | */ 151 | exports.isUndefined = v => v === undefined; -------------------------------------------------------------------------------- /step0/app/api/util/return.msg.js: -------------------------------------------------------------------------------- 1 | // 200 - success 2 | exports.success200 = res => res.status(200).json({}); 3 | 4 | // 200 - return Model 5 | exports.success200RetObj = (res, obj) => { 6 | res.body = JSON.stringify(obj); 7 | return res.status(200).json(obj); 8 | }; 9 | 10 | // 201 - create 11 | exports.success201 = res => res.status(201).json({}); 12 | 13 | // 201 - return Model 14 | exports.success201RetObj = (res, obj) => { 15 | res.body = JSON.stringify(obj); 16 | return res.status(201).json(obj); 17 | }; 18 | 19 | // 204 - delete 20 | exports.success204 = res => res.status(204).send(); -------------------------------------------------------------------------------- /step0/app/api/util/test/hash.creator.spec.js: -------------------------------------------------------------------------------- 1 | require('should'); 2 | 3 | const crypto = require('crypto'); 4 | const uuid = require('node-uuid'); 5 | 6 | const {getSalt, getHash, getExpiredTime} = require('../hash.creator'); 7 | 8 | describe('암호화 모듈 테스트', _ => { 9 | const testData_pass = 'password'; 10 | const testData_salt = 'ee90b870f73fd520876367d467e8cff89742e0ab606334a9853b7b87e0c79084'; 11 | const testData_hash = '6ae62531db312043b335a025f8898a3e05fb5985398be5e56c02cbc3c35f6457'; 12 | 13 | it('암호화 모듈 테스트 1 - uuid 생성', () => { 14 | uuid.v1().length.should.be.equal(36); 15 | }); 16 | 17 | it('암호화 모듈 테스트 2 - slat 생성', () => { 18 | const salt = crypto.createHash('sha256').update(uuid.v1()).digest('hex'); 19 | salt.length.should.be.equal(64); 20 | }); 21 | 22 | it('암호화 모듈 테스트 3 - getSlat 함수 테스트', () => { 23 | const salt = getSalt(); 24 | salt.length.should.be.equal(64); 25 | }); 26 | 27 | it('암호화 모듈 테스트 4 - hash 생성', () => { 28 | const hash = crypto.pbkdf2Sync(testData_pass, testData_salt, 10000, 32, 'sha256').toString('hex'); 29 | hash.length.should.be.equal(64); 30 | hash.should.be.equal(testData_hash); 31 | }); 32 | 33 | it('암호화 모듈 테스트 5 - getHash 함수 테스트', () => { 34 | const hash = getHash(testData_pass, testData_salt); 35 | hash.length.should.be.equal(64); 36 | hash.should.be.equal(testData_hash); 37 | }); 38 | 39 | it('암호화 모듈 테스트 6 - expired Time 생성', () => { 40 | const expiredTime = new Date(); 41 | const thisTime = expiredTime.getTime(); 42 | expiredTime.setMinutes(expiredTime.getMinutes() + 120); 43 | 44 | (expiredTime.getTime() - thisTime).should.be.equal(1000 * 60 * 60 * 2); 45 | }); 46 | 47 | it('암호화 모듈 테스트 7 - getExpiredTime 함수 테스트', () => { 48 | const expiredTime = getExpiredTime(); 49 | 50 | (expiredTime - Date.now()).should.be.lessThanOrEqual(1000 * 60 * 60 * 2); 51 | }); 52 | }); -------------------------------------------------------------------------------- /step0/app/api/v1/connect/connect.controller.js: -------------------------------------------------------------------------------- 1 | const co = require('co'); 2 | 3 | const retMsg = require('../../util/return.msg.js'); 4 | const {getSalt, getHash, getExpiredTime} = require('../../util/hash.creator'); 5 | const {tpcm, tpci, tpcc, tnf, tu} = require('../../util/param.checker'); 6 | 7 | const {findOneUser} = require('../../service/user.service'); 8 | const {findOneConnection, createConnection, destroyConnection} = require('../../service/connect.service'); 9 | 10 | /** 11 | * clientSalt 가져오기 Controller 12 | * 13 | * @param req 14 | * @param res 15 | */ 16 | exports.getClientSalt = (req, res) => co(function* () { 17 | const {userId: id} = req.query; 18 | const user = yield findOneUser(undefined, {id}); 19 | 20 | if (!user) { 21 | return retMsg.success200RetObj(res, { 22 | salt: getSalt() 23 | }); 24 | } 25 | 26 | return retMsg.success200RetObj(res, { 27 | salt: user.clientSalt 28 | }) 29 | }); 30 | 31 | /** 32 | * 로그인 인증 확인 Middleware 33 | * 34 | * @param req 35 | * @param res 36 | * @param next 37 | */ 38 | exports.loginValidation = (req, res, next) => co(function* () { 39 | const {userId: id = tpcm('userId'), hash: hash1st = tpcm('hash')} = req.body; 40 | if (hash1st.length === '64') tpci('hash'); 41 | 42 | const user = yield findOneUser(undefined, {id}); 43 | 44 | if (!user) tnf(); 45 | 46 | const {serverSalt, hashToken} = user; 47 | const hash2nd = getHash(hash1st, serverSalt); 48 | if (hashToken !== hash2nd) tu(); 49 | 50 | return next(); 51 | }).catch(err => { 52 | console.log(err); 53 | next(err); 54 | }); 55 | 56 | /** 57 | * 로그인 Controller 58 | * 59 | * @param req 60 | * @param res 61 | */ 62 | exports.create = (req, res) => co(function* () { 63 | const {userId} = req.body; 64 | 65 | yield destroyConnection({userId}); 66 | const {accessToken} = yield createConnection({ 67 | userId, 68 | accessToken: getSalt(), 69 | expiredTime: getExpiredTime() 70 | }); 71 | 72 | return retMsg.success200RetObj(res, {accessToken}); 73 | }); 74 | 75 | /** 76 | * 로그인 갱신 Controller 77 | * 78 | * @param req 79 | * @param res 80 | * @param next 81 | */ 82 | exports.update = (req, res, next) => co(function* () { 83 | const {userId} = req.body; 84 | const connection = findOneConnection({userId}); 85 | 86 | if(!connection) tpcc(); 87 | 88 | // 인증정보 갱신 89 | const accessToken = getSalt(); 90 | connection.accessToken = accessToken; 91 | connection.expiredTime = getExpiredTime(); 92 | 93 | yield connection.save(); 94 | 95 | retMsg.success200RetObj(res, {accessToken}); 96 | }).catch(err => { 97 | console.log(err); 98 | next(err); 99 | }); 100 | 101 | /** 102 | * 로그아웃 Controller 103 | * 104 | * @param res 105 | * @param req 106 | */ 107 | exports.destroy = (req, res) => co(function* () { 108 | const {accessToken} = req.body; 109 | const result = yield destroyConnection({accessToken}); 110 | 111 | retMsg.success204(res); 112 | }); -------------------------------------------------------------------------------- /step0/app/api/v1/connect/connect.router.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const { 4 | getClientSalt, loginValidation, create, update, destroy 5 | } = require('./connect.controller'); 6 | 7 | const auth = require('../../util/authorize.checker'); 8 | 9 | // client salt 가져오기 10 | router.get('/salt', getClientSalt); 11 | 12 | // 로그인 13 | router.post('/', loginValidation, create); 14 | 15 | // 로그인 갱신 16 | router.put('/', loginValidation, update); 17 | 18 | // 로그아웃 19 | router.delete('/', auth, destroy); 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /step0/app/api/v1/user/user.controller.js: -------------------------------------------------------------------------------- 1 | const co = require('co'); 2 | 3 | const retMsg = require('../../util/return.msg'); 4 | const {getSalt, getHash} = require('../../util/hash.creator'); 5 | const {tpcm, tpci, tpcd, nf, tnf} = require('../../util/param.checker'); 6 | 7 | const {findOneUser, createUser} = require('../../service/user.service'); 8 | 9 | /** 10 | * 유저 정보 조회 Controller 11 | * 12 | * @param req 13 | * @param res 14 | * @param next 15 | */ 16 | exports.index = ({params: {userId: id}, res, next}) => co(function* () { 17 | const user = yield findOneUser( 18 | ['id', 'userName', 'userAge', 'userEmail'], 19 | {id} 20 | ); 21 | 22 | if (!user) return next(nf()); 23 | 24 | return retMsg.success200RetObj(res, user); 25 | }); 26 | 27 | /** 28 | * 유저 등록 init Controller 29 | * 30 | * @param req 31 | * @param res 32 | */ 33 | exports.init = (req, res) => { 34 | const {userId: id} = req.body; 35 | 36 | const clientSalt = getSalt(); 37 | const serverSalt = getSalt(); 38 | 39 | // 유저데이터를 추가 40 | // return값은 clientSalt만 보냄 41 | 42 | const {clientSalt: salt} = createUser({id, clientSalt, serverSalt}); 43 | 44 | return retMsg.success200RetObj(res, {salt}); 45 | }; 46 | 47 | /** 48 | * 유저 등록 create Controller 49 | * 50 | * @param req 51 | * @param res 52 | */ 53 | exports.create = (req, res, next) => co(function* () { 54 | const {userId: id} = req.params; 55 | 56 | const { 57 | hash = tpcm('hash'), 58 | userName = 'NONE', 59 | userAge = 0, 60 | userEmail = 'NONE' 61 | } = req.body; 62 | 63 | // hash 정보체크 64 | // 유저정보는 선택사항이기 때문에 입력값이 없으면 정보없음으로 처리 65 | // 단 나이정보는 intteger이기 때문에 0으로 처 66 | if (hash.length === '64') tpci('hash'); 67 | 68 | const user = yield findOneUser(undefined, {id}); 69 | 70 | if(!user) tnf() 71 | 72 | // 2차 hash 생성 73 | const secondHash = getHash(hash, user.serverSalt); 74 | 75 | user.hashToken = secondHash; 76 | user.userName = userName; 77 | user.userAge = userAge; 78 | user.userEmail = userEmail; 79 | 80 | const result = yield user.save(); 81 | console.log(result); 82 | 83 | return retMsg.success201(res); 84 | }).catch(err => { 85 | console.log(err); 86 | next(err); 87 | }); 88 | 89 | /** 90 | * 유저 ID 중복체크 91 | * 92 | * @param req 93 | * @param res 94 | * @param next 95 | */ 96 | exports.duplicationCheckByUser = (req, res, next) => co(function* () { 97 | const {userId: id = tpcm('userId')} = req.body; 98 | const user = yield findOneUser(undefined, {id}); 99 | 100 | if(!user) return next(); 101 | 102 | next(tpcd('userId')); 103 | }).catch(err => { 104 | console.log(err); 105 | next(err); 106 | }); -------------------------------------------------------------------------------- /step0/app/api/v1/user/user.router.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const {duplicationCheckByUser, index, init, create} = require('./user.controller'); 5 | 6 | // 유저 정보 조회 API 7 | router.get('/:userId', index); 8 | 9 | // 유저 등록 init API 10 | router.post('/', duplicationCheckByUser, init); 11 | 12 | // 유저 등록 create API 13 | router.post('/:userId', create); 14 | 15 | module.exports = router; -------------------------------------------------------------------------------- /step0/app/config/environment.js: -------------------------------------------------------------------------------- 1 | const environments = require('./config.json'); 2 | 3 | module.exports = environments[process.env.NODE_ENV || 'dev']; -------------------------------------------------------------------------------- /step0/app/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | 4 | const app = express(); 5 | 6 | app.use(bodyParser.json()); // for parsing application/json 7 | app.use(bodyParser.urlencoded({ 8 | extended: true 9 | })); // for parsing applic ation/x-www-form-urlencoded 10 | 11 | app.use('/v1/users', require('./api/v1/user/user.router')); 12 | app.use('/v1/connections', require('./api/v1/connect/connect.router')); 13 | 14 | // not call Web API 15 | app.use((req, res) => { 16 | res.status(404).send(); 17 | }); 18 | 19 | /** 20 | * Error Handler 21 | */ 22 | const error = require('./api/util/error.handler'); 23 | app.use(error); 24 | 25 | module.exports = app; -------------------------------------------------------------------------------- /step0/app/model/mysql.connection.js: -------------------------------------------------------------------------------- 1 | const sequelize = require('sequelize'); 2 | const {database, dialect, username, password, host, port} = require('../config/environment'); 3 | 4 | const db = new sequelize( 5 | database, username, password, 6 | { 7 | host, dialect, port, 8 | logging: msg => console.log(msg) 9 | } 10 | ); 11 | 12 | module.exports = db; -------------------------------------------------------------------------------- /step0/app/model/userConnectInfo.js: -------------------------------------------------------------------------------- 1 | const sequelize = require('sequelize'); 2 | const db = require('./mysql.connection'); 3 | 4 | const UserConnectInfo = db.define('userConnectInfo', 5 | { 6 | userId: { 7 | type: sequelize.STRING(45), 8 | primaryKey: true, 9 | references: { 10 | model: 'userInfo', 11 | key: 'id' 12 | } 13 | }, 14 | accessToken: sequelize.CHAR(64), 15 | expiredTime: sequelize.DATE 16 | }, 17 | { 18 | createdAt: false, 19 | updatedAt: false, 20 | tableName: 'userConnectInfo', 21 | indexes: [ 22 | {fields: ['accessToken']} 23 | ] 24 | } 25 | ); 26 | 27 | module.exports = UserConnectInfo; -------------------------------------------------------------------------------- /step0/app/model/userInfo.js: -------------------------------------------------------------------------------- 1 | const sequelize = require('sequelize'); 2 | const db = require('./mysql.connection'); 3 | 4 | /** 5 | * Table: userInfo 6 | * 7 | * id: 유저 ID - pk 8 | * 9 | * serverSalt: 2차 Hash를 만들기 위한 salt 값 10 | * clientSalt: 1차 Hash를 만들기 위한 salt 값 11 | * hashToken: 2차 Hash 12 | * 13 | * userName: 유저이름 14 | * userAge: 유저나이 15 | * userEmail: 유저 이메일 주소 16 | * 17 | * @type {*} 18 | */ 19 | const UserInfo = db.define('userInfo', 20 | { 21 | id: { 22 | type: sequelize.STRING(45), 23 | primaryKey: true 24 | }, 25 | serverSalt: sequelize.CHAR(64), 26 | clientSalt: sequelize.CHAR(64), 27 | hashToken: sequelize.CHAR(64), 28 | userName: sequelize.STRING(32), 29 | userAge: sequelize.INTEGER, 30 | userEmail: sequelize.STRING 31 | }, 32 | { 33 | tableName: 'userInfo' 34 | } 35 | ); 36 | 37 | module.exports = UserInfo; -------------------------------------------------------------------------------- /step0/app/models.js: -------------------------------------------------------------------------------- 1 | const db = require('./model/mysql.connection'); 2 | 3 | /** 4 | * MODEL 5 | */ 6 | const UserInfo = require('./model/userInfo'); 7 | const UserConnectInfo = require('./model/userConnectInfo'); 8 | 9 | UserInfo.hasOne(UserConnectInfo, { 10 | foreignKey: 'userId', 11 | constraints: false 12 | }); 13 | 14 | UserConnectInfo.belongsTo(UserInfo, { 15 | foreignKey: 'userId', 16 | constraints: false 17 | }); 18 | 19 | module.exports = { 20 | db, 21 | UserInfo, 22 | UserConnectInfo 23 | }; -------------------------------------------------------------------------------- /step0/bin/sync-database.js: -------------------------------------------------------------------------------- 1 | const models = require('../app/models'); 2 | 3 | /* 4 | force : true 서버 재시작시 데이터 초기화 5 | false 서버 재시작시 데이터 유지 6 | */ 7 | module.exports = () => { 8 | return models.sequelize.sync({force: false}) 9 | }; -------------------------------------------------------------------------------- /step0/bin/www.js: -------------------------------------------------------------------------------- 1 | const https = require('https'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | const app = require('../app'); 6 | const port = 3000; 7 | 8 | const dir = path.resolve(__dirname, '../'); 9 | global.$dir = dir; 10 | 11 | const options = { 12 | key: fs.readFileSync(`${dir}/key/key.pem`, 'utf-8'), 13 | cert: fs.readFileSync(`${dir}/key/cert.pem`, 'utf-8') 14 | }; 15 | 16 | https.createServer(options, app).listen(port, _ => { 17 | console.log(`{{Server Start}}-NODE_ENV[${process.env.NODE_ENV}]-PORT[${port}]`); 18 | }); -------------------------------------------------------------------------------- /step0/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step1-express-https", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/geojson": { 8 | "version": "1.0.4", 9 | "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-1.0.4.tgz", 10 | "integrity": "sha512-idP+xKlqFG1egc5M52mDat/Z0VMrwY93LCd81dzW/IjeTIYTMWuzVu+fBf19QK/mX9K7jM2UNN5nzDRgM950GA==" 11 | }, 12 | "@types/node": { 13 | "version": "8.0.32", 14 | "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.32.tgz", 15 | "integrity": "sha512-n1zzgeQehndikZc/8N4rGSZc99cO6Tb3OInKzvWYniJsT/jet3m57buaBFa5cMeVNFosN4PKZ2LM1y16CFD7Rg==" 16 | }, 17 | "accepts": { 18 | "version": "1.3.4", 19 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", 20 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", 21 | "requires": { 22 | "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 23 | "negotiator": "0.6.1" 24 | } 25 | }, 26 | "ansicolors": { 27 | "version": "0.2.1", 28 | "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz", 29 | "integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=" 30 | }, 31 | "array-flatten": { 32 | "version": "1.1.1", 33 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 34 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 35 | }, 36 | "asynckit": { 37 | "version": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 38 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 39 | "dev": true 40 | }, 41 | "balanced-match": { 42 | "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 43 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 44 | "dev": true 45 | }, 46 | "bluebird": { 47 | "version": "3.5.1", 48 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 49 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" 50 | }, 51 | "body-parser": { 52 | "version": "1.18.2", 53 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 54 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 55 | "requires": { 56 | "bytes": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 57 | "content-type": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 58 | "debug": "2.6.9", 59 | "depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 60 | "http-errors": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 61 | "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 62 | "on-finished": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 63 | "qs": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 64 | "raw-body": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 65 | "type-is": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz" 66 | }, 67 | "dependencies": { 68 | "debug": { 69 | "version": "2.6.9", 70 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 71 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 72 | "requires": { 73 | "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 74 | } 75 | } 76 | } 77 | }, 78 | "brace-expansion": { 79 | "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 80 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 81 | "dev": true, 82 | "requires": { 83 | "balanced-match": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 84 | "concat-map": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 85 | } 86 | }, 87 | "browser-stdout": { 88 | "version": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", 89 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", 90 | "dev": true 91 | }, 92 | "bytes": { 93 | "version": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 94 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 95 | }, 96 | "cardinal": { 97 | "version": "1.0.0", 98 | "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz", 99 | "integrity": "sha1-UOIcGwqjdyn5N33vGWtanOyTLuk=", 100 | "requires": { 101 | "ansicolors": "0.2.1", 102 | "redeyed": "1.0.1" 103 | } 104 | }, 105 | "cls-bluebird": { 106 | "version": "2.0.1", 107 | "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.0.1.tgz", 108 | "integrity": "sha1-wlmkgK4CwOUGE0MHuxPbMERu4uc=", 109 | "requires": { 110 | "is-bluebird": "1.0.2", 111 | "shimmer": "1.1.0" 112 | } 113 | }, 114 | "co": { 115 | "version": "4.6.0", 116 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 117 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 118 | }, 119 | "combined-stream": { 120 | "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", 121 | "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", 122 | "dev": true, 123 | "requires": { 124 | "delayed-stream": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" 125 | } 126 | }, 127 | "commander": { 128 | "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", 129 | "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", 130 | "dev": true, 131 | "requires": { 132 | "graceful-readlink": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" 133 | } 134 | }, 135 | "component-emitter": { 136 | "version": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 137 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", 138 | "dev": true 139 | }, 140 | "concat-map": { 141 | "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 142 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 143 | "dev": true 144 | }, 145 | "content-disposition": { 146 | "version": "0.5.2", 147 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 148 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 149 | }, 150 | "content-type": { 151 | "version": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 152 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 153 | }, 154 | "cookie": { 155 | "version": "0.3.1", 156 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 157 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 158 | }, 159 | "cookie-signature": { 160 | "version": "1.0.6", 161 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 162 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 163 | }, 164 | "cookiejar": { 165 | "version": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", 166 | "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=", 167 | "dev": true 168 | }, 169 | "core-util-is": { 170 | "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 171 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 172 | }, 173 | "debug": { 174 | "version": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", 175 | "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", 176 | "requires": { 177 | "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 178 | } 179 | }, 180 | "delayed-stream": { 181 | "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 182 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 183 | "dev": true 184 | }, 185 | "denque": { 186 | "version": "1.2.2", 187 | "resolved": "https://registry.npmjs.org/denque/-/denque-1.2.2.tgz", 188 | "integrity": "sha512-x92Ql74lcTbGylXILO9Xf9S0cMpEPP04zVp2bB9e2C7G/n/Q1SgLl78RaSYEPSgpDX9uLgQXCEGAS5BI5dP3yA==" 189 | }, 190 | "depd": { 191 | "version": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 192 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 193 | }, 194 | "destroy": { 195 | "version": "1.0.4", 196 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 197 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 198 | }, 199 | "diff": { 200 | "version": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", 201 | "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", 202 | "dev": true 203 | }, 204 | "dottie": { 205 | "version": "2.0.0", 206 | "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.0.tgz", 207 | "integrity": "sha1-2hkZgci41xPKARXViYzzl8Lw3dA=" 208 | }, 209 | "ee-first": { 210 | "version": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 211 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 212 | }, 213 | "encodeurl": { 214 | "version": "1.0.1", 215 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", 216 | "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" 217 | }, 218 | "escape-html": { 219 | "version": "1.0.3", 220 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 221 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 222 | }, 223 | "escape-string-regexp": { 224 | "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 225 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 226 | "dev": true 227 | }, 228 | "esprima": { 229 | "version": "3.0.0", 230 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz", 231 | "integrity": "sha1-U88kes2ncxPlUcOqLnM0LT+099k=" 232 | }, 233 | "etag": { 234 | "version": "1.8.1", 235 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 236 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 237 | }, 238 | "express": { 239 | "version": "4.16.1", 240 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.1.tgz", 241 | "integrity": "sha512-STB7LZ4N0L+81FJHGla2oboUHTk4PaN1RsOkoRh9OSeEKylvF5hwKYVX1xCLFaCT7MD0BNG/gX2WFMLqY6EMBw==", 242 | "requires": { 243 | "accepts": "1.3.4", 244 | "array-flatten": "1.1.1", 245 | "body-parser": "1.18.2", 246 | "content-disposition": "0.5.2", 247 | "content-type": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 248 | "cookie": "0.3.1", 249 | "cookie-signature": "1.0.6", 250 | "debug": "2.6.9", 251 | "depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 252 | "encodeurl": "1.0.1", 253 | "escape-html": "1.0.3", 254 | "etag": "1.8.1", 255 | "finalhandler": "1.1.0", 256 | "fresh": "0.5.2", 257 | "merge-descriptors": "1.0.1", 258 | "methods": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 259 | "on-finished": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 260 | "parseurl": "1.3.2", 261 | "path-to-regexp": "0.1.7", 262 | "proxy-addr": "2.0.2", 263 | "qs": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 264 | "range-parser": "1.2.0", 265 | "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 266 | "send": "0.16.1", 267 | "serve-static": "1.13.1", 268 | "setprototypeof": "1.1.0", 269 | "statuses": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 270 | "type-is": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", 271 | "utils-merge": "1.0.1", 272 | "vary": "1.1.2" 273 | }, 274 | "dependencies": { 275 | "debug": { 276 | "version": "2.6.9", 277 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 278 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 279 | "requires": { 280 | "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 281 | } 282 | }, 283 | "setprototypeof": { 284 | "version": "1.1.0", 285 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 286 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 287 | } 288 | } 289 | }, 290 | "extend": { 291 | "version": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 292 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", 293 | "dev": true 294 | }, 295 | "finalhandler": { 296 | "version": "1.1.0", 297 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", 298 | "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", 299 | "requires": { 300 | "debug": "2.6.9", 301 | "encodeurl": "1.0.1", 302 | "escape-html": "1.0.3", 303 | "on-finished": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 304 | "parseurl": "1.3.2", 305 | "statuses": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 306 | "unpipe": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" 307 | }, 308 | "dependencies": { 309 | "debug": { 310 | "version": "2.6.9", 311 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 312 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 313 | "requires": { 314 | "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 315 | } 316 | } 317 | } 318 | }, 319 | "form-data": { 320 | "version": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", 321 | "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", 322 | "dev": true, 323 | "requires": { 324 | "asynckit": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 325 | "combined-stream": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", 326 | "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz" 327 | } 328 | }, 329 | "formidable": { 330 | "version": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", 331 | "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=", 332 | "dev": true 333 | }, 334 | "forwarded": { 335 | "version": "0.1.2", 336 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 337 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 338 | }, 339 | "fresh": { 340 | "version": "0.5.2", 341 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 342 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 343 | }, 344 | "fs.realpath": { 345 | "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 346 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 347 | "dev": true 348 | }, 349 | "generate-function": { 350 | "version": "2.0.0", 351 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", 352 | "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" 353 | }, 354 | "generic-pool": { 355 | "version": "3.1.8", 356 | "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.1.8.tgz", 357 | "integrity": "sha1-CYRLZUW8kXfsIYvTXUrYlMZb4nE=" 358 | }, 359 | "glob": { 360 | "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", 361 | "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", 362 | "dev": true, 363 | "requires": { 364 | "fs.realpath": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 365 | "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 366 | "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 367 | "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 368 | "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 369 | "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" 370 | } 371 | }, 372 | "graceful-readlink": { 373 | "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", 374 | "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", 375 | "dev": true 376 | }, 377 | "growl": { 378 | "version": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 379 | "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", 380 | "dev": true 381 | }, 382 | "has-flag": { 383 | "version": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 384 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 385 | "dev": true 386 | }, 387 | "he": { 388 | "version": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 389 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 390 | "dev": true 391 | }, 392 | "http-errors": { 393 | "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 394 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 395 | "requires": { 396 | "depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 397 | "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 398 | "setprototypeof": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 399 | "statuses": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz" 400 | } 401 | }, 402 | "iconv-lite": { 403 | "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 404 | "integrity": "sha1-90aPYBNfXl2tM5nAqBvpoWA6CCs=" 405 | }, 406 | "inflection": { 407 | "version": "1.12.0", 408 | "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", 409 | "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" 410 | }, 411 | "inflight": { 412 | "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 413 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 414 | "dev": true, 415 | "requires": { 416 | "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 417 | "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" 418 | } 419 | }, 420 | "inherits": { 421 | "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 422 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 423 | }, 424 | "ipaddr.js": { 425 | "version": "1.5.2", 426 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", 427 | "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" 428 | }, 429 | "is-bluebird": { 430 | "version": "1.0.2", 431 | "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", 432 | "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" 433 | }, 434 | "isarray": { 435 | "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 436 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 437 | }, 438 | "json3": { 439 | "version": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", 440 | "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", 441 | "dev": true 442 | }, 443 | "lodash": { 444 | "version": "4.17.4", 445 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 446 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" 447 | }, 448 | "lodash._baseassign": { 449 | "version": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", 450 | "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", 451 | "dev": true, 452 | "requires": { 453 | "lodash._basecopy": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", 454 | "lodash.keys": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" 455 | } 456 | }, 457 | "lodash._basecopy": { 458 | "version": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", 459 | "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", 460 | "dev": true 461 | }, 462 | "lodash._basecreate": { 463 | "version": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", 464 | "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", 465 | "dev": true 466 | }, 467 | "lodash._getnative": { 468 | "version": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", 469 | "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", 470 | "dev": true 471 | }, 472 | "lodash._isiterateecall": { 473 | "version": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", 474 | "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", 475 | "dev": true 476 | }, 477 | "lodash.create": { 478 | "version": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", 479 | "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", 480 | "dev": true, 481 | "requires": { 482 | "lodash._baseassign": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", 483 | "lodash._basecreate": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", 484 | "lodash._isiterateecall": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz" 485 | } 486 | }, 487 | "lodash.isarguments": { 488 | "version": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", 489 | "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", 490 | "dev": true 491 | }, 492 | "lodash.isarray": { 493 | "version": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", 494 | "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", 495 | "dev": true 496 | }, 497 | "lodash.keys": { 498 | "version": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", 499 | "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", 500 | "dev": true, 501 | "requires": { 502 | "lodash._getnative": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", 503 | "lodash.isarguments": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", 504 | "lodash.isarray": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" 505 | } 506 | }, 507 | "long": { 508 | "version": "3.2.0", 509 | "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", 510 | "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" 511 | }, 512 | "lru-cache": { 513 | "version": "4.1.1", 514 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", 515 | "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", 516 | "requires": { 517 | "pseudomap": "1.0.2", 518 | "yallist": "2.1.2" 519 | } 520 | }, 521 | "media-typer": { 522 | "version": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 523 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 524 | }, 525 | "merge-descriptors": { 526 | "version": "1.0.1", 527 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 528 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 529 | }, 530 | "methods": { 531 | "version": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 532 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 533 | }, 534 | "mime": { 535 | "version": "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz", 536 | "integrity": "sha1-aeng21HUTyo7VuSLeBfX0Tfxo0M=", 537 | "dev": true 538 | }, 539 | "mime-db": { 540 | "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 541 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" 542 | }, 543 | "mime-types": { 544 | "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 545 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 546 | "requires": { 547 | "mime-db": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz" 548 | } 549 | }, 550 | "minimatch": { 551 | "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 552 | "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", 553 | "dev": true, 554 | "requires": { 555 | "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz" 556 | } 557 | }, 558 | "minimist": { 559 | "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 560 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 561 | "dev": true 562 | }, 563 | "mkdirp": { 564 | "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 565 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 566 | "dev": true, 567 | "requires": { 568 | "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" 569 | } 570 | }, 571 | "mocha": { 572 | "version": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", 573 | "integrity": "sha1-HgSA/jbS2lhY0etqzDhBiybqog0=", 574 | "dev": true, 575 | "requires": { 576 | "browser-stdout": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", 577 | "commander": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", 578 | "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", 579 | "diff": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", 580 | "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 581 | "glob": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", 582 | "growl": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 583 | "he": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 584 | "json3": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", 585 | "lodash.create": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", 586 | "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 587 | "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz" 588 | } 589 | }, 590 | "moment": { 591 | "version": "2.18.1", 592 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", 593 | "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" 594 | }, 595 | "moment-timezone": { 596 | "version": "0.5.13", 597 | "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.13.tgz", 598 | "integrity": "sha1-mc5cfYJyYusPH3AgRBd/YHRde5A=", 599 | "requires": { 600 | "moment": "2.18.1" 601 | } 602 | }, 603 | "ms": { 604 | "version": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 605 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 606 | }, 607 | "mysql2": { 608 | "version": "1.4.2", 609 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.4.2.tgz", 610 | "integrity": "sha1-teBACf1tY/AHVSU9+IVAolMmQLI=", 611 | "requires": { 612 | "cardinal": "1.0.0", 613 | "denque": "1.2.2", 614 | "generate-function": "2.0.0", 615 | "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 616 | "long": "3.2.0", 617 | "lru-cache": "4.1.1", 618 | "named-placeholders": "1.1.1", 619 | "object-assign": "4.1.1", 620 | "readable-stream": "2.3.2", 621 | "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 622 | "seq-queue": "0.0.5", 623 | "sqlstring": "2.3.0" 624 | }, 625 | "dependencies": { 626 | "readable-stream": { 627 | "version": "2.3.2", 628 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", 629 | "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=", 630 | "requires": { 631 | "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 632 | "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 633 | "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 634 | "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 635 | "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 636 | "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 637 | "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" 638 | } 639 | } 640 | } 641 | }, 642 | "named-placeholders": { 643 | "version": "1.1.1", 644 | "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.1.tgz", 645 | "integrity": "sha1-O3oNJiA910s6nfTJz7gnsvuQfmQ=", 646 | "requires": { 647 | "lru-cache": "2.5.0" 648 | }, 649 | "dependencies": { 650 | "lru-cache": { 651 | "version": "2.5.0", 652 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz", 653 | "integrity": "sha1-2COIrpyWC+y+oMc7uet5tsbOmus=" 654 | } 655 | } 656 | }, 657 | "negotiator": { 658 | "version": "0.6.1", 659 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 660 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 661 | }, 662 | "node-uuid": { 663 | "version": "1.4.8", 664 | "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", 665 | "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" 666 | }, 667 | "object-assign": { 668 | "version": "4.1.1", 669 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 670 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 671 | }, 672 | "on-finished": { 673 | "version": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 674 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 675 | "requires": { 676 | "ee-first": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" 677 | } 678 | }, 679 | "once": { 680 | "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 681 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 682 | "dev": true, 683 | "requires": { 684 | "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" 685 | } 686 | }, 687 | "parseurl": { 688 | "version": "1.3.2", 689 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 690 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 691 | }, 692 | "path-is-absolute": { 693 | "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 694 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 695 | "dev": true 696 | }, 697 | "path-to-regexp": { 698 | "version": "0.1.7", 699 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 700 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 701 | }, 702 | "process-nextick-args": { 703 | "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 704 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 705 | }, 706 | "proxy-addr": { 707 | "version": "2.0.2", 708 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", 709 | "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", 710 | "requires": { 711 | "forwarded": "0.1.2", 712 | "ipaddr.js": "1.5.2" 713 | } 714 | }, 715 | "pseudomap": { 716 | "version": "1.0.2", 717 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 718 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 719 | }, 720 | "qs": { 721 | "version": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 722 | "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=" 723 | }, 724 | "range-parser": { 725 | "version": "1.2.0", 726 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 727 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 728 | }, 729 | "raw-body": { 730 | "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 731 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 732 | "requires": { 733 | "bytes": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 734 | "http-errors": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 735 | "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 736 | "unpipe": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" 737 | } 738 | }, 739 | "readable-stream": { 740 | "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 741 | "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", 742 | "dev": true, 743 | "requires": { 744 | "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 745 | "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 746 | "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 747 | "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 748 | "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 749 | "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 750 | "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" 751 | } 752 | }, 753 | "redeyed": { 754 | "version": "1.0.1", 755 | "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz", 756 | "integrity": "sha1-6WwZO0DAgWsArshCaY5hGF5VSYo=", 757 | "requires": { 758 | "esprima": "3.0.0" 759 | } 760 | }, 761 | "retry-as-promised": { 762 | "version": "2.3.1", 763 | "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-2.3.1.tgz", 764 | "integrity": "sha1-91BZGD+XMHccCbrR7tV1N5McvJ0=", 765 | "requires": { 766 | "bluebird": "3.5.1", 767 | "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz" 768 | } 769 | }, 770 | "safe-buffer": { 771 | "version": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 772 | "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" 773 | }, 774 | "semver": { 775 | "version": "5.4.1", 776 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", 777 | "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" 778 | }, 779 | "send": { 780 | "version": "0.16.1", 781 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", 782 | "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", 783 | "requires": { 784 | "debug": "2.6.9", 785 | "depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 786 | "destroy": "1.0.4", 787 | "encodeurl": "1.0.1", 788 | "escape-html": "1.0.3", 789 | "etag": "1.8.1", 790 | "fresh": "0.5.2", 791 | "http-errors": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 792 | "mime": "1.4.1", 793 | "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 794 | "on-finished": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 795 | "range-parser": "1.2.0", 796 | "statuses": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz" 797 | }, 798 | "dependencies": { 799 | "debug": { 800 | "version": "2.6.9", 801 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 802 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 803 | "requires": { 804 | "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 805 | } 806 | }, 807 | "mime": { 808 | "version": "1.4.1", 809 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 810 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 811 | } 812 | } 813 | }, 814 | "seq-queue": { 815 | "version": "0.0.5", 816 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", 817 | "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" 818 | }, 819 | "sequelize": { 820 | "version": "4.13.5", 821 | "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-4.13.5.tgz", 822 | "integrity": "sha512-0sOQBWYnnzP8pkmo6E4vFHIy5Ye2U3zNHcKo5HCRxdjOXs7G+uybiUd6vRh+Sj0XsBVfhwdADyjf0jmmirUWFA==", 823 | "requires": { 824 | "bluebird": "3.5.1", 825 | "cls-bluebird": "2.0.1", 826 | "debug": "3.1.0", 827 | "depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 828 | "dottie": "2.0.0", 829 | "generic-pool": "3.1.8", 830 | "inflection": "1.12.0", 831 | "lodash": "4.17.4", 832 | "moment": "2.18.1", 833 | "moment-timezone": "0.5.13", 834 | "retry-as-promised": "2.3.1", 835 | "semver": "5.4.1", 836 | "terraformer-wkt-parser": "1.1.2", 837 | "toposort-class": "1.0.1", 838 | "uuid": "3.1.0", 839 | "validator": "8.2.0", 840 | "wkx": "0.4.2" 841 | }, 842 | "dependencies": { 843 | "debug": { 844 | "version": "3.1.0", 845 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 846 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 847 | "requires": { 848 | "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 849 | } 850 | }, 851 | "uuid": { 852 | "version": "3.1.0", 853 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", 854 | "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" 855 | } 856 | } 857 | }, 858 | "serve-static": { 859 | "version": "1.13.1", 860 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", 861 | "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", 862 | "requires": { 863 | "encodeurl": "1.0.1", 864 | "escape-html": "1.0.3", 865 | "parseurl": "1.3.2", 866 | "send": "0.16.1" 867 | } 868 | }, 869 | "setprototypeof": { 870 | "version": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 871 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 872 | }, 873 | "shimmer": { 874 | "version": "1.1.0", 875 | "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.1.0.tgz", 876 | "integrity": "sha1-l9c3cTf/u6tCVSLkKf4KqJpIizU=" 877 | }, 878 | "should": { 879 | "version": "https://registry.npmjs.org/should/-/should-13.0.1.tgz", 880 | "integrity": "sha1-jZBzgy/5Q34GbJgr0eUHk4rLey4=", 881 | "dev": true, 882 | "requires": { 883 | "should-equal": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", 884 | "should-format": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", 885 | "should-type": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", 886 | "should-type-adaptors": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", 887 | "should-util": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz" 888 | } 889 | }, 890 | "should-equal": { 891 | "version": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", 892 | "integrity": "sha1-YHLPgwRzYIZ+aOmLCdcRQ9BO4MM=", 893 | "dev": true, 894 | "requires": { 895 | "should-type": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz" 896 | } 897 | }, 898 | "should-format": { 899 | "version": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", 900 | "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", 901 | "dev": true, 902 | "requires": { 903 | "should-type": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", 904 | "should-type-adaptors": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz" 905 | } 906 | }, 907 | "should-type": { 908 | "version": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", 909 | "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", 910 | "dev": true 911 | }, 912 | "should-type-adaptors": { 913 | "version": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", 914 | "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", 915 | "dev": true, 916 | "requires": { 917 | "should-type": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", 918 | "should-util": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz" 919 | } 920 | }, 921 | "should-util": { 922 | "version": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", 923 | "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", 924 | "dev": true 925 | }, 926 | "sqlstring": { 927 | "version": "2.3.0", 928 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.0.tgz", 929 | "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg=" 930 | }, 931 | "statuses": { 932 | "version": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 933 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 934 | }, 935 | "string_decoder": { 936 | "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 937 | "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", 938 | "requires": { 939 | "safe-buffer": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz" 940 | } 941 | }, 942 | "superagent": { 943 | "version": "https://registry.npmjs.org/superagent/-/superagent-3.6.0.tgz", 944 | "integrity": "sha1-62eWUQV8NGIZnHuQK2lsJTUOG4c=", 945 | "dev": true, 946 | "requires": { 947 | "component-emitter": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 948 | "cookiejar": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", 949 | "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", 950 | "extend": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 951 | "form-data": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", 952 | "formidable": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", 953 | "methods": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 954 | "mime": "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz", 955 | "qs": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 956 | "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz" 957 | } 958 | }, 959 | "supertest": { 960 | "version": "https://registry.npmjs.org/supertest/-/supertest-3.0.0.tgz", 961 | "integrity": "sha1-jUu2j9GDDuBwM7HFpamkAhyWUpY=", 962 | "dev": true, 963 | "requires": { 964 | "methods": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 965 | "superagent": "https://registry.npmjs.org/superagent/-/superagent-3.6.0.tgz" 966 | } 967 | }, 968 | "supports-color": { 969 | "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", 970 | "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", 971 | "dev": true, 972 | "requires": { 973 | "has-flag": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz" 974 | } 975 | }, 976 | "terraformer": { 977 | "version": "1.0.8", 978 | "resolved": "https://registry.npmjs.org/terraformer/-/terraformer-1.0.8.tgz", 979 | "integrity": "sha1-UeCtiXRvzyFh3G9lqnDkI3fItZM=", 980 | "requires": { 981 | "@types/geojson": "1.0.4" 982 | } 983 | }, 984 | "terraformer-wkt-parser": { 985 | "version": "1.1.2", 986 | "resolved": "https://registry.npmjs.org/terraformer-wkt-parser/-/terraformer-wkt-parser-1.1.2.tgz", 987 | "integrity": "sha1-M2oMj8gglKWv+DKI9prt7NNpvww=", 988 | "requires": { 989 | "terraformer": "1.0.8" 990 | } 991 | }, 992 | "toposort-class": { 993 | "version": "1.0.1", 994 | "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", 995 | "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" 996 | }, 997 | "type-is": { 998 | "version": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", 999 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", 1000 | "requires": { 1001 | "media-typer": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1002 | "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz" 1003 | } 1004 | }, 1005 | "unpipe": { 1006 | "version": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1007 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1008 | }, 1009 | "util-deprecate": { 1010 | "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1011 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1012 | }, 1013 | "utils-merge": { 1014 | "version": "1.0.1", 1015 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1016 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 1017 | }, 1018 | "validator": { 1019 | "version": "8.2.0", 1020 | "resolved": "https://registry.npmjs.org/validator/-/validator-8.2.0.tgz", 1021 | "integrity": "sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA==" 1022 | }, 1023 | "vary": { 1024 | "version": "1.1.2", 1025 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1026 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1027 | }, 1028 | "wkx": { 1029 | "version": "0.4.2", 1030 | "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.2.tgz", 1031 | "integrity": "sha1-d201pjSlwi5lbkdEvetU+D/Szo0=", 1032 | "requires": { 1033 | "@types/node": "8.0.32" 1034 | } 1035 | }, 1036 | "wrappy": { 1037 | "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1038 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1039 | "dev": true 1040 | }, 1041 | "yallist": { 1042 | "version": "2.1.2", 1043 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 1044 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 1045 | } 1046 | } 1047 | } 1048 | -------------------------------------------------------------------------------- /step0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step1-express-https", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=test bin/www.js", 8 | "test": "NODE_ENV=test node_modules/.bin/mocha app/api/**/*.spec.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "body-parser": "^1.18.2", 15 | "co": "^4.6.0", 16 | "express": "^4.16.1", 17 | "mysql2": "^1.4.2", 18 | "node-uuid": "^1.4.8", 19 | "sequelize": "^4.13.5" 20 | }, 21 | "devDependencies": { 22 | "mocha": "^3.5.3", 23 | "should": "^13.0.1", 24 | "supertest": "^3.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /step0_1/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'standard', 3 | rules: { 4 | 'semi': ['error', 'always'] 5 | } 6 | }; -------------------------------------------------------------------------------- /step0_1/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /step0_1/.lintgnore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .eslintrc.js -------------------------------------------------------------------------------- /step0_1/app/index.js: -------------------------------------------------------------------------------- 1 | const app = require('express')(); 2 | const middlewares = require('./middleware'); 3 | const routes = require('./routes'); 4 | 5 | // middleware 연동 6 | middlewares.init(app); 7 | 8 | // routes 연결 9 | routes(app); 10 | 11 | // Error middleware 연동 12 | middlewares.error(app); 13 | 14 | module.exports = app; 15 | -------------------------------------------------------------------------------- /step0_1/app/middleware/acao.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res, next) => { 2 | res.header('Access-Control-Allow-Origin', '*'); 3 | res.header('Access-Control-Allow-Headers', 'Content-Type'); 4 | next(); 5 | }; 6 | -------------------------------------------------------------------------------- /step0_1/app/middleware/bodyparser.js: -------------------------------------------------------------------------------- 1 | const bodyParser = require('body-parser'); 2 | 3 | // for parsing application/json 4 | module.exports = bodyParser.json(); 5 | -------------------------------------------------------------------------------- /step0_1/app/middleware/bodyparser.urlencoded.js: -------------------------------------------------------------------------------- 1 | const bodyParser = require('body-parser'); 2 | 3 | // for parsing application/x-www-form-urlencoded 4 | module.exports = bodyParser.urlencoded({ 5 | extended: true, 6 | limit: `${5 * 1024 * 1024}b`, 7 | parameterLimit: 1000000 8 | }); 9 | -------------------------------------------------------------------------------- /step0_1/app/middleware/cookiparser.js: -------------------------------------------------------------------------------- 1 | const cookieParser = require('cookie-parser'); 2 | 3 | module.exports = cookieParser(); 4 | -------------------------------------------------------------------------------- /step0_1/app/middleware/defauleRoute.middleware.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res) => res.status(404).send(); 2 | -------------------------------------------------------------------------------- /step0_1/app/middleware/index.js: -------------------------------------------------------------------------------- 1 | const middlewares = [ 2 | require('./acao'), 3 | require('./bodyparser.js'), 4 | require('./bodyparser.urlencoded'), 5 | require('./cookiparser') 6 | ]; 7 | 8 | const error = [ 9 | require('./defauleRoute.middleware'), 10 | require('../routes/routeLib/response/error.handler') 11 | ]; 12 | 13 | module.exports = { 14 | init: app => { 15 | middlewares.forEach(m => app.use(m)); 16 | }, 17 | error: app => { 18 | error.forEach(m => app.use(m)); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/connection/controller/createConnection.js: -------------------------------------------------------------------------------- 1 | const { 2 | userConnection: { 3 | createConnection, destroyConnection 4 | } 5 | } = require('$service'); 6 | 7 | const {hash: {getSalt, getExpiredTime}, resMsg} = require('$routeLib'); 8 | 9 | /** 10 | * Create Connection Controller 11 | * 12 | * @param req 13 | * @param res 14 | * @param next 15 | */ 16 | module.exports = async ({body}, res, next) => { 17 | try { 18 | const {userId} = body; 19 | 20 | await destroyConnection({userId}); 21 | const {accessToken} = await createConnection({userId, accessToken: getSalt(), expiredTime: getExpiredTime()}); 22 | 23 | resMsg.success201RetObjWithToken(res, accessToken); 24 | } catch (e) { 25 | next(e); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/connection/controller/deleteConnection.js: -------------------------------------------------------------------------------- 1 | const {resMsg} = require('$routeLib'); 2 | 3 | /** 4 | * Delete Connection Controller 5 | * 6 | * @param req 7 | * @param res 8 | * @param next 9 | */ 10 | module.exports = (body, res) => { 11 | resMsg.tokenClear(res); 12 | }; 13 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/connection/controller/getClientSalt.js: -------------------------------------------------------------------------------- 1 | const {user: {findOneUser}} = require('$service'); 2 | 3 | const {hash: {getSalt}, resMsg} = require('$routeLib'); 4 | 5 | /** 6 | * Get ClientSalt Controller 7 | * 8 | * @param req 9 | * @param res 10 | * @param next 11 | */ 12 | module.exports = async ({query: {userId: id}}, res, next) => { 13 | try { 14 | const user = await findOneUser(undefined, {id}); 15 | 16 | if (!user) { 17 | resMsg.success200RetObj(res, { 18 | salt: getSalt() 19 | }); 20 | } else { 21 | resMsg.success200RetObj(res, { 22 | salt: user.clientSalt 23 | }); 24 | } 25 | } catch (e) { 26 | next(e); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/connection/controller/updateConnection.js: -------------------------------------------------------------------------------- 1 | const { 2 | userConnection: { 3 | findOneConnection 4 | } 5 | } = require('$service'); 6 | 7 | const {hash: {getSalt, getExpiredTime}, resMsg, err} = require('$routeLib'); 8 | 9 | /** 10 | * Update Connection Controller 11 | * 12 | * @param req 13 | * @param res 14 | * @param next 15 | */ 16 | module.exports = async ({body}, res, next) => { 17 | try { 18 | const {userId} = body; 19 | const connection = findOneConnection({userId}); 20 | if (!connection) err.noConnection(); 21 | 22 | // 인증정보 갱신 23 | const accessToken = getSalt(); 24 | connection.accessToken = accessToken; 25 | connection.expiredTime = getExpiredTime(); 26 | 27 | await connection.save(); 28 | 29 | resMsg.success201RetObjWithToken(res, accessToken); 30 | } catch (e) { 31 | next(e); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/connection/index.js: -------------------------------------------------------------------------------- 1 | const path = '/v1/connection'; 2 | const router = require('express').Router(); 3 | 4 | const {auth} = require('../../../routeMiddleware'); 5 | const loginValidation = require('./middleware/loginValidation'); 6 | const {validConnection} = require('./validate'); 7 | 8 | // client salt 가져오기 9 | router.get('/salt', require('./controller/getClientSalt')); 10 | 11 | // Create Connection 12 | router.post('/', validConnection, loginValidation, require('./controller/createConnection')); 13 | 14 | // 로그인 갱신 15 | router.put('/', validConnection, loginValidation, require('./controller/updateConnection')); 16 | 17 | // 로그아웃 18 | router.delete('/', auth, require('./controller/deleteConnection')); 19 | 20 | module.exports = {path, router}; 21 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/connection/middleware/loginValidation.js: -------------------------------------------------------------------------------- 1 | const {user: {findOneUser}} = require('$service'); 2 | const {hash: {getHash}, error} = require('$routeLib'); 3 | 4 | /** 5 | * 접속 정보 확인 Middleware 6 | * 7 | * @param body 8 | * @param res 9 | * @param next 10 | */ 11 | module.exports = async ({body}, res, next) => { 12 | try { 13 | const {userId: id, hash: hash1st} = body; 14 | 15 | const user = await findOneUser(undefined, {id}); 16 | if (!user) error.notFoundUser(); 17 | 18 | const {serverSalt, hashToken} = user; 19 | const hash2nd = getHash(hash1st, serverSalt); 20 | if (hashToken !== hash2nd) error.credentialsMismatch(); 21 | 22 | next(); 23 | } catch (e) { 24 | next(e); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/connection/validate/index.js: -------------------------------------------------------------------------------- 1 | const {validate} = require('$routeLib'); 2 | const rules = require('./rules'); 3 | 4 | /** 5 | * Connection 생성, 갱신 - 인자값 Validation 체크 6 | * 7 | * @param body 8 | * @param res 9 | * @param next 10 | */ 11 | exports.validConnection = async ({body}, res, next) => { 12 | try { 13 | await validate({body}, rules.createConnection); 14 | } catch (e) { 15 | next(e); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/connection/validate/rules.js: -------------------------------------------------------------------------------- 1 | const {rules: {userId, hash}} = require('$routeLib'); 2 | 3 | /** 4 | * Connection 생성 - Validation 규칙 5 | */ 6 | exports.createConnection = { 7 | body: {userId, hash} 8 | }; 9 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/user/controller/createUser.js: -------------------------------------------------------------------------------- 1 | const { 2 | user: { 3 | findOneUser 4 | } 5 | } = require('$service'); 6 | 7 | const {hash: {getHash}, err, resMsg} = require('$routeLib'); 8 | 9 | /** 10 | * Create Connection Controller 11 | * 12 | * @param req 13 | * @param res 14 | * @param next 15 | */ 16 | module.exports = async ({params: {userId: id}, body}, res, next) => { 17 | try { 18 | const {hash, userName = 'NONE', userAge = 0, userEmail = 'NONE'} = body; 19 | 20 | const user = await findOneUser(undefined, {id}); 21 | if (!user) err.notFoundUser(); 22 | 23 | // 2차 hash 생성 24 | const secondHash = getHash(hash, user.serverSalt); 25 | user.hashToken = secondHash; 26 | user.userName = userName; 27 | user.userAge = userAge; 28 | user.userEmail = userEmail; 29 | 30 | const result = await user.save(); 31 | console.log(result); 32 | 33 | resMsg.success201(); 34 | } catch (e) { 35 | next(e); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/user/controller/createUserInit.js: -------------------------------------------------------------------------------- 1 | const { 2 | user: { 3 | createUser 4 | } 5 | } = require('$service'); 6 | 7 | const {hash: {getSalt}, resMsg} = require('$routeLib'); 8 | 9 | /** 10 | * Create Connection Controller 11 | * 12 | * @param req 13 | * @param res 14 | * @param next 15 | */ 16 | module.exports = async ({body: {userId: id}}, res, next) => { 17 | try { 18 | const clientSalt = getSalt(); 19 | const serverSalt = getSalt(); 20 | 21 | // 유저데이터를 추가 22 | // return값은 clientSalt만 보냄 23 | const {clientSalt: salt} = createUser({id, clientSalt, serverSalt}); 24 | 25 | resMsg.success201RetObj(res, {salt}); 26 | } catch (e) { 27 | next(e); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/user/controller/showUser.js: -------------------------------------------------------------------------------- 1 | const {user: {findOneUser}} = require('$service'); 2 | 3 | const {err, retMsg} = require('$routeLib'); 4 | 5 | /** 6 | * Get User Controller 7 | * 8 | * @param req 9 | * @param res 10 | * @param next 11 | */ 12 | module.exports = async ({params: {userId: id}}, res, next) => { 13 | try { 14 | const user = await findOneUser( 15 | ['id', 'userName', 'userAge', 'userEmail'], 16 | {id} 17 | ); 18 | 19 | if (!user) err.noConnection(); 20 | 21 | retMsg.success200RetObj(res, user); 22 | } catch (e) { 23 | next(e); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/user/index.js: -------------------------------------------------------------------------------- 1 | const path = '/v1/users'; 2 | const router = require('express').Router(); 3 | 4 | const duplicationCheckByUser = require('./middleware/duplicationCheckByUser'); 5 | const {validCreateUser, validCreateUserInit} = require('./validate'); 6 | 7 | // 유저 정보 조회 API 8 | router.get('/:userId', require('./controller/showUser')); 9 | 10 | // 유저 등록 init API 11 | router.post('/', validCreateUser, duplicationCheckByUser, require('./controller/createUserInit')); 12 | 13 | // 유저 등록 create API 14 | router.post('/:userId', validCreateUserInit, require('./controller/createUser')); 15 | 16 | module.exports = {path, router}; 17 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/user/middleware/duplicationCheckByUser.js: -------------------------------------------------------------------------------- 1 | const { 2 | user: { 3 | findOneUser 4 | } 5 | } = require('$service'); 6 | 7 | const {err} = require('$routeLib'); 8 | 9 | /** 10 | * Create Connection Controller 11 | * 12 | * @param req 13 | * @param res 14 | * @param next 15 | */ 16 | module.exports = async ({body: {userId: id}}, res, next) => { 17 | try { 18 | const user = await findOneUser(undefined, {id}); 19 | 20 | if (!user) next(); 21 | else err.duplicate('user'); 22 | } catch (e) { 23 | next(e); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/user/validate/index.js: -------------------------------------------------------------------------------- 1 | const {validate} = require('$routeLib'); 2 | const rules = require('./rules'); 3 | 4 | /** 5 | * User 생성 1단계 - 인자값 Validation 체크 6 | * 7 | * @param body 8 | * @param res 9 | * @param next 10 | */ 11 | exports.validCreateUserInit = async ({body}, res, next) => { 12 | try { 13 | await validate({body}, rules.createUserInit); 14 | } catch (e) { 15 | next(e); 16 | } 17 | }; 18 | 19 | /** 20 | * User 생성 2단계 - 인자값 Validation 체크 21 | * 22 | * @param body 23 | * @param res 24 | * @param next 25 | */ 26 | exports.validCreateUser = async ({body}, res, next) => { 27 | try { 28 | await validate({body}, rules.createUser); 29 | } catch (e) { 30 | next(e); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /step0_1/app/routes/api/v1/user/validate/rules.js: -------------------------------------------------------------------------------- 1 | const {rules: {userId, hash}} = require('$routeLib'); 2 | 3 | /** 4 | * Connection 생성 1단계 - Validation 규칙 5 | */ 6 | exports.createUserInit = { 7 | body: {userId} 8 | }; 9 | 10 | /** 11 | * Connection 생성 2단계 - Validation 규칙 12 | */ 13 | exports.createUser = { 14 | body: {userId, hash} 15 | }; 16 | -------------------------------------------------------------------------------- /step0_1/app/routes/index.js: -------------------------------------------------------------------------------- 1 | const routes = [ 2 | require('./api/v1/user'), 3 | require('./api/v1/connection') 4 | ]; 5 | 6 | module.exports = app => { 7 | routes.forEach(({path, router}) => app.use(path, router)); 8 | }; 9 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeLib/hash/hash.creator.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const uuid = require('node-uuid'); 3 | 4 | /** 5 | * salt값 생성 6 | * 7 | * @param _ 8 | */ 9 | exports.getSalt = _ => crypto.createHash('sha256').update(uuid.v1()).digest('hex'); 10 | 11 | /** 12 | * hash값 생성 13 | * 14 | * @param hash 15 | * @param salt 16 | */ 17 | exports.getHash = (hash, salt) => crypto.pbkdf2Sync(hash, salt, 10000, 32, 'sha256').toString('hex'); 18 | 19 | /** 20 | * 인증만료시간 생성 21 | * 22 | * @param _ 23 | */ 24 | exports.getExpiredTime = _ => { 25 | const expiredTime = new Date(); 26 | return expiredTime.setMinutes(expiredTime.getMinutes() + 120); 27 | }; 28 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeLib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | hash: require('./hash/hash.creator'), 3 | resMsg: require('./response/responseMessage'), 4 | error: require('./response/error'), 5 | code: require('./response/responseCode'), 6 | validate: require('./validate/validateFunc'), 7 | rules: require('./validate/rules') 8 | }; -------------------------------------------------------------------------------- /step0_1/app/routes/routeLib/response/error.handler.js: -------------------------------------------------------------------------------- 1 | const error400BadRequest = (res, code, data) => res.status(400).json({code, data}); 2 | 3 | const error401Unauthorized = (res, code) => { 4 | if (code) res.status(401).send(); 5 | else res.status(401).json({code}); 6 | }; 7 | 8 | const error403Forbidden = res => res.status(403).send(); 9 | 10 | const error404NotFound = res => res.status(404).send(); 11 | 12 | module.exports = (err, req, res, next) => { 13 | if (!(err instanceof Map)) { 14 | error404NotFound(res); 15 | } else { 16 | const statusCode = err.get('statusCode'); 17 | const message = err.get('message'); 18 | const code = err.get('code'); 19 | const data = err.get('data'); 20 | 21 | if (message) res.statusMessage = message; 22 | 23 | switch (statusCode) { 24 | case 400: 25 | error400BadRequest(res, code, data); 26 | break; 27 | case 401: 28 | error401Unauthorized(res, code, data); 29 | break; 30 | case 403: 31 | error403Forbidden(res); 32 | break; 33 | case 404: 34 | error404NotFound(res); 35 | break; 36 | } 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeLib/response/error.js: -------------------------------------------------------------------------------- 1 | const {NO_CONNECTION, DUPLICATE, EXPIRED_ACCESSTOKEN} = require('./responseCode'); 2 | 3 | /** 4 | * Validation Mismatch - 인자 값이 유효하지 않음 5 | * 6 | * @param key 7 | * @param message 8 | */ 9 | exports.validationMismatch = (key, message, code) => { 10 | throw new Map([ 11 | ['statusCode', 400], 12 | ['message', message], 13 | ['code', code], 14 | ['data', key] 15 | ]); 16 | }; 17 | 18 | /** 19 | * Duplicate Data - 중복되는 정보 20 | * 21 | * @param key 22 | */ 23 | exports.duplicate = key => { 24 | throw new Map([ 25 | ['statusCode', 400], 26 | ['message', 'Duplicate Data'], 27 | ['code', DUPLICATE], 28 | ['data', key] 29 | ]); 30 | }; 31 | 32 | /** 33 | * Credential Mismatch - 인증정보가 일치하지 않음 34 | */ 35 | exports.credentialsMismatch = _ => { 36 | throw new Map([ 37 | ['statusCode', 401], 38 | ['message', 'Credential Mismatch'] 39 | ]); 40 | }; 41 | 42 | /** 43 | * No Connection - 유저 접속기록이 없음 44 | */ 45 | exports.noConnection = _ => { 46 | throw new Map([ 47 | ['statusCode', 401], 48 | ['message', 'No Connection'], 49 | ['code', NO_CONNECTION] 50 | ]); 51 | }; 52 | 53 | /** 54 | * Expired accessToken - 인증이 만료된 accessToken 55 | */ 56 | exports.expiredToken = _ => { 57 | throw new Map([ 58 | ['statusCode', 401], 59 | ['message', 'Expired Access Token'], 60 | ['code', EXPIRED_ACCESSTOKEN] 61 | ]); 62 | }; 63 | 64 | /** 65 | * Not Found User - 유저 정보가 없음 66 | */ 67 | exports.notFoundUser = _ => { 68 | throw new Map([ 69 | ['statusCode', 404], 70 | ['message', 'Not Found User'] 71 | ]); 72 | }; 73 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeLib/response/responseCode.js: -------------------------------------------------------------------------------- 1 | exports.MISSING_PARAM = -1; 2 | 3 | exports.INVALID_PARAM = -2; 4 | 5 | exports.DUPLICATE = -3; 6 | 7 | exports.INVALID_ACCESSTOKEN = -4; 8 | 9 | exports.EXPIRED_ACCESSTOKEN = -5; 10 | 11 | exports.NO_CONNECTION = -6; 12 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeLib/response/responseMessage.js: -------------------------------------------------------------------------------- 1 | // 200 - success 2 | exports.success200 = res => res.status(200).send(); 3 | 4 | // 200 - return Model 5 | exports.success200RetObj = (res, obj) => res.status(200).json(obj); 6 | 7 | // 201 - create 8 | exports.success201 = res => res.status(201).send(); 9 | 10 | // 201 - return Model 11 | exports.success201RetObj = (res, obj) => res.status(201).json(obj); 12 | 13 | // 201 - response JSON with Token 14 | exports.success201RetObjWithToken = (res, accessToken, obj = {}) => { 15 | res.cookie('accessToken', accessToken, { 16 | httpOnly: true 17 | }); 18 | 19 | this.success201RetObj(obj); 20 | }; 21 | 22 | // 204 - delete 23 | exports.success204 = res => res.status(204).send(); 24 | 25 | // 204 - Token Clear 26 | exports.tokenClear = res => { 27 | res.clearCookie('accessToken'); 28 | this.success204(res); 29 | }; 30 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeLib/validate/rules.js: -------------------------------------------------------------------------------- 1 | const { 2 | MISSING_PARAM, INVALID_PARAM 3 | } = require('../response/responseCode'); 4 | 5 | /** 6 | * userId - Parameter 규칙 7 | */ 8 | exports.userId = [ 9 | { 10 | isValid: v => !!v, 11 | message: 'Missing Parameter', 12 | code: MISSING_PARAM 13 | } 14 | ]; 15 | 16 | /** 17 | * hash - Parameter 규칙 18 | */ 19 | exports.hash = [ 20 | { 21 | isValid: v => !!v, 22 | message: 'Missing Parameter', 23 | code: MISSING_PARAM 24 | }, 25 | { 26 | isValid: v => v.length === 64, 27 | message: 'Invalid Parameter', 28 | code: INVALID_PARAM 29 | } 30 | ]; 31 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeLib/validate/validateFunc.js: -------------------------------------------------------------------------------- 1 | const error = require('../response/error'); 2 | 3 | /** 4 | * 인자 값 Valid 체크 5 | * 6 | * @param data 7 | * @param rules 8 | */ 9 | module.exports = (data, rules) => new Promise((resolve, reject) => { 10 | Object.keys(data).forEach(d => Object.keys(rules[d]).forEach(k => { 11 | rules[d][k].forEach(({isValid, message, code}) => { 12 | if (!isValid[d][k]) reject(error.validationMismatch(k, message, code)); 13 | }); 14 | })); 15 | 16 | resolve(); 17 | }); 18 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeMiddleware/authorize.checker.js: -------------------------------------------------------------------------------- 1 | const {findOneConnection} = require('$service'); 2 | 3 | const { 4 | hash: {getExpiredTime}, 5 | code: {MISSING_PARAM, INVALID_PARAM}, 6 | err, validate 7 | } = require('$routeLib'); 8 | 9 | /** 10 | * 인증키 확인 Middleware 11 | * 12 | * @param req 13 | * @param res 14 | * @param next 15 | */ 16 | module.exports = async ({cookies}, res, next) => { 17 | try { 18 | await validate({cookies}, { 19 | cookies: { 20 | accessToken: [ 21 | { 22 | isValid: v => !!v, 23 | message: 'Missing Parameter', 24 | code: MISSING_PARAM 25 | }, 26 | { 27 | isValid: v => v.length === 64, 28 | message: 'Invalid Parameter', 29 | code: INVALID_PARAM 30 | } 31 | ] 32 | } 33 | }); 34 | 35 | const {accessToken} = cookies; 36 | const connection = await findOneConnection({accessToken}); 37 | if (!connection) err.noConnection(); 38 | 39 | const timeNum = connection.expiredTime.getTime() - new Date().getTime(); 40 | if (timeNum < 0) err.expiredToken(); 41 | 42 | // 인증시간 갱신 43 | connection.expiredTime = getExpiredTime(); 44 | await connection.save(); 45 | 46 | next(); 47 | } catch (e) { 48 | next(e); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /step0_1/app/routes/routeMiddleware/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | auth: require('./authorize.checker') 3 | }; 4 | -------------------------------------------------------------------------------- /step0_1/config/db.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": "sam_study", 3 | "username": "root", 4 | "password": "1111", 5 | "host": "127.0.0.1", 6 | "port": 3306, 7 | "dialect": "mysql", 8 | "logging": true 9 | } -------------------------------------------------------------------------------- /step0_1/db/index.js: -------------------------------------------------------------------------------- 1 | const Sequelize = require('sequelize'); 2 | 3 | const models = require('./model'); 4 | const {database, username, password, host, port, dialect, logging} = require('../config/db.config.json'); 5 | 6 | const sequelize = new Sequelize(database, username, password, { 7 | host, 8 | port, 9 | dialect, 10 | pool: { 11 | max: 5, 12 | min: 0, 13 | acquire: 30000, 14 | idle: 10000 15 | }, 16 | logging 17 | }); 18 | 19 | module.exports = models({sequelize}, Sequelize); 20 | -------------------------------------------------------------------------------- /step0_1/db/model/index.js: -------------------------------------------------------------------------------- 1 | const models = [ 2 | require('./user'), 3 | require('./userConnection') 4 | ]; 5 | 6 | module.exports = (obj, sequelize) => { 7 | models.forEach(v => v(obj, sequelize)); 8 | 9 | return obj; 10 | }; 11 | -------------------------------------------------------------------------------- /step0_1/db/model/user.js: -------------------------------------------------------------------------------- 1 | module.exports = (obj, sequelize) => { 2 | const name = 'user'; 3 | 4 | /** 5 | * Table: user 6 | * 7 | * id: 유저 ID - pk 8 | * 9 | * serverSalt: 2차 Hash를 만들기 위한 salt 값 10 | * clientSalt: 1차 Hash를 만들기 위한 salt 값 11 | * hashToken: 2차 Hash 12 | * 13 | * userName: 유저이름 14 | * userAge: 유저나이 15 | * userEmail: 유저 이메일 주소 16 | */ 17 | const model = obj.sequelize.define(name, { 18 | id: { 19 | type: sequelize.STRING(45), 20 | primaryKey: true 21 | }, 22 | serverSalt: sequelize.CHAR(64), 23 | clientSalt: sequelize.CHAR(64), 24 | hashToken: sequelize.CHAR(64), 25 | userName: sequelize.STRING(32), 26 | userAge: sequelize.INTEGER, 27 | userEmail: sequelize.STRING 28 | }) 29 | 30 | obj[name] = model; 31 | }; 32 | -------------------------------------------------------------------------------- /step0_1/db/model/userConnection.js: -------------------------------------------------------------------------------- 1 | module.exports = (obj, sequelize) => { 2 | const name = 'userConnection'; 3 | const model = obj.sequelize.define(name, 4 | { 5 | userId: { 6 | type: sequelize.STRING(45), 7 | primaryKey: true, 8 | references: { 9 | model: obj.user, 10 | key: 'id' 11 | } 12 | }, 13 | accessToken: sequelize.CHAR(64), 14 | expiredTime: sequelize.DATE 15 | }, 16 | { 17 | createdAt: false, 18 | updatedAt: false, 19 | indexes: [ 20 | {fields: ['accessToken']} 21 | ] 22 | }); 23 | 24 | obj[name] = model; 25 | }; 26 | -------------------------------------------------------------------------------- /step0_1/db/service/index.js: -------------------------------------------------------------------------------- 1 | const services = { 2 | user: require('./user.service'), 3 | userConnection: require('./userConnection.service') 4 | }; 5 | 6 | module.exports = services; 7 | -------------------------------------------------------------------------------- /step0_1/db/service/user.service.js: -------------------------------------------------------------------------------- 1 | const {user} = require('../index'); 2 | 3 | /** 4 | * 유저 정보 조회 Service 5 | * 6 | * @param where 7 | */ 8 | exports.findOneUser = (attributes, where) => user.findOne({attributes, where}); 9 | 10 | /** 11 | * 유저 정보 추가 Service 12 | * 13 | * @param user 14 | */ 15 | exports.createUser = obj => user.create(obj); 16 | -------------------------------------------------------------------------------- /step0_1/db/service/userConnection.service.js: -------------------------------------------------------------------------------- 1 | const {userConnection} = require('../index'); 2 | 3 | /** 4 | * 유저 접속 기록 조회 Service 5 | * 6 | * @param where 7 | */ 8 | exports.findOneConnection = where => userConnection.findOne({where}); 9 | 10 | /** 11 | * 유저 접속 기록 추가 Service 12 | * 13 | * @param connect 14 | */ 15 | exports.createConnection = connect => userConnection.create(connect); 16 | 17 | /** 18 | * 유저 접속 기록 삭제 Service 19 | * 20 | * @param where 21 | */ 22 | exports.destroyConnection = where => userConnection.destroy({where}); 23 | -------------------------------------------------------------------------------- /step0_1/index.js: -------------------------------------------------------------------------------- 1 | require('sexy-require'); 2 | 3 | const app = require('./app'); 4 | const {sequelize} = require('./db'); 5 | const port = 3000; 6 | 7 | ;(async _ => { 8 | await sequelize.sync({force: false}); 9 | await app.listen(port, _ => console.log(`{{Server Start}}-NODE_ENV[${process.env.NODE_ENV}]-PORT[${port}]`)); 10 | })(); 11 | -------------------------------------------------------------------------------- /step0_1/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step0_1", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/geojson": { 8 | "version": "1.0.6", 9 | "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-1.0.6.tgz", 10 | "integrity": "sha512-Xqg/lIZMrUd0VRmSRbCAewtwGZiAk3mEUDvV4op1tGl+LvyPcb/MIOSxTl9z+9+J+R4/vpjiCAT4xeKzH9ji1w==" 11 | }, 12 | "@types/node": { 13 | "version": "9.3.0", 14 | "resolved": "https://registry.npmjs.org/@types/node/-/node-9.3.0.tgz", 15 | "integrity": "sha512-wNBfvNjzsJl4tswIZKXCFQY0lss9nKUyJnG6T94X/eqjRgI2jHZ4evdjhQYBSan/vGtF6XVXPApOmNH2rf0KKw==" 16 | }, 17 | "accepts": { 18 | "version": "1.3.4", 19 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", 20 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", 21 | "requires": { 22 | "mime-types": "2.1.17", 23 | "negotiator": "0.6.1" 24 | } 25 | }, 26 | "acorn": { 27 | "version": "5.3.0", 28 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz", 29 | "integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==", 30 | "dev": true 31 | }, 32 | "acorn-jsx": { 33 | "version": "3.0.1", 34 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", 35 | "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", 36 | "dev": true, 37 | "requires": { 38 | "acorn": "3.3.0" 39 | }, 40 | "dependencies": { 41 | "acorn": { 42 | "version": "3.3.0", 43 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", 44 | "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", 45 | "dev": true 46 | } 47 | } 48 | }, 49 | "ajv": { 50 | "version": "5.5.2", 51 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", 52 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", 53 | "dev": true, 54 | "requires": { 55 | "co": "4.6.0", 56 | "fast-deep-equal": "1.0.0", 57 | "fast-json-stable-stringify": "2.0.0", 58 | "json-schema-traverse": "0.3.1" 59 | } 60 | }, 61 | "ajv-keywords": { 62 | "version": "2.1.1", 63 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", 64 | "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", 65 | "dev": true 66 | }, 67 | "ansi-escapes": { 68 | "version": "3.0.0", 69 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", 70 | "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", 71 | "dev": true 72 | }, 73 | "ansi-regex": { 74 | "version": "2.1.1", 75 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 76 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 77 | "dev": true 78 | }, 79 | "ansi-styles": { 80 | "version": "2.2.1", 81 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 82 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 83 | "dev": true 84 | }, 85 | "ansicolors": { 86 | "version": "0.2.1", 87 | "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz", 88 | "integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=" 89 | }, 90 | "argparse": { 91 | "version": "1.0.9", 92 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", 93 | "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", 94 | "dev": true, 95 | "requires": { 96 | "sprintf-js": "1.0.3" 97 | } 98 | }, 99 | "array-flatten": { 100 | "version": "1.1.1", 101 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 102 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 103 | }, 104 | "array-union": { 105 | "version": "1.0.2", 106 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 107 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", 108 | "dev": true, 109 | "requires": { 110 | "array-uniq": "1.0.3" 111 | } 112 | }, 113 | "array-uniq": { 114 | "version": "1.0.3", 115 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 116 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", 117 | "dev": true 118 | }, 119 | "arrify": { 120 | "version": "1.0.1", 121 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 122 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 123 | "dev": true 124 | }, 125 | "babel-code-frame": { 126 | "version": "6.26.0", 127 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 128 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 129 | "dev": true, 130 | "requires": { 131 | "chalk": "1.1.3", 132 | "esutils": "2.0.2", 133 | "js-tokens": "3.0.2" 134 | }, 135 | "dependencies": { 136 | "chalk": { 137 | "version": "1.1.3", 138 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 139 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 140 | "dev": true, 141 | "requires": { 142 | "ansi-styles": "2.2.1", 143 | "escape-string-regexp": "1.0.5", 144 | "has-ansi": "2.0.0", 145 | "strip-ansi": "3.0.1", 146 | "supports-color": "2.0.0" 147 | } 148 | }, 149 | "strip-ansi": { 150 | "version": "3.0.1", 151 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 152 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 153 | "dev": true, 154 | "requires": { 155 | "ansi-regex": "2.1.1" 156 | } 157 | } 158 | } 159 | }, 160 | "balanced-match": { 161 | "version": "1.0.0", 162 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 163 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 164 | "dev": true 165 | }, 166 | "bluebird": { 167 | "version": "3.5.1", 168 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 169 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" 170 | }, 171 | "body-parser": { 172 | "version": "1.18.2", 173 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 174 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 175 | "requires": { 176 | "bytes": "3.0.0", 177 | "content-type": "1.0.4", 178 | "debug": "2.6.9", 179 | "depd": "1.1.2", 180 | "http-errors": "1.6.2", 181 | "iconv-lite": "0.4.19", 182 | "on-finished": "2.3.0", 183 | "qs": "6.5.1", 184 | "raw-body": "2.3.2", 185 | "type-is": "1.6.15" 186 | } 187 | }, 188 | "brace-expansion": { 189 | "version": "1.1.8", 190 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 191 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 192 | "dev": true, 193 | "requires": { 194 | "balanced-match": "1.0.0", 195 | "concat-map": "0.0.1" 196 | } 197 | }, 198 | "builtin-modules": { 199 | "version": "1.1.1", 200 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 201 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 202 | "dev": true 203 | }, 204 | "bytes": { 205 | "version": "3.0.0", 206 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 207 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 208 | }, 209 | "caller-path": { 210 | "version": "0.1.0", 211 | "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", 212 | "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", 213 | "dev": true, 214 | "requires": { 215 | "callsites": "0.2.0" 216 | } 217 | }, 218 | "callsites": { 219 | "version": "0.2.0", 220 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", 221 | "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", 222 | "dev": true 223 | }, 224 | "cardinal": { 225 | "version": "1.0.0", 226 | "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz", 227 | "integrity": "sha1-UOIcGwqjdyn5N33vGWtanOyTLuk=", 228 | "requires": { 229 | "ansicolors": "0.2.1", 230 | "redeyed": "1.0.1" 231 | } 232 | }, 233 | "chalk": { 234 | "version": "2.3.0", 235 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", 236 | "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", 237 | "dev": true, 238 | "requires": { 239 | "ansi-styles": "3.2.0", 240 | "escape-string-regexp": "1.0.5", 241 | "supports-color": "4.5.0" 242 | }, 243 | "dependencies": { 244 | "ansi-styles": { 245 | "version": "3.2.0", 246 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", 247 | "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", 248 | "dev": true, 249 | "requires": { 250 | "color-convert": "1.9.1" 251 | } 252 | }, 253 | "supports-color": { 254 | "version": "4.5.0", 255 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", 256 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", 257 | "dev": true, 258 | "requires": { 259 | "has-flag": "2.0.0" 260 | } 261 | } 262 | } 263 | }, 264 | "chardet": { 265 | "version": "0.4.2", 266 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", 267 | "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", 268 | "dev": true 269 | }, 270 | "circular-json": { 271 | "version": "0.3.3", 272 | "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", 273 | "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", 274 | "dev": true 275 | }, 276 | "cli-cursor": { 277 | "version": "2.1.0", 278 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 279 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 280 | "dev": true, 281 | "requires": { 282 | "restore-cursor": "2.0.0" 283 | } 284 | }, 285 | "cli-width": { 286 | "version": "2.2.0", 287 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 288 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 289 | "dev": true 290 | }, 291 | "cls-bluebird": { 292 | "version": "2.1.0", 293 | "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", 294 | "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", 295 | "requires": { 296 | "is-bluebird": "1.0.2", 297 | "shimmer": "1.2.0" 298 | } 299 | }, 300 | "co": { 301 | "version": "4.6.0", 302 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 303 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", 304 | "dev": true 305 | }, 306 | "color-convert": { 307 | "version": "1.9.1", 308 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", 309 | "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", 310 | "dev": true, 311 | "requires": { 312 | "color-name": "1.1.3" 313 | } 314 | }, 315 | "color-name": { 316 | "version": "1.1.3", 317 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 318 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 319 | "dev": true 320 | }, 321 | "concat-map": { 322 | "version": "0.0.1", 323 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 324 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 325 | "dev": true 326 | }, 327 | "concat-stream": { 328 | "version": "1.6.0", 329 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", 330 | "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", 331 | "dev": true, 332 | "requires": { 333 | "inherits": "2.0.3", 334 | "readable-stream": "2.3.3", 335 | "typedarray": "0.0.6" 336 | } 337 | }, 338 | "contains-path": { 339 | "version": "0.1.0", 340 | "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", 341 | "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", 342 | "dev": true 343 | }, 344 | "content-disposition": { 345 | "version": "0.5.2", 346 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 347 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 348 | }, 349 | "content-type": { 350 | "version": "1.0.4", 351 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 352 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 353 | }, 354 | "cookie": { 355 | "version": "0.3.1", 356 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 357 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 358 | }, 359 | "cookie-parser": { 360 | "version": "1.4.3", 361 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", 362 | "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", 363 | "requires": { 364 | "cookie": "0.3.1", 365 | "cookie-signature": "1.0.6" 366 | } 367 | }, 368 | "cookie-signature": { 369 | "version": "1.0.6", 370 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 371 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 372 | }, 373 | "core-util-is": { 374 | "version": "1.0.2", 375 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 376 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 377 | }, 378 | "cross-spawn": { 379 | "version": "5.1.0", 380 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", 381 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", 382 | "dev": true, 383 | "requires": { 384 | "lru-cache": "4.1.1", 385 | "shebang-command": "1.2.0", 386 | "which": "1.3.0" 387 | } 388 | }, 389 | "debug": { 390 | "version": "2.6.9", 391 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 392 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 393 | "requires": { 394 | "ms": "2.0.0" 395 | } 396 | }, 397 | "deep-is": { 398 | "version": "0.1.3", 399 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 400 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 401 | "dev": true 402 | }, 403 | "del": { 404 | "version": "2.2.2", 405 | "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", 406 | "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", 407 | "dev": true, 408 | "requires": { 409 | "globby": "5.0.0", 410 | "is-path-cwd": "1.0.0", 411 | "is-path-in-cwd": "1.0.0", 412 | "object-assign": "4.1.1", 413 | "pify": "2.3.0", 414 | "pinkie-promise": "2.0.1", 415 | "rimraf": "2.6.2" 416 | } 417 | }, 418 | "denque": { 419 | "version": "1.2.2", 420 | "resolved": "https://registry.npmjs.org/denque/-/denque-1.2.2.tgz", 421 | "integrity": "sha512-x92Ql74lcTbGylXILO9Xf9S0cMpEPP04zVp2bB9e2C7G/n/Q1SgLl78RaSYEPSgpDX9uLgQXCEGAS5BI5dP3yA==" 422 | }, 423 | "depd": { 424 | "version": "1.1.2", 425 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 426 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 427 | }, 428 | "destroy": { 429 | "version": "1.0.4", 430 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 431 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 432 | }, 433 | "doctrine": { 434 | "version": "2.1.0", 435 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", 436 | "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", 437 | "dev": true, 438 | "requires": { 439 | "esutils": "2.0.2" 440 | } 441 | }, 442 | "dottie": { 443 | "version": "2.0.0", 444 | "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.0.tgz", 445 | "integrity": "sha1-2hkZgci41xPKARXViYzzl8Lw3dA=" 446 | }, 447 | "ee-first": { 448 | "version": "1.1.1", 449 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 450 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 451 | }, 452 | "encodeurl": { 453 | "version": "1.0.1", 454 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", 455 | "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" 456 | }, 457 | "error-ex": { 458 | "version": "1.3.1", 459 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", 460 | "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", 461 | "dev": true, 462 | "requires": { 463 | "is-arrayish": "0.2.1" 464 | } 465 | }, 466 | "escape-html": { 467 | "version": "1.0.3", 468 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 469 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 470 | }, 471 | "escape-string-regexp": { 472 | "version": "1.0.5", 473 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 474 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 475 | "dev": true 476 | }, 477 | "eslint": { 478 | "version": "4.15.0", 479 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.15.0.tgz", 480 | "integrity": "sha512-zEO/Z1ZUxIQ+MhDVKkVTUYpIPDTEJLXGMrkID+5v1NeQHtCz6FZikWuFRgxE1Q/RV2V4zVl1u3xmpPADHhMZ6A==", 481 | "dev": true, 482 | "requires": { 483 | "ajv": "5.5.2", 484 | "babel-code-frame": "6.26.0", 485 | "chalk": "2.3.0", 486 | "concat-stream": "1.6.0", 487 | "cross-spawn": "5.1.0", 488 | "debug": "3.1.0", 489 | "doctrine": "2.1.0", 490 | "eslint-scope": "3.7.1", 491 | "eslint-visitor-keys": "1.0.0", 492 | "espree": "3.5.2", 493 | "esquery": "1.0.0", 494 | "esutils": "2.0.2", 495 | "file-entry-cache": "2.0.0", 496 | "functional-red-black-tree": "1.0.1", 497 | "glob": "7.1.2", 498 | "globals": "11.1.0", 499 | "ignore": "3.3.7", 500 | "imurmurhash": "0.1.4", 501 | "inquirer": "3.3.0", 502 | "is-resolvable": "1.0.1", 503 | "js-yaml": "3.10.0", 504 | "json-stable-stringify-without-jsonify": "1.0.1", 505 | "levn": "0.3.0", 506 | "lodash": "4.17.4", 507 | "minimatch": "3.0.4", 508 | "mkdirp": "0.5.1", 509 | "natural-compare": "1.4.0", 510 | "optionator": "0.8.2", 511 | "path-is-inside": "1.0.2", 512 | "pluralize": "7.0.0", 513 | "progress": "2.0.0", 514 | "require-uncached": "1.0.3", 515 | "semver": "5.5.0", 516 | "strip-ansi": "4.0.0", 517 | "strip-json-comments": "2.0.1", 518 | "table": "4.0.2", 519 | "text-table": "0.2.0" 520 | }, 521 | "dependencies": { 522 | "debug": { 523 | "version": "3.1.0", 524 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 525 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 526 | "dev": true, 527 | "requires": { 528 | "ms": "2.0.0" 529 | } 530 | } 531 | } 532 | }, 533 | "eslint-config-standard": { 534 | "version": "10.2.1", 535 | "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", 536 | "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", 537 | "dev": true 538 | }, 539 | "eslint-import-resolver-node": { 540 | "version": "0.3.2", 541 | "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", 542 | "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", 543 | "dev": true, 544 | "requires": { 545 | "debug": "2.6.9", 546 | "resolve": "1.5.0" 547 | } 548 | }, 549 | "eslint-module-utils": { 550 | "version": "2.1.1", 551 | "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz", 552 | "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", 553 | "dev": true, 554 | "requires": { 555 | "debug": "2.6.9", 556 | "pkg-dir": "1.0.0" 557 | } 558 | }, 559 | "eslint-plugin-import": { 560 | "version": "2.8.0", 561 | "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz", 562 | "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==", 563 | "dev": true, 564 | "requires": { 565 | "builtin-modules": "1.1.1", 566 | "contains-path": "0.1.0", 567 | "debug": "2.6.9", 568 | "doctrine": "1.5.0", 569 | "eslint-import-resolver-node": "0.3.2", 570 | "eslint-module-utils": "2.1.1", 571 | "has": "1.0.1", 572 | "lodash.cond": "4.5.2", 573 | "minimatch": "3.0.4", 574 | "read-pkg-up": "2.0.0" 575 | }, 576 | "dependencies": { 577 | "doctrine": { 578 | "version": "1.5.0", 579 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", 580 | "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", 581 | "dev": true, 582 | "requires": { 583 | "esutils": "2.0.2", 584 | "isarray": "1.0.0" 585 | } 586 | } 587 | } 588 | }, 589 | "eslint-plugin-node": { 590 | "version": "5.2.1", 591 | "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", 592 | "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", 593 | "dev": true, 594 | "requires": { 595 | "ignore": "3.3.7", 596 | "minimatch": "3.0.4", 597 | "resolve": "1.5.0", 598 | "semver": "5.3.0" 599 | }, 600 | "dependencies": { 601 | "semver": { 602 | "version": "5.3.0", 603 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", 604 | "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", 605 | "dev": true 606 | } 607 | } 608 | }, 609 | "eslint-plugin-promise": { 610 | "version": "3.6.0", 611 | "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.6.0.tgz", 612 | "integrity": "sha512-YQzM6TLTlApAr7Li8vWKR+K3WghjwKcYzY0d2roWap4SLK+kzuagJX/leTetIDWsFcTFnKNJXWupDCD6aZkP2Q==", 613 | "dev": true 614 | }, 615 | "eslint-plugin-standard": { 616 | "version": "3.0.1", 617 | "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", 618 | "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", 619 | "dev": true 620 | }, 621 | "eslint-scope": { 622 | "version": "3.7.1", 623 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", 624 | "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", 625 | "dev": true, 626 | "requires": { 627 | "esrecurse": "4.2.0", 628 | "estraverse": "4.2.0" 629 | } 630 | }, 631 | "eslint-visitor-keys": { 632 | "version": "1.0.0", 633 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", 634 | "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", 635 | "dev": true 636 | }, 637 | "espree": { 638 | "version": "3.5.2", 639 | "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz", 640 | "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", 641 | "dev": true, 642 | "requires": { 643 | "acorn": "5.3.0", 644 | "acorn-jsx": "3.0.1" 645 | } 646 | }, 647 | "esprima": { 648 | "version": "4.0.0", 649 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", 650 | "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", 651 | "dev": true 652 | }, 653 | "esquery": { 654 | "version": "1.0.0", 655 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", 656 | "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", 657 | "dev": true, 658 | "requires": { 659 | "estraverse": "4.2.0" 660 | } 661 | }, 662 | "esrecurse": { 663 | "version": "4.2.0", 664 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", 665 | "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", 666 | "dev": true, 667 | "requires": { 668 | "estraverse": "4.2.0", 669 | "object-assign": "4.1.1" 670 | } 671 | }, 672 | "estraverse": { 673 | "version": "4.2.0", 674 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 675 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 676 | "dev": true 677 | }, 678 | "esutils": { 679 | "version": "2.0.2", 680 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 681 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 682 | "dev": true 683 | }, 684 | "etag": { 685 | "version": "1.8.1", 686 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 687 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 688 | }, 689 | "express": { 690 | "version": "4.16.2", 691 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", 692 | "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", 693 | "requires": { 694 | "accepts": "1.3.4", 695 | "array-flatten": "1.1.1", 696 | "body-parser": "1.18.2", 697 | "content-disposition": "0.5.2", 698 | "content-type": "1.0.4", 699 | "cookie": "0.3.1", 700 | "cookie-signature": "1.0.6", 701 | "debug": "2.6.9", 702 | "depd": "1.1.2", 703 | "encodeurl": "1.0.1", 704 | "escape-html": "1.0.3", 705 | "etag": "1.8.1", 706 | "finalhandler": "1.1.0", 707 | "fresh": "0.5.2", 708 | "merge-descriptors": "1.0.1", 709 | "methods": "1.1.2", 710 | "on-finished": "2.3.0", 711 | "parseurl": "1.3.2", 712 | "path-to-regexp": "0.1.7", 713 | "proxy-addr": "2.0.2", 714 | "qs": "6.5.1", 715 | "range-parser": "1.2.0", 716 | "safe-buffer": "5.1.1", 717 | "send": "0.16.1", 718 | "serve-static": "1.13.1", 719 | "setprototypeof": "1.1.0", 720 | "statuses": "1.3.1", 721 | "type-is": "1.6.15", 722 | "utils-merge": "1.0.1", 723 | "vary": "1.1.2" 724 | } 725 | }, 726 | "external-editor": { 727 | "version": "2.1.0", 728 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", 729 | "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", 730 | "dev": true, 731 | "requires": { 732 | "chardet": "0.4.2", 733 | "iconv-lite": "0.4.19", 734 | "tmp": "0.0.33" 735 | } 736 | }, 737 | "fast-deep-equal": { 738 | "version": "1.0.0", 739 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", 740 | "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", 741 | "dev": true 742 | }, 743 | "fast-json-stable-stringify": { 744 | "version": "2.0.0", 745 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 746 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", 747 | "dev": true 748 | }, 749 | "fast-levenshtein": { 750 | "version": "2.0.6", 751 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 752 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 753 | "dev": true 754 | }, 755 | "figures": { 756 | "version": "2.0.0", 757 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 758 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 759 | "dev": true, 760 | "requires": { 761 | "escape-string-regexp": "1.0.5" 762 | } 763 | }, 764 | "file-entry-cache": { 765 | "version": "2.0.0", 766 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", 767 | "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", 768 | "dev": true, 769 | "requires": { 770 | "flat-cache": "1.3.0", 771 | "object-assign": "4.1.1" 772 | } 773 | }, 774 | "finalhandler": { 775 | "version": "1.1.0", 776 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", 777 | "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", 778 | "requires": { 779 | "debug": "2.6.9", 780 | "encodeurl": "1.0.1", 781 | "escape-html": "1.0.3", 782 | "on-finished": "2.3.0", 783 | "parseurl": "1.3.2", 784 | "statuses": "1.3.1", 785 | "unpipe": "1.0.0" 786 | } 787 | }, 788 | "find-up": { 789 | "version": "1.1.2", 790 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 791 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 792 | "dev": true, 793 | "requires": { 794 | "path-exists": "2.1.0", 795 | "pinkie-promise": "2.0.1" 796 | } 797 | }, 798 | "flat-cache": { 799 | "version": "1.3.0", 800 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", 801 | "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", 802 | "dev": true, 803 | "requires": { 804 | "circular-json": "0.3.3", 805 | "del": "2.2.2", 806 | "graceful-fs": "4.1.11", 807 | "write": "0.2.1" 808 | } 809 | }, 810 | "forwarded": { 811 | "version": "0.1.2", 812 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 813 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 814 | }, 815 | "fresh": { 816 | "version": "0.5.2", 817 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 818 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 819 | }, 820 | "fs.realpath": { 821 | "version": "1.0.0", 822 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 823 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 824 | "dev": true 825 | }, 826 | "function-bind": { 827 | "version": "1.1.1", 828 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 829 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 830 | "dev": true 831 | }, 832 | "functional-red-black-tree": { 833 | "version": "1.0.1", 834 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 835 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 836 | "dev": true 837 | }, 838 | "generate-function": { 839 | "version": "2.0.0", 840 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", 841 | "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" 842 | }, 843 | "generic-pool": { 844 | "version": "3.4.0", 845 | "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.4.0.tgz", 846 | "integrity": "sha512-lYsIpjkyNBnRLKrcnJlXTEXB2ISmK9g7N4WqWwXbvr+tVB1+raaFnHoCYecWnuCo/XGHgM935WOWmr5Zx3tJKw==" 847 | }, 848 | "glob": { 849 | "version": "7.1.2", 850 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 851 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 852 | "dev": true, 853 | "requires": { 854 | "fs.realpath": "1.0.0", 855 | "inflight": "1.0.6", 856 | "inherits": "2.0.3", 857 | "minimatch": "3.0.4", 858 | "once": "1.4.0", 859 | "path-is-absolute": "1.0.1" 860 | } 861 | }, 862 | "globals": { 863 | "version": "11.1.0", 864 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.1.0.tgz", 865 | "integrity": "sha512-uEuWt9mqTlPDwSqi+sHjD4nWU/1N+q0fiWI9T1mZpD2UENqX20CFD5T/ziLZvztPaBKl7ZylUi1q6Qfm7E2CiQ==", 866 | "dev": true 867 | }, 868 | "globby": { 869 | "version": "5.0.0", 870 | "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", 871 | "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", 872 | "dev": true, 873 | "requires": { 874 | "array-union": "1.0.2", 875 | "arrify": "1.0.1", 876 | "glob": "7.1.2", 877 | "object-assign": "4.1.1", 878 | "pify": "2.3.0", 879 | "pinkie-promise": "2.0.1" 880 | } 881 | }, 882 | "graceful-fs": { 883 | "version": "4.1.11", 884 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 885 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 886 | "dev": true 887 | }, 888 | "has": { 889 | "version": "1.0.1", 890 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", 891 | "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", 892 | "dev": true, 893 | "requires": { 894 | "function-bind": "1.1.1" 895 | } 896 | }, 897 | "has-ansi": { 898 | "version": "2.0.0", 899 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 900 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 901 | "dev": true, 902 | "requires": { 903 | "ansi-regex": "2.1.1" 904 | } 905 | }, 906 | "has-flag": { 907 | "version": "2.0.0", 908 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 909 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", 910 | "dev": true 911 | }, 912 | "hosted-git-info": { 913 | "version": "2.5.0", 914 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", 915 | "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", 916 | "dev": true 917 | }, 918 | "http-errors": { 919 | "version": "1.6.2", 920 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 921 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 922 | "requires": { 923 | "depd": "1.1.1", 924 | "inherits": "2.0.3", 925 | "setprototypeof": "1.0.3", 926 | "statuses": "1.3.1" 927 | }, 928 | "dependencies": { 929 | "depd": { 930 | "version": "1.1.1", 931 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 932 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 933 | }, 934 | "setprototypeof": { 935 | "version": "1.0.3", 936 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 937 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 938 | } 939 | } 940 | }, 941 | "iconv-lite": { 942 | "version": "0.4.19", 943 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 944 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 945 | }, 946 | "ignore": { 947 | "version": "3.3.7", 948 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", 949 | "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", 950 | "dev": true 951 | }, 952 | "imurmurhash": { 953 | "version": "0.1.4", 954 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 955 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 956 | "dev": true 957 | }, 958 | "inflection": { 959 | "version": "1.12.0", 960 | "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", 961 | "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" 962 | }, 963 | "inflight": { 964 | "version": "1.0.6", 965 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 966 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 967 | "dev": true, 968 | "requires": { 969 | "once": "1.4.0", 970 | "wrappy": "1.0.2" 971 | } 972 | }, 973 | "inherits": { 974 | "version": "2.0.3", 975 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 976 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 977 | }, 978 | "inquirer": { 979 | "version": "3.3.0", 980 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", 981 | "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", 982 | "dev": true, 983 | "requires": { 984 | "ansi-escapes": "3.0.0", 985 | "chalk": "2.3.0", 986 | "cli-cursor": "2.1.0", 987 | "cli-width": "2.2.0", 988 | "external-editor": "2.1.0", 989 | "figures": "2.0.0", 990 | "lodash": "4.17.4", 991 | "mute-stream": "0.0.7", 992 | "run-async": "2.3.0", 993 | "rx-lite": "4.0.8", 994 | "rx-lite-aggregates": "4.0.8", 995 | "string-width": "2.1.1", 996 | "strip-ansi": "4.0.0", 997 | "through": "2.3.8" 998 | } 999 | }, 1000 | "ipaddr.js": { 1001 | "version": "1.5.2", 1002 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", 1003 | "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" 1004 | }, 1005 | "is-arrayish": { 1006 | "version": "0.2.1", 1007 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 1008 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 1009 | "dev": true 1010 | }, 1011 | "is-bluebird": { 1012 | "version": "1.0.2", 1013 | "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", 1014 | "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" 1015 | }, 1016 | "is-builtin-module": { 1017 | "version": "1.0.0", 1018 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", 1019 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", 1020 | "dev": true, 1021 | "requires": { 1022 | "builtin-modules": "1.1.1" 1023 | } 1024 | }, 1025 | "is-fullwidth-code-point": { 1026 | "version": "2.0.0", 1027 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1028 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1029 | "dev": true 1030 | }, 1031 | "is-path-cwd": { 1032 | "version": "1.0.0", 1033 | "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", 1034 | "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", 1035 | "dev": true 1036 | }, 1037 | "is-path-in-cwd": { 1038 | "version": "1.0.0", 1039 | "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", 1040 | "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", 1041 | "dev": true, 1042 | "requires": { 1043 | "is-path-inside": "1.0.1" 1044 | } 1045 | }, 1046 | "is-path-inside": { 1047 | "version": "1.0.1", 1048 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", 1049 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", 1050 | "dev": true, 1051 | "requires": { 1052 | "path-is-inside": "1.0.2" 1053 | } 1054 | }, 1055 | "is-promise": { 1056 | "version": "2.1.0", 1057 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 1058 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", 1059 | "dev": true 1060 | }, 1061 | "is-resolvable": { 1062 | "version": "1.0.1", 1063 | "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", 1064 | "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==", 1065 | "dev": true 1066 | }, 1067 | "isarray": { 1068 | "version": "1.0.0", 1069 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1070 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 1071 | }, 1072 | "isexe": { 1073 | "version": "2.0.0", 1074 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1075 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1076 | "dev": true 1077 | }, 1078 | "js-tokens": { 1079 | "version": "3.0.2", 1080 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 1081 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 1082 | "dev": true 1083 | }, 1084 | "js-yaml": { 1085 | "version": "3.10.0", 1086 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", 1087 | "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", 1088 | "dev": true, 1089 | "requires": { 1090 | "argparse": "1.0.9", 1091 | "esprima": "4.0.0" 1092 | } 1093 | }, 1094 | "json-schema-traverse": { 1095 | "version": "0.3.1", 1096 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", 1097 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", 1098 | "dev": true 1099 | }, 1100 | "json-stable-stringify-without-jsonify": { 1101 | "version": "1.0.1", 1102 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1103 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 1104 | "dev": true 1105 | }, 1106 | "levn": { 1107 | "version": "0.3.0", 1108 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 1109 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 1110 | "dev": true, 1111 | "requires": { 1112 | "prelude-ls": "1.1.2", 1113 | "type-check": "0.3.2" 1114 | } 1115 | }, 1116 | "load-json-file": { 1117 | "version": "2.0.0", 1118 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", 1119 | "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", 1120 | "dev": true, 1121 | "requires": { 1122 | "graceful-fs": "4.1.11", 1123 | "parse-json": "2.2.0", 1124 | "pify": "2.3.0", 1125 | "strip-bom": "3.0.0" 1126 | } 1127 | }, 1128 | "locate-path": { 1129 | "version": "2.0.0", 1130 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 1131 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 1132 | "dev": true, 1133 | "requires": { 1134 | "p-locate": "2.0.0", 1135 | "path-exists": "3.0.0" 1136 | }, 1137 | "dependencies": { 1138 | "path-exists": { 1139 | "version": "3.0.0", 1140 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1141 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1142 | "dev": true 1143 | } 1144 | } 1145 | }, 1146 | "lodash": { 1147 | "version": "4.17.4", 1148 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 1149 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" 1150 | }, 1151 | "lodash.cond": { 1152 | "version": "4.5.2", 1153 | "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", 1154 | "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", 1155 | "dev": true 1156 | }, 1157 | "long": { 1158 | "version": "3.2.0", 1159 | "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", 1160 | "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" 1161 | }, 1162 | "lru-cache": { 1163 | "version": "4.1.1", 1164 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", 1165 | "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", 1166 | "requires": { 1167 | "pseudomap": "1.0.2", 1168 | "yallist": "2.1.2" 1169 | } 1170 | }, 1171 | "media-typer": { 1172 | "version": "0.3.0", 1173 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1174 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 1175 | }, 1176 | "merge-descriptors": { 1177 | "version": "1.0.1", 1178 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1179 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 1180 | }, 1181 | "methods": { 1182 | "version": "1.1.2", 1183 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1184 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 1185 | }, 1186 | "mime": { 1187 | "version": "1.4.1", 1188 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 1189 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 1190 | }, 1191 | "mime-db": { 1192 | "version": "1.30.0", 1193 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 1194 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" 1195 | }, 1196 | "mime-types": { 1197 | "version": "2.1.17", 1198 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 1199 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 1200 | "requires": { 1201 | "mime-db": "1.30.0" 1202 | } 1203 | }, 1204 | "mimic-fn": { 1205 | "version": "1.1.0", 1206 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", 1207 | "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", 1208 | "dev": true 1209 | }, 1210 | "minimatch": { 1211 | "version": "3.0.4", 1212 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1213 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1214 | "dev": true, 1215 | "requires": { 1216 | "brace-expansion": "1.1.8" 1217 | } 1218 | }, 1219 | "minimist": { 1220 | "version": "0.0.8", 1221 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1222 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 1223 | "dev": true 1224 | }, 1225 | "mkdirp": { 1226 | "version": "0.5.1", 1227 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1228 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1229 | "dev": true, 1230 | "requires": { 1231 | "minimist": "0.0.8" 1232 | } 1233 | }, 1234 | "moment": { 1235 | "version": "2.20.1", 1236 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", 1237 | "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg==" 1238 | }, 1239 | "moment-timezone": { 1240 | "version": "0.5.14", 1241 | "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.14.tgz", 1242 | "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=", 1243 | "requires": { 1244 | "moment": "2.20.1" 1245 | } 1246 | }, 1247 | "ms": { 1248 | "version": "2.0.0", 1249 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1250 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 1251 | }, 1252 | "mute-stream": { 1253 | "version": "0.0.7", 1254 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 1255 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", 1256 | "dev": true 1257 | }, 1258 | "mysql2": { 1259 | "version": "1.5.1", 1260 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.5.1.tgz", 1261 | "integrity": "sha1-JBHW+5WK+GsjBLelO8VLJud+aCs=", 1262 | "requires": { 1263 | "cardinal": "1.0.0", 1264 | "denque": "1.2.2", 1265 | "generate-function": "2.0.0", 1266 | "iconv-lite": "0.4.19", 1267 | "long": "3.2.0", 1268 | "lru-cache": "4.1.1", 1269 | "named-placeholders": "1.1.1", 1270 | "object-assign": "4.1.1", 1271 | "readable-stream": "2.3.2", 1272 | "safe-buffer": "5.1.1", 1273 | "seq-queue": "0.0.5", 1274 | "sqlstring": "2.3.0" 1275 | }, 1276 | "dependencies": { 1277 | "readable-stream": { 1278 | "version": "2.3.2", 1279 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", 1280 | "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=", 1281 | "requires": { 1282 | "core-util-is": "1.0.2", 1283 | "inherits": "2.0.3", 1284 | "isarray": "1.0.0", 1285 | "process-nextick-args": "1.0.7", 1286 | "safe-buffer": "5.1.1", 1287 | "string_decoder": "1.0.3", 1288 | "util-deprecate": "1.0.2" 1289 | } 1290 | } 1291 | } 1292 | }, 1293 | "named-placeholders": { 1294 | "version": "1.1.1", 1295 | "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.1.tgz", 1296 | "integrity": "sha1-O3oNJiA910s6nfTJz7gnsvuQfmQ=", 1297 | "requires": { 1298 | "lru-cache": "2.5.0" 1299 | }, 1300 | "dependencies": { 1301 | "lru-cache": { 1302 | "version": "2.5.0", 1303 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz", 1304 | "integrity": "sha1-2COIrpyWC+y+oMc7uet5tsbOmus=" 1305 | } 1306 | } 1307 | }, 1308 | "natural-compare": { 1309 | "version": "1.4.0", 1310 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1311 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1312 | "dev": true 1313 | }, 1314 | "negotiator": { 1315 | "version": "0.6.1", 1316 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 1317 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 1318 | }, 1319 | "node-uuid": { 1320 | "version": "1.4.8", 1321 | "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", 1322 | "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" 1323 | }, 1324 | "normalize-package-data": { 1325 | "version": "2.4.0", 1326 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", 1327 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", 1328 | "dev": true, 1329 | "requires": { 1330 | "hosted-git-info": "2.5.0", 1331 | "is-builtin-module": "1.0.0", 1332 | "semver": "5.5.0", 1333 | "validate-npm-package-license": "3.0.1" 1334 | } 1335 | }, 1336 | "object-assign": { 1337 | "version": "4.1.1", 1338 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1339 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 1340 | }, 1341 | "on-finished": { 1342 | "version": "2.3.0", 1343 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1344 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1345 | "requires": { 1346 | "ee-first": "1.1.1" 1347 | } 1348 | }, 1349 | "once": { 1350 | "version": "1.4.0", 1351 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1352 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1353 | "dev": true, 1354 | "requires": { 1355 | "wrappy": "1.0.2" 1356 | } 1357 | }, 1358 | "onetime": { 1359 | "version": "2.0.1", 1360 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 1361 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 1362 | "dev": true, 1363 | "requires": { 1364 | "mimic-fn": "1.1.0" 1365 | } 1366 | }, 1367 | "optionator": { 1368 | "version": "0.8.2", 1369 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 1370 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 1371 | "dev": true, 1372 | "requires": { 1373 | "deep-is": "0.1.3", 1374 | "fast-levenshtein": "2.0.6", 1375 | "levn": "0.3.0", 1376 | "prelude-ls": "1.1.2", 1377 | "type-check": "0.3.2", 1378 | "wordwrap": "1.0.0" 1379 | } 1380 | }, 1381 | "os-tmpdir": { 1382 | "version": "1.0.2", 1383 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1384 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 1385 | "dev": true 1386 | }, 1387 | "p-limit": { 1388 | "version": "1.2.0", 1389 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", 1390 | "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", 1391 | "dev": true, 1392 | "requires": { 1393 | "p-try": "1.0.0" 1394 | } 1395 | }, 1396 | "p-locate": { 1397 | "version": "2.0.0", 1398 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 1399 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 1400 | "dev": true, 1401 | "requires": { 1402 | "p-limit": "1.2.0" 1403 | } 1404 | }, 1405 | "p-try": { 1406 | "version": "1.0.0", 1407 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 1408 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", 1409 | "dev": true 1410 | }, 1411 | "parse-json": { 1412 | "version": "2.2.0", 1413 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 1414 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 1415 | "dev": true, 1416 | "requires": { 1417 | "error-ex": "1.3.1" 1418 | } 1419 | }, 1420 | "parseurl": { 1421 | "version": "1.3.2", 1422 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 1423 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 1424 | }, 1425 | "path-exists": { 1426 | "version": "2.1.0", 1427 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 1428 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 1429 | "dev": true, 1430 | "requires": { 1431 | "pinkie-promise": "2.0.1" 1432 | } 1433 | }, 1434 | "path-is-absolute": { 1435 | "version": "1.0.1", 1436 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1437 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1438 | "dev": true 1439 | }, 1440 | "path-is-inside": { 1441 | "version": "1.0.2", 1442 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1443 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 1444 | "dev": true 1445 | }, 1446 | "path-parse": { 1447 | "version": "1.0.5", 1448 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", 1449 | "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", 1450 | "dev": true 1451 | }, 1452 | "path-to-regexp": { 1453 | "version": "0.1.7", 1454 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1455 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 1456 | }, 1457 | "path-type": { 1458 | "version": "2.0.0", 1459 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", 1460 | "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", 1461 | "dev": true, 1462 | "requires": { 1463 | "pify": "2.3.0" 1464 | } 1465 | }, 1466 | "pify": { 1467 | "version": "2.3.0", 1468 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1469 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 1470 | "dev": true 1471 | }, 1472 | "pinkie": { 1473 | "version": "2.0.4", 1474 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1475 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 1476 | "dev": true 1477 | }, 1478 | "pinkie-promise": { 1479 | "version": "2.0.1", 1480 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1481 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1482 | "dev": true, 1483 | "requires": { 1484 | "pinkie": "2.0.4" 1485 | } 1486 | }, 1487 | "pkg-dir": { 1488 | "version": "1.0.0", 1489 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", 1490 | "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", 1491 | "dev": true, 1492 | "requires": { 1493 | "find-up": "1.1.2" 1494 | } 1495 | }, 1496 | "pluralize": { 1497 | "version": "7.0.0", 1498 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", 1499 | "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", 1500 | "dev": true 1501 | }, 1502 | "prelude-ls": { 1503 | "version": "1.1.2", 1504 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1505 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1506 | "dev": true 1507 | }, 1508 | "process-nextick-args": { 1509 | "version": "1.0.7", 1510 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 1511 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 1512 | }, 1513 | "progress": { 1514 | "version": "2.0.0", 1515 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", 1516 | "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", 1517 | "dev": true 1518 | }, 1519 | "proxy-addr": { 1520 | "version": "2.0.2", 1521 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", 1522 | "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", 1523 | "requires": { 1524 | "forwarded": "0.1.2", 1525 | "ipaddr.js": "1.5.2" 1526 | } 1527 | }, 1528 | "pseudomap": { 1529 | "version": "1.0.2", 1530 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 1531 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 1532 | }, 1533 | "qs": { 1534 | "version": "6.5.1", 1535 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 1536 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 1537 | }, 1538 | "range-parser": { 1539 | "version": "1.2.0", 1540 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 1541 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 1542 | }, 1543 | "raw-body": { 1544 | "version": "2.3.2", 1545 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 1546 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 1547 | "requires": { 1548 | "bytes": "3.0.0", 1549 | "http-errors": "1.6.2", 1550 | "iconv-lite": "0.4.19", 1551 | "unpipe": "1.0.0" 1552 | } 1553 | }, 1554 | "read-pkg": { 1555 | "version": "2.0.0", 1556 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", 1557 | "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", 1558 | "dev": true, 1559 | "requires": { 1560 | "load-json-file": "2.0.0", 1561 | "normalize-package-data": "2.4.0", 1562 | "path-type": "2.0.0" 1563 | } 1564 | }, 1565 | "read-pkg-up": { 1566 | "version": "2.0.0", 1567 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", 1568 | "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", 1569 | "dev": true, 1570 | "requires": { 1571 | "find-up": "2.1.0", 1572 | "read-pkg": "2.0.0" 1573 | }, 1574 | "dependencies": { 1575 | "find-up": { 1576 | "version": "2.1.0", 1577 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 1578 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 1579 | "dev": true, 1580 | "requires": { 1581 | "locate-path": "2.0.0" 1582 | } 1583 | } 1584 | } 1585 | }, 1586 | "readable-stream": { 1587 | "version": "2.3.3", 1588 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 1589 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 1590 | "dev": true, 1591 | "requires": { 1592 | "core-util-is": "1.0.2", 1593 | "inherits": "2.0.3", 1594 | "isarray": "1.0.0", 1595 | "process-nextick-args": "1.0.7", 1596 | "safe-buffer": "5.1.1", 1597 | "string_decoder": "1.0.3", 1598 | "util-deprecate": "1.0.2" 1599 | } 1600 | }, 1601 | "redeyed": { 1602 | "version": "1.0.1", 1603 | "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz", 1604 | "integrity": "sha1-6WwZO0DAgWsArshCaY5hGF5VSYo=", 1605 | "requires": { 1606 | "esprima": "3.0.0" 1607 | }, 1608 | "dependencies": { 1609 | "esprima": { 1610 | "version": "3.0.0", 1611 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz", 1612 | "integrity": "sha1-U88kes2ncxPlUcOqLnM0LT+099k=" 1613 | } 1614 | } 1615 | }, 1616 | "require-uncached": { 1617 | "version": "1.0.3", 1618 | "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", 1619 | "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", 1620 | "dev": true, 1621 | "requires": { 1622 | "caller-path": "0.1.0", 1623 | "resolve-from": "1.0.1" 1624 | } 1625 | }, 1626 | "resolve": { 1627 | "version": "1.5.0", 1628 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", 1629 | "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", 1630 | "dev": true, 1631 | "requires": { 1632 | "path-parse": "1.0.5" 1633 | } 1634 | }, 1635 | "resolve-from": { 1636 | "version": "1.0.1", 1637 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", 1638 | "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", 1639 | "dev": true 1640 | }, 1641 | "restore-cursor": { 1642 | "version": "2.0.0", 1643 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 1644 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 1645 | "dev": true, 1646 | "requires": { 1647 | "onetime": "2.0.1", 1648 | "signal-exit": "3.0.2" 1649 | } 1650 | }, 1651 | "retry-as-promised": { 1652 | "version": "2.3.2", 1653 | "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-2.3.2.tgz", 1654 | "integrity": "sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c=", 1655 | "requires": { 1656 | "bluebird": "3.5.1", 1657 | "debug": "2.6.9" 1658 | } 1659 | }, 1660 | "rimraf": { 1661 | "version": "2.6.2", 1662 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 1663 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 1664 | "dev": true, 1665 | "requires": { 1666 | "glob": "7.1.2" 1667 | } 1668 | }, 1669 | "run-async": { 1670 | "version": "2.3.0", 1671 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", 1672 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", 1673 | "dev": true, 1674 | "requires": { 1675 | "is-promise": "2.1.0" 1676 | } 1677 | }, 1678 | "rx-lite": { 1679 | "version": "4.0.8", 1680 | "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", 1681 | "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", 1682 | "dev": true 1683 | }, 1684 | "rx-lite-aggregates": { 1685 | "version": "4.0.8", 1686 | "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", 1687 | "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", 1688 | "dev": true, 1689 | "requires": { 1690 | "rx-lite": "4.0.8" 1691 | } 1692 | }, 1693 | "safe-buffer": { 1694 | "version": "5.1.1", 1695 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 1696 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 1697 | }, 1698 | "semver": { 1699 | "version": "5.5.0", 1700 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", 1701 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" 1702 | }, 1703 | "send": { 1704 | "version": "0.16.1", 1705 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", 1706 | "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", 1707 | "requires": { 1708 | "debug": "2.6.9", 1709 | "depd": "1.1.2", 1710 | "destroy": "1.0.4", 1711 | "encodeurl": "1.0.1", 1712 | "escape-html": "1.0.3", 1713 | "etag": "1.8.1", 1714 | "fresh": "0.5.2", 1715 | "http-errors": "1.6.2", 1716 | "mime": "1.4.1", 1717 | "ms": "2.0.0", 1718 | "on-finished": "2.3.0", 1719 | "range-parser": "1.2.0", 1720 | "statuses": "1.3.1" 1721 | } 1722 | }, 1723 | "seq-queue": { 1724 | "version": "0.0.5", 1725 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", 1726 | "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" 1727 | }, 1728 | "sequelize": { 1729 | "version": "4.31.2", 1730 | "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-4.31.2.tgz", 1731 | "integrity": "sha512-ldbh1tNPpeFZ30bWAW0HqW2rinjmCmvb2lqRQ/TxhjIT70ypnQzFhBjXeIxZDFtov5koaw9NTbaOwJQn8nkYgA==", 1732 | "requires": { 1733 | "bluebird": "3.5.1", 1734 | "cls-bluebird": "2.1.0", 1735 | "debug": "3.1.0", 1736 | "depd": "1.1.2", 1737 | "dottie": "2.0.0", 1738 | "generic-pool": "3.4.0", 1739 | "inflection": "1.12.0", 1740 | "lodash": "4.17.4", 1741 | "moment": "2.20.1", 1742 | "moment-timezone": "0.5.14", 1743 | "retry-as-promised": "2.3.2", 1744 | "semver": "5.5.0", 1745 | "terraformer-wkt-parser": "1.1.2", 1746 | "toposort-class": "1.0.1", 1747 | "uuid": "3.2.1", 1748 | "validator": "9.2.0", 1749 | "wkx": "0.4.2" 1750 | }, 1751 | "dependencies": { 1752 | "debug": { 1753 | "version": "3.1.0", 1754 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 1755 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 1756 | "requires": { 1757 | "ms": "2.0.0" 1758 | } 1759 | }, 1760 | "uuid": { 1761 | "version": "3.2.1", 1762 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", 1763 | "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" 1764 | } 1765 | } 1766 | }, 1767 | "serve-static": { 1768 | "version": "1.13.1", 1769 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", 1770 | "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", 1771 | "requires": { 1772 | "encodeurl": "1.0.1", 1773 | "escape-html": "1.0.3", 1774 | "parseurl": "1.3.2", 1775 | "send": "0.16.1" 1776 | } 1777 | }, 1778 | "setprototypeof": { 1779 | "version": "1.1.0", 1780 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 1781 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 1782 | }, 1783 | "sexy-require": { 1784 | "version": "0.1.0", 1785 | "resolved": "https://registry.npmjs.org/sexy-require/-/sexy-require-0.1.0.tgz", 1786 | "integrity": "sha1-5j7pvytaI24kXzaFCCEEcT02d2Y=" 1787 | }, 1788 | "shebang-command": { 1789 | "version": "1.2.0", 1790 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1791 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1792 | "dev": true, 1793 | "requires": { 1794 | "shebang-regex": "1.0.0" 1795 | } 1796 | }, 1797 | "shebang-regex": { 1798 | "version": "1.0.0", 1799 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1800 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1801 | "dev": true 1802 | }, 1803 | "shimmer": { 1804 | "version": "1.2.0", 1805 | "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.0.tgz", 1806 | "integrity": "sha512-xTCx2vohXC2EWWDqY/zb4+5Mu28D+HYNSOuFzsyRDRvI/e1ICb69afwaUwfjr+25ZXldbOLyp+iDUZHq8UnTag==" 1807 | }, 1808 | "signal-exit": { 1809 | "version": "3.0.2", 1810 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1811 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1812 | "dev": true 1813 | }, 1814 | "slice-ansi": { 1815 | "version": "1.0.0", 1816 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", 1817 | "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", 1818 | "dev": true, 1819 | "requires": { 1820 | "is-fullwidth-code-point": "2.0.0" 1821 | } 1822 | }, 1823 | "spdx-correct": { 1824 | "version": "1.0.2", 1825 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", 1826 | "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", 1827 | "dev": true, 1828 | "requires": { 1829 | "spdx-license-ids": "1.2.2" 1830 | } 1831 | }, 1832 | "spdx-expression-parse": { 1833 | "version": "1.0.4", 1834 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", 1835 | "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", 1836 | "dev": true 1837 | }, 1838 | "spdx-license-ids": { 1839 | "version": "1.2.2", 1840 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", 1841 | "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", 1842 | "dev": true 1843 | }, 1844 | "sprintf-js": { 1845 | "version": "1.0.3", 1846 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1847 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1848 | "dev": true 1849 | }, 1850 | "sqlstring": { 1851 | "version": "2.3.0", 1852 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.0.tgz", 1853 | "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg=" 1854 | }, 1855 | "statuses": { 1856 | "version": "1.3.1", 1857 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 1858 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 1859 | }, 1860 | "string-width": { 1861 | "version": "2.1.1", 1862 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1863 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1864 | "dev": true, 1865 | "requires": { 1866 | "is-fullwidth-code-point": "2.0.0", 1867 | "strip-ansi": "4.0.0" 1868 | } 1869 | }, 1870 | "string_decoder": { 1871 | "version": "1.0.3", 1872 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 1873 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 1874 | "requires": { 1875 | "safe-buffer": "5.1.1" 1876 | } 1877 | }, 1878 | "strip-ansi": { 1879 | "version": "4.0.0", 1880 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1881 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1882 | "dev": true, 1883 | "requires": { 1884 | "ansi-regex": "3.0.0" 1885 | }, 1886 | "dependencies": { 1887 | "ansi-regex": { 1888 | "version": "3.0.0", 1889 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 1890 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 1891 | "dev": true 1892 | } 1893 | } 1894 | }, 1895 | "strip-bom": { 1896 | "version": "3.0.0", 1897 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 1898 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 1899 | "dev": true 1900 | }, 1901 | "strip-json-comments": { 1902 | "version": "2.0.1", 1903 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1904 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1905 | "dev": true 1906 | }, 1907 | "supports-color": { 1908 | "version": "2.0.0", 1909 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1910 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1911 | "dev": true 1912 | }, 1913 | "table": { 1914 | "version": "4.0.2", 1915 | "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", 1916 | "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", 1917 | "dev": true, 1918 | "requires": { 1919 | "ajv": "5.5.2", 1920 | "ajv-keywords": "2.1.1", 1921 | "chalk": "2.3.0", 1922 | "lodash": "4.17.4", 1923 | "slice-ansi": "1.0.0", 1924 | "string-width": "2.1.1" 1925 | } 1926 | }, 1927 | "terraformer": { 1928 | "version": "1.0.8", 1929 | "resolved": "https://registry.npmjs.org/terraformer/-/terraformer-1.0.8.tgz", 1930 | "integrity": "sha1-UeCtiXRvzyFh3G9lqnDkI3fItZM=", 1931 | "requires": { 1932 | "@types/geojson": "1.0.6" 1933 | } 1934 | }, 1935 | "terraformer-wkt-parser": { 1936 | "version": "1.1.2", 1937 | "resolved": "https://registry.npmjs.org/terraformer-wkt-parser/-/terraformer-wkt-parser-1.1.2.tgz", 1938 | "integrity": "sha1-M2oMj8gglKWv+DKI9prt7NNpvww=", 1939 | "requires": { 1940 | "terraformer": "1.0.8" 1941 | } 1942 | }, 1943 | "text-table": { 1944 | "version": "0.2.0", 1945 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1946 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1947 | "dev": true 1948 | }, 1949 | "through": { 1950 | "version": "2.3.8", 1951 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1952 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1953 | "dev": true 1954 | }, 1955 | "tmp": { 1956 | "version": "0.0.33", 1957 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1958 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1959 | "dev": true, 1960 | "requires": { 1961 | "os-tmpdir": "1.0.2" 1962 | } 1963 | }, 1964 | "toposort-class": { 1965 | "version": "1.0.1", 1966 | "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", 1967 | "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" 1968 | }, 1969 | "type-check": { 1970 | "version": "0.3.2", 1971 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1972 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1973 | "dev": true, 1974 | "requires": { 1975 | "prelude-ls": "1.1.2" 1976 | } 1977 | }, 1978 | "type-is": { 1979 | "version": "1.6.15", 1980 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", 1981 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", 1982 | "requires": { 1983 | "media-typer": "0.3.0", 1984 | "mime-types": "2.1.17" 1985 | } 1986 | }, 1987 | "typedarray": { 1988 | "version": "0.0.6", 1989 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1990 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1991 | "dev": true 1992 | }, 1993 | "unpipe": { 1994 | "version": "1.0.0", 1995 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1996 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1997 | }, 1998 | "util-deprecate": { 1999 | "version": "1.0.2", 2000 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2001 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 2002 | }, 2003 | "utils-merge": { 2004 | "version": "1.0.1", 2005 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 2006 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 2007 | }, 2008 | "validate-npm-package-license": { 2009 | "version": "3.0.1", 2010 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", 2011 | "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", 2012 | "dev": true, 2013 | "requires": { 2014 | "spdx-correct": "1.0.2", 2015 | "spdx-expression-parse": "1.0.4" 2016 | } 2017 | }, 2018 | "validator": { 2019 | "version": "9.2.0", 2020 | "resolved": "https://registry.npmjs.org/validator/-/validator-9.2.0.tgz", 2021 | "integrity": "sha512-6Ij4Eo0KM4LkR0d0IegOwluG5453uqT5QyF5SV5Ezvm8/zmkKI/L4eoraafZGlZPC9guLkwKzgypcw8VGWWnGA==" 2022 | }, 2023 | "vary": { 2024 | "version": "1.1.2", 2025 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 2026 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 2027 | }, 2028 | "which": { 2029 | "version": "1.3.0", 2030 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", 2031 | "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", 2032 | "dev": true, 2033 | "requires": { 2034 | "isexe": "2.0.0" 2035 | } 2036 | }, 2037 | "wkx": { 2038 | "version": "0.4.2", 2039 | "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.2.tgz", 2040 | "integrity": "sha1-d201pjSlwi5lbkdEvetU+D/Szo0=", 2041 | "requires": { 2042 | "@types/node": "9.3.0" 2043 | } 2044 | }, 2045 | "wordwrap": { 2046 | "version": "1.0.0", 2047 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 2048 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 2049 | "dev": true 2050 | }, 2051 | "wrappy": { 2052 | "version": "1.0.2", 2053 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2054 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2055 | "dev": true 2056 | }, 2057 | "write": { 2058 | "version": "0.2.1", 2059 | "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", 2060 | "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", 2061 | "dev": true, 2062 | "requires": { 2063 | "mkdirp": "0.5.1" 2064 | } 2065 | }, 2066 | "yallist": { 2067 | "version": "2.1.2", 2068 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 2069 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 2070 | } 2071 | } 2072 | } 2073 | -------------------------------------------------------------------------------- /step0_1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step0_1", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "body-parser": "^1.18.2", 14 | "cookie-parser": "^1.4.3", 15 | "express": "^4.16.2", 16 | "mysql2": "^1.5.1", 17 | "node-uuid": "^1.4.8", 18 | "sequelize": "^4.31.2", 19 | "sexy-require": "^0.1.0" 20 | }, 21 | "devDependencies": { 22 | "eslint": "^4.6.1", 23 | "eslint-config-standard": "^10.2.1", 24 | "eslint-plugin-import": "^2.7.0", 25 | "eslint-plugin-node": "^5.1.1", 26 | "eslint-plugin-promise": "^3.5.0", 27 | "eslint-plugin-standard": "^3.0.1" 28 | }, 29 | "path": { 30 | "$service": "/db/service", 31 | "$routeLib": "/app/routes/routeLib" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /step1-express/README.md: -------------------------------------------------------------------------------- 1 | # step1 - express 2 | 3 | express http 웹서버 만들기 예제 4 | 5 | 소스코드 실행 6 | - `$ npm install` 7 | - `$ npm start` 8 | 9 | ### 자주 사용 될 es6 문법 10 | 11 | * 변수와 상수 선언 12 | 13 | ```javascript 14 | let a = 1; 15 | const b = 2; 16 | 17 | a += 2; 18 | b += 3; // Attempt to assign const variable 19 | ``` 20 | 21 | * Template Literals 22 | 23 | ```javascript 24 | const name = 'sam'; 25 | const age = 29; 26 | 27 | const msg = ` 28 | Template Strings Test 29 | 30 | 저의 이름은 ${name}입니다. 31 | 나이는 ${age} 입니다. 32 | `; 33 | 34 | console.log(msg); 35 | 36 | // 37 | //Template Strings Test 38 | // 39 | //저의 이름은 sam입니다. 40 | //나이는 29 입니다. 41 | ``` 42 | 43 | * Arrow Function 44 | 45 | ```javascript 46 | const printName = (name) => { 47 | console.log(`제 이름은 ${name}입니다.`); 48 | } 49 | 50 | printName('sam'); 51 | ``` 52 | 53 | ```javascript 54 | const printName = name => console.log(`제 이름은 ${name}입니다.`); 55 | 56 | printName('sam'); 57 | ``` 58 | 59 | * Destructuring 60 | 61 | ```javascript 62 | const [first, ,third] = ['apple', 'banana', 'cherry']; 63 | console.log(first); // apple 64 | console.log(third); // cherry 65 | 66 | const {name, age} = {name: 'sam', age: 29} 67 | console.log(name); // sam 68 | console.log(age); // age 69 | 70 | const f = ['apple', 'banana', 'cherry']; 71 | //Array.prototype.entries() 72 | //메서드는 배열의 각 인덱스에 대한 key/value 쌍을 가지는 새로운 Array Iterator 객체를 반환 73 | for(const [i, val] of f.entries()){ 74 | console.log(`${i}, ${val}`); 75 | } 76 | // 0, apple 77 | // 1, banana 78 | // 2, cherry 79 | 80 | const names = [ 81 | {name: 'sam', age: 29}, 82 | {name: 'seungjin', age: 27} 83 | ]; 84 | for(const {name = 'noname', age} of names){ 85 | console.log(`이름 : ${name}, 나이 : ${age}`); 86 | } 87 | // 이름 : sam, 나이 : 29 88 | // 이름 : seungjin, 나이 : 27 89 | ``` 90 | 91 | * Spread Operator 92 | 93 | ```javascript 94 | const print = (...arr) => console.log(arr); 95 | const a = ['apple', 'banana']; 96 | const b = ['cherry']; 97 | 98 | print([...a, ...b]); 99 | ``` 100 | 101 | * Property Shorthand 102 | 103 | ```javascript 104 | const apple = '사과'; 105 | const banana = '바나나'; 106 | const cherry = '체리'; 107 | 108 | const fruits = {apple, banana, cherry}; 109 | console.log(fruits); 110 | ``` 111 | 112 | * Method Properties 113 | 114 | ```javascript 115 | const human = { 116 | eat(name, food) { 117 | console.log(`${name}이(가) ${food}을(를) 먹었다.`); 118 | } 119 | }; 120 | 121 | human.eat('sam', 'apple'); 122 | ``` -------------------------------------------------------------------------------- /step1-express/app/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const app = express(); 4 | 5 | app.get('/', (req, res) => res.send('Hello Express')); 6 | 7 | module.exports = app; -------------------------------------------------------------------------------- /step1-express/bin/www.js: -------------------------------------------------------------------------------- 1 | const app = require('../app'); 2 | const port = 3000; 3 | 4 | app.listen(port, _ => { 5 | console.log(`{{Server Start}}-NODE_ENV[${process.env.NODE_ENV}]-PORT[${port}]`); 6 | }); -------------------------------------------------------------------------------- /step1-express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step1-express", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "bin/www.js" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "express": "^4.15.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /step2-https/README.md: -------------------------------------------------------------------------------- 1 | 출처) [http://blog.saltfactory.net/implements-nodejs-based-https-server/](http://blog.saltfactory.net/implements-nodejs-based-https-server/) -------------------------------------------------------------------------------- /step2-https/app/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const app = express(); 4 | 5 | app.get('/', (req, res) => res.send('Hello Express')); 6 | 7 | module.exports = app; -------------------------------------------------------------------------------- /step2-https/bin/www.js: -------------------------------------------------------------------------------- 1 | const https = require('https'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | const app = require('../app'); 6 | const port = 3000; 7 | 8 | const dir = path.resolve(__dirname, '../'); 9 | global.$dir = dir; 10 | 11 | const options = { 12 | key: fs.readFileSync(`${dir}/key/key.pem`, 'utf-8'), 13 | cert: fs.readFileSync(`${dir}/key/cert.pem`, 'utf-8') 14 | }; 15 | 16 | https.createServer(options, app).listen(port, _ => { 17 | console.log(`{{Server Start}}-NODE_ENV[${process.env.NODE_ENV}]-PORT[${port}]`); 18 | }); -------------------------------------------------------------------------------- /step2-https/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step1-express-https", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "bin/www.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.15.4" 14 | } 15 | } 16 | --------------------------------------------------------------------------------