diff --git a/web/public/js/components.js b/web/public/js/components.js index ebefbbf5..fc7fef44 100644 --- a/web/public/js/components.js +++ b/web/public/js/components.js @@ -329,6 +329,16 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
去审核
+ + +
+ 查看调度状态 » +
+ + +
+ 查看详情 » +
@@ -473,6 +483,58 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
+`}),Vue.component("ns-records-health-check-config-box",{props:["value"],data:function(){let e=this.value;return{config:e=null==e?{isOn:!1,port:80,timeoutSeconds:5,countUp:1,countDown:3}:e,portString:e.port.toString(),timeoutSecondsString:e.timeoutSeconds.toString(),countUpString:e.countUp.toString(),countDownString:e.countDown.toString()}},watch:{portString:function(e){e=parseInt(e.toString());isNaN(e)||65535 + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用健康检查 + +

选中后,表示启用当前域名下A/AAAA记录的健康检查;启用此设置后,你仍需设置单个A/AAAA记录的健康检查。

+
默认检测端口 + +

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

+
默认超时时间 +
+ + +
+
默认连续上线次数 +
+ + +
+

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

+
默认连续下线次数 +
+ + +
+

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

+
+
`}),Vue.component("ns-node-ddos-protection-config-box",{props:["v-ddos-protection-config","v-default-configs","v-is-node","v-cluster-is-on"],data:function(){let e=this.vDdosProtectionConfig;return null==(e=null==e?{tcp:{isPrior:!1,isOn:!1,maxConnections:0,maxConnectionsPerIP:0,newConnectionsRate:0,newConnectionsRateBlockTimeout:0,newConnectionsSecondlyRate:0,newConnectionSecondlyRateBlockTimeout:0,allowIPList:[],ports:[]}}:e).tcp&&(e.tcp={isPrior:!1,isOn:!1,maxConnections:0,maxConnectionsPerIP:0,newConnectionsRate:0,newConnectionsRateBlockTimeout:0,newConnectionsSecondlyRate:0,newConnectionSecondlyRateBlockTimeout:0,allowIPList:[],ports:[]}),{config:e,defaultConfigs:this.vDefaultConfigs,isNode:this.vIsNode,isAddingPort:!1}},methods:{changeTCPPorts:function(e){this.config.tcp.ports=e},changeTCPAllowIPList:function(e){this.config.tcp.allowIPList=e}},template:`
@@ -794,6 +856,93 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio  
+`}),Vue.component("ns-record-health-check-config-box",{props:["value","v-parent-config"],data:function(){let e=this.value;null==e&&(e={isOn:!1,port:0,timeoutSeconds:0,countUp:0,countDown:0});var t=this.vParentConfig;return{config:e,portString:e.port.toString(),timeoutSecondsString:e.timeoutSeconds.toString(),countUpString:e.countUp.toString(),countDownString:e.countDown.toString(),portIsEditing:0 + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用当前记录健康检查 + +
检测端口 + + 默认{{parentConfig.port}} +   [修改] + +
+ + +

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

+
+
超时时间 + + 默认{{parentConfig.timeoutSeconds}}秒 +   [修改] + +
+ +
+ + +
+
+
默认连续上线次数 + + 默认{{parentConfig.countUp}}次 +   [修改] + +
+ +
+ + +
+

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

+
+
默认连续下线次数 + + 默认{{parentConfig.countDown}}次 +   [修改] + +
+ +
+ + +
+

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

+
+
+
`}),Vue.component("ns-create-records-table",{props:["v-types"],data:function(){let e=this.vTypes;return{types:e=null==e?[]:e,records:[{name:"",type:"A",value:"",routeCodes:[],ttl:600,index:0}],lastIndex:0,isAddingRoutes:!1}},methods:{add:function(){this.records.push({name:"",type:"A",value:"",routeCodes:[],ttl:600,index:++this.lastIndex});let e=this;setTimeout(function(){e.$refs.nameInputs.$last().focus()},100)},remove:function(e){this.records.$remove(e)},addRoutes:function(){this.isAddingRoutes=!0},cancelRoutes:function(){let e=this;setTimeout(function(){e.isAddingRoutes=!1},1e3)},changeRoutes:function(e,t){e.routeCodes=null==t?[]:t.map(function(e){return e.code})}},template:`
@@ -1515,7 +1664,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio - {{rule.checkpointOptions.period}}秒/{{rule.checkpointOptions.threshold}}请求 + {{rule.checkpointOptions.period}}秒内请求数 @@ -2141,7 +2290,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
-
`}),Vue.component("http-firewall-checkpoint-referer-block",{props:["v-checkpoint"],data:function(){let e=!0,t=!0,i=[],n=[],s={},o=("boolean"==typeof(s=null==(s=null!=window.parent.UPDATING_RULE?window.parent.UPDATING_RULE.checkpointOptions:s)?{}:s).allowEmpty&&(e=s.allowEmpty),"boolean"==typeof s.allowSameDomain&&(t=s.allowSameDomain),null!=s.allowDomains&&"object"==typeof s.allowDomains&&(i=s.allowDomains),null!=s.denyDomains&&"object"==typeof s.denyDomains&&(n=s.denyDomains),this);return setTimeout(function(){o.change()},100),{allowEmpty:e,allowSameDomain:t,allowDomains:i,denyDomains:n,options:{},value:0}},watch:{allowEmpty:function(){this.change()},allowSameDomain:function(){this.change()}},methods:{changeAllowDomains:function(e){this.allowDomains=e,this.change()},changeDenyDomains:function(e){this.denyDomains=e,this.change()},change:function(){this.vCheckpoint.options=[{code:"allowEmpty",value:this.allowEmpty},{code:"allowSameDomain",value:this.allowSameDomain},{code:"allowDomains",value:this.allowDomains},{code:"denyDomains",value:this.denyDomains}]}},template:`
+
`}),Vue.component("http-firewall-checkpoint-referer-block",{props:["v-checkpoint"],data:function(){let e=!0,t=!0,i=[],n=[],s=!0,o={},a=("boolean"==typeof(o=null==(o=null!=window.parent.UPDATING_RULE?window.parent.UPDATING_RULE.checkpointOptions:o)?{}:o).allowEmpty&&(e=o.allowEmpty),"boolean"==typeof o.allowSameDomain&&(t=o.allowSameDomain),null!=o.allowDomains&&"object"==typeof o.allowDomains&&(i=o.allowDomains),null!=o.denyDomains&&"object"==typeof o.denyDomains&&(n=o.denyDomains),"boolean"==typeof o.checkOrigin&&(s=o.checkOrigin),this);return setTimeout(function(){a.change()},100),{allowEmpty:e,allowSameDomain:t,allowDomains:i,denyDomains:n,checkOrigin:s,options:{},value:0}},watch:{allowEmpty:function(){this.change()},allowSameDomain:function(){this.change()},checkOrigin:function(){this.change()}},methods:{changeAllowDomains:function(e){this.allowDomains=e,this.change()},changeDenyDomains:function(e){this.denyDomains=e,this.change()},change:function(){this.vCheckpoint.options=[{code:"allowEmpty",value:this.allowEmpty},{code:"allowSameDomain",value:this.allowSameDomain},{code:"allowDomains",value:this.allowDomains},{code:"denyDomains",value:this.denyDomains},{code:"checkOrigin",value:this.checkOrigin}]}},template:`
@@ -2173,6 +2322,13 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio

禁止的来源域名列表,比如example.org*.example.org;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

+ + + +
同时检查Origin + +

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

+
`}),Vue.component("http-access-log-partitions-box",{props:["v-partition","v-day","v-query"],mounted:function(){let t=this;Tea.action("/servers/logs/partitionData").params({day:this.vDay}).success(function(e){t.partitions=[],e.data.partitions.reverse().forEach(function(e){t.partitions.push({code:e,isDisabled:!1,hasLogs:!1})}),0=t.partitions.length||(t.checkingPartition=i,t.checkLogs())}))}},template:`
@@ -2248,7 +2404,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio

备用源站 [添加备用源站]

暂时还没有备用源站。

-
`}),Vue.component("origin-list-table",{props:["v-origins","v-origin-type"],data:function(){return{}},methods:{deleteOrigin:function(e){this.$emit("deleteOrigin",e,this.vOriginType)},updateOrigin:function(e){this.$emit("updateOrigin",e,this.vOriginType)}},template:` +`}),Vue.component("origin-list-table",{props:["v-origins","v-origin-type"],data:function(){let t=!1,e=this.vOrigins;return null!=e&&0 @@ -2261,12 +2417,14 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio {{origin.addr}}   -
+
{{origin.name}} 证书 主机名: {{origin.host}} 端口跟随 + 匹配: {{domain}} + 匹配: 所有域名
{{origin.weight}} @@ -2278,15 +2436,63 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio 删除 -`}),Vue.component("http-cors-header-config-box",{props:["value"],data:function(){let e=this.value;return{config:e=null==e?{isOn:!1,allowMethods:[],allowOrigin:"",allowCredentials:!0,exposeHeaders:[],maxAge:0,requestHeaders:[],requestMethod:""}:e}},template:`
+`}),Vue.component("http-cors-header-config-box",{props:["value"],data:function(){let e=this.value,t=(null==(e=null==e?{isOn:!1,allowMethods:[],allowOrigin:"",allowCredentials:!0,exposeHeaders:[],maxAge:0,requestHeaders:[],requestMethod:"",optionsMethodOnly:!1}:e).allowMethods&&(e.allowMethods=[]),null==e.exposeHeaders&&(e.exposeHeaders=[]),e.maxAge.toString());return"0"==t&&(t=""),{config:e,maxAgeSecondsString:t,moreOptionsVisible:!1}},watch:{maxAgeSecondsString:function(e){let t=parseInt(e);isNaN(t)&&(t=0),this.config.maxAge=t}},methods:{changeMoreOptions:function(e){this.moreOptionsVisible=e},addDefaultAllowMethods:function(){let t=this;["PUT","GET","POST","DELETE","HEAD","OPTIONS","PATCH"].forEach(function(e){t.config.allowMethods.$contains(e)||t.config.allowMethods.push(e)})}},template:`
- - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用CORS自适应跨域 - -
启用CORS自适应跨域 + +

启用后,自动在响应Header中增加对应的Access-Control-*相关内容。

+
允许的请求方法列表 + +

[添加默认]Access-Control-Allow-Methods值设置。所访问资源允许使用的方法列表,不设置则表示默认为PUTGETPOSTDELETEHEADOPTIONSPATCH

+
预检结果缓存时间 +
+ + +
+

Access-Control-Max-Age值设置。预检结果缓存时间,0或者不填表示使用浏览器默认设置。注意每个浏览器有不同的缓存时间上限。

+
允许服务器暴露的Header + +

Access-Control-Expose-Headers值设置。允许服务器暴露的Header,请注意Header的大小写。

+
实际请求方法 + +

Access-Control-Request-Method值设置。实际请求服务器时使用的方法,比如POST

+
仅OPTIONS有效 + +

选中后,表示当前CORS设置仅在OPTIONS方法请求时有效。

+
`}),Vue.component("http-firewall-policy-selector",{props:["v-http-firewall-policy"],mounted:function(){let t=this;Tea.action("/servers/components/waf/count").post().success(function(e){t.count=e.data.count})},data:function(){return{count:0,firewallPolicy:this.vHttpFirewallPolicy}},methods:{remove:function(){this.firewallPolicy=null},select:function(){let t=this;teaweb.popup("/servers/components/waf/selectPopup",{callback:function(e){t.firewallPolicy=e.data.firewallPolicy}})},create:function(){let t=this;teaweb.popup("/servers/components/waf/createPopup",{height:"26em",callback:function(e){t.firewallPolicy=e.data.firewallPolicy}})}},template:`
@@ -2571,7 +2777,7 @@ example2.com
-
`}),Vue.component("http-referers-config-box",{props:["v-referers-config","v-is-location","v-is-group"],data:function(){let e=this.vReferersConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,allowEmpty:!0,allowSameDomain:!0,allowDomains:[],denyDomains:[]}:e).allowDomains&&(e.allowDomains=[]),null==e.denyDomains&&(e.denyDomains=[]),{config:e}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeAllowDomains:function(e){"object"==typeof e&&(this.config.allowDomains=e,this.$forceUpdate())},changeDenyDomains:function(e){"object"==typeof e&&(this.config.denyDomains=e,this.$forceUpdate())}},template:`
+
`}),Vue.component("http-referers-config-box",{props:["v-referers-config","v-is-location","v-is-group"],data:function(){let e=this.vReferersConfig;return null==(e=null==e?{isPrior:!1,isOn:!1,allowEmpty:!0,allowSameDomain:!0,allowDomains:[],denyDomains:[],checkOrigin:!0}:e).allowDomains&&(e.allowDomains=[]),null==e.denyDomains&&(e.denyDomains=[]),{config:e}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn},changeAllowDomains:function(e){"object"==typeof e&&(this.config.allowDomains=e,this.$forceUpdate())},changeDenyDomains:function(e){"object"==typeof e&&(this.config.denyDomains=e,this.$forceUpdate())}},template:`
@@ -2616,6 +2822,13 @@ example2.com

禁止的来源域名列表,比如example.org*.example.org;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

+ + + +
同时检查Origin + +

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

+
@@ -3069,7 +3282,7 @@ example2.com
`}),Vue.component("user-selector",{props:["v-user-id","data-url"],data:function(){let e=this.vUserId,t=(null==e&&(e=0),this.dataUrl);return null!=t&&0!=t.length||(t="/servers/users/options"),{users:[],userId:e,dataURL:t}},methods:{change:function(e){null!=e?this.$emit("change",e.id):this.$emit("change",0)},clear:function(){this.$refs.comboBox.clear()}},template:`
-
`}),Vue.component("http-header-policy-box",{props:["v-request-header-policy","v-request-header-ref","v-response-header-policy","v-response-header-ref","v-params","v-is-location","v-is-group","v-has-group-request-config","v-has-group-response-config","v-group-setting-url"],data:function(){let e="response";"#request"==window.location.hash&&(e="request");let t=this.vRequestHeaderRef,i=(null==t&&(t={isPrior:!1,isOn:!0,headerPolicyId:0}),this.vResponseHeaderRef),n=(null==i&&(i={isPrior:!1,isOn:!0,headerPolicyId:0}),[]),s=[];var o=this.vRequestHeaderPolicy;null!=o&&(null!=o.setHeaders&&(n=o.setHeaders),null!=o.deleteHeaders&&(s=o.deleteHeaders));let a=[],l=[];o=this.vResponseHeaderPolicy;null!=o&&(null!=o.setHeaders&&(a=o.setHeaders),null!=o.deleteHeaders&&(l=o.deleteHeaders));let c={isOn:!1};return null!=o.cors&&(c=o.cors),{type:e,typeName:"request"==e?"请求":"响应",requestHeaderRef:t,responseHeaderRef:i,requestSettingHeaders:n,requestDeletingHeaders:s,responseSettingHeaders:a,responseDeletingHeaders:l,responseCORS:c}},methods:{selectType:function(e){this.type=e,window.location.hash="#"+e,window.location.reload()},addSettingHeader:function(e){teaweb.popup("/servers/server/settings/headers/createSetPopup?"+this.vParams+"&headerPolicyId="+e+"&type="+this.type,{callback:function(){teaweb.successRefresh("保存成功")}})},addDeletingHeader:function(e,t){teaweb.popup("/servers/server/settings/headers/createDeletePopup?"+this.vParams+"&headerPolicyId="+e+"&type="+t,{callback:function(){teaweb.successRefresh("保存成功")}})},updateSettingPopup:function(e,t){teaweb.popup("/servers/server/settings/headers/updateSetPopup?"+this.vParams+"&headerPolicyId="+e+"&headerId="+t+"&type="+this.type,{callback:function(){teaweb.successRefresh("保存成功")}})},deleteDeletingHeader:function(e,t){teaweb.confirm("确定要删除'"+t+"'吗?",function(){Tea.action("/servers/server/settings/headers/deleteDeletingHeader").params({headerPolicyId:e,headerName:t}).post().refresh()})},deleteHeader:function(e,t,i){teaweb.confirm("确定要删除此Header吗?",function(){this.$post("/servers/server/settings/headers/delete").params({headerPolicyId:e,type:t,headerId:i}).refresh()})},updateCORS:function(e){teaweb.popup("/servers/server/settings/headers/updateCORSPopup?"+this.vParams+"&headerPolicyId="+e+"&type="+this.type,{callback:function(){teaweb.successRefresh("保存成功")}})}},template:`
+
`}),Vue.component("http-header-policy-box",{props:["v-request-header-policy","v-request-header-ref","v-response-header-policy","v-response-header-ref","v-params","v-is-location","v-is-group","v-has-group-request-config","v-has-group-response-config","v-group-setting-url"],data:function(){let e="response";"#request"==window.location.hash&&(e="request");let t=this.vRequestHeaderRef,i=(null==t&&(t={isPrior:!1,isOn:!0,headerPolicyId:0}),this.vResponseHeaderRef),n=(null==i&&(i={isPrior:!1,isOn:!0,headerPolicyId:0}),[]),s=[],o=[];var a=this.vRequestHeaderPolicy;null!=a&&(null!=a.setHeaders&&(n=a.setHeaders),null!=a.deleteHeaders&&(s=a.deleteHeaders),null!=a.nonStandardHeaders&&(o=a.nonStandardHeaders));let l=[],c=[],r=[];a=this.vResponseHeaderPolicy;null!=a&&(null!=a.setHeaders&&(l=a.setHeaders),null!=a.deleteHeaders&&(c=a.deleteHeaders),null!=a.nonStandardHeaders&&(r=a.nonStandardHeaders));let d={isOn:!1};return null!=a.cors&&(d=a.cors),{type:e,typeName:"request"==e?"请求":"响应",requestHeaderRef:t,responseHeaderRef:i,requestSettingHeaders:n,requestDeletingHeaders:s,requestNonStandardHeaders:o,responseSettingHeaders:l,responseDeletingHeaders:c,responseNonStandardHeaders:r,responseCORS:d}},methods:{selectType:function(e){this.type=e,window.location.hash="#"+e,window.location.reload()},addSettingHeader:function(e){teaweb.popup("/servers/server/settings/headers/createSetPopup?"+this.vParams+"&headerPolicyId="+e+"&type="+this.type,{callback:function(){teaweb.successRefresh("保存成功")}})},addDeletingHeader:function(e,t){teaweb.popup("/servers/server/settings/headers/createDeletePopup?"+this.vParams+"&headerPolicyId="+e+"&type="+t,{callback:function(){teaweb.successRefresh("保存成功")}})},addNonStandardHeader:function(e,t){teaweb.popup("/servers/server/settings/headers/createNonStandardPopup?"+this.vParams+"&headerPolicyId="+e+"&type="+t,{callback:function(){teaweb.successRefresh("保存成功")}})},updateSettingPopup:function(e,t){teaweb.popup("/servers/server/settings/headers/updateSetPopup?"+this.vParams+"&headerPolicyId="+e+"&headerId="+t+"&type="+this.type,{callback:function(){teaweb.successRefresh("保存成功")}})},deleteDeletingHeader:function(e,t){teaweb.confirm("确定要删除'"+t+"'吗?",function(){Tea.action("/servers/server/settings/headers/deleteDeletingHeader").params({headerPolicyId:e,headerName:t}).post().refresh()})},deleteNonStandardHeader:function(e,t){teaweb.confirm("确定要删除'"+t+"'吗?",function(){Tea.action("/servers/server/settings/headers/deleteNonStandardHeader").params({headerPolicyId:e,headerName:t}).post().refresh()})},deleteHeader:function(e,t,i){teaweb.confirm("确定要删除此Header吗?",function(){this.$post("/servers/server/settings/headers/delete").params({headerPolicyId:e,type:t,headerId:i}).refresh()})},updateCORS:function(e){teaweb.popup("/servers/server/settings/headers/updateCORSPopup?"+this.vParams+"&headerPolicyId="+e+"&type="+this.type,{height:"30em",callback:function(){teaweb.successRefresh("保存成功")}})}},template:`
-

设置请求Header [添加新Header]

+

设置请求Header   [添加新Header]

暂时还没有Header。

@@ -3123,20 +3336,31 @@ example2.com
-

删除请求Header

-

这里可以设置需要从请求中删除的Header。

+

其他设置

- - - - + + + + + + + + + +
需要删除的Header -
-
{{headerName}}
-
-
- -
删除Header +
+
{{headerName}}
+
+
+ +
非标Header +
+
{{headerName}}
+
+
+ +
@@ -3156,7 +3380,7 @@ example2.com 由于已经在当前服务分组中进行了对应的配置,在这里的配置将不会生效。
-

设置响应Header [添加新Header]

+

设置响应Header   [添加新Header]

将会覆盖已有的同名Header。

暂时还没有Header。

@@ -3179,6 +3403,11 @@ example2.com 跳转禁用替换 + + +
+ 建议使用当前页面下方的"CORS自适应跨域"功能代替Access-Control-*-*相关Header。 +
@@ -3186,31 +3415,38 @@ example2.com
{{header.value}} 修改   删除
-

删除响应Header

-

这里可以设置需要从响应中删除的Header。

- - - - - - -
需要删除的Header -
-
{{headerName}}
-
-
- -
-

其他设置

- - - - + + + + + + + + + + + + + +
CORS自适应跨域 - 已启用未启用   [修改] -
删除Header +
+
{{headerName}}  
+
+
+ +
非标Header +
+
{{headerName}}  
+
+
+ +
CORS自适应跨域 + 已启用未启用   [修改] +

启用后,服务器可以服务器会自动生成Access-Control-*-*相关的Header。

+
@@ -3608,7 +3844,7 @@ example2.com - 耗时:{{formatCost(accessLog.requestTime)}} ms   ({{accessLog.humanTime}})   -`});var punycode=new function(){this.utf16={decode:function(e){for(var t,i,n=[],s=0,o=e.length;s>>10&1023|55296)),t=56320|1023&t),i.push(String.fromCharCode(t))}return i.join("")}};var b=2147483647;function y(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function x(e,t,i){var n;for(e=i?Math.floor(e/700):e>>1,e+=Math.floor(e/t),n=0;455= 0x80");d.push(e.charCodeAt(n))}for(s=0Math.floor((b-m)/a))throw RangeError("punycode_overflow(1)");if(m+=r*a,r<(r=l<=v?1:v+26<=l?26:l-v))break;if(a>Math.floor(b/(36-r)))throw RangeError("punycode_overflow(2)");a*=36-r}if(v=x(m-o,i=d.length+1,0===o),Math.floor(m/i)>b-h)throw RangeError("punycode_overflow(3)");h+=Math.floor(m/i),m%=i,t&&p.splice(m,0,e.charCodeAt(s-1)-65<26),d.splice(m,0,h),m++}if(t)for(m=0,c=d.length;mMath.floor((b-v)/(i+1)))throw RangeError("punycode_overflow (1)");for(v+=(s-m)*(i+1),m=s,g=0;gb)return Error("punycode_overflow(2)");if(c==m){for(o=v,a=36;!(o<(l=a<=f?1:f+26<=a?26:a-f));a+=36)h.push(String.fromCharCode(y(l+(o-l)%(36-l),0))),o=Math.floor((o-l)/(36-l));h.push(String.fromCharCode(y(o,t&&r[g]?1:0))),f=x(v,i+1,i==n),v=0,++i}}++v,++m}return h.join("")},this.ToASCII=function(e){for(var t=e.split("."),i=[],n=0;n +`});var punycode=new function(){this.utf16={decode:function(e){for(var t,i,n=[],s=0,o=e.length;s>>10&1023|55296)),t=56320|1023&t),i.push(String.fromCharCode(t))}return i.join("")}};var b=2147483647;function y(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function x(e,t,i){var n;for(e=i?Math.floor(e/700):e>>1,e+=Math.floor(e/t),n=0;455= 0x80");d.push(e.charCodeAt(n))}for(s=0Math.floor((b-v)/a))throw RangeError("punycode_overflow(1)");if(v+=r*a,r<(r=l<=m?1:m+26<=l?26:l-m))break;if(a>Math.floor(b/(36-r)))throw RangeError("punycode_overflow(2)");a*=36-r}if(m=x(v-o,i=d.length+1,0===o),Math.floor(v/i)>b-h)throw RangeError("punycode_overflow(3)");h+=Math.floor(v/i),v%=i,t&&p.splice(v,0,e.charCodeAt(s-1)-65<26),d.splice(v,0,h),v++}if(t)for(v=0,c=d.length;vMath.floor((b-m)/(i+1)))throw RangeError("punycode_overflow (1)");for(m+=(s-v)*(i+1),v=s,g=0;gb)return Error("punycode_overflow(2)");if(c==v){for(o=m,a=36;!(o<(l=a<=f?1:f+26<=a?26:a-f));a+=36)h.push(String.fromCharCode(y(l+(o-l)%(36-l),0))),o=Math.floor((o-l)/(36-l));h.push(String.fromCharCode(y(o,t&&r[g]?1:0))),f=x(m,i+1,i==n),m=0,++i}}++m,++v}return h.join("")},this.ToASCII=function(e){for(var t=e.split("."),i=[],n=0;n 默认设置
状态码:{{options.statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 超时时间:{{options.timeout}}秒 / 最大封禁时长:{{options.timeoutMax}}秒 @@ -4397,7 +4633,7 @@ example2.com - {{rule.checkpointOptions.period}}秒/{{rule.checkpointOptions.threshold}}请求 + {{rule.checkpointOptions.period}}秒内请求数 @@ -4982,6 +5218,26 @@ example2.com
+
`}),Vue.component("http-pages-box",{props:["v-pages"],data:function(){let e=[];return{pages:e=null!=this.vPages?this.vPages:e}},methods:{addPage:function(){let t=this;teaweb.popup("/servers/server/settings/pages/createPopup",{height:"26em",callback:function(e){t.pages.push(e.data.page)}})},updatePage:function(t,e){let i=this;teaweb.popup("/servers/server/settings/pages/updatePopup?pageId="+e,{height:"26em",callback:function(e){Vue.set(i.pages,t,e.data.page)}})},removePage:function(e){let t=this;teaweb.confirm("确定要移除此页面吗?",function(){t.pages.$remove(e)})}},template:`
+ + + + + + +
自定义页面 +
+
+ {{page.status}} -> {{page.url}}[HTML内容] +
+
+
+
+ +
+

根据响应状态码返回一些自定义页面,比如404,500等错误页面。

+
+
`}),Vue.component("firewall-syn-flood-config-box",{props:["v-syn-flood-config"],data:function(){let e=this.vSynFloodConfig;return{config:e=null==e?{isOn:!1,minAttempts:10,timeoutSeconds:600,ignoreLocal:!0}:e,isEditing:!1,minAttempts:e.minAttempts,timeoutSeconds:e.timeoutSeconds}},methods:{edit:function(){this.isEditing=!this.isEditing}},watch:{minAttempts:function(e){let t=parseInt(e);(t=isNaN(t)?10:t)<5&&(t=5),this.config.minAttempts=t},timeoutSeconds:function(e){let t=parseInt(e);(t=isNaN(t)?10:t)<60&&(t=60),this.config.timeoutSeconds=t}},template:``}),Vue.component("file-textarea",{props:["value"],data:function(){let e=this.value;return{realValue:e="string"!=typeof e?"":e}},mounted:function(){},methods:{dragover:function(){},drop:function(e){let t=this;e.dataTransfer.items[0].getAsFile().text().then(function(e){t.setValue(e)})},setValue:function(e){this.realValue=e},focus:function(){this.$refs.textarea.focus()}},template:''}),Vue.component("more-options-angle",{data:function(){return{isVisible:!1}},methods:{show:function(){this.isVisible=!this.isVisible,this.$emit("change",this.isVisible)}},template:'更多选项收起选项'}),Vue.component("columns-grid",{props:[],mounted:function(){this.columns=this.calculateColumns();let e=this;window.addEventListener("resize",function(){e.columns=e.calculateColumns()})},data:function(){return{columns:"four"}},methods:{calculateColumns:function(){var e=window.innerWidth;let i=Math.floor(e/250);0==i&&(i=1);var n=this.$el.getElementsByClassName("column");if(0!=n.length){e=n.length;i>e&&(i=e);for(let t=0;t -`}),Vue.component("inner-menu-item",{props:["href","active","code"],data:function(){var e,t=this.active;return void 0===t&&(e="",t=(e=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:e)==this.code),{vHref:null==this.href?"":this.href,vActive:t}},template:'\t\t[] \t\t'}),Vue.component("health-check-config-box",{props:["v-health-check-config","v-check-domain-url"],data:function(){let t=this.vHealthCheckConfig,i="http",n="",s="/",o="";if(null==t){t={isOn:!1,url:"",interval:{count:60,unit:"second"},statusCodes:[200],timeout:{count:10,unit:"second"},countTries:3,tryDelay:{count:100,unit:"ms"},autoDown:!0,countUp:1,countDown:3,userAgent:"",onlyBasicRequest:!0,accessLogIsOn:!0};let e=this;setTimeout(function(){e.changeURL()},500)}else{try{let e=new URL(t.url);i=e.protocol.substring(0,e.protocol.length-1);var a=(o="%24%7Bhost%7D"==(o=e.host)?"${host}":o).indexOf(":");0 +`}),Vue.component("inner-menu-item",{props:["href","active","code"],data:function(){var e,t=this.active;return void 0===t&&(e="",t=(e=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:e)==this.code),{vHref:null==this.href?"":this.href,vActive:t}},template:'\t\t[] \t\t'}),Vue.component("health-check-config-box",{props:["v-health-check-config","v-check-domain-url","v-is-plus"],data:function(){let t=this.vHealthCheckConfig,i="http",n="",s="/",o="";if(null==t){t={isOn:!1,url:"",interval:{count:60,unit:"second"},statusCodes:[200],timeout:{count:10,unit:"second"},countTries:3,tryDelay:{count:100,unit:"ms"},autoDown:!0,countUp:1,countDown:3,userAgent:"",onlyBasicRequest:!0,accessLogIsOn:!0};let e=this;setTimeout(function(){e.changeURL()},500)}else{try{let e=new URL(t.url);i=e.protocol.substring(0,e.protocol.length-1);var a=(o="%24%7Bhost%7D"==(o=e.host)?"${host}":o).indexOf(":");0 @@ -5386,13 +5642,13 @@ example2.com - + @@ -5493,8 +5749,8 @@ example2.com -`}),Vue.component("dot",{template:''}),Vue.component("time-duration-box",{props:["v-name","v-value","v-count","v-unit"],mounted:function(){this.change()},data:function(){let e=this.vValue;return"number"!=typeof(e=null==e?{count:this.vCount,unit:this.vUnit}:e).count&&(e.count=-1),{duration:e,countString:0<=e.count?e.count.toString():""}},watch:{countString:function(e){var e=e.trim();0==e.length?this.duration.count=-1:(e=parseInt(e),isNaN(e)||(this.duration.count=e),this.change())}},methods:{change:function(){this.$emit("change",this.duration)}},template:`
- +
`}),Vue.component("dot",{template:''}),Vue.component("time-duration-box",{props:["name","v-name","v-value","v-count","v-unit"],mounted:function(){this.change()},data:function(){let e=this.vValue,t=("number"!=typeof(e=null==e?{count:this.vCount,unit:this.vUnit}:e).count&&(e.count=-1),"");return"string"==typeof this.name&&0 +
@@ -5708,6 +5964,126 @@ example2.com
+`}),Vue.component("node-schedule-conds-box",{props:["value","v-params","v-operators"],mounted:function(){this.formatConds(this.condsConfig.conds),this.$forceUpdate()},data:function(){let e=this.value,t=(null==(e=null==e?{conds:[],connector:"and"}:e).conds&&(e.conds=[]),{}),i=(this.vParams.forEach(function(e){t[e.code]=e}),{});return this.vOperators.forEach(function(e){i[e.code]=e.name}),{condsConfig:e,params:this.vParams,paramMap:t,operatorMap:i,operator:"",isAdding:!1,paramCode:"",param:null,valueBandwidth:{count:100,unit:"mb"},valueTraffic:{count:1,unit:"gb"},valueCPU:80,valueMemory:90,valueLoad:20}},watch:{paramCode:function(i){0==i.length?this.param=null:this.param=this.params.$find(function(e,t){return t.code==i}),this.$emit("changeparam",this.param)}},methods:{add:function(){this.isAdding=!0},confirm:function(){if(null==this.param)teaweb.warn("请选择参数");else if(null!=this.param.operators&&0 + + + +
+ + + {{paramMap[cond.param].name}} + {{operatorMap[cond.operator]}} {{cond.valueFormat}} +   + + +    + +
+ +
+
自动下线自动下线IP
-

选中后系统会根据健康检查的结果自动标记节点的上线/下线状态,并可能自动同步DNS设置。

+

选中后系统会根据健康检查的结果自动标记节点IP节点的上线/下线状态,并可能自动同步DNS设置。注意:免费版的只能整体上下线整个节点,商业版的可以下线单个IP。

+ + + + + + + + + + + + + + +
参数 + +

{{param.description}}

+
操作符 + +
{{param.valueName}} + +
+
+
+ +
+
+ +
+
+
+ + +
+
+
+ +
+
+ +
+
+
+ + +
+
+ + % +
+
+ + +
+
+ + % +
+
+ + +
+ +
+
+   取消 + + +
+ +
+`}),Vue.component("node-schedule-action-box",{props:["value","v-actions"],data:function(){let e=this.value;return null==e&&(e={code:"",params:{}}),{actions:this.vActions,currentAction:null,actionConfig:e}},watch:{"actionConfig.code":function(i){0==i.length?this.currentAction=null:this.currentAction=this.actions.$find(function(e,t){return t.code==i}),this.actionConfig.params={}}},template:`
+ +
+
+ +
+

{{currentAction.description}}

+ +
+ +

接收通知的URL。

+
+
`}),Vue.component("node-ip-address-thresholds-view",{props:["v-thresholds"],data:function(){let e=this.vThresholds;return null==e?e=[]:e.forEach(function(e){null==e.items&&(e.items=[]),null==e.actions&&(e.actions=[])}),{thresholds:e,allItems:window.IP_ADDR_THRESHOLD_ITEMS,allOperators:[{name:"小于等于",code:"lte"},{name:"大于",code:"gt"},{name:"不等于",code:"neq"},{name:"小于",code:"lt"},{name:"大于等于",code:"gte"}],allActions:window.IP_ADDR_THRESHOLD_ACTIONS}},methods:{itemName:function(t){let i="";return this.allItems.forEach(function(e){e.code==t&&(i=e.name)}),i},itemUnitName:function(t){let i="";return this.allItems.forEach(function(e){e.code==t&&(i=e.unit)}),i},itemDurationUnitName:function(e){switch(e){case"minute":return"分钟";case"second":return"秒";case"hour":return"小时";case"day":return"天"}return e},itemOperatorName:function(t){let i="";return this.allOperators.forEach(function(e){e.code==t&&(i=e.name)}),i},actionName:function(t){let i="";return this.allActions.forEach(function(e){e.code==t&&(i=e.name)}),i}},template:`
@@ -5958,6 +6334,15 @@ example2.com

{{levels[levelCode - 1].description}}

+
`}),Vue.component("node-schedule-conds-viewer",{props:["value","v-params","v-operators"],mounted:function(){this.formatConds(this.condsConfig.conds),this.$forceUpdate()},data:function(){let t={},i=(this.vParams.forEach(function(e){t[e.code]=e}),{});return this.vOperators.forEach(function(e){i[e.code]=e.name}),{condsConfig:this.value,paramMap:t,operatorMap:i}},methods:{formatConds:function(e){let t=this;e.forEach(function(e){switch(t.paramMap[e.param].valueType){case"bandwidth":return void(e.valueFormat=e.value.count+e.value.unit[0].toUpperCase()+e.value.unit.substring(1)+"ps");case"traffic":return void(e.valueFormat=e.value.count+e.value.unit.toUpperCase());case"cpu":case"memory":return void(e.valueFormat=e.value+"%");case"load":return void(e.valueFormat=e.value)}})}},template:`
+ + + {{paramMap[cond.param].name}} + {{operatorMap[cond.operator]}} {{cond.valueFormat}} + + +    +
`}),Vue.component("dns-route-selector",{props:["v-all-routes","v-routes"],data:function(){let e=this.vRoutes;return(e=null==e?[]:e).$sort(function(e,t){return e.domainId==t.domainId?e.code
diff --git a/web/public/js/components.src.js b/web/public/js/components.src.js index ab37c1c5..1f3b934b 100755 --- a/web/public/js/components.src.js +++ b/web/public/js/components.src.js @@ -1156,6 +1156,16 @@ Vue.component("message-row", { + + + + + + @@ -1528,6 +1538,116 @@ Vue.component("ns-access-log-ref-box", {
` }) +Vue.component("ns-records-health-check-config-box", { + props:["value"], + data: function () { + let config = this.value + if (config == null) { + config = { + isOn: false, + port: 80, + timeoutSeconds: 5, + countUp: 1, + countDown: 3 + } + } + return { + config: config, + portString: config.port.toString(), + timeoutSecondsString: config.timeoutSeconds.toString(), + countUpString: config.countUp.toString(), + countDownString: config.countDown.toString() + } + }, + watch: { + portString: function (value) { + let port = parseInt(value.toString()) + if (isNaN(port) || port > 65535 || port < 1) { + this.config.port = 80 + } else { + this.config.port = port + } + }, + timeoutSecondsString: function (value) { + let timeoutSeconds = parseInt(value.toString()) + if (isNaN(timeoutSeconds) || timeoutSeconds > 1000 || timeoutSeconds < 1) { + this.config.timeoutSeconds = 5 + } else { + this.config.timeoutSeconds = timeoutSeconds + } + }, + countUpString: function (value) { + let countUp = parseInt(value.toString()) + if (isNaN(countUp) || countUp > 1000 || countUp < 1) { + this.config.countUp = 1 + } else { + this.config.countUp = countUp + } + }, + countDownString: function (value) { + let countDown = parseInt(value.toString()) + if (isNaN(countDown) || countDown > 1000 || countDown < 1) { + this.config.countDown = 3 + } else { + this.config.countDown = countDown + } + } + }, + template: `
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用健康检查 + +

选中后,表示启用当前域名下A/AAAA记录的健康检查;启用此设置后,你仍需设置单个A/AAAA记录的健康检查。

+
默认检测端口 + +

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

+
默认超时时间 +
+ + +
+
默认连续上线次数 +
+ + +
+

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

+
默认连续下线次数 +
+ + +
+

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

+
+
+
` +}) + Vue.component("ns-node-ddos-protection-config-box", { props: ["v-ddos-protection-config", "v-default-configs", "v-is-node", "v-cluster-is-on"], data: function () { @@ -2269,6 +2389,161 @@ Vue.component("ns-route-ranges-box", {
` }) +Vue.component("ns-record-health-check-config-box", { + props:["value", "v-parent-config"], + data: function () { + let config = this.value + if (config == null) { + config = { + isOn: false, + port: 0, + timeoutSeconds: 0, + countUp: 0, + countDown: 0 + } + } + + let parentConfig = this.vParentConfig + + return { + config: config, + portString: config.port.toString(), + timeoutSecondsString: config.timeoutSeconds.toString(), + countUpString: config.countUp.toString(), + countDownString: config.countDown.toString(), + + portIsEditing: config.port > 0, + timeoutSecondsIsEditing: config.timeoutSeconds > 0, + countUpIsEditing: config.countUp > 0, + countDownIsEditing: config.countDown > 0, + + parentConfig: parentConfig + } + }, + watch: { + portString: function (value) { + let port = parseInt(value.toString()) + if (isNaN(port) || port > 65535 || port < 1) { + this.config.port = 0 + } else { + this.config.port = port + } + }, + timeoutSecondsString: function (value) { + let timeoutSeconds = parseInt(value.toString()) + if (isNaN(timeoutSeconds) || timeoutSeconds > 1000 || timeoutSeconds < 1) { + this.config.timeoutSeconds = 0 + } else { + this.config.timeoutSeconds = timeoutSeconds + } + }, + countUpString: function (value) { + let countUp = parseInt(value.toString()) + if (isNaN(countUp) || countUp > 1000 || countUp < 1) { + this.config.countUp = 0 + } else { + this.config.countUp = countUp + } + }, + countDownString: function (value) { + let countDown = parseInt(value.toString()) + if (isNaN(countDown) || countDown > 1000 || countDown < 1) { + this.config.countDown = 0 + } else { + this.config.countDown = countDown + } + } + }, + template: `
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
启用当前记录健康检查 + +
检测端口 + + 默认{{parentConfig.port}} +   [修改] + +
+ + +

通过尝试连接A/AAAA记录中的IP加此端口来确定当前记录是否健康。

+
+
超时时间 + + 默认{{parentConfig.timeoutSeconds}}秒 +   [修改] + +
+ +
+ + +
+
+
默认连续上线次数 + + 默认{{parentConfig.countUp}}次 +   [修改] + +
+ +
+ + +
+

连续检测{{config.countUp}}N次成功后,认为当前记录是在线的。

+
+
默认连续下线次数 + + 默认{{parentConfig.countDown}}次 +   [修改] + +
+ +
+ + +
+

连续检测{{config.countDown}}N次失败后,认为当前记录是离线的。

+
+
+
+
` +}) + Vue.component("ns-create-records-table", { props: ["v-types"], data: function () { @@ -4291,7 +4566,7 @@ Vue.component("http-firewall-rule-label", { - {{rule.checkpointOptions.period}}秒/{{rule.checkpointOptions.threshold}}请求 + {{rule.checkpointOptions.period}}秒内请求数 @@ -6249,6 +6524,7 @@ Vue.component("http-firewall-checkpoint-referer-block", { let allowSameDomain = true let allowDomains = [] let denyDomains = [] + let checkOrigin = true let options = {} if (window.parent.UPDATING_RULE != null) { @@ -6270,6 +6546,9 @@ Vue.component("http-firewall-checkpoint-referer-block", { if (options.denyDomains != null && typeof (options.denyDomains) == "object") { denyDomains = options.denyDomains } + if (typeof options.checkOrigin == "boolean") { + checkOrigin = options.checkOrigin + } let that = this setTimeout(function () { @@ -6281,6 +6560,7 @@ Vue.component("http-firewall-checkpoint-referer-block", { allowSameDomain: allowSameDomain, allowDomains: allowDomains, denyDomains: denyDomains, + checkOrigin: checkOrigin, options: {}, value: 0 } @@ -6291,6 +6571,9 @@ Vue.component("http-firewall-checkpoint-referer-block", { }, allowSameDomain: function () { this.change() + }, + checkOrigin: function () { + this.change() } }, methods: { @@ -6320,6 +6603,10 @@ Vue.component("http-firewall-checkpoint-referer-block", { code: "denyDomains", value: this.denyDomains }, + { + code: "checkOrigin", + value: this.checkOrigin + } ] } }, @@ -6355,6 +6642,13 @@ Vue.component("http-firewall-checkpoint-referer-block", {

禁止的来源域名列表,比如example.org*.example.org;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

+ + 同时检查Origin + + +

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

+ + ` }) @@ -6748,7 +7042,19 @@ Vue.component("origin-list-box", { Vue.component("origin-list-table", { props: ["v-origins", "v-origin-type"], data: function () { - return {} + let hasMatchedDomains = false + let origins = this.vOrigins + if (origins != null && origins.length > 0) { + origins.forEach(function (origin) { + if (origin.domains != null && origin.domains.length > 0) { + hasMatchedDomains = true + } + }) + } + + return { + hasMatchedDomains: hasMatchedDomains + } }, methods: { deleteOrigin: function (originId) { @@ -6771,12 +7077,14 @@ Vue.component("origin-list-table", { {{origin.addr}}   -
+
{{origin.name}} 证书 主机名: {{origin.host}} 端口跟随 + 匹配: {{domain}} + 匹配: 所有域名
{{origin.weight}} @@ -6804,23 +7112,110 @@ Vue.component("http-cors-header-config-box", { exposeHeaders: [], maxAge: 0, requestHeaders: [], - requestMethod: "" + requestMethod: "", + optionsMethodOnly: false } } + if (config.allowMethods == null) { + config.allowMethods = [] + } + if (config.exposeHeaders == null) { + config.exposeHeaders = [] + } + + let maxAgeSecondsString = config.maxAge.toString() + if (maxAgeSecondsString == "0") { + maxAgeSecondsString = "" + } return { - config: config + config: config, + + maxAgeSecondsString: maxAgeSecondsString, + + moreOptionsVisible: false + } + }, + watch: { + maxAgeSecondsString: function (v) { + let seconds = parseInt(v) + if (isNaN(seconds)) { + seconds = 0 + } + this.config.maxAge = seconds + } + }, + methods: { + changeMoreOptions: function (visible) { + this.moreOptionsVisible = visible + }, + addDefaultAllowMethods: function () { + let that = this + let defaultMethods = ["PUT", "GET", "POST", "DELETE", "HEAD", "OPTIONS", "PATCH"] + defaultMethods.forEach(function (method) { + if (!that.config.allowMethods.$contains(method)) { + that.config.allowMethods.push(method) + } + }) } }, template: `
- - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
启用CORS自适应跨域 - -
启用CORS自适应跨域 + +

启用后,自动在响应Header中增加对应的Access-Control-*相关内容。

+
允许的请求方法列表 + +

[添加默认]Access-Control-Allow-Methods值设置。所访问资源允许使用的方法列表,不设置则表示默认为PUTGETPOSTDELETEHEADOPTIONSPATCH

+
预检结果缓存时间 +
+ + +
+

Access-Control-Max-Age值设置。预检结果缓存时间,0或者不填表示使用浏览器默认设置。注意每个浏览器有不同的缓存时间上限。

+
允许服务器暴露的Header + +

Access-Control-Expose-Headers值设置。允许服务器暴露的Header,请注意Header的大小写。

+
实际请求方法 + +

Access-Control-Request-Method值设置。实际请求服务器时使用的方法,比如POST

+
仅OPTIONS有效 + +

选中后,表示当前CORS设置仅在OPTIONS方法请求时有效。

+
` @@ -7674,7 +8069,8 @@ Vue.component("http-referers-config-box", { allowEmpty: true, allowSameDomain: true, allowDomains: [], - denyDomains: [] + denyDomains: [], + checkOrigin: true } } if (config.allowDomains == null) { @@ -7749,6 +8145,13 @@ Vue.component("http-referers-config-box", {

禁止的来源域名列表,比如example.org*.example.org;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。

+ + 同时检查Origin + + +

如果请求没有指定Referer Header,则尝试检查Origin Header,多用于跨站调用。

+ +
@@ -8998,6 +9401,7 @@ Vue.component("http-header-policy-box", { // 请求相关 let requestSettingHeaders = [] let requestDeletingHeaders = [] + let requestNonStandardHeaders = [] let requestPolicy = this.vRequestHeaderPolicy if (requestPolicy != null) { @@ -9007,11 +9411,15 @@ Vue.component("http-header-policy-box", { if (requestPolicy.deleteHeaders != null) { requestDeletingHeaders = requestPolicy.deleteHeaders } + if (requestPolicy.nonStandardHeaders != null) { + requestNonStandardHeaders = requestPolicy.nonStandardHeaders + } } // 响应相关 let responseSettingHeaders = [] let responseDeletingHeaders = [] + let responseNonStandardHeaders = [] let responsePolicy = this.vResponseHeaderPolicy if (responsePolicy != null) { @@ -9021,6 +9429,9 @@ Vue.component("http-header-policy-box", { if (responsePolicy.deleteHeaders != null) { responseDeletingHeaders = responsePolicy.deleteHeaders } + if (responsePolicy.nonStandardHeaders != null) { + responseNonStandardHeaders = responsePolicy.nonStandardHeaders + } } let responseCORS = { @@ -9033,12 +9444,16 @@ Vue.component("http-header-policy-box", { return { type: type, typeName: (type == "request") ? "请求" : "响应", + requestHeaderRef: requestHeaderRef, responseHeaderRef: responseHeaderRef, requestSettingHeaders: requestSettingHeaders, requestDeletingHeaders: requestDeletingHeaders, + requestNonStandardHeaders: requestNonStandardHeaders, + responseSettingHeaders: responseSettingHeaders, responseDeletingHeaders: responseDeletingHeaders, + responseNonStandardHeaders: responseNonStandardHeaders, responseCORS: responseCORS } }, @@ -9062,8 +9477,15 @@ Vue.component("http-header-policy-box", { } }) }, + addNonStandardHeader: function (policyId, type) { + teaweb.popup("/servers/server/settings/headers/createNonStandardPopup?" + this.vParams + "&headerPolicyId=" + policyId + "&type=" + type, { + callback: function () { + teaweb.successRefresh("保存成功") + } + }) + }, updateSettingPopup: function (policyId, headerId) { - teaweb.popup("/servers/server/settings/headers/updateSetPopup?" + this.vParams + "&headerPolicyId=" + policyId + "&headerId=" + headerId+ "&type=" + this.type, { + teaweb.popup("/servers/server/settings/headers/updateSetPopup?" + this.vParams + "&headerPolicyId=" + policyId + "&headerId=" + headerId + "&type=" + this.type, { callback: function () { teaweb.successRefresh("保存成功") } @@ -9080,6 +9502,17 @@ Vue.component("http-header-policy-box", { .refresh() }) }, + deleteNonStandardHeader: function (policyId, headerName) { + teaweb.confirm("确定要删除'" + headerName + "'吗?", function () { + Tea.action("/servers/server/settings/headers/deleteNonStandardHeader") + .params({ + headerPolicyId: policyId, + headerName: headerName + }) + .post() + .refresh() + }) + }, deleteHeader: function (policyId, type, headerId) { teaweb.confirm("确定要删除此Header吗?", function () { this.$post("/servers/server/settings/headers/delete") @@ -9094,6 +9527,7 @@ Vue.component("http-header-policy-box", { }, updateCORS: function (policyId) { teaweb.popup("/servers/server/settings/headers/updateCORSPopup?" + this.vParams + "&headerPolicyId=" + policyId + "&type=" + this.type, { + height: "30em", callback: function () { teaweb.successRefresh("保存成功") } @@ -9125,7 +9559,7 @@ Vue.component("http-header-policy-box", { 由于已经在当前服务分组中进行了对应的配置,在这里的配置将不会生效。
-

设置请求Header [添加新Header]

+

设置请求Header   [添加新Header]

暂时还没有Header。

@@ -9154,20 +9588,31 @@ Vue.component("http-header-policy-box", {
-

删除请求Header

-

这里可以设置需要从请求中删除的Header。

+

其他设置

- - - - + + + + + + + + + +
需要删除的Header -
-
{{headerName}}
-
-
- -
删除Header +
+
{{headerName}}
+
+
+ +
非标Header +
+
{{headerName}}
+
+
+ +
@@ -9187,7 +9632,7 @@ Vue.component("http-header-policy-box", { 由于已经在当前服务分组中进行了对应的配置,在这里的配置将不会生效。
-

设置响应Header [添加新Header]

+

设置响应Header   [添加新Header]

将会覆盖已有的同名Header。

暂时还没有Header。

@@ -9210,6 +9655,11 @@ Vue.component("http-header-policy-box", { 跳转禁用替换 + + +
+ 建议使用当前页面下方的"CORS自适应跨域"功能代替Access-Control-*-*相关Header。 +
@@ -9217,31 +9667,38 @@ Vue.component("http-header-policy-box", {
{{header.value}} 修改   删除
-

删除响应Header

-

这里可以设置需要从响应中删除的Header。

- - - - - - -
需要删除的Header -
-
{{headerName}}
-
-
- -
-

其他设置

- - - - + + + + + + + + + + + + + +
CORS自适应跨域 - 已启用未启用   [修改] -
删除Header +
+
{{headerName}}  
+
+
+ +
非标Header +
+
{{headerName}}  
+
+
+ +
CORS自适应跨域 + 已启用未启用   [修改] +

启用后,服务器可以服务器会自动生成Access-Control-*-*相关的Header。

+
@@ -12473,7 +12930,7 @@ Vue.component("http-firewall-rules-box", { - {{rule.checkpointOptions.period}}秒/{{rule.checkpointOptions.threshold}}请求 + {{rule.checkpointOptions.period}}秒内请求数 @@ -14216,6 +14673,67 @@ Vue.component("user-agent-config-box", { ` }) +Vue.component("http-pages-box", { + props: ["v-pages"], + data: function () { + let pages = [] + if (this.vPages != null) { + pages = this.vPages + } + + return { + pages: pages + } + }, + methods: { + addPage: function () { + let that = this + teaweb.popup("/servers/server/settings/pages/createPopup", { + height: "26em", + callback: function (resp) { + that.pages.push(resp.data.page) + } + }) + }, + updatePage: function (pageIndex, pageId) { + let that = this + teaweb.popup("/servers/server/settings/pages/updatePopup?pageId=" + pageId, { + height: "26em", + callback: function (resp) { + Vue.set(that.pages, pageIndex, resp.data.page) + } + }) + }, + removePage: function (pageIndex) { + let that = this + teaweb.confirm("确定要移除此页面吗?", function () { + that.pages.$remove(pageIndex) + }) + } + }, + template: `
+ + + + + + +
自定义页面 +
+
+ {{page.status}} -> {{page.url}}[HTML内容] +
+
+
+
+ +
+

根据响应状态码返回一些自定义页面,比如404,500等错误页面。

+
+
+
` +}) + Vue.component("firewall-syn-flood-config-box", { props: ["v-syn-flood-config"], data: function () { @@ -15972,7 +16490,7 @@ Vue.component("inner-menu-item", { }); Vue.component("health-check-config-box", { - props: ["v-health-check-config", "v-check-domain-url"], + props: ["v-health-check-config", "v-check-domain-url", "v-is-plus"], data: function () { let healthCheckConfig = this.vHealthCheckConfig let urlProtocol = "http" @@ -16042,6 +16560,7 @@ Vue.component("health-check-config-box", { healthCheckConfig.countDown = 3 } } + return { healthCheck: healthCheckConfig, advancedVisible: false, @@ -16210,13 +16729,13 @@ Vue.component("health-check-config-box", { - 自动下线 + 自动下线IP
-

选中后系统会根据健康检查的结果自动标记节点的上线/下线状态,并可能自动同步DNS设置。

+

选中后系统会根据健康检查的结果自动标记节点IP节点的上线/下线状态,并可能自动同步DNS设置。注意:免费版的只能整体上下线整个节点,商业版的可以下线单个IP。

@@ -16609,7 +17128,7 @@ Vue.component("dot", { }) Vue.component("time-duration-box", { - props: ["v-name", "v-value", "v-count", "v-unit"], + props: ["name", "v-name", "v-value", "v-count", "v-unit"], mounted: function () { this.change() }, @@ -16624,9 +17143,18 @@ Vue.component("time-duration-box", { if (typeof (v["count"]) != "number") { v["count"] = -1 } + + let realName = "" + if (typeof this.name == "string" && this.name.length > 0) { + realName = this.name + } else if (typeof this.vName == "string" && this.vName.length > 0) { + realName = this.vName + } + return { duration: v, - countString: (v.count >= 0) ? v.count.toString() : "" + countString: (v.count >= 0) ? v.count.toString() : "", + realName: realName } }, watch: { @@ -16649,7 +17177,7 @@ Vue.component("time-duration-box", { } }, template: `
- +
@@ -17978,6 +18506,359 @@ Vue.component("node-ip-addresses-box", {
` }) +Vue.component("node-schedule-conds-box", { + props: ["value", "v-params", "v-operators"], + mounted: function () { + this.formatConds(this.condsConfig.conds) + this.$forceUpdate() + }, + data: function () { + let condsConfig = this.value + if (condsConfig == null) { + condsConfig = { + conds: [], + connector: "and" + } + } + if (condsConfig.conds == null) { + condsConfig.conds = [] + } + + let paramMap = {} + this.vParams.forEach(function (param) { + paramMap[param.code] = param + }) + + let operatorMap = {} + this.vOperators.forEach(function (operator) { + operatorMap[operator.code] = operator.name + }) + + return { + condsConfig: condsConfig, + params: this.vParams, + paramMap: paramMap, + operatorMap: operatorMap, + operator: "", + + isAdding: false, + + paramCode: "", + param: null, + + valueBandwidth: { + count: 100, + unit: "mb" + }, + valueTraffic: { + count: 1, + unit: "gb" + }, + valueCPU: 80, + valueMemory: 90, + valueLoad: 20 + } + }, + watch: { + paramCode: function (code) { + if (code.length == 0) { + this.param = null + } else { + this.param = this.params.$find(function (k, v) { + return v.code == code + }) + } + this.$emit("changeparam", this.param) + } + }, + methods: { + add: function () { + this.isAdding = true + }, + confirm: function () { + if (this.param == null) { + teaweb.warn("请选择参数") + return + } + if (this.param.operators != null && this.param.operators.length > 0 && this.operator.length == 0) { + teaweb.warn("请选择操作符") + return + } + if (this.param.operators == null || this.param.operators.length == 0) { + this.operator = "" + } + + let value = null + switch (this.param.valueType) { + case "bandwidth": { + if (this.valueBandwidth.unit.length == 0) { + teaweb.warn("请选择带宽单位") + return + } + let count = parseInt(this.valueBandwidth.count.toString()) + if (isNaN(count)) { + count = 0 + } + if (count < 0) { + count = 0 + } + value = { + count: count, + unit: this.valueBandwidth.unit + } + } + break + case "traffic": { + if (this.valueTraffic.unit.length == 0) { + teaweb.warn("请选择带宽单位") + return + } + let count = parseInt(this.valueTraffic.count.toString()) + if (isNaN(count)) { + count = 0 + } + if (count < 0) { + count = 0 + } + value = { + count: count, + unit: this.valueTraffic.unit + } + } + break + case "cpu": + let cpu = parseInt(this.valueCPU.toString()) + if (isNaN(cpu)) { + cpu = 0 + } + if (cpu < 0) { + cpu = 0 + } + if (cpu > 100) { + cpu = 100 + } + value = cpu + break + case "memory": + let memory = parseInt(this.valueMemory.toString()) + if (isNaN(memory)) { + memory = 0 + } + if (memory < 0) { + memory = 0 + } + if (memory > 100) { + memory = 100 + } + value = memory + break + case "load": + let load = parseInt(this.valueLoad.toString()) + if (isNaN(load)) { + load = 0 + } + if (load < 0) { + load = 0 + } + value = load + break + } + + this.condsConfig.conds.push({ + param: this.param.code, + operator: this.operator, + value: value + }) + this.formatConds(this.condsConfig.conds) + + this.cancel() + }, + cancel: function () { + this.isAdding = false + this.paramCode = "" + this.param = null + }, + remove: function (index) { + this.condsConfig.conds.$remove(index) + }, + formatConds: function (conds) { + let that = this + conds.forEach(function (cond) { + switch (that.paramMap[cond.param].valueType) { + case "bandwidth": + cond.valueFormat = cond.value.count + cond.value.unit[0].toUpperCase() + cond.value.unit.substring(1) + "ps" + return + case "traffic": + cond.valueFormat = cond.value.count + cond.value.unit.toUpperCase() + return + case "cpu": + cond.valueFormat = cond.value + "%" + return + case "memory": + cond.valueFormat = cond.value + "%" + return + case "load": + cond.valueFormat = cond.value + return + } + }) + } + }, + template: `
+ + + +
+ + + {{paramMap[cond.param].name}} + {{operatorMap[cond.operator]}} {{cond.valueFormat}} +   + + +    + +
+ +
+ + + + + + + + + + + + + + + +
参数 + +

{{param.description}}

+
操作符 + +
{{param.valueName}} + +
+
+
+ +
+
+ +
+
+
+ + +
+
+
+ +
+
+ +
+
+
+ + +
+
+ + % +
+
+ + +
+
+ + % +
+
+ + +
+ +
+
+   取消 +
+ +
+ +
+
` +}) + +Vue.component("node-schedule-action-box", { + props: ["value", "v-actions"], + data: function () { + let actionConfig = this.value + if (actionConfig == null) { + actionConfig = { + code: "", + params: {} + } + } + + return { + actions: this.vActions, + currentAction: null, + actionConfig: actionConfig + } + }, + watch: { + "actionConfig.code": function (actionCode) { + if (actionCode.length == 0) { + this.currentAction = null + } else { + this.currentAction = this.actions.$find(function (k, v) { + return v.code == actionCode + }) + } + this.actionConfig.params = {} + } + }, + template: `
+ +
+
+ +
+

{{currentAction.description}}

+ +
+ +

接收通知的URL。

+
+
+
` +}) + // 节点IP阈值 Vue.component("node-ip-address-thresholds-view", { props: ["v-thresholds"], @@ -18773,6 +19654,65 @@ Vue.component("node-level-selector", { ` }) +Vue.component("node-schedule-conds-viewer", { + props: ["value", "v-params", "v-operators"], + mounted: function () { + this.formatConds(this.condsConfig.conds) + this.$forceUpdate() + }, + data: function () { + let paramMap = {} + this.vParams.forEach(function (param) { + paramMap[param.code] = param + }) + + let operatorMap = {} + this.vOperators.forEach(function (operator) { + operatorMap[operator.code] = operator.name + }) + + return { + condsConfig: this.value, + paramMap: paramMap, + operatorMap: operatorMap + } + }, + methods: { + formatConds: function (conds) { + let that = this + conds.forEach(function (cond) { + switch (that.paramMap[cond.param].valueType) { + case "bandwidth": + cond.valueFormat = cond.value.count + cond.value.unit[0].toUpperCase() + cond.value.unit.substring(1) + "ps" + return + case "traffic": + cond.valueFormat = cond.value.count + cond.value.unit.toUpperCase() + return + case "cpu": + cond.valueFormat = cond.value + "%" + return + case "memory": + cond.valueFormat = cond.value + "%" + return + case "load": + cond.valueFormat = cond.value + return + } + }) + } + }, + template: `
+ + + {{paramMap[cond.param].name}} + {{operatorMap[cond.operator]}} {{cond.valueFormat}} + + +    + +
` +}) + Vue.component("dns-route-selector", { props: ["v-all-routes", "v-routes"], data: function () {