1. add login api
2. add get channel list api
This commit is contained in:
parent
ff36b00097
commit
4e610d87e3
17
bin/hashPass.js
Normal file
17
bin/hashPass.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
require('module-alias/register')
|
||||||
|
const {
|
||||||
|
hashPassword
|
||||||
|
} = require('@libs/tools')
|
||||||
|
|
||||||
|
let args = process.argv
|
||||||
|
let pass = args[2] || ''
|
||||||
|
if (typeof pass !== 'string' || pass.trim().length === 0) {
|
||||||
|
console.log('command: node hashPass <pass string>')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
hashPassword(pass).then(r => {
|
||||||
|
console.log(`Password: ${r}`)
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
@ -2,6 +2,7 @@ module.exports = {
|
|||||||
port: process.env.NODE_PORT || 10230,
|
port: process.env.NODE_PORT || 10230,
|
||||||
url: process.env.HOST_URL || '',
|
url: process.env.HOST_URL || '',
|
||||||
image_root: process.env.IMAGE_ROOT || '/image',
|
image_root: process.env.IMAGE_ROOT || '/image',
|
||||||
|
salt_round: process.env.SALT_ROUND || 10,
|
||||||
line: {
|
line: {
|
||||||
secret: process.env.LINE_SECRET || '',
|
secret: process.env.LINE_SECRET || '',
|
||||||
access: process.env.LINE_ACCESS || ''
|
access: process.env.LINE_ACCESS || ''
|
||||||
|
@ -44,11 +44,96 @@ const chkObject = function (key = '', type = '', empty = false) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const resObject = (key = null, message = null, msgCode = null) => {
|
/**
|
||||||
|
* parse number
|
||||||
|
* @param {any} v input number
|
||||||
|
* @param {number} def default number
|
||||||
|
* @param {number} min min number
|
||||||
|
* @param {number} max max number
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
const toInt = (v, def = 0, min = null, max = null) => {
|
||||||
|
if (!isFinite(def)) def = 0
|
||||||
|
if (typeof def === 'string') def = parseInt(def)
|
||||||
|
min = isFinite(min) ? (typeof min === 'string' ? parseInt(min) : min) : null
|
||||||
|
max = isFinite(max) ? (typeof max === 'string' ? parseInt(max) : max) : null
|
||||||
|
if (!isFinite(v)) return def
|
||||||
|
v = parseInt(v)
|
||||||
|
if (min !== null && v < min) v = min
|
||||||
|
if (max !== null && v > max) v = max
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* response object
|
||||||
|
* @param {string} key response key
|
||||||
|
* @param {string|object} message response object or message
|
||||||
|
* @param {number} msgCode message code
|
||||||
|
*/
|
||||||
|
const resObject = (key = null, message = null, msgCode = null) => {
|
||||||
|
if (key === null || typeof key !== 'string' || key.trim().length === 0) key = 'InternalError'
|
||||||
|
key = key.trim()
|
||||||
|
let resObj = _.cloneDeep(resMessage[key] || {})
|
||||||
|
|
||||||
|
if (msgCode !== null && isFinite(msgCode)) {
|
||||||
|
resObj.obj.msgCode = toInt(msgCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof message === 'string' && message.trim().length > 0) {
|
||||||
|
resObj.obj.message = message.trim()
|
||||||
|
} else if (typeof message === 'object') {
|
||||||
|
resObj.obj = message
|
||||||
|
}
|
||||||
|
return resObj
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API Error cls
|
||||||
|
*/
|
||||||
|
class APIError extends Error {
|
||||||
|
set apiMsg (txt = '') {
|
||||||
|
if (typeof txt !== 'string') txt = null
|
||||||
|
this._apiMsg = txt
|
||||||
|
}
|
||||||
|
get apiMsg () {
|
||||||
|
return this._apiMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
set msgCode (code = 0) {
|
||||||
|
this._code = toInt(code, 0)
|
||||||
|
}
|
||||||
|
get msgCode () {
|
||||||
|
return this._code
|
||||||
|
}
|
||||||
|
|
||||||
|
set resKey (txt = '') {
|
||||||
|
if (typeof txt !== 'string' || txt.trim().length === 0) txt = 'InternalError'
|
||||||
|
this._resKey = txt
|
||||||
|
}
|
||||||
|
get resKey () {
|
||||||
|
return this._resKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const genError = (key = null, message = null, msgCode = null) => {
|
||||||
|
let cls = new APIError()
|
||||||
|
cls.apiMsg = message
|
||||||
|
cls.msgCode = msgCode
|
||||||
|
cls.resKey = key
|
||||||
|
return cls
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkSession = async (c, n) => {
|
||||||
|
if (!('session' in c) || !('user' in c.session) || !('loginType' in c.session)) throw genError('NotLogin')
|
||||||
|
|
||||||
|
return n()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
chkObject,
|
chkObject,
|
||||||
resObject
|
resObject,
|
||||||
|
toInt,
|
||||||
|
APIError,
|
||||||
|
genError,
|
||||||
|
checkSession
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,13 @@ module.exports = {
|
|||||||
message: 'login first'
|
message: 'login first'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Forbidden: {
|
||||||
|
status: 403,
|
||||||
|
obj: {
|
||||||
|
status: 403,
|
||||||
|
message: 'Forbidden'
|
||||||
|
}
|
||||||
|
},
|
||||||
NotFound: {
|
NotFound: {
|
||||||
status: 404,
|
status: 404,
|
||||||
obj: {
|
obj: {
|
||||||
|
64
libs/tools/index.js
Normal file
64
libs/tools/index.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
const config = require('@config/index')
|
||||||
|
const bcrypt = require('bcrypt')
|
||||||
|
const {
|
||||||
|
toInt
|
||||||
|
} = require('@libs/route-utils')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash password func
|
||||||
|
* @param {string} pass password string
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
const hashPassword = async (pass = '') => {
|
||||||
|
if (typeof pass !== 'string' || pass.trim().length === 0) return null
|
||||||
|
let saltRound = toInt(config.salt_round, 1, 1)
|
||||||
|
// gen salt
|
||||||
|
let salt = await new Promise((resolve, reject) => {
|
||||||
|
bcrypt.genSalt(saltRound, (err, saltStr) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve(saltStr)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let passHash = new Promise((resolve, reject) => {
|
||||||
|
bcrypt.hash(pass, salt, (err, hash) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve(hash)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return passHash
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compare password and hash
|
||||||
|
* @param {string} password password string
|
||||||
|
* @param {string} hash hash string
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const comparePassword = async (password = '', hash = '') => {
|
||||||
|
if (typeof password !== 'string' || password.trim().length === 0) return null
|
||||||
|
if (typeof hash !== 'string' || hash.trim().length === 0) return null
|
||||||
|
let check = new Promise((resolve, reject) => {
|
||||||
|
bcrypt.compare(password, hash, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return !!check
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
hashPassword,
|
||||||
|
comparePassword
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
|
"bcrypt": "^3.0.0",
|
||||||
"cheerio": "^1.0.0-rc.2",
|
"cheerio": "^1.0.0-rc.2",
|
||||||
"cron": "^1.3.0",
|
"cron": "^1.3.0",
|
||||||
"dotenv": "^6.0.0",
|
"dotenv": "^6.0.0",
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
const Router = require('koa-router')
|
const Router = require('koa-router')
|
||||||
const koaBody = require('koa-body')
|
const koaBody = require('koa-body')
|
||||||
const {
|
const {
|
||||||
chkObject
|
chkObject,
|
||||||
|
resObject,
|
||||||
|
APIError,
|
||||||
|
genError
|
||||||
} = require('@libs/route-utils')
|
} = require('@libs/route-utils')
|
||||||
const DB = require('@libs/database')
|
const DB = require('@libs/database')
|
||||||
const r = new Router()
|
const r = new Router()
|
||||||
|
const {
|
||||||
|
comparePassword
|
||||||
|
} = require('@libs/tools')
|
||||||
|
|
||||||
r.use(async (c, n) => {
|
r.use(async (c, n) => {
|
||||||
c.obj = {}
|
c.obj = {}
|
||||||
@ -14,12 +20,28 @@ r.use(async (c, n) => {
|
|||||||
await n()
|
await n()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
c.obj = resObject(err instanceof APIError ? err.resKey : 'InternalError', err.apiMsg || null, err.msgCode || null)
|
||||||
}
|
}
|
||||||
c.db.release()
|
c.db.release()
|
||||||
})
|
})
|
||||||
|
|
||||||
r.post('/login', koaBody(), async (c, n) => {
|
r.post('/login', koaBody(), async (c, n) => {
|
||||||
if (!c.chkBody('account', 'string') || !c.chkBody('password', 'string')) throw new Error('DataFormat')
|
if (!c.chkBody('account', 'string') || !c.chkBody('password', 'string')) throw genError('DataFormat')
|
||||||
|
|
||||||
|
let text = `select * from "public"."account" where "account" = $1 limit 1`
|
||||||
|
let values = [c.request.body.account]
|
||||||
|
let userAcc = await c.db.query({text, values})
|
||||||
|
if (userAcc.rowCount === 0) throw genError('NotFound', 'user not found')
|
||||||
|
if (!comparePassword(c.request.body.password, userAcc.rows[0].password)) throw genError('DataFormat', 'account or password error')
|
||||||
|
|
||||||
|
let user = userAcc.rows[0]
|
||||||
|
delete user.password
|
||||||
|
c.session.user = user
|
||||||
|
c.session.loginType = 'system'
|
||||||
|
|
||||||
|
c.obj = resObject('Success')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
r.use('/twitch', require('./twitch').routes())
|
||||||
|
|
||||||
module.exports = r
|
module.exports = r
|
||||||
|
41
route/api/twitch/index.js
Normal file
41
route/api/twitch/index.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
const Router = require('koa-router')
|
||||||
|
const {
|
||||||
|
genError,
|
||||||
|
checkSession,
|
||||||
|
resObject
|
||||||
|
} = require('@libs/route-utils')
|
||||||
|
const r = new Router()
|
||||||
|
|
||||||
|
const typeTwitch = async (c, n) => {
|
||||||
|
let text = `select * from "public"."twitch_channel" where "id" = $1`
|
||||||
|
let values = [c.session.user.id]
|
||||||
|
let result = await c.db.query({text, values})
|
||||||
|
c.state.channelList = result.rows
|
||||||
|
return n()
|
||||||
|
}
|
||||||
|
|
||||||
|
const typeSystem = async (c, n) => {
|
||||||
|
let text = `select * form "public"."twitch_channel"`
|
||||||
|
let values = [c.session.user.id]
|
||||||
|
let result = await c.db.query({text, values})
|
||||||
|
c.state.channelList = result.rows
|
||||||
|
return n()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.get('/channels', checkSession, async (c, n) => {
|
||||||
|
if (c.session.loginType === 'twitch') {
|
||||||
|
return typeTwitch(c, n)
|
||||||
|
} else if (c.session.loginType === 'system') {
|
||||||
|
return typeSystem(c, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw genError('Forbidden')
|
||||||
|
}, async (c, n) => {
|
||||||
|
if (!('channelList' in c.state) || !Array.isArray(c.state.channelList)) throw genError('InternalError')
|
||||||
|
|
||||||
|
c.obj = resObject('Success', {
|
||||||
|
list: c.state.channelList
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = r
|
Loading…
Reference in New Issue
Block a user