index.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import * as R from 'ramda'
  2. import { WAF_RULE_OPTS_MAP, WAF_RULE_TYPES, WAF_RULE_TYPES_MAP, RATE_LIMIT_RULE_TYPES } from '../constants'
  3. export const encodeRuleListToDescription = (ruleList) => {
  4. const list = []
  5. ruleList.forEach(rules => {
  6. const listInner = []
  7. rules.forEach(rule => {
  8. const { type, name, opt, value } = rule
  9. if (type && opt && WAF_RULE_OPTS_MAP[opt]) {
  10. const valueType = WAF_RULE_TYPES_MAP[type].valueType
  11. const str = WAF_RULE_OPTS_MAP[opt].valueFormat(type, name, formatRuleValue(value, R.is(Function, valueType) ? valueType(opt) : valueType, ''))
  12. listInner.push(str)
  13. }
  14. })
  15. list.push(`(${listInner.join(' and ')})`)
  16. })
  17. return list.join(' or ')
  18. }
  19. export const decodeRuleExpression = (expr = '', defaultValue = []) => {
  20. const list = splitExpr(expr)
  21. const ret = []
  22. list.forEach(arr => {
  23. const group = []
  24. arr.forEach(str => {
  25. for (const key in WAF_RULE_OPTS_MAP) {
  26. const decode = WAF_RULE_OPTS_MAP[key].decodeDescription ? WAF_RULE_OPTS_MAP[key].decodeDescription(str) : null
  27. if (decode) {
  28. group.push(decode)
  29. break
  30. }
  31. }
  32. })
  33. if (group.length) {
  34. ret.push(group)
  35. }
  36. })
  37. return ret.length ? ret : defaultValue
  38. }
  39. export const decodeRateLimitCustomRules = (rules) => {
  40. return rules.map(rule => {
  41. let row = {}
  42. for (let i = 0; i < RATE_LIMIT_RULE_TYPES.length; i++) {
  43. const item = RATE_LIMIT_RULE_TYPES[i]
  44. const decode = item.decodeDescription ? item.decodeDescription(rule) : null
  45. if (decode) {
  46. row = decode
  47. break
  48. }
  49. }
  50. return row
  51. })
  52. }
  53. function smartSplit (expr, sep) {
  54. const result = []
  55. let buf = ''
  56. let paren = 0
  57. let inQuote = false
  58. let quoteChar = ''
  59. let i = 0
  60. const sepLen = sep.length
  61. while (i < expr.length) {
  62. // 检查引号
  63. if (!inQuote && (expr[i] === '"' || expr[i] === "'")) {
  64. inQuote = true
  65. quoteChar = expr[i]
  66. buf += expr[i]
  67. i++
  68. continue
  69. }
  70. if (inQuote && expr[i] === quoteChar) {
  71. inQuote = false
  72. buf += expr[i]
  73. i++
  74. continue
  75. }
  76. // 检查括号
  77. if (!inQuote) {
  78. if (expr[i] === '(') paren++
  79. if (expr[i] === ')') paren--
  80. }
  81. // 检查分隔符
  82. if (!inQuote && paren === 0) {
  83. if (expr.slice(i, i + sepLen).toLowerCase() === sep &&
  84. (i + sepLen === expr.length || /[\s(]/.test(expr[i + sepLen]))) {
  85. result.push(buf.trim())
  86. buf = ''
  87. i += sepLen
  88. continue
  89. }
  90. }
  91. buf += expr[i]
  92. i++
  93. }
  94. if (buf.trim()) result.push(buf.trim())
  95. return result.map(str => {
  96. if (str.startsWith('(') && str.endsWith(')')) {
  97. return str.slice(1, -1)
  98. }
  99. return str
  100. })
  101. }
  102. // 递归拆分
  103. function splitExpr (expr) {
  104. // 先按 or 拆
  105. const orParts = smartSplit(expr, 'or')
  106. // 每一段再按 and 拆
  107. return orParts.map(part => smartSplit(part, 'and'))
  108. }
  109. export const formatRuleValue = (originValue, valueType, defaultValue = undefined) => {
  110. let value = defaultValue
  111. if (valueType === 'multi-select') {
  112. if ((originValue && R.is(String, originValue)) || R.is(Number, originValue)) {
  113. value = [originValue]
  114. } else if (R.is(Boolean, originValue)) {
  115. value = []
  116. } else if (R.is(Array, originValue)) {
  117. value = originValue
  118. } else {
  119. value = []
  120. }
  121. } else if (valueType === 'single-select') {
  122. if ((originValue && R.is(String, originValue)) || R.is(Number, originValue)) {
  123. value = [originValue]
  124. } else if (R.is(Boolean, originValue)) {
  125. value = []
  126. } else if (R.is(Array, originValue)) {
  127. value = originValue.length ? originValue[0] : []
  128. } else {
  129. value = []
  130. }
  131. } else if (valueType === 'input' || valueType === 'input-number') {
  132. if (R.is(Boolean, originValue)) {
  133. value = undefined
  134. } else if (R.is(Array, originValue)) {
  135. value = originValue.length ? originValue[0] : []
  136. } else if (R.is(Number, originValue) || R.is(String, originValue)) {
  137. value = originValue
  138. }
  139. } else if (valueType === 'switch') {
  140. if (R.is(Boolean, originValue)) {
  141. value = originValue
  142. } else {
  143. value = false
  144. }
  145. }
  146. return value
  147. }
  148. export const getRuleConfig = (rule) => {
  149. const ruleTypes = WAF_RULE_TYPES
  150. const ret = { valueType: 'input', isShowName: false }
  151. if (rule.type) {
  152. const target = ruleTypes.filter(item => item.type === rule.type)
  153. if (target.length) {
  154. ret.valueType = R.is(Function, target[0].valueType) ? target[0].valueType(rule.opt) : target[0].valueType
  155. ret.isShowName = R.is(Function, target[0].isShowName) ? target[0].isShowName(rule.type, rule.opt) : target[0].isShowName
  156. ret.optDisabled = target[0].optDisabled
  157. ret.valueOpts = R.is(Function, target[0].valueOpts) ? target[0].valueOpts(ret.valueType) : target[0].valueOpts || []
  158. ret.opts = target[0].opts || []
  159. if (target[0].valueExtra) {
  160. ret.valueExtra = R.is(Function, target[0].valueExtra) ? target[0].valueExtra(rule.type, rule.opt) : target[0].valueExtra
  161. }
  162. ret.props = R.is(Function, target[0].props) ? target[0].props(rule.type, rule.opt) : target[0].props || {}
  163. }
  164. }
  165. return ret
  166. }