// 动作选择 Vue.component("http-firewall-actions-box", { props: ["v-actions", "v-firewall-policy", "v-action-configs", "v-group-type"], mounted: function () { let that = this Tea.action("/servers/iplists/levelOptions") .success(function (resp) { that.ipListLevels = resp.data.levels }) .post() this.loadJS(function () { let box = document.getElementById("actions-box") Sortable.create(box, { draggable: ".label", handle: ".icon.handle", onStart: function () { that.cancel() }, onUpdate: function (event) { let labels = box.getElementsByClassName("label") let newConfigs = [] for (let i = 0; i < labels.length; i++) { let index = parseInt(labels[i].getAttribute("data-index")) newConfigs.push(that.configs[index]) } that.configs = newConfigs } }) }) }, data: function () { if (this.vFirewallPolicy.inbound == null) { this.vFirewallPolicy.inbound = {} } if (this.vFirewallPolicy.inbound.groups == null) { this.vFirewallPolicy.inbound.groups = [] } if (this.vFirewallPolicy.outbound == null) { this.vFirewallPolicy.outbound = {} } if (this.vFirewallPolicy.outbound.groups == null) { this.vFirewallPolicy.outbound.groups = [] } let id = 0 let configs = [] if (this.vActionConfigs != null) { configs = this.vActionConfigs configs.forEach(function (v) { v.id = (id++) }) } var defaultPageBody = ` 403 Forbidden \t

403 Forbidden

Connection: \${remoteAddr} (Client) -> \${serverAddr} (Server)
Request ID: \${requestId}
` return { id: id, actions: this.vActions, configs: configs, isAdding: false, editingIndex: -1, action: null, actionCode: "", actionOptions: {}, // IPList相关 ipListLevels: [], // 动作参数 blockTimeout: "", blockTimeoutMax: "", blockScope: "global", captchaLife: "", captchaMaxFails: "", captchaFailBlockTimeout: "", get302Life: "", post307Life: "", recordIPType: "black", recordIPLevel: "critical", recordIPTimeout: "", recordIPListId: 0, recordIPListName: "", tagTags: [], pageStatus: 403, pageBody: defaultPageBody, defaultPageBody: defaultPageBody, redirectStatus: 307, redirectURL: "", goGroupName: "", goGroupId: 0, goGroup: null, goSetId: 0, goSetName: "", jsCookieLife: "", jsCookieMaxFails: "", jsCookieFailBlockTimeout: "", statusOptions: [ {"code": 301, "text": "Moved Permanently"}, {"code": 308, "text": "Permanent Redirect"}, {"code": 302, "text": "Found"}, {"code": 303, "text": "See Other"}, {"code": 307, "text": "Temporary Redirect"} ] } }, watch: { actionCode: function (code) { this.action = this.actions.$find(function (k, v) { return v.code == code }) this.actionOptions = {} }, blockTimeout: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["timeout"] = 0 } else { this.actionOptions["timeout"] = v } }, blockTimeoutMax: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["timeoutMax"] = 0 } else { this.actionOptions["timeoutMax"] = v } }, blockScope: function (v) { this.actionOptions["scope"] = v }, captchaLife: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["life"] = 0 } else { this.actionOptions["life"] = v } }, captchaMaxFails: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["maxFails"] = 0 } else { this.actionOptions["maxFails"] = v } }, captchaFailBlockTimeout: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["failBlockTimeout"] = 0 } else { this.actionOptions["failBlockTimeout"] = v } }, get302Life: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["life"] = 0 } else { this.actionOptions["life"] = v } }, post307Life: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["life"] = 0 } else { this.actionOptions["life"] = v } }, recordIPType: function (v) { this.recordIPListId = 0 }, recordIPTimeout: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["timeout"] = 0 } else { this.actionOptions["timeout"] = v } }, goGroupId: function (groupId) { let group = this.vFirewallPolicy.inbound.groups.$find(function (k, v) { return v.id == groupId }) this.goGroup = group if (group == null) { // search outbound groups group = this.vFirewallPolicy.outbound.groups.$find(function (k, v) { return v.id == groupId }) if (group == null) { this.goGroupName = "" } else { this.goGroup = group this.goGroupName = group.name } } else { this.goGroupName = group.name } this.goSetId = 0 this.goSetName = "" }, goSetId: function (setId) { if (this.goGroup == null) { return } let set = this.goGroup.sets.$find(function (k, v) { return v.id == setId }) if (set == null) { this.goSetId = 0 this.goSetName = "" } else { this.goSetName = set.name } }, jsCookieLife: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["life"] = 0 } else { this.actionOptions["life"] = v } }, jsCookieMaxFails: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["maxFails"] = 0 } else { this.actionOptions["maxFails"] = v } }, jsCookieFailBlockTimeout: function (v) { v = parseInt(v) if (isNaN(v)) { this.actionOptions["failBlockTimeout"] = 0 } else { this.actionOptions["failBlockTimeout"] = v } }, }, methods: { add: function () { this.action = null this.actionCode = "page" this.isAdding = true this.actionOptions = {} // 动作参数 this.blockTimeout = "" this.blockTimeoutMax = "" this.blockScope = "global" this.captchaLife = "" this.captchaMaxFails = "" this.captchaFailBlockTimeout = "" this.jsCookieLife = "" this.jsCookieMaxFails = "" this.jsCookieFailBlockTimeout = "" this.get302Life = "" this.post307Life = "" this.recordIPLevel = "critical" this.recordIPType = "black" this.recordIPTimeout = "" this.recordIPListId = 0 this.recordIPListName = "" this.tagTags = [] this.pageStatus = 403 this.pageBody = this.defaultPageBody this.redirectStatus = 307 this.redirectURL = "" this.goGroupName = "" this.goGroupId = 0 this.goGroup = null this.goSetId = 0 this.goSetName = "" let that = this this.action = this.vActions.$find(function (k, v) { return v.code == that.actionCode }) // 滚到界面底部 this.scroll() }, remove: function (index) { this.isAdding = false this.editingIndex = -1 this.configs.$remove(index) }, update: function (index, config) { if (this.isAdding && this.editingIndex == index) { this.cancel() return } this.add() this.isAdding = true this.editingIndex = index this.actionCode = config.code this.action = this.actions.$find(function (k, v) { return v.code == config.code }) switch (config.code) { case "block": this.blockTimeout = "" this.blockTimeoutMax = "" if (config.options.timeout != null || config.options.timeout > 0) { this.blockTimeout = config.options.timeout.toString() } if (config.options.timeoutMax != null || config.options.timeoutMax > 0) { this.blockTimeoutMax = config.options.timeoutMax.toString() } if (config.options.scope != null && config.options.scope.length > 0) { this.blockScope = config.options.scope } else { this.blockScope = "global" // 兼容先前版本遗留的默认值 } break case "allow": break case "log": break case "captcha": this.captchaLife = "" if (config.options.life != null || config.options.life > 0) { this.captchaLife = config.options.life.toString() } this.captchaMaxFails = "" if (config.options.maxFails != null || config.options.maxFails > 0) { this.captchaMaxFails = config.options.maxFails.toString() } this.captchaFailBlockTimeout = "" if (config.options.failBlockTimeout != null || config.options.failBlockTimeout > 0) { this.captchaFailBlockTimeout = config.options.failBlockTimeout.toString() } break case "js_cookie": this.jsCookieLife = "" if (config.options.life != null || config.options.life > 0) { this.jsCookieLife = config.options.life.toString() } this.jsCookieMaxFails = "" if (config.options.maxFails != null || config.options.maxFails > 0) { this.jsCookieMaxFails = config.options.maxFails.toString() } this.jsCookieFailBlockTimeout = "" if (config.options.failBlockTimeout != null || config.options.failBlockTimeout > 0) { this.jsCookieFailBlockTimeout = config.options.failBlockTimeout.toString() } break case "notify": break case "get_302": this.get302Life = "" if (config.options.life != null || config.options.life > 0) { this.get302Life = config.options.life.toString() } break case "post_307": this.post307Life = "" if (config.options.life != null || config.options.life > 0) { this.post307Life = config.options.life.toString() } break; case "record_ip": if (config.options != null) { this.recordIPLevel = config.options.level this.recordIPType = config.options.type if (config.options.timeout > 0) { this.recordIPTimeout = config.options.timeout.toString() } let that = this // VUE需要在函数执行完之后才会调用watch函数,这样会导致设置的值被覆盖,所以这里使用setTimeout setTimeout(function () { that.recordIPListId = config.options.ipListId that.recordIPListName = config.options.ipListName }) } break case "tag": this.tagTags = [] if (config.options.tags != null) { this.tagTags = config.options.tags } break case "page": this.pageStatus = 403 this.pageBody = this.defaultPageBody if (config.options.status != null) { this.pageStatus = config.options.status } if (config.options.body != null) { this.pageBody = config.options.body } break case "redirect": this.redirectStatus = 307 this.redirectURL = "" if (config.options.status != null) { this.redirectStatus = config.options.status } if (config.options.url != null) { this.redirectURL = config.options.url } break case "go_group": if (config.options != null) { this.goGroupName = config.options.groupName this.goGroupId = config.options.groupId this.goGroup = this.vFirewallPolicy.inbound.groups.$find(function (k, v) { return v.id == config.options.groupId }) } break case "go_set": if (config.options != null) { this.goGroupName = config.options.groupName this.goGroupId = config.options.groupId this.goGroup = this.vFirewallPolicy.inbound.groups.$find(function (k, v) { return v.id == config.options.groupId }) // VUE需要在函数执行完之后才会调用watch函数,这样会导致设置的值被覆盖,所以这里使用setTimeout let that = this setTimeout(function () { that.goSetId = config.options.setId if (that.goGroup != null) { let set = that.goGroup.sets.$find(function (k, v) { return v.id == config.options.setId }) if (set != null) { that.goSetName = set.name } } }) } break } // 滚到界面底部 this.scroll() }, cancel: function () { this.isAdding = false this.editingIndex = -1 }, confirm: function () { if (this.action == null) { return } if (this.actionOptions == null) { this.actionOptions = {} } // record_ip if (this.actionCode == "record_ip") { let timeout = parseInt(this.recordIPTimeout) if (isNaN(timeout)) { timeout = 0 } if (this.recordIPListId < 0) { return } // recordIPListId can be 0 this.actionOptions = { type: this.recordIPType, level: this.recordIPLevel, timeout: timeout, ipListId: this.recordIPListId, ipListName: this.recordIPListName } } else if (this.actionCode == "tag") { // tag if (this.tagTags == null || this.tagTags.length == 0) { return } this.actionOptions = { tags: this.tagTags } } else if (this.actionCode == "page") { let pageStatus = this.pageStatus.toString() if (!pageStatus.match(/^\d{3}$/)) { pageStatus = 403 } else { pageStatus = parseInt(pageStatus) } this.actionOptions = { status: pageStatus, body: this.pageBody } } else if (this.actionCode == "redirect") { let redirectStatus = this.redirectStatus.toString() if (!redirectStatus.match(/^\d{3}$/)) { redirectStatus = 307 } else { redirectStatus = parseInt(redirectStatus) } if (this.redirectURL.length == 0) { teaweb.warn("请输入跳转到URL") return } this.actionOptions = { status: redirectStatus, url: this.redirectURL } } else if (this.actionCode == "go_group") { // go_group let groupId = this.goGroupId if (typeof (groupId) == "string") { groupId = parseInt(groupId) if (isNaN(groupId)) { groupId = 0 } } if (groupId <= 0) { return } this.actionOptions = { groupId: groupId.toString(), groupName: this.goGroupName } } else if (this.actionCode == "go_set") { // go_set let groupId = this.goGroupId if (typeof (groupId) == "string") { groupId = parseInt(groupId) if (isNaN(groupId)) { groupId = 0 } } let setId = this.goSetId if (typeof (setId) == "string") { setId = parseInt(setId) if (isNaN(setId)) { setId = 0 } } if (setId <= 0) { return } this.actionOptions = { groupId: groupId.toString(), groupName: this.goGroupName, setId: setId.toString(), setName: this.goSetName } } let options = {} for (let k in this.actionOptions) { if (this.actionOptions.hasOwnProperty(k)) { options[k] = this.actionOptions[k] } } if (this.editingIndex > -1) { this.configs[this.editingIndex] = { id: this.configs[this.editingIndex].id, code: this.actionCode, name: this.action.name, options: options } } else { this.configs.push({ id: (this.id++), code: this.actionCode, name: this.action.name, options: options }) } this.cancel() }, removeRecordIPList: function () { this.recordIPListId = 0 }, selectRecordIPList: function () { let that = this teaweb.popup("/servers/iplists/selectPopup?type=" + this.recordIPType, { width: "50em", height: "30em", callback: function (resp) { that.recordIPListId = resp.data.list.id that.recordIPListName = resp.data.list.name } }) }, changeTags: function (tags) { this.tagTags = tags }, loadJS: function (callback) { if (typeof Sortable != "undefined") { callback() return } // 引入js let jsFile = document.createElement("script") jsFile.setAttribute("src", "/js/sortable.min.js") jsFile.addEventListener("load", function () { callback() }) document.head.appendChild(jsFile) }, scroll: function () { setTimeout(function () { let mainDiv = document.getElementsByClassName("main") if (mainDiv.length > 0) { mainDiv[0].scrollTo(0, 1000) } }, 10) } }, template: `
{{config.name}} ({{config.code.toUpperCase()}}) :封禁时长{{config.options.timeout}}-{{config.options.timeoutMax}} :有效期{{config.options.life}}秒 / 最多失败{{config.options.maxFails}}次 :有效期{{config.options.life}}秒 / 最多失败{{config.options.maxFails}}次 :有效期{{config.options.life}}秒 :有效期{{config.options.life}}秒 {{config.options.ipListName}} :{{config.options.tags.join(", ")}} :[{{config.options.status}}] :{{config.options.url}} :{{config.options.groupName}} :{{config.options.groupName}} / {{config.options.setName}}   [所有网站] [当前网站]      
动作类型 *

{{action.description}}

封禁范围

只封禁用户对当前网站的访问,其他服务不受影响。

封禁用户对所有网站的访问。

封禁时长
最大封禁时长

选填项。如果同时填写了封禁时长和最大封禁时长,则会在两者之间随机选择一个数字作为最终的封禁时长。

有效时间

验证通过后在这个时间内不再验证;如果为空或者为0表示默认。

最多失败次数

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单;如果为空或者为0表示默认。

失败拦截时间

在达到最多失败次数(大于0)时,自动拦截的时间;如果为空或者为0表示默认。

有效时间

验证通过后在这个时间内不再验证;如果为空或者为0表示默认。

最多失败次数

允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单;如果为空或者为0表示默认。

失败拦截时间

在达到最多失败次数(大于0)时,自动拦截的时间;如果为空或者为0表示默认。

有效时间

验证通过后在这个时间内不再验证。

有效时间

验证通过后在这个时间内不再验证。

IP名单类型 *
选择IP名单
{{recordIPListName}}

如不选择,则自动添加到当前策略的IP名单中。

级别
超时时间

0表示不超时。

标签 *
状态码 *
网页内容
状态码 *
跳转到URL
下一个分组 *
下一个分组 *
下一个规则集 *
 

系统总是会先执行记录日志、标签等不会修改请求的动作,再执行阻止、验证码等可能改变请求的动作。

` })