diff --git a/build/build.sh b/build/build.sh index ef58326c..c2b699ed 100755 --- a/build/build.sh +++ b/build/build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash function build() { - ROOT=$(dirname $0) + ROOT=$(dirname "$0") JS_ROOT=$ROOT/../web/public/js NAME="edge-admin" DIST=$ROOT/"../dist/${NAME}" @@ -9,15 +9,15 @@ function build() { ARCH=${2} TAG=${3} - if [ -z $OS ]; then + if [ -z "$OS" ]; then echo "usage: build.sh OS ARCH" exit fi - if [ -z $ARCH ]; then + if [ -z "$ARCH" ]; then echo "usage: build.sh OS ARCH" exit fi - if [ -z $TAG ]; then + if [ -z "$TAG" ]; then TAG="community" fi @@ -25,7 +25,7 @@ function build() { echo "checking required commands ..." commands=("zip" "unzip" "go" "find" "sed") for cmd in "${commands[@]}"; do - if [ `which ${cmd}` ]; then + if [ "$(which "${cmd}")" ]; then echo "checking ${cmd}: ok" else echo "checking ${cmd}: not found" @@ -33,49 +33,49 @@ function build() { fi done - VERSION=$(lookup-version $ROOT/../internal/const/const.go) + VERSION=$(lookup-version "$ROOT"/../internal/const/const.go) ZIP="${NAME}-${OS}-${ARCH}-${TAG}-v${VERSION}.zip" # build edge-api - APINodeVersion=$(lookup-version $ROOT"/../../EdgeAPI/internal/const/const.go") + APINodeVersion=$(lookup-version "$ROOT""/../../EdgeAPI/internal/const/const.go") echo "building edge-api v${APINodeVersion} ..." EDGE_API_BUILD_SCRIPT=$ROOT"/../../EdgeAPI/build/build.sh" - if [ ! -f $EDGE_API_BUILD_SCRIPT ]; then + if [ ! -f "$EDGE_API_BUILD_SCRIPT" ]; then echo "unable to find edge-api build script 'EdgeAPI/build/build.sh'" exit fi - cd $ROOT"/../../EdgeAPI/build" + cd "$ROOT""/../../EdgeAPI/build" || exit echo "==============================" - ./build.sh $OS $ARCH $TAG + ./build.sh "$OS" "$ARCH" $TAG echo "==============================" - cd - + cd - || exit # generate files echo "generating files ..." - go run -tags $TAG $ROOT/../cmd/edge-admin/main.go generate - if [ `which uglifyjs` ]; then + go run -tags $TAG "$ROOT"/../cmd/edge-admin/main.go generate + if [ "$(which uglifyjs)" ]; then echo "compress to component.js ..." - uglifyjs --compress --mangle -- ${JS_ROOT}/components.src.js > ${JS_ROOT}/components.js + uglifyjs --compress --mangle -- "${JS_ROOT}"/components.src.js > "${JS_ROOT}"/components.js else echo "copy to component.js ..." - cp ${JS_ROOT}/components.src.js ${JS_ROOT}/components.js + cp "${JS_ROOT}"/components.src.js "${JS_ROOT}"/components.js fi # create dir & copy files echo "copying ..." - if [ ! -d $DIST ]; then - mkdir $DIST - mkdir $DIST/bin - mkdir $DIST/configs - mkdir $DIST/logs + if [ ! -d "$DIST" ]; then + mkdir "$DIST" + mkdir "$DIST"/bin + mkdir "$DIST"/configs + mkdir "$DIST"/logs fi - cp -R $ROOT/../web $DIST/ - rm -f $DIST/web/tmp/* - rm -rf $DIST/web/public/js/components - rm -f $DIST/web/public/js/components.src.js - cp $ROOT/configs/server.template.yaml $DIST/configs/ + cp -R "$ROOT"/../web "$DIST"/ + rm -f "$DIST"/web/tmp/* + rm -rf "$DIST"/web/public/js/components + rm -f "$DIST"/web/public/js/components.src.js + cp "$ROOT"/configs/server.template.yaml "$DIST"/configs/ # change _plus.[ext] to .[ext] if [ "${TAG}" = "plus" ]; then @@ -83,30 +83,30 @@ function build() { exts=("html" "js" "css") for ext in "${exts[@]}"; do pattern="*_plus."${ext} - find $DIST/web/views -type f -name $pattern | \ + find "$DIST"/web/views -type f -name "$pattern" | \ while read filename; do - mv ${filename} "${filename/_plus."${ext}"/."${ext}"}" + mv "${filename}" "${filename/_plus."${ext}"/."${ext}"}" done done fi EDGE_API_ZIP_FILE=$ROOT"/../../EdgeAPI/dist/edge-api-${OS}-${ARCH}-${TAG}-v${APINodeVersion}.zip" - cp $EDGE_API_ZIP_FILE $DIST/ - cd $DIST/ - unzip -q $(basename $EDGE_API_ZIP_FILE) - rm -f $(basename $EDGE_API_ZIP_FILE) - cd - + cp "$EDGE_API_ZIP_FILE" "$DIST"/ + cd "$DIST"/ || exit + unzip -q "$(basename "$EDGE_API_ZIP_FILE")" + rm -f "$(basename "$EDGE_API_ZIP_FILE")" + cd - || exit # build - echo "building "${NAME}" ..." - env GOOS=$OS GOARCH=$ARCH go build -trimpath -tags $TAG -ldflags="-s -w" -o $DIST/bin/${NAME} $ROOT/../cmd/edge-admin/main.go + echo "building ${NAME} ..." + env GOOS="$OS" GOARCH="$ARCH" go build -trimpath -tags $TAG -ldflags="-s -w" -o "$DIST"/bin/${NAME} "$ROOT"/../cmd/edge-admin/main.go # delete hidden files - find $DIST -name ".DS_Store" -delete - find $DIST -name ".gitignore" -delete - find $DIST -name "*.less" -delete - find $DIST -name "*.css.map" -delete - find $DIST -name "*.js.map" -delete + find "$DIST" -name ".DS_Store" -delete + find "$DIST" -name ".gitignore" -delete + find "$DIST" -name "*.less" -delete + find "$DIST" -name "*.css.map" -delete + find "$DIST" -name "*.js.map" -delete # zip echo "zip files ..." @@ -123,15 +123,15 @@ function build() { function lookup-version() { FILE=$1 - VERSION_DATA=$(cat $FILE) + VERSION_DATA=$(cat "$FILE") re="Version[ ]+=[ ]+\"([0-9.]+)\"" if [[ $VERSION_DATA =~ $re ]]; then VERSION=${BASH_REMATCH[1]} - echo $VERSION + echo "$VERSION" else echo "could not match version" exit fi } -build $1 $2 $3 +build "$1" "$2" "$3" diff --git a/dist/.gitignore b/dist/.gitignore index a903b654..51f51b4f 100644 --- a/dist/.gitignore +++ b/dist/.gitignore @@ -1,2 +1,2 @@ *.zip -shield-admin \ No newline at end of file +edge-admin \ No newline at end of file diff --git a/web/public/js/components.js b/web/public/js/components.js index 157acddc..c855ec8d 100644 --- a/web/public/js/components.js +++ b/web/public/js/components.js @@ -417,48 +417,191 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
-`}),Vue.component("ns-route-ranges-box",{props:["v-ranges"],data:function(){let e=this.vRanges;return{ranges:e=null==e?[]:e,isAdding:!1,isAddingBatch:!1,ipRangeFrom:"",ipRangeTo:"",batchIPRange:""}},methods:{add:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.ipRangeFrom.focus()},100)},remove:function(e){this.ranges.$remove(e)},cancelIPRange:function(){this.isAdding=!1,this.ipRangeFrom="",this.ipRangeTo=""},confirmIPRange:function(){let e=this;this.ipRangeFrom=this.ipRangeFrom.trim(),this.validateIP(this.ipRangeFrom)?(this.ipRangeTo=this.ipRangeTo.trim(),this.validateIP(this.ipRangeTo)?(this.ranges.push({type:"ipRange",params:{ipFrom:this.ipRangeFrom,ipTo:this.ipRangeTo}}),this.cancelIPRange()):teaweb.warn("结束IP填写错误",function(){e.$refs.ipRangeTo.focus()})):teaweb.warn("开始IP填写错误",function(){e.$refs.ipRangeFrom.focus()})},addBatch:function(){this.isAddingBatch=!0;let e=this;setTimeout(function(){e.$refs.batchIPRange.focus()},100)},cancelBatchIPRange:function(){this.isAddingBatch=!1,this.batchIPRange=""},confirmBatchIPRange:function(){let a=this,e=this.batchIPRange;if(0==e.length)teaweb.warn("请填写要加入的IP范围",function(){a.$refs.batchIPRange.focus()});else{let n=[],o="";e.split("\n").forEach(function(t){if(0!=(t=t.trim()).length){let e=(t=t.replace(",",",")).split(",");var i,s;2!=e.length?o=t:(i=e[0].trim(),s=e[1].trim(),a.validateIP(i)&&a.validateIP(s)?n.push({type:"ipRange",params:{ipFrom:i,ipTo:s}}):o=t)}}),0 +`}),Vue.component("ns-route-ranges-box",{props:["v-ranges"],data:function(){let e=this.vRanges;return{ranges:e=null==e?[]:e,isAdding:!1,isAddingBatch:!1,rangeType:"ipRange",isReverse:!1,ipRangeFrom:"",ipRangeTo:"",batchIPRange:"",ipCIDR:"",batchIPCIDR:"",regions:[],regionType:"country"}},methods:{addIPRange:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.ipRangeFrom.focus()},100)},addCIDR:function(){this.isAdding=!0;let e=this;setTimeout(function(){e.$refs.ipCIDR.focus()},100)},addRegions:function(){this.isAdding=!0},addRegion:function(e){this.regionType=e},remove:function(e){this.ranges.$remove(e)},cancelIPRange:function(){this.isAdding=!1,this.ipRangeFrom="",this.ipRangeTo="",this.isReverse=!1},cancelIPCIDR:function(){this.isAdding=!1,this.ipCIDR="",this.isReverse=!1},cancelRegions:function(){this.isAdding=!1,this.regions=[],this.regionType="country",this.isReverse=!1},confirmIPRange:function(){let e=this;this.ipRangeFrom=this.ipRangeFrom.trim(),this.validateIP(this.ipRangeFrom)?(this.ipRangeTo=this.ipRangeTo.trim(),this.validateIP(this.ipRangeTo)?(this.ranges.push({type:"ipRange",params:{ipFrom:this.ipRangeFrom,ipTo:this.ipRangeTo,isReverse:this.isReverse}}),this.cancelIPRange()):teaweb.warn("结束IP填写错误",function(){e.$refs.ipRangeTo.focus()})):teaweb.warn("开始IP填写错误",function(){e.$refs.ipRangeFrom.focus()})},confirmIPCIDR:function(){let e=this;0==this.ipCIDR.length?teaweb.warn("请填写CIDR",function(){e.$refs.ipCIDR.focus()}):this.validateCIDR(this.ipCIDR)?(this.ranges.push({type:"cidr",params:{cidr:this.ipCIDR,isReverse:this.isReverse}}),this.cancelIPCIDR()):teaweb.warn("请输入正确的CIDR",function(){e.$refs.ipCIDR.focus()})},confirmRegions:function(){0==this.regions.length||this.ranges.push({type:"region",params:{regions:this.regions,isReverse:this.isReverse}}),this.cancelRegions()},addBatchIPRange:function(){this.isAddingBatch=!0;let e=this;setTimeout(function(){e.$refs.batchIPRange.focus()},100)},addBatchCIDR:function(){this.isAddingBatch=!0;let e=this;setTimeout(function(){e.$refs.batchIPCIDR.focus()},100)},cancelBatchIPRange:function(){this.isAddingBatch=!1,this.batchIPRange="",this.isReverse=!1},cancelBatchIPCIDR:function(){this.isAddingBatch=!1,this.batchIPCIDR="",this.isReverse=!1},confirmBatchIPRange:function(){let a=this,e=this.batchIPRange;if(0==e.length)teaweb.warn("请填写要加入的IP范围",function(){a.$refs.batchIPRange.focus()});else{let n=[],o="";e.split("\n").forEach(function(t){if(0!=(t=t.trim()).length){let e=(t=t.replace(",",",")).split(",");var i,s;2!=e.length?o=t:(i=e[0].trim(),s=e[1].trim(),a.validateIP(i)&&a.validateIP(s)?n.push({type:"ipRange",params:{ipFrom:i,ipTo:s,isReverse:a.isReverse}}):o=t)}}),0
+ [排除] IP范围: - {{range.params.ipFrom}} - {{range.params.ipTo}}   + CIDR: + 区域: + {{range.params.ipFrom}} - {{range.params.ipTo}} + {{range.params.cidr}} + {{region.name}} +  
- -
-
-
- -
-
-
-
- -
-
-   - -
+ +
+ +
+ + + + + + + + + + + + + +
开始IP * + +
结束IP * + +
排除 + +

选中后表示线路中排除当前条件。

+
+   +
-
- - -
-
- -

每行一条,格式为开始IP,结束IP,比如192.168.1.100,192.168.1.200

-
-
+ + +
+ + + + + + + + + +
IP范围列表 * + +

每行一条,格式为开始IP,结束IP,比如192.168.1.100,192.168.1.200

+
排除 + +

选中后表示线路中排除当前条件。

+
  - + +
+ +
+   +
-
-   - + +
+ +
+ + + + + + + + + +
CIDR * + +

类似于192.168.2.1/24

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+ + +
+ + + + + + + + + +
IP范围列表 * + +

每行一条,格式为IP/MASK,比如192.168.2.1/24

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+ +
+   + +
+
+ + +
+ +
+ + + + + + + + + + + + + +
已添加 +
+ {{region.name}} +
+
添加新国家/地区省份城市ISP + + * + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+   +   +   +   +
+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+   +
`}),Vue.component("ns-route-selector",{props:["v-route-code"],mounted:function(){let t=this;Tea.action("/ns/routes/options").post().success(function(e){t.routes=e.data.routes})},data:function(){let e=this.vRouteCode;return{routeCode:e=null==e?"":e,routes:[]}},template:`
@@ -2416,7 +2559,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
-
`}),Vue.component("http-compression-config-box",{props:["v-compression-config","v-is-location","v-is-group"],mounted:function(){let e=this;sortLoad(function(){e.initSortableTypes()})},data:function(){let t=this.vCompressionConfig,e=(null==(t=null==t?{isPrior:!1,isOn:!1,useDefaultTypes:!0,types:["brotli","gzip","deflate"],level:5,decompressData:!1,gzipRef:null,deflateRef:null,brotliRef:null,minLength:{count:0,unit:"kb"},maxLength:{count:0,unit:"kb"},mimeTypes:["text/*","application/*","font/*"],extensions:[".js",".json",".html",".htm",".xml",".css",".woff2",".txt"],conds:null}:t).types&&(t.types=[]),null==t.mimeTypes&&(t.mimeTypes=[]),null==t.extensions&&(t.extensions=[]),[{name:"Gzip",code:"gzip",isOn:!0},{name:"Deflate",code:"deflate",isOn:!0},{name:"Brotli",code:"brotli",isOn:!0}]),i=[];return t.types.forEach(function(t){e.forEach(function(e){t==e.code&&(e.isOn=!0,i.push(e))})}),e.forEach(function(e){t.types.$contains(e.code)||(e.isOn=!1,i.push(e))}),{config:t,moreOptionsVisible:!1,allTypes:i}},watch:{"config.level":function(e){let t=parseInt(e);isNaN(t)||t<1?t=1:10 +
`}),Vue.component("http-compression-config-box",{props:["v-compression-config","v-is-location","v-is-group"],mounted:function(){let e=this;sortLoad(function(){e.initSortableTypes()})},data:function(){let t=this.vCompressionConfig,e=(null==(t=null==t?{isPrior:!1,isOn:!1,useDefaultTypes:!0,types:["brotli","gzip","zstd","deflate"],level:5,decompressData:!1,gzipRef:null,deflateRef:null,brotliRef:null,minLength:{count:0,unit:"kb"},maxLength:{count:0,unit:"kb"},mimeTypes:["text/*","application/*","font/*"],extensions:[".js",".json",".html",".htm",".xml",".css",".woff2",".txt"],conds:null}:t).types&&(t.types=[]),null==t.mimeTypes&&(t.mimeTypes=[]),null==t.extensions&&(t.extensions=[]),[{name:"Gzip",code:"gzip",isOn:!0},{name:"Deflate",code:"deflate",isOn:!0},{name:"Brotli",code:"brotli",isOn:!0},{name:"ZSTD",code:"zstd",isOn:!0}]),i=[];return t.types.forEach(function(t){e.forEach(function(e){t==e.code&&(e.isOn=!0,i.push(e))})}),e.forEach(function(e){t.types.$contains(e.code)||(e.isOn=!1,i.push(e))}),{config:t,moreOptionsVisible:!1,allTypes:i}},watch:{"config.level":function(e){let t=parseInt(e);isNaN(t)||t<1?t=1:10 @@ -2463,7 +2606,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
- +
@@ -4291,7 +4434,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio diff --git a/web/public/js/components.src.js b/web/public/js/components.src.js index 9a48256e..ee90954b 100755 --- a/web/public/js/components.src.js +++ b/web/public/js/components.src.js @@ -1438,21 +1438,46 @@ Vue.component("ns-route-ranges-box", { isAdding: false, isAddingBatch: false, + // 类型 + rangeType: "ipRange", + isReverse: false, + // IP范围 ipRangeFrom: "", ipRangeTo: "", - batchIPRange: "" + batchIPRange: "", + + // CIDR + ipCIDR: "", + batchIPCIDR: "", + + // region + regions: [], + regionType: "country" } }, methods: { - add: function () { + addIPRange: function () { this.isAdding = true let that = this setTimeout(function () { that.$refs.ipRangeFrom.focus() }, 100) }, + addCIDR: function () { + this.isAdding = true + let that = this + setTimeout(function () { + that.$refs.ipCIDR.focus() + }, 100) + }, + addRegions: function () { + this.isAdding = true + }, + addRegion: function (regionType) { + this.regionType = regionType + }, remove: function (index) { this.ranges.$remove(index) }, @@ -1460,6 +1485,18 @@ Vue.component("ns-route-ranges-box", { this.isAdding = false this.ipRangeFrom = "" this.ipRangeTo = "" + this.isReverse = false + }, + cancelIPCIDR: function () { + this.isAdding = false + this.ipCIDR = "" + this.isReverse = false + }, + cancelRegions: function () { + this.isAdding = false + this.regions = [] + this.regionType = "country" + this.isReverse = false }, confirmIPRange: function () { // 校验IP @@ -1484,21 +1521,74 @@ Vue.component("ns-route-ranges-box", { type: "ipRange", params: { ipFrom: this.ipRangeFrom, - ipTo: this.ipRangeTo + ipTo: this.ipRangeTo, + isReverse: this.isReverse } }) this.cancelIPRange() }, - addBatch: function () { + confirmIPCIDR: function () { + let that = this + if (this.ipCIDR.length == 0) { + teaweb.warn("请填写CIDR", function () { + that.$refs.ipCIDR.focus() + }) + return + } + if (!this.validateCIDR(this.ipCIDR)) { + teaweb.warn("请输入正确的CIDR", function () { + that.$refs.ipCIDR.focus() + }) + return + } + + + this.ranges.push({ + type: "cidr", + params: { + cidr: this.ipCIDR, + isReverse: this.isReverse + } + }) + this.cancelIPCIDR() + }, + confirmRegions: function () { + if (this.regions.length == 0) { + this.cancelRegions() + return + } + this.ranges.push({ + type: "region", + params: { + regions: this.regions, + isReverse: this.isReverse + } + }) + this.cancelRegions() + }, + addBatchIPRange: function () { this.isAddingBatch = true let that = this setTimeout(function () { that.$refs.batchIPRange.focus() }, 100) }, + addBatchCIDR: function () { + this.isAddingBatch = true + let that = this + setTimeout(function () { + that.$refs.batchIPCIDR.focus() + }, 100) + }, cancelBatchIPRange: function () { this.isAddingBatch = false this.batchIPRange = "" + this.isReverse = false + }, + cancelBatchIPCIDR: function () { + this.isAddingBatch = false + this.batchIPCIDR = "" + this.isReverse = false }, confirmBatchIPRange: function () { let that = this @@ -1533,7 +1623,8 @@ Vue.component("ns-route-ranges-box", { type: "ipRange", params: { ipFrom: ipFrom, - ipTo: ipTo + ipTo: ipTo, + isReverse: that.isReverse } }) }) @@ -1548,7 +1639,114 @@ Vue.component("ns-route-ranges-box", { }) this.cancelBatchIPRange() }, + confirmBatchIPCIDR: function () { + let that = this + let rangesText = this.batchIPCIDR + if (rangesText.length == 0) { + teaweb.warn("请填写要加入的CIDR", function () { + that.$refs.batchIPCIDR.focus() + }) + return + } + + let validRanges = [] + let invalidLine = "" + rangesText.split("\n").forEach(function (line) { + let cidr = line.trim() + if (cidr.length == 0) { + return + } + if (!that.validateCIDR(cidr)) { + invalidLine = line + return + } + validRanges.push({ + type: "cidr", + params: { + cidr: cidr, + isReverse: that.isReverse + } + }) + }) + if (invalidLine.length > 0) { + teaweb.warn("'" + invalidLine + "'格式错误", function () { + that.$refs.batchIPCIDR.focus() + }) + return + } + validRanges.forEach(function (v) { + that.ranges.push(v) + }) + this.cancelBatchIPCIDR() + }, + selectRegionCountry: function (country) { + if (country == null) { + return + } + this.regions.push({ + type: "country", + id: country.id, + name: country.name + }) + this.$refs.regionCountryComboBox.clear() + }, + selectRegionProvince: function (province) { + if (province == null) { + return + } + this.regions.push({ + type: "province", + id: province.id, + name: province.name + }) + this.$refs.regionProvinceComboBox.clear() + }, + selectRegionCity: function (city) { + if (city == null) { + return + } + this.regions.push({ + type: "city", + id: city.id, + name: city.name + }) + this.$refs.regionCityComboBox.clear() + }, + selectRegionProvider: function (provider) { + if (provider == null) { + return + } + this.regions.push({ + type: "provider", + id: provider.id, + name: provider.name + }) + this.$refs.regionProviderComboBox.clear() + }, + removeRegion: function (index) { + this.regions.$remove(index) + }, validateIP: function (ip) { + if (ip.length == 0) { + return + } + + // IPv6 + if (ip.indexOf(":") >= 0) { + let pieces = ip.split(":") + if (pieces.length > 8) { + return false + } + let isOk = true + pieces.forEach(function (piece) { + if (!/^[\da-fA-F]{0,4}$/.test(piece)) { + isOk = false + } + }) + + return isOk + } + if (!ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)) { return false } @@ -1561,50 +1759,215 @@ Vue.component("ns-route-ranges-box", { } }) return isOk + }, + validateCIDR: function (cidr) { + let pieces = cidr.split("/") + if (pieces.length != 2) { + return false + } + let ip = pieces[0] + if (!this.validateIP(ip)) { + return false + } + let mask = pieces[1] + if (!/^\d{1,3}$/.test(mask)) { + return false + } + mask = parseInt(mask, 10) + if (cidr.indexOf(":") >= 0) { // IPv6 + return mask <= 128 + } + return mask <= 32 + }, + updateRangeType: function (rangeType) { + this.rangeType = rangeType } }, template: `
+ [排除] IP范围: - {{range.params.ipFrom}} - {{range.params.ipTo}}   + CIDR: + 区域: + {{range.params.ipFrom}} - {{range.params.ipTo}} + {{range.params.cidr}} + {{region.name}} +  
- -
-
-
- -
-
-
-
- -
-
-   - -
+ +
+ +
+ + + + + + + + + + + + + +
开始IP * + +
结束IP * + +
排除 + +

选中后表示线路中排除当前条件。

+
+   +
-
- - -
-
- -

每行一条,格式为开始IP,结束IP,比如192.168.1.100,192.168.1.200

-
-
+ + +
+ + + + + + + + + +
IP范围列表 * + +

每行一条,格式为开始IP,结束IP,比如192.168.1.100,192.168.1.200

+
排除 + +

选中后表示线路中排除当前条件。

+
  - + +
+ +
+   +
-
-   - + +
+ +
+ + + + + + + + + +
CIDR * + +

类似于192.168.2.1/24

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+ + +
+ + + + + + + + + +
IP范围列表 * + +

每行一条,格式为IP/MASK,比如192.168.2.1/24

+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+ +
+   + +
+
+ + +
+ +
+ + + + + + + + + + + + + +
已添加 +
+ {{region.name}} +
+
添加新国家/地区省份城市ISP + + * + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+   +   +   +   +
+
排除 + +

选中后表示线路中排除当前条件。

+
+   + +
+
+   +
` }) @@ -7237,7 +7600,7 @@ Vue.component("http-compression-config-box", { isPrior: false, isOn: false, useDefaultTypes: true, - types: ["brotli", "gzip", "deflate"], + types: ["brotli", "gzip", "zstd", "deflate"], level: 5, decompressData: false, gzipRef: null, @@ -7276,6 +7639,11 @@ Vue.component("http-compression-config-box", { name: "Brotli", code: "brotli", isOn: true + }, + { + name: "ZSTD", + code: "zstd", + isOn: true } ] @@ -7412,7 +7780,7 @@ Vue.component("http-compression-config-box", {
- +
@@ -13092,7 +13460,7 @@ Vue.component("combo-box", {