commit d4f9e78e2a8d06fb82590e9d9c9eba4530f6f8ec Author: Jay Date: Tue Mar 13 23:34:27 2018 +0800 first diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..aaae49a --- /dev/null +++ b/.drone.yml @@ -0,0 +1,25 @@ +pipeline: + build: + image: node:${NODE_VERSION} + environment: + - DB_HOST=database + - DB_PORT=5432 + - DB_USER=postgres + - DB_NAME=mystorage + - NODE_ENV=test + - HOST_URL="http://localhost:10230" + commands: + - npm install + - npm run dbtool + - npm run test +services: + database: + image: postgres + environment: + - POSTGRES_USER=postgres + - POSTGRES_DB=mystorage +matrix: + NODE_VERSION: + - latest + - "8" + - "9" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c006bd2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules +doc +config/dev-config.js +package-lock.json +notes +.vscode diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..966cada --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "common-libs"] + path = common-libs + url = https://github.com/ViewSonicCloud/backend-libs.git diff --git a/app.js b/app.js new file mode 100644 index 0000000..723f43a --- /dev/null +++ b/app.js @@ -0,0 +1,33 @@ +const Koa = require('koa') +const app = new Koa() +const path = require('path') +const fs = require('fs') +const config = require('./config') + +// require middleware +const cors = require('kcors') +const koaBody = require('koa-body') +const koaSession = require('koa-session2') +const koaLogger = require('koa-logger') +const koaMount = require('koa-mount') +const koaStatic = require('koa-static') + +if (process.env['NODE_ENV'] !== 'test') { + app.use(koaLogger()) +} + +app.use(cors()) +app.use(koaSession()) +app.use(koaStatic(path.resolve(__dirname, 'public'), { + maxage: 600000 +})) +const rootRouter = require('./route') + +app.use(rootRouter.allowedMethods()) +app.use(rootRouter.routes()) + +const server = app.listen(config.port, () => { + console.log(`start on port ${server.address().port}`) +}) + +module.exports = server \ No newline at end of file diff --git a/config/index.js b/config/index.js new file mode 100644 index 0000000..c613339 --- /dev/null +++ b/config/index.js @@ -0,0 +1,11 @@ +module.exports = { + linkaddr: process.env.HOST_URL || 'localhost:10230', + port: process.env.PORT || 10230, + database: { + host: process.env.DB_HOST || 'localhost', + port: process.env.DB_PORT || 5432, + db: process.env.DB_NAME || 'mystorage', + user: process.env.DB_USER || 'postgres', + pass: process.env.DB_PASS || '', + } +} \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..af595c8 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,21 @@ +# build docker file $ docker build -t vstorage:latest -f docker/Dockerfile . +FROM node:9 +LABEL Author=Jay +ENV DB_HOST localhost +ENV DB_PORT 5432 +ENV DB_USER postgres +ENV DB_PASS "" +ENV DB_NAME mystorage +ENV HOST_URL localhost +ENV AWS_KEY "" +ENV AWS_SECRET "" +ENV AWS_REGION "" +ENV S3_BUCKET "" +ENV NODE_ENV "" +ENV SESSION_KEY "" +RUN mkdir -p /data +WORKDIR /data +COPY / /data +RUN npm install +EXPOSE 10230 +CMD ["npm", "start"] \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..a7a9110 --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +process.env.__BASE = __dirname + +const server = require('./app') diff --git a/libs/crypto.js b/libs/crypto.js new file mode 100644 index 0000000..751dde9 --- /dev/null +++ b/libs/crypto.js @@ -0,0 +1,83 @@ +var crypto = require('crypto') + +/** + * @param {Number} len + */ +var random = (len = 32) => { + var buf = crypto.randomBytes(len) + return buf.toString('hex') +} + +/** + * + * @param {string} str + */ +var sha256 = (str, tostr = 'base64') => { + return crypto.createHash('sha256').update(str).digest(tostr) +} + +/** + * + * @param {string} str + */ +var genPassHash = (str) => { + var hash = random(16) + var pass = sha256(str + hash) + return `$${hash}$${pass}` +} + +/** + * + * @param {string} plain + * @param {string} hash + */ +var comparePass = (plain, hash) => { + var match = hash.match(/^\$(.+?)\$(.+)$/) + if (match == null || match.length < 3 || !match[1] || !match[2]) return false + var pass = sha256(plain + match[1]) + if (pass === match[2]) return true + return false +} + +const pbkdf2 = (pass, salt, count, len, tostr = false) => { + let hlen = crypto.createHash('sha256').update('').digest().length + let blockCount = Math.ceil(len / hlen) + + let s256 = (s) => { return crypto.createHash('sha256').update(s).digest() } + + let out = [] + for (let i = 0; i < blockCount; i++) { + let loopBuf = Buffer.alloc(4) + loopBuf.writeInt32BE(i) + let saltBuf = Buffer.from(salt) + let last = Buffer.concat([saltBuf, loopBuf], saltBuf.length + loopBuf.length) + let passBuf = Buffer.from(pass) + last = s256(Buffer.concat([passBuf, last], passBuf.length + last.length)) + let xor = Buffer.from(last) + for (let j = 1; j < count; j++) { + last = s256(Buffer.concat([passBuf, last], passBuf.length + last.length)) + xor = last.map((t, idx) => { + return t ^ xor[idx] + }) + } + out.push(xor) + } + let olen = 0 + for (let i in out) { + olen += out[i].length + } + let raw = Buffer.concat([...out], olen) + if (!tostr) { + return raw.slice(0, len) + } else { + return Buffer.from(raw.slice(0, len)).toString('hex') + } +} + +module.exports = { + random, + sha256, + genPassHash, + comparePass, + pbkdf2 +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..4b53246 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "mystorage_v2", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node index.js", + "check": "standard --fix --verbose", + "test": "mocha --exit test/index.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "kcors": "^2.2.1", + "koa": "^2.5.0", + "koa-body": "^2.5.0", + "koa-logger": "^3.2.0", + "koa-mount": "^3.0.0", + "koa-router": "^7.4.0", + "koa-session2": "^2.2.5", + "koa-static": "^4.0.2" + }, + "devDependencies": { + "chai": "^4.1.2", + "chai-http": "^3.0.0", + "mocha": "^4.1.0", + "standard": "^10.0.3" + } +} diff --git a/route/api/index.js b/route/api/index.js new file mode 100644 index 0000000..ab9bc12 --- /dev/null +++ b/route/api/index.js @@ -0,0 +1,62 @@ +const Router = require('koa-router') +const r = new Router() +const { + resObject, + MError +} = require('../utils') + +r.use(async(c, n) => { + c.obj = c.obj || {} + c.chkBody = function (key = '', type = '', empty = false) { + const uuidChk = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i + if (!(key in c.request.body)) return false + + switch (type) { + case 'string': + if (typeof c.request.body[key] !== 'string' || (!empty && !c.request.body[key])) return false + break + case 'number': + if (!isFinite(c.request.body[key])) return false + break + case 'boolean': + if (typeof c.request.body[key] !== 'boolean') return false + break + case 'array': + if (!Array.isArray(c.request.body[key]) || (!empty && c.request.body[key].length === 0)) return false + break + case 'uuid': + if (typeof c.request.body[key] !== 'string') return false + if (!empty && c.request.body[key] === '') return false + if (!empty && !uuidChk.test(c.request.body[key])) return false + break + default: + return false + } + + return true + } + + let obj = null + try { + await n() + } catch (e) { + console.log(e) + obj = resObject(e instanceof MError ? e.mtype : 'InternalError', e.msg || '') + } + + if (Object.keys(c.obj).length > 0 && 'status' in c.obj && 'obj' in c.obj) { + c.status = c.obj.status + c.body = c.obj.obj + } + + if (obj !== null) { + c.status = obj.status + c.body = obj.obj + } +}) + +r.get('/', async (c, n) => { + c.obj = resObject('Success') +}) + +module.exports = r diff --git a/route/index.js b/route/index.js new file mode 100644 index 0000000..a37c404 --- /dev/null +++ b/route/index.js @@ -0,0 +1,11 @@ +const Router = require('koa-router') +const r = new Router() + +r.use('/api', require('./api').routes()) + +r.get('/', async (c, n) => { + c.status = 200 + c.body = "" +}) + +module.exports = r diff --git a/route/utils/index.js b/route/utils/index.js new file mode 100644 index 0000000..1e844a4 --- /dev/null +++ b/route/utils/index.js @@ -0,0 +1,65 @@ +const message = require('./message') +/** + * api response message util + * @param {String} key + * @param {String} msg + */ +const resObject = function (key = '', msg = null) { + if (!key || !(key in message)) { + // default message + return + } + + let obj = Object.assign({}, message[key]) + + if (typeof msg === 'string' && msg.length > 0) obj.obj.message = msg + if (msg !== null && typeof msg === 'object') obj.obj = msg + + return obj +} + +const genError = function (type, msg = '') { + let err = new MError() + err.mtype = type + err.msg = msg + return err +} + +class MError extends Error { + /** + * @param {String} str + */ + constructor (str) { + super(str) + this._mtype = '' + this._msg = '' + } + + /** + * @param {String} type + */ + set mtype (type = '') { + this._mtype = type + } + + get mtype () { + return this._mtype + } + + /** + * @param {String} s + */ + set msg (s = '') { + this._msg = s + } + + get msg () { + return this._msg + } +} + +module.exports = { + resObject, + MError, + genError +} diff --git a/route/utils/message/index.js b/route/utils/message/index.js new file mode 100644 index 0000000..98a0c36 --- /dev/null +++ b/route/utils/message/index.js @@ -0,0 +1,16 @@ +module.exports = { + Success: { + status: 200, + obj: { + resCode: 0, + message: 'success' + } + }, + InternalError: { + status: 500, + obj: { + resCode: 500, + message: 'Internal Error' + } + } +} \ No newline at end of file diff --git a/test/api/index.js b/test/api/index.js new file mode 100644 index 0000000..e6a2aa7 --- /dev/null +++ b/test/api/index.js @@ -0,0 +1,10 @@ + +it('api root test', done => { + chai.request(server) + .get('/api') + .end((err, res) => { + chai.expect(err).to.be.null + chai.expect(res).to.be.status(200) + done() + }) +}) \ No newline at end of file diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..191db16 --- /dev/null +++ b/test/index.js @@ -0,0 +1,17 @@ +process.env['NODE_ENV'] = 'test' +global.chai = require('chai') +global.chaiHttp = require('chai-http') +global.server = require('../app') + +global.chai.use(chaiHttp) + + +global.importTest = (name, path) => { + describe(name, () => { + require(path) + }) +} + +describe('Project Test', () => { + importTest('Test API', './api') +}) \ No newline at end of file