From 05cd622456129aa3d1533019e2e53ca1beffd9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=A5=A5=E8=B6=85?= Date: Fri, 7 Jul 2023 09:51:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96WAF=E5=8C=BA=E5=9F=9F/?= =?UTF-8?q?=E7=9C=81=E4=BB=BD=E5=B0=81=E7=A6=81=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=BB=85=E5=85=81=E8=AE=B8=E3=80=81=E5=A2=9E=E5=8A=A0=E4=B8=AD?= =?UTF-8?q?=E5=9B=BD=E9=A6=99=E6=B8=AF=E6=BE=B3=E5=8F=B0=E3=80=81=E5=86=85?= =?UTF-8?q?=E5=9C=B0=E7=AD=89=E7=89=B9=E6=AE=8A=E5=8C=BA=E5=9F=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/rpc.json | 8 +- pkg/rpc/pb/model_region_country.pb.go | 16 +- .../protos/models/model_region_country.proto | 1 + .../http_firewall_region_config.go | 106 ++++++++++- .../http_firewall_region_config_test.go | 180 ++++++++++++++++++ pkg/serverconfigs/regionconfigs/china.go | 41 ++++ 6 files changed, 341 insertions(+), 11 deletions(-) create mode 100644 pkg/serverconfigs/firewallconfigs/http_firewall_region_config_test.go create mode 100644 pkg/serverconfigs/regionconfigs/china.go diff --git a/build/rpc.json b/build/rpc.json index cf8c871..4681e7c 100644 --- a/build/rpc.json +++ b/build/rpc.json @@ -3064,7 +3064,8 @@ "code": "rpc createHTTPRewriteRule (CreateHTTPRewriteRuleRequest) returns (CreateHTTPRewriteRuleResponse);", "doc": "创建重写规则", "roles": [ - "admin" + "admin", + "user" ], "isDeprecated": false }, @@ -3075,7 +3076,8 @@ "code": "rpc updateHTTPRewriteRule (UpdateHTTPRewriteRuleRequest) returns (RPCSuccess);", "doc": "修改重写规则", "roles": [ - "admin" + "admin", + "user" ], "isDeprecated": false } @@ -21079,7 +21081,7 @@ }, { "name": "RegionCountry", - "code": "message RegionCountry {\n\tint64 id = 1;\n\tstring name = 2;\n\trepeated string codes = 3;\n\trepeated string pinyin = 4;\n\tstring customName = 5;\n\trepeated string customCodes = 6;\n\tstring displayName = 7;\n}", + "code": "message RegionCountry {\n\tint64 id = 1;\n\tstring name = 2;\n\trepeated string codes = 3;\n\trepeated string pinyin = 4;\n\tstring customName = 5;\n\trepeated string customCodes = 6;\n\tstring displayName = 7;\n\tbool isCommon = 8; // 是否常用\n}", "doc": "国家/地区" }, { diff --git a/pkg/rpc/pb/model_region_country.pb.go b/pkg/rpc/pb/model_region_country.pb.go index 29e1e2b..7e617fa 100644 --- a/pkg/rpc/pb/model_region_country.pb.go +++ b/pkg/rpc/pb/model_region_country.pb.go @@ -38,6 +38,7 @@ type RegionCountry struct { CustomName string `protobuf:"bytes,5,opt,name=customName,proto3" json:"customName,omitempty"` CustomCodes []string `protobuf:"bytes,6,rep,name=customCodes,proto3" json:"customCodes,omitempty"` DisplayName string `protobuf:"bytes,7,opt,name=displayName,proto3" json:"displayName,omitempty"` + IsCommon bool `protobuf:"varint,8,opt,name=isCommon,proto3" json:"isCommon,omitempty"` // 是否常用 } func (x *RegionCountry) Reset() { @@ -121,12 +122,19 @@ func (x *RegionCountry) GetDisplayName() string { return "" } +func (x *RegionCountry) GetIsCommon() bool { + if x != nil { + return x.IsCommon + } + return false +} + var File_models_model_region_country_proto protoreflect.FileDescriptor var file_models_model_region_country_proto_rawDesc = []byte{ 0x0a, 0x21, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0xc5, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, + 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0xe1, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, @@ -138,8 +146,10 @@ var file_models_model_region_country_proto_rawDesc = []byte{ 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x42, - 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x69, 0x73, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x42, 0x06, 0x5a, 0x04, 0x2e, + 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/rpc/protos/models/model_region_country.proto b/pkg/rpc/protos/models/model_region_country.proto index f657431..6edccec 100644 --- a/pkg/rpc/protos/models/model_region_country.proto +++ b/pkg/rpc/protos/models/model_region_country.proto @@ -12,4 +12,5 @@ message RegionCountry { string customName = 5; repeated string customCodes = 6; string displayName = 7; + bool isCommon = 8; // 是否常用 } \ No newline at end of file diff --git a/pkg/serverconfigs/firewallconfigs/http_firewall_region_config.go b/pkg/serverconfigs/firewallconfigs/http_firewall_region_config.go index 71ce515..76611ba 100644 --- a/pkg/serverconfigs/firewallconfigs/http_firewall_region_config.go +++ b/pkg/serverconfigs/firewallconfigs/http_firewall_region_config.go @@ -1,11 +1,17 @@ package firewallconfigs -import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" +import ( + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared" +) type HTTPFirewallRegionConfig struct { - IsOn bool `yaml:"isOn" json:"isOn"` - DenyCountryIds []int64 `yaml:"denyCountryIds" json:"denyCountryIds"` // 封禁的国家|地区 - DenyProvinceIds []int64 `yaml:"denyProvinceIds" json:"denyProvinceIds"` // 封禁的省或自治区 + IsOn bool `yaml:"isOn" json:"isOn"` + + AllowCountryIds []int64 `yaml:"allowCountryIds" json:"allowCountryIds"` // 允许的国家/地区 + DenyCountryIds []int64 `yaml:"denyCountryIds" json:"denyCountryIds"` // 封禁的国家/地区 + AllowProvinceIds []int64 `yaml:"allowProvinceIds" json:"allowProvinceIds"` // 允许的省或自治区 + DenyProvinceIds []int64 `yaml:"denyProvinceIds" json:"denyProvinceIds"` // 封禁的省或自治区 CountryOnlyURLPatterns []*shared.URLPattern `yaml:"countryOnlyURLPatterns" json:"countryOnlyURLPatterns"` // 仅限的URL CountryExceptURLPatterns []*shared.URLPattern `yaml:"countryExceptURLPatterns" json:"countryExceptURLPatterns"` // 排除的URL @@ -14,11 +20,37 @@ type HTTPFirewallRegionConfig struct { ProvinceExceptURLPatterns []*shared.URLPattern `yaml:"provinceExceptURLPatterns" json:"provinceExceptURLPatterns"` // 排除的URL isNotEmpty bool + + allowCountryIdMap map[int64]bool + denyCountryIdMap map[int64]bool + allowProvinceIdMap map[int64]bool + denyProvinceIdMap map[int64]bool } func (this *HTTPFirewallRegionConfig) Init() error { - this.isNotEmpty = len(this.DenyCountryIds) > 0 || len(this.DenyProvinceIds) > 0 + // countries and provinces + this.isNotEmpty = len(this.AllowCountryIds) > 0 || len(this.AllowProvinceIds) > 0 || len(this.DenyCountryIds) > 0 || len(this.DenyProvinceIds) > 0 + this.allowCountryIdMap = map[int64]bool{} + for _, countryId := range this.AllowCountryIds { + this.allowCountryIdMap[countryId] = true + } + this.denyCountryIdMap = map[int64]bool{} + for _, countryId := range this.DenyCountryIds { + this.denyCountryIdMap[countryId] = true + } + + this.allowProvinceIdMap = map[int64]bool{} + for _, provinceId := range this.AllowProvinceIds { + this.allowProvinceIdMap[provinceId] = true + } + + this.denyProvinceIdMap = map[int64]bool{} + for _, provinceId := range this.DenyProvinceIds { + this.denyProvinceIdMap[provinceId] = true + } + + // url patterns for _, pattern := range this.CountryExceptURLPatterns { err := pattern.Init() if err != nil { @@ -54,6 +86,70 @@ func (this *HTTPFirewallRegionConfig) IsNotEmpty() bool { return this.isNotEmpty } +func (this *HTTPFirewallRegionConfig) IsAllowedCountry(countryId int64, provinceId int64) bool { + if len(this.allowCountryIdMap) > 0 { + if this.allowCountryIdMap[countryId] { + return true + } + + // china sub regions + if countryId == regionconfigs.RegionChinaId && provinceId > 0 { + if this.allowCountryIdMap[regionconfigs.RegionChinaIdHK] && provinceId == regionconfigs.RegionChinaProvinceIdHK { + return true + } + if this.allowCountryIdMap[regionconfigs.RegionChinaIdMO] && provinceId == regionconfigs.RegionChinaProvinceIdMO { + return true + } + if this.allowCountryIdMap[regionconfigs.RegionChinaIdTW] && provinceId == regionconfigs.RegionChinaProvinceIdTW { + return true + } + if this.allowCountryIdMap[regionconfigs.RegionChinaIdMainland] && regionconfigs.CheckRegionProvinceIsInChinaMainland(provinceId) { + return true + } + } + + return false + } + if len(this.denyCountryIdMap) > 0 { + if !this.denyCountryIdMap[countryId] { + // china sub regions + if countryId == regionconfigs.RegionChinaId && provinceId > 0 { + if this.denyCountryIdMap[regionconfigs.RegionChinaIdHK] && provinceId == regionconfigs.RegionChinaProvinceIdHK { + return false + } + if this.denyCountryIdMap[regionconfigs.RegionChinaIdMO] && provinceId == regionconfigs.RegionChinaProvinceIdMO { + return false + } + if this.denyCountryIdMap[regionconfigs.RegionChinaIdTW] && provinceId == regionconfigs.RegionChinaProvinceIdTW { + return false + } + if this.denyCountryIdMap[regionconfigs.RegionChinaIdMainland] && regionconfigs.CheckRegionProvinceIsInChinaMainland(provinceId) { + return false + } + } + + return true + } + + return false + } + + return true +} + +func (this *HTTPFirewallRegionConfig) IsAllowedProvince(countryId int64, provinceId int64) bool { + if countryId != regionconfigs.RegionChinaId { + return true + } + if len(this.allowProvinceIdMap) > 0 { + return this.allowProvinceIdMap[provinceId] + } + if len(this.denyProvinceIdMap) > 0 { + return !this.denyProvinceIdMap[provinceId] + } + return true +} + func (this *HTTPFirewallRegionConfig) MatchCountryURL(url string) bool { // except if len(this.CountryExceptURLPatterns) > 0 { diff --git a/pkg/serverconfigs/firewallconfigs/http_firewall_region_config_test.go b/pkg/serverconfigs/firewallconfigs/http_firewall_region_config_test.go new file mode 100644 index 0000000..0c2d8d6 --- /dev/null +++ b/pkg/serverconfigs/firewallconfigs/http_firewall_region_config_test.go @@ -0,0 +1,180 @@ +// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . + +package firewallconfigs_test + +import ( + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/regionconfigs" + "github.com/iwind/TeaGo/assert" + "testing" +) + +func TestHTTPFirewallRegionConfig_IsAllowed(t *testing.T) { + var a = assert.NewAssertion(t) + + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowCountryIds = []int64{1, 2, 3} + config.DenyCountryIds = []int64{4, 5, 6} + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsTrue(config.IsAllowedCountry(1, 1)) + a.IsFalse(config.IsAllowedCountry(0, 0)) + a.IsFalse(config.IsAllowedCountry(4, 0)) + } + + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowCountryIds = []int64{1, 2, 3} + config.DenyCountryIds = []int64{1, 2, 3} + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsTrue(config.IsAllowedCountry(1, 1)) + a.IsFalse(config.IsAllowedCountry(0, 0)) + a.IsFalse(config.IsAllowedCountry(4, 0)) + } + + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowCountryIds = []int64{} + config.DenyCountryIds = []int64{1, 2, 3} + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsFalse(config.IsAllowedCountry(1, 0)) + a.IsTrue(config.IsAllowedCountry(0, 0)) + a.IsTrue(config.IsAllowedCountry(4, 0)) + } + + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowProvinceIds = []int64{1, 2, 3} + config.DenyProvinceIds = []int64{4, 5, 6} + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsTrue(config.IsAllowedProvince(1, 1)) + a.IsFalse(config.IsAllowedProvince(1, 0)) + a.IsFalse(config.IsAllowedProvince(1, 4)) + } + + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowProvinceIds = []int64{} + config.DenyProvinceIds = []int64{4, 5, 6} + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsTrue(config.IsAllowedProvince(1, 1)) + a.IsTrue(config.IsAllowedProvince(1, 3)) + a.IsFalse(config.IsAllowedProvince(1, 4)) + } + + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowProvinceIds = []int64{} + config.DenyProvinceIds = []int64{} + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsTrue(config.IsAllowedProvince(1, 1)) + a.IsTrue(config.IsAllowedProvince(1, 4)) + a.IsTrue(config.IsAllowedProvince(1, 4)) + } + + // the greater China area: Taiwan & Hongkong & Macao + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowCountryIds = []int64{ + regionconfigs.RegionChinaIdHK, + regionconfigs.RegionChinaIdMO, + regionconfigs.RegionChinaIdTW, + //regionconfigs.RegionChinaIdMainland, + } + config.DenyCountryIds = []int64{} + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsTrue(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdHK)) + a.IsTrue(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdTW)) + a.IsTrue(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdMO)) + a.IsFalse(config.IsAllowedCountry(1, 1)) + a.IsFalse(config.IsAllowedCountry(1, 0)) + } + + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowCountryIds = []int64{ + regionconfigs.RegionChinaIdHK, + regionconfigs.RegionChinaIdMainland, + } + config.DenyCountryIds = []int64{} + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsTrue(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdHK)) + a.IsFalse(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdTW)) + a.IsFalse(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdMO)) + a.IsTrue(config.IsAllowedCountry(1, 1)) + a.IsFalse(config.IsAllowedCountry(1, 0)) + } + + { + var config = &firewallconfigs.HTTPFirewallRegionConfig{} + config.AllowCountryIds = []int64{} + config.DenyCountryIds = []int64{ + regionconfigs.RegionChinaIdHK, + regionconfigs.RegionChinaIdMainland, + } + err := config.Init() + if err != nil { + t.Fatal(err) + } + a.IsFalse(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdHK)) + a.IsTrue(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdTW)) + a.IsTrue(config.IsAllowedCountry(1, regionconfigs.RegionChinaProvinceIdMO)) + a.IsFalse(config.IsAllowedCountry(1, 1)) + a.IsTrue(config.IsAllowedCountry(1, 0)) + } +} + +func Benchmark_HTTPFirewallRegionConfig_Map(b *testing.B) { + var m = map[int64]bool{} + const max = 50 + for i := 0; i < max; i++ { + m[int64(i)] = true + } + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _ = m[int64(i%max)] + } +} + +func Benchmark_HTTPFirewallRegionConfig_Slice(b *testing.B) { + var m = []int64{} + const max = 50 + for i := 0; i < max; i++ { + m = append(m, int64(i)) + } + b.ResetTimer() + + for i := 0; i < b.N; i++ { + var l = int64(i % max) + for _, v := range m { + if v == l { + break + } + } + } +} diff --git a/pkg/serverconfigs/regionconfigs/china.go b/pkg/serverconfigs/regionconfigs/china.go new file mode 100644 index 0000000..c10df3c --- /dev/null +++ b/pkg/serverconfigs/regionconfigs/china.go @@ -0,0 +1,41 @@ +// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . + +package regionconfigs + +type RegionId = int64 +type RegionProvinceId = int64 + +const ( + RegionChinaId RegionId = 1 + RegionChinaIdHK RegionId = 261 + RegionChinaIdTW RegionId = 262 + RegionChinaIdMO RegionId = 263 + RegionChinaIdMainland RegionId = 264 + + RegionChinaProvinceIdHK RegionProvinceId = 32 + RegionChinaProvinceIdTW RegionProvinceId = 34 + RegionChinaProvinceIdMO RegionProvinceId = 33 +) + +func CheckRegionIsInGreaterChina(regionId RegionId) bool { + return regionId == RegionChinaId || + regionId == RegionChinaIdHK || + regionId == RegionChinaIdTW || + regionId == RegionChinaIdMO || + regionId == RegionChinaIdMainland +} + +func FindAllGreaterChinaSubRegionIds() []RegionId { + return []RegionId{ + RegionChinaIdMainland, RegionChinaIdHK, RegionChinaIdMO, RegionChinaIdTW, + } +} + +func CheckRegionProvinceIsInChinaMainland(regionProvinceId RegionProvinceId) bool { + if regionProvinceId <= 0 { + return false + } + return regionProvinceId != RegionChinaProvinceIdHK && + regionProvinceId != RegionChinaProvinceIdMO && + regionProvinceId != RegionChinaProvinceIdTW +}