first
This commit is contained in:
commit
d4f9e78e2a
25
.drone.yml
Normal file
25
.drone.yml
Normal file
@ -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"
|
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
node_modules
|
||||||
|
doc
|
||||||
|
config/dev-config.js
|
||||||
|
package-lock.json
|
||||||
|
notes
|
||||||
|
.vscode
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "common-libs"]
|
||||||
|
path = common-libs
|
||||||
|
url = https://github.com/ViewSonicCloud/backend-libs.git
|
33
app.js
Normal file
33
app.js
Normal file
@ -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
|
11
config/index.js
Normal file
11
config/index.js
Normal file
@ -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 || '',
|
||||||
|
}
|
||||||
|
}
|
21
docker/Dockerfile
Normal file
21
docker/Dockerfile
Normal file
@ -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"]
|
3
index.js
Normal file
3
index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
process.env.__BASE = __dirname
|
||||||
|
|
||||||
|
const server = require('./app')
|
83
libs/crypto.js
Normal file
83
libs/crypto.js
Normal file
@ -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
|
||||||
|
}
|
30
package.json
Normal file
30
package.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
62
route/api/index.js
Normal file
62
route/api/index.js
Normal file
@ -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
|
11
route/index.js
Normal file
11
route/index.js
Normal file
@ -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
|
65
route/utils/index.js
Normal file
65
route/utils/index.js
Normal file
@ -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
|
||||||
|
}
|
16
route/utils/message/index.js
Normal file
16
route/utils/message/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module.exports = {
|
||||||
|
Success: {
|
||||||
|
status: 200,
|
||||||
|
obj: {
|
||||||
|
resCode: 0,
|
||||||
|
message: 'success'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InternalError: {
|
||||||
|
status: 500,
|
||||||
|
obj: {
|
||||||
|
resCode: 500,
|
||||||
|
message: 'Internal Error'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
test/api/index.js
Normal file
10
test/api/index.js
Normal file
@ -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()
|
||||||
|
})
|
||||||
|
})
|
17
test/index.js
Normal file
17
test/index.js
Normal file
@ -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')
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user