WafRuleCreate.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. <template>
  2. <base-dialog :width="1000" @cancel="cancelDialog">
  3. <div slot="header">{{params.title || $t('compute.perform_create')}}</div>
  4. <div slot="body">
  5. <a-form-model :model="form" :rules="rules" ref="form" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
  6. <a-form-model-item :label="$t('network.waf.rule_type')" prop="rule_type" :extra="$t(`network.waf.rule_type.${form.rule_type}.extra`)">
  7. <a-select v-model="form.rule_type" :placeholder="$t('network.waf.rule_type')">
  8. <a-select-option v-for="item in ruleTypes" :key="item" :value="item">
  9. {{ $t(`network.waf.rule_type.${item}`) }}
  10. </a-select-option>
  11. </a-select>
  12. </a-form-model-item>
  13. <a-form-model-item v-if="form.rule_type !== 'managed'" :label="$t('network.waf.rule_name')" prop="name">
  14. <a-input v-model="form.name" :placeholder="$t('network.waf.rule_name')" />
  15. </a-form-model-item>
  16. <a-form-item :label="$t('network.waf.rule')" v-if="form.rule_type === 'custom' || form.rule_type === 'rate_limit'" required>
  17. <rule-form ref="ruleForm" :form="form" :ruleType="form.rule_type" :rules="rules" />
  18. </a-form-item>
  19. <!-- 速率限制规则 -->
  20. <template v-if="form.rule_type === 'rate_limit'" class="mb-0">
  21. <a-form-model-item :label="$t('network.waf.cache_status')">
  22. <a-checkbox v-model="form.cache_status">
  23. {{ $t('network.waf.cache_status_limit') }}
  24. </a-checkbox>
  25. </a-form-model-item>
  26. <a-form-item :label="$t('network.waf.rule_limit.characteristics')" required>
  27. <rate-limit-rule-form ref="rateLimitRules" :form="form" ruleFormKey="rate_limit_rules" />
  28. <a-form-model-item :extra="rateLimitRuleExtra">
  29. <a-checkbox v-model="form.customCounter">
  30. {{ $t('network.waf.rule_limit.use_custom_counter') }}
  31. </a-checkbox>
  32. </a-form-model-item>
  33. <rule-form v-if="form.customCounter" ref="rateLimitCustomRules" :form="form" ruleFormKey="rate_limit_custom_rules" ruleType="ratelimit_custom" />
  34. </a-form-item>
  35. <a-form-item :label="$t('network.waf.rule_limit.title')" class="mb-0" required>
  36. <div class="d-flex">
  37. <a-form-model-item class="mr-2" prop="period">
  38. <a-select v-model="form.period" style="width: 150px" :placeholder="$t('network.waf.rule_limit.period')">
  39. <a-select-option v-for="item in periodOptions" :key="item" :value="item">
  40. {{ $t(`network.waf.rule_limit_period.${item}`) }}
  41. </a-select-option>
  42. </a-select>
  43. </a-form-model-item>
  44. {{ $t('network.waf.rule_limit.period_text') }}
  45. <a-form-model-item class="ml-2 mr-2" prop="requests_per_period">
  46. <a-input-number v-model="form.requests_per_period" style="width: 100px" :placeholder="$t('network.waf.rule_limit.request_count')" />
  47. </a-form-model-item>
  48. {{ $t('network.waf.rule_limit.period_text_2') }}
  49. </div>
  50. </a-form-item>
  51. </template>
  52. <!-- 采取措施 -->
  53. <a-form-model-item v-if="form.rule_type === 'custom' || form.rule_type === 'rate_limit' || form.rule_type === 'ua'" :label="$t('network.waf.rule_action.title')" :extra="ruleActionExtra" prop="rule_action">
  54. <a-select v-model="form.rule_action" :placeholder="$t('network.waf.rule_action.title')">
  55. <a-select-option v-for="item in ruleActions" :key="item.key" :value="item.key">
  56. {{ item.label }}
  57. </a-select-option>
  58. </a-select>
  59. </a-form-model-item>
  60. <!-- 阻止措施 -->
  61. <template v-if="form.rule_type === 'custom' && form.rule_action === 'block'">
  62. <a-form-model-item :label="$t('network.waf.response_type')" prop="response_type">
  63. <a-select v-model="form.response_type" :placeholder="$t('network.waf.response_type')">
  64. <a-select-option v-for="item in blockTypeOptions" :key="item.key" :value="item.key">
  65. {{ item.label }}
  66. </a-select-option>
  67. </a-select>
  68. </a-form-model-item>
  69. <a-form-model-item v-if="form.response_type !== 'default'" :label="$t('network.waf.response_content')" prop="response_content">
  70. <a-textarea v-model="form.response_content" :placeholder="$t('network.waf.response_content')" />
  71. </a-form-model-item>
  72. <a-form-model-item :label="$t('network.waf.response_code')" prop="response_code">
  73. <a-input-number :disabled="form.response_type === 'default'" v-model="form.response_code" :placeholder="$t('network.waf.response_code')" />
  74. </a-form-model-item>
  75. </template>
  76. <!-- 自定义规则 -->
  77. <template v-if="form.rule_type === 'custom'">
  78. <a-form-item :label="$t('network.waf.custom_index')" class="mb-0" required>
  79. <div>
  80. <a-form-model-item class="mr-2" prop="custom_index">
  81. <a-select v-model="form.custom_index" :placeholder="$t('network.waf.custom_index')">
  82. <a-select-option value="first">{{ $t('network.waf.custom_index.first') }}</a-select-option>
  83. <a-select-option value="last">{{ $t('network.waf.custom_index.last') }}</a-select-option>
  84. <a-select-option value="custom">{{ $t('network.waf.custom_index.custom') }}</a-select-option>
  85. </a-select>
  86. </a-form-model-item>
  87. <a-form-model-item prop="custom_index_rule">
  88. <a-select v-if="form.custom_index === 'custom'" v-model="form.custom_index_rule" :placeholder="$t('network.waf.custom_index_rule')">
  89. <a-select-option v-for="item in customRules" :key="item.id" :value="item.id">
  90. {{ item.name }}
  91. </a-select-option>
  92. </a-select>
  93. </a-form-model-item>
  94. </div>
  95. </a-form-item>
  96. </template>
  97. <!-- 速率限制规则 持续时间 放置位置 -->
  98. <template v-if="form.rule_type === 'rate_limit'">
  99. <a-form-item :label="$t('network.waf.rule_limit_method')" class="mb-0" required>
  100. <a-form-model-item prop="rate_limit_method" class="mb-0" :extra="rateLimitMethodExtra">
  101. <a-radio-group v-model="form.rate_limit_method">
  102. <a-radio-button value="duration">
  103. {{ $t('network.waf.rule_limit_method.time_duration', [form.rule_action ? $t(`network.waf.rule_action.${form.rule_action}`) : '']) }}
  104. </a-radio-button>
  105. <a-radio-button value="limit">
  106. {{ $t('network.waf.rule_limit_method.rate_limit') }}
  107. </a-radio-button>
  108. </a-radio-group>
  109. </a-form-model-item>
  110. <a-form-model-item prop="mitigation_timeout" v-if="form.rate_limit_method === 'duration'">
  111. <a-select v-model="form.mitigation_timeout" :placeholder="$t('network.waf.rule_duration.title')" prop="mitigation_timeout">
  112. <a-select-option v-for="item in durationOptions" :key="item" :value="item">
  113. {{ $t(`network.waf.rule_limit_period.${item}`) }}
  114. </a-select-option>
  115. </a-select>
  116. </a-form-model-item>
  117. </a-form-item>
  118. <a-form-model-item :label="$t('network.waf.custom_index')" prop="rate_limit_index">
  119. <a-select v-model="form.rate_limit_index" :placeholder="$t('network.waf.custom_index')">
  120. <a-select-option value="first">{{ $t('network.waf.custom_index.first') }}</a-select-option>
  121. <a-select-option value="last">{{ $t('network.waf.custom_index.last') }}</a-select-option>
  122. </a-select>
  123. </a-form-model-item>
  124. </template>
  125. <!-- 托管规则 -->
  126. <template v-if="form.rule_type === 'managed'">
  127. <a-form-model-item :label="$t('network.waf.rule_managed.rule_set')" prop="rule_managed_rule_set">
  128. <a-select v-model="form.rule_managed_rule_set" :placeholder="$t('network.waf.rule_managed.rule_set')">
  129. <a-select-option v-for="item in ruleManagedRuleSetOptions" :key="item.key" :value="item.key">
  130. {{ item.label }}
  131. </a-select-option>
  132. </a-select>
  133. </a-form-model-item>
  134. </template>
  135. <!-- IP 访问规则 -->
  136. <template v-if="form.rule_type === 'access'">
  137. <a-form-model-item :label="$t('network.waf.ip_range')" prop="ip_range" :extra="$t('network.waf.ip_range.extra')">
  138. <a-select v-model="form.ip_range" :placeholder="$t('network.waf.ip_range')">
  139. <a-select-option v-for="item in ipRangeOptions" :key="item.key" :value="item.key">
  140. {{ item.label }}
  141. </a-select-option>
  142. </a-select>
  143. </a-form-model-item>
  144. <a-form-model-item :label="$t('network.waf.rule_action.title')" prop="rule_action">
  145. <a-select v-model="form.rule_action" :placeholder="$t('network.waf.rule_action.title')">
  146. <a-select-option v-for="item in ruleActions" :key="item.key" :value="item.key">
  147. {{ item.label }}
  148. </a-select-option>
  149. </a-select>
  150. </a-form-model-item>
  151. <a-form-model-item :label="$t('network.waf.ip_rule_scope')" prop="ip_rule_scope">
  152. <a-select v-model="form.ip_rule_scope" :placeholder="$t('network.waf.ip_rule_scope')">
  153. <a-select-option v-for="item in ipRuleScopeOptions" :key="item.key" :value="item.key">
  154. {{ item.label }}
  155. </a-select-option>
  156. </a-select>
  157. </a-form-model-item>
  158. <a-form-model-item :label="$t('network.waf.ip_rule_notes')">
  159. <a-input v-model="form.ip_rule_notes" :placeholder="$t('network.waf.ip_rule_notes')" />
  160. </a-form-model-item>
  161. </template>
  162. <!-- 区域锁定规则 -->
  163. <template v-if="form.rule_type === 'lockdown'">
  164. <a-form-model-item label="URL" prop="lockdown_url" :extra="$t('network.waf.lockdown_url.extra')">
  165. <a-input v-model="form.lockdown_url" placeholder="URL" />
  166. </a-form-model-item>
  167. <a-form-model-item label="IP / CIDR" prop="lockdown_ip" :extra="$t('network.waf.lockdown_ip.extra')">
  168. <a-input v-model="form.lockdown_ip" placeholder="IP / CIDR" />
  169. </a-form-model-item>
  170. <span><span class="mr-2">{{$t('network.text_94')}}</span><a-switch v-model="form.is_show_lockdown_priority" /></span>
  171. <a-form-model-item class="mt-3" v-if="form.is_show_lockdown_priority" :label="$t('network.waf.priority')">
  172. <a-input-number v-model="form.priority" :min="1" :step="1" :placeholder="$t('network.waf.priority')" />
  173. </a-form-model-item>
  174. </template>
  175. <!-- 用户代理阻止 -->
  176. <template v-if="form.rule_type === 'ua'">
  177. <a-form-model-item :label="$t('network.waf.user_agent_value')" prop="ua_value" :extra="$t('network.waf.user_agent_value.extra')">
  178. <a-input v-model="form.ua_value" :placeholder="$t('network.waf.user_agent_value')" />
  179. </a-form-model-item>
  180. </template>
  181. </a-form-model>
  182. </div>
  183. <div slot="footer">
  184. <a-button type="primary" @click="handleConfirm" :loading="loading">{{ $t('dialog.ok') }}</a-button>
  185. <a-button @click="cancelDialog" v-if="params.type !== 'info'">{{ $t('network.text_33') }}</a-button>
  186. </div>
  187. </base-dialog>
  188. </template>
  189. <script>
  190. import DialogMixin from '@/mixins/dialog'
  191. import WindowsMixin from '@/mixins/windows'
  192. import RuleForm from '../components/RuleForm'
  193. import RateLimitRuleForm from '../components/RateLimitRuleForm'
  194. import { RULE_ACTIONS, BLOCK_TYPES, COUNTRYS, RATE_LIMIT_RULE_TYPES } from '../constants'
  195. import { encodeRuleListToDescription, decodeRuleExpression, decodeRateLimitCustomRules } from '../utils'
  196. export default {
  197. name: 'WafRuleCreateDialog',
  198. components: {
  199. RuleForm,
  200. RateLimitRuleForm,
  201. },
  202. mixins: [DialogMixin, WindowsMixin],
  203. props: {
  204. parmas: Object,
  205. },
  206. data () {
  207. const initData = this.params.data ? this.params.data[0] : {}
  208. // eslint-disable-next-line
  209. let responseContent, initAction, period, requestsPerPeriod, mitigationTimeout, responseType = 'default', responseCode = 403, ruleManagedRuleSet, cacheStatus = true, customCounter = false, ipRange, ipRuleScope, ipRuleNotes, lockdownUrl, lockdownIp, uaValue, isShowLockdownPriority = false, priority
  210. let initRules = [
  211. [
  212. { type: undefined, name: undefined, value: undefined, opt: undefined },
  213. ],
  214. ]
  215. const rateLimitRules = [
  216. [
  217. { type: 'ip.src', value: undefined },
  218. ],
  219. ]
  220. let rateLimitCustomRules = [
  221. [
  222. { type: undefined, name: undefined, value: undefined, opt: undefined },
  223. ],
  224. ]
  225. // let rateLimitRules = [[
  226. // {
  227. // type: 'ip.src',
  228. // value: undefined,
  229. // },
  230. // ]]
  231. if (initData.type === 'custom') {
  232. initAction = initData.action.action
  233. initRules = decodeRuleExpression(initData.expression, initRules)
  234. if (initAction === 'block' && initData.config?.action_parameters?.response) {
  235. responseType = initData.config.action_parameters.response.content_type
  236. responseCode = initData.config.action_parameters.response.status_code
  237. responseContent = initData.config.action_parameters.response.content
  238. }
  239. // TODO index不固定
  240. }
  241. if (initData.type === 'rate_limit') {
  242. initAction = initData.action.action
  243. initRules = decodeRuleExpression(initData.expression, initRules)
  244. rateLimitRules[0] = decodeRateLimitCustomRules(initData.config.ratelimit.characteristics)
  245. cacheStatus = !initData.config.ratelimit.requests_to_origin
  246. period = initData.config.ratelimit.period
  247. requestsPerPeriod = initData.config.ratelimit.requests_per_period
  248. mitigationTimeout = initData.config.ratelimit.mitigation_timeout
  249. customCounter = initData.config.customCounter
  250. if (customCounter) {
  251. rateLimitCustomRules = decodeRuleExpression(initData.config.ratelimit.counting_expression, rateLimitCustomRules)
  252. }
  253. }
  254. if (initData.type === 'managed') {
  255. ruleManagedRuleSet = initData.name
  256. }
  257. if (initData.type === 'access') {
  258. initAction = initData.action.action
  259. ipRange = initData.config.configuration.value
  260. ipRuleScope = initData.config.mode
  261. ipRuleNotes = initData.config.notes
  262. }
  263. if (initData.type === 'ua') {
  264. initAction = initData.action.action
  265. uaValue = initData.config.configuration.value
  266. }
  267. if (initData.type === 'lockdown') {
  268. initAction = initData.action.action
  269. lockdownUrl = initData.config.urls.join(',')
  270. lockdownIp = initData.config.configurations.map(item => item.value).join(',')
  271. if (initData.priority) {
  272. isShowLockdownPriority = true
  273. priority = initData.priority
  274. }
  275. }
  276. return {
  277. loading: false,
  278. form: {
  279. name: initData.name || undefined,
  280. rule_type: initData.type || 'custom',
  281. rules: initRules,
  282. rate_limit_rules: rateLimitRules,
  283. rate_limit_custom_rules: rateLimitCustomRules,
  284. period,
  285. requests_per_period: requestsPerPeriod,
  286. mitigation_timeout: mitigationTimeout,
  287. response_type: responseType,
  288. response_content: responseContent,
  289. response_code: responseCode,
  290. cache_status: cacheStatus,
  291. rate_limit_method: 'duration',
  292. rule_managed_skip_type: 'other',
  293. rule_managed_log_request: true,
  294. ip_range: ipRange,
  295. rule_action: initAction,
  296. ip_rule_scope: ipRuleScope || 'zone',
  297. ip_rule_notes: ipRuleNotes,
  298. lockdown_url: lockdownUrl,
  299. lockdown_ip: lockdownIp,
  300. custom_index: 'last',
  301. custom_index_rule: 'last',
  302. rate_limit_index: undefined,
  303. ua_value: uaValue,
  304. rule_managed_rule_set: ruleManagedRuleSet,
  305. is_show_lockdown_priority: isShowLockdownPriority,
  306. priority,
  307. customCounter,
  308. },
  309. ruleTypes: ['custom', 'rate_limit', 'managed', 'access', 'ua', 'lockdown'],
  310. durationOptions: ['10', '60', '120', '300', '600', '3600', '86400'],
  311. periodOptions: ['10', '60', '120', '300', '600', '3600'],
  312. blockTypeOptions: BLOCK_TYPES,
  313. ruleManagedSkipTargetOptions: [],
  314. ipRuleScopeOptions: [
  315. { key: 'zone', label: this.$t('network.waf.ip_rule_scope.zone') },
  316. { key: 'account', label: this.$t('network.waf.ip_rule_scope.account') },
  317. ],
  318. customRules: [],
  319. ruleManagedRuleSetOptions: [
  320. {
  321. key: 'Cloudflare Managed Ruleset',
  322. label: 'Cloudflare Managed Ruleset',
  323. },
  324. {
  325. key: 'Cloudflare OWASP Core Ruleset',
  326. label: 'Cloudflare OWASP Core Ruleset',
  327. },
  328. ],
  329. rules: {
  330. rule_type: { required: true },
  331. name: { required: true, message: this.$t('common.tips.input', [this.$t('network.waf.rule_name')]) },
  332. rule_action: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.rule_action.title')]) },
  333. custom_index_rule: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.custom_index_rule')]) },
  334. period: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.rule_limit.period')]) },
  335. requests_per_period: { required: true, message: this.$t('common.tips.input', [this.$t('network.waf.rule_limit.request_count')]) },
  336. rate_limit_method: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.rule_limit_method')]) },
  337. mitigation_timeout: { required: true, message: this.$t('common.tips.input', [this.$t('network.waf.rule_duration.title')]) },
  338. rule_managed_rule_set: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.rule_managed.rule_set')]) },
  339. rate_limit_index: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.custom_index')]) },
  340. ip_range: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.ip_range')]) },
  341. ip_rule_scope: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.ip_rule_scope')]) },
  342. ua_value: { required: true, message: this.$t('common.tips.input', [this.$t('network.waf.user_agent_value')]) },
  343. response_type: { required: true, message: this.$t('common.tips.select', [this.$t('network.waf.response_type')]) },
  344. response_code: { required: true, message: this.$t('common.tips.input', [this.$t('network.waf.response_code')]) },
  345. response_content: { required: true, message: this.$t('common.tips.input', [this.$t('network.waf.response_content')]) },
  346. // type: { required: true, message: this.$t('common.tips.select', [this.$t('network.field')]) },
  347. // value: { required: true, message: this.$t('common.required_cols', [this.$t('network.value')]) },
  348. lockdown_url: {
  349. required: true,
  350. validator: (rule, value, callback) => {
  351. const reg = /^((https?:\/\/)?([\w-]+\.)+[\w-]+(\/[\w\-./?%&=]*)?)(,\s*(https?:\/\/)?([\w-]+\.)+[\w-]+(\/[\w\-./?%&=]*)?)*$/i
  352. if (value && reg.test(value)) {
  353. callback()
  354. } else {
  355. callback(new Error(this.$t('common.tips.input', ['URL'])))
  356. }
  357. },
  358. },
  359. lockdown_ip: {
  360. required: true,
  361. validator: (rule, value, callback) => {
  362. const reg = /^((?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(?:\/(3[0-2]|[12]?\d))?)(,\s*(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(?:\/(3[0-2]|[12]?\d))?)*$/
  363. if (value && reg.test(value)) {
  364. callback()
  365. } else {
  366. callback(new Error(this.$t('common.tips.input', ['IP / CIDR'])))
  367. }
  368. },
  369. },
  370. },
  371. }
  372. },
  373. computed: {
  374. ruleActionExtra () {
  375. return this.form.rule_action ? this.$t(`network.waf.rule_action.${this.form.rule_action}.extra`) : ''
  376. },
  377. ruleExpression () {
  378. return encodeRuleListToDescription(this.form.rules)
  379. },
  380. rateLimitCustomExpression () {
  381. return encodeRuleListToDescription(this.form.rate_limit_custom_rules)
  382. },
  383. ruleActions () {
  384. const { rule_type } = this.form
  385. if (rule_type === 'custom') {
  386. return RULE_ACTIONS.filter(item => !['allow'].includes(item.key))
  387. }
  388. if (rule_type === 'ua') {
  389. return RULE_ACTIONS.filter(item => ['managed_challenge', 'block', 'js_challenge', 'challenge'].includes(item.key))
  390. }
  391. if (rule_type === 'access') {
  392. return RULE_ACTIONS.filter(item => ['managed_challenge', 'allow', 'block', 'js_challenge', 'challenge'].includes(item.key))
  393. }
  394. if (rule_type === 'rate_limit') {
  395. return RULE_ACTIONS.filter(item => ['managed_challenge', 'log', 'block', 'js_challenge', 'challenge'].includes(item.key))
  396. }
  397. return RULE_ACTIONS
  398. },
  399. // rules () {
  400. // return decodeRuleExpression(this.ruleExpression)
  401. // },
  402. rateLimitRulesValue () {
  403. return this.form.rate_limit_rules[0].map(row => {
  404. if (row.type) {
  405. const target = RATE_LIMIT_RULE_TYPES.find(item => item.type === row.type)
  406. if (target) {
  407. return target.valueFormat(row.type, row.value)
  408. }
  409. }
  410. return ''
  411. }).filter(item => item)
  412. },
  413. ipRangeOptions () {
  414. return [...COUNTRYS, { key: 'T1', label: 'TOR' }, { key: 'XX', label: 'Unknown states, other entities or organizations' }]
  415. },
  416. rateLimitMethodExtra () {
  417. return this.$t(`network.waf.rule_limit_method.extra.${this.form.rate_limit_method}`, [this.form.rule_action ? this.$t(`network.waf.rule_action.${this.form.rule_action}`) : this.$t('compute.text_863')])
  418. },
  419. rateLimitRuleExtra () {
  420. return this.form.customCounter ? this.$t('network.waf.rule_limit.use_custom_counter.extra') : ''
  421. },
  422. },
  423. watch: {
  424. 'form.rules': {
  425. handler () {
  426. if (this.$refs.ruleForm) {
  427. this.$refs.ruleForm.validateRule()
  428. }
  429. },
  430. deep: true,
  431. },
  432. 'form.rate_limit_rules': {
  433. handler () {
  434. if (this.$refs.rateLimitRules) {
  435. this.$refs.rateLimitRules.validateRule()
  436. }
  437. },
  438. deep: true,
  439. },
  440. 'form.rate_limit_custom_rules': {
  441. handler () {
  442. if (this.$refs.rateLimitCustomRules) {
  443. this.$refs.rateLimitCustomRules.validateRule()
  444. }
  445. },
  446. deep: true,
  447. },
  448. },
  449. created () {
  450. this.$M = new this.$Manager('waf_rules')
  451. this.fetchCustomRules()
  452. },
  453. methods: {
  454. fetchCustomRules () {
  455. try {
  456. this.$M.list({
  457. params: { limit: 0, type: 'custom' },
  458. }).then(res => {
  459. this.customRules = res.data.data
  460. })
  461. } catch (e) {
  462. throw e
  463. }
  464. },
  465. genParams () {
  466. const {
  467. name,
  468. rule_type,
  469. rule_action,
  470. custom_index,
  471. custom_index_rule,
  472. cache_status,
  473. customCounter,
  474. period,
  475. requests_per_period,
  476. rate_limit_method,
  477. mitigation_timeout,
  478. rate_limit_index,
  479. rule_managed_rule_set,
  480. ua_value,
  481. ip_rule_scope,
  482. ip_rule_notes,
  483. ip_range,
  484. lockdown_url,
  485. lockdown_ip,
  486. is_show_lockdown_priority,
  487. priority,
  488. response_type,
  489. response_code,
  490. response_content,
  491. } = this.form
  492. const ret = {
  493. name,
  494. type: rule_type,
  495. waf_instance_id: this.params.waf.id,
  496. config: {},
  497. }
  498. if (this.form.rule_type === 'custom') {
  499. ret.action = { action: rule_action }
  500. ret.expression = this.ruleExpression
  501. if (custom_index === 'first') {
  502. ret.config.position = { index: 1 }
  503. } else if (custom_index === 'last') {
  504. ret.config.position = { index: this.customRules.length + 1 }
  505. } else if (custom_index === 'custom') {
  506. ret.config.position = { after: custom_index_rule }
  507. }
  508. if (rule_action === 'block') {
  509. if (response_type !== 'default') {
  510. ret.config.action_parameters = { response: { content_type: response_type, status_code: response_code, content: response_content } }
  511. }
  512. }
  513. } else if (rule_type === 'rate_limit') {
  514. ret.expression = this.ruleExpression
  515. ret.config.ratelimit = {}
  516. ret.config.ratelimit.requests_to_origin = !cache_status
  517. ret.config.ratelimit.characteristics = this.rateLimitRulesValue
  518. ret.config.ratelimit.rate_exceeds = 'request_base'
  519. ret.config.customCounter = customCounter
  520. if (ret.config.customCounter) {
  521. ret.config.ratelimit.counting_expression = this.rateLimitCustomExpression
  522. }
  523. ret.config.ratelimit.requests_per_period = requests_per_period
  524. ret.config.ratelimit.period = period
  525. ret.action = { action: rule_action }
  526. if (rate_limit_method === 'duration') {
  527. ret.config.ratelimit.mitigation_timeout = mitigation_timeout
  528. }
  529. if (rate_limit_index === 'first') {
  530. ret.config.ratelimit.position = { index: 1 }
  531. }
  532. } else if (rule_type === 'managed') {
  533. ret.name = rule_managed_rule_set
  534. ret.description = rule_managed_rule_set
  535. ret.action = { action: 'execute' }
  536. } else if (rule_type === 'ua') {
  537. ret.action = { action: rule_action }
  538. ret.config.configuration = {
  539. target: 'ua',
  540. value: ua_value,
  541. }
  542. } else if (rule_type === 'access') {
  543. ret.action = { action: rule_action }
  544. ret.config.mode = ip_rule_scope
  545. ret.config.configuration = {
  546. target: 'country',
  547. value: ip_range,
  548. }
  549. ret.config.notes = ip_rule_notes
  550. } else if (rule_type === 'lockdown') {
  551. ret.config.urls = lockdown_url.split(',').map(item => item.trim())
  552. ret.config.configurations = lockdown_ip.split(',').map(item => item.trim()).map(item => {
  553. return {
  554. target: item.includes('/') ? 'ip_range' : 'ip',
  555. value: item,
  556. }
  557. })
  558. if (is_show_lockdown_priority) {
  559. ret.priority = priority
  560. }
  561. ret.action = { action: 'execute' }
  562. }
  563. return ret
  564. },
  565. async handleConfirm () {
  566. if (this.params.type === 'info') {
  567. this.cancelDialog()
  568. return
  569. }
  570. try {
  571. this.loading = true
  572. await this.$refs.form.validate()
  573. if (this.$refs.ruleForm) {
  574. const validate = this.$refs.ruleForm.validateRule()
  575. if (!validate) {
  576. this.loading = false
  577. return
  578. }
  579. }
  580. if (this.$refs.rateLimitRules) {
  581. const validate = this.$refs.rateLimitRules.validateRule()
  582. if (!validate) {
  583. this.loading = false
  584. return
  585. }
  586. }
  587. if (this.$refs.rateLimitCustomRules) {
  588. const validate = this.$refs.rateLimitCustomRules.validateRule()
  589. if (!validate) {
  590. this.loading = false
  591. return
  592. }
  593. }
  594. const data = this.genParams()
  595. await new this.$Manager('waf_rules').create({ data })
  596. this.loading = false
  597. this.params.success()
  598. this.cancelDialog()
  599. } catch (e) {
  600. this.loading = false
  601. throw e
  602. }
  603. },
  604. },
  605. }
  606. </script>