UNPKG

titbit-toolkit

Version:

titbit框架的工具集,包括跨域、静态资源处理,权限过滤,请求计时,cookie,session,jwt等大量中间件

267 lines (217 loc) 6.92 kB
'use strict' /** * 用于param或者query检测的中间件扩展,启用此扩展,会自动进行属性值的检测。 * 支持声明式的设计,避免重复劳动。 */ let TYPE_STRING = 1 let TYPE_NUMBER = 2 class ParamCheck { constructor(options = {}) { this.type = ['query', 'param', 'body'] this.key = 'param' this.data = {} this.errorMessage = "提交数据不符合要求" //设置禁止提交的字段 this.deny = null this.denyMessage = '存在禁止提交的数据' this.deleteDeny = false for (let k in options) { switch (k) { case 'key': if (this.type.indexOf(options[k]) >= 0) { this.key = options[k] } break case 'data': if (typeof options[k] === 'object') { this.data = options[k] } break case 'errorMessage': this[k] = options[k] break case 'deny': if (typeof options[k] === 'string') { options[k] = [options[k]] } if (Array.isArray(options[k])) { this.deny = options[k] } break case 'deleteDeny': this.deleteDeny = !!options[k] break default: this[k] = options[k] } } let data_type = '' for (let k in this.data) { data_type = typeof this.data[k] if (data_type === 'string' || data_type === 'number') { this.data[k] = { __is_value__: true, __value__: this.data[k], __type__: data_type === 'string' ? TYPE_STRING : TYPE_NUMBER } continue } this.data[k].__is_value__ = false if (this.data[k].callback && typeof this.data[k].callback === 'function') { this.data[k].__is_call__ = true } else { this.data[k].__is_call__ = false } } } /** * * @param {object} obj c.param or c.query * @param {*} k key name * @param {*} rule filter rule * * rule描述了如何进行数据的过滤,如果rule是字符串或数字则要求严格相等。 * 否则rule应该是一个object,可以包括的属性如下: * - callback 用于过滤的回调函数,在验证时,会传递数据,除此之外没有其他参数。 * - must false|true,表示是不是必须,如果must为true,则表示数据不能是undefined。 * - default 默认值,如果存在,而参数属性未定义,则赋予默认值。 * - to int|float 要转换成哪种类型。 * - min 最小值,可以 >= 此值,数字或字符串。 * - max 最大值,可以 <= 此值,数字或字符串。 */ checkData(obj, k, rule, method, ost) { let typ = typeof rule ost.ok = true ost.key = k if (!rule.__is_value__) { if (obj[k] === undefined) { if (rule.must) { ost.ok = false return false } if (rule.default !== undefined) { obj[k] = rule.default return true } } else { //数据初始必然是字符串,转换只能是整数或浮点数或boolean。 if (rule.to) { if (isNaN(obj[k])) { ost.ok = false return false } switch(rule.to) { case 'int': obj[k] = parseInt(obj[k]) if (isNaN(obj[k])) { if (rule.default !== undefined) { obj[k] = rule.default return true } ost.ok = false return false } break case 'float': obj[k] = parseFloat(obj[k]) if (isNaN(obj[k])) { if (rule.default !== undefined) { obj[k] = rule.default return true } ost.ok = false return false } break case 'boolean': case 'bool': obj[k] = obj[k] === 'true' ? true : false break } } if (rule.min !== undefined && obj[k] < rule.min) { ost.ok = false return false } if (rule.max !== undefined && obj[k] > rule.max) { ost.ok = false return false } } //无论obj[k]是否存在,只要存在callback,就要执行。 if (rule.__is_call__) { if (rule.callback(obj, k, method) !== false) { return true } ost.ok = false return false } } else if (rule.__type__ === TYPE_STRING) { if (obj[k] === undefined || obj[k] !== rule.__value__) { ost.ok = false return false } } else if (rule.__type__ === TYPE_NUMBER) { if (obj[k] === undefined || obj[k] != rule.__value__) { ost.ok = false return false } } return true } dataFilter(c) { let d = c[this.key] let ost = {ok: true, key: ''} if (this.key !== 'body' || (c.body !== c.rawBody && typeof c.body === 'object')) { for (let k in this.data) { if (!this.checkData(d, k, this.data[k], c.method, ost)) { return ost } } } return ost } mid() { let self = this let dataObject = this.data if (!Array.isArray(this.deny) || this.deny.length === 0) this.deny = null if (this.deny) { if (this.deleteDeny) { return async (c, next) => { if (self.key !== 'body' || (c.body !== c.rawBody && typeof c.body === 'object')) { let obj = c[self.key] for (let k of self.deny) { if (obj[k] !== undefined) delete obj[k] } } let r = self.dataFilter(c) if (!r.ok) { return c.status(400).send(dataObject[r.key].errorMessage || self.errorMessage) } await next() } } return async (c, next) => { if (self.key !== 'body' || (c.body !== c.rawBody && typeof c.body === 'object')) { let obj = c[self.key] for (let k of self.deny) { if (obj[k] !== undefined) return c.status(400).send(self.denyMessage) } } let r = self.dataFilter(c) if (!r.ok) { return c.status(400).send(dataObject[r.key].errorMessage || self.errorMessage) } await next() } } return async (c, next) => { let r = self.dataFilter(c) if (!r.ok) { return c.status(400).send(dataObject[r.key].errorMessage || self.errorMessage) } await next() } } } module.exports = ParamCheck