diff --git a/internal/utils/strings.go b/internal/utils/strings.go index 1c83b53c..f9a0008e 100644 --- a/internal/utils/strings.go +++ b/internal/utils/strings.go @@ -5,7 +5,7 @@ import ( "strings" ) -// format address +// FormatAddress format address func FormatAddress(addr string) string { if strings.HasSuffix(addr, "unix:") { return addr @@ -17,7 +17,7 @@ func FormatAddress(addr string) string { return addr } -// 分割数字 +// SplitNumbers 分割数字 func SplitNumbers(numbers string) (result []int64) { if len(numbers) == 0 { return diff --git a/internal/utils/strings_stream.go b/internal/utils/strings_stream.go new file mode 100644 index 00000000..b53aaed3 --- /dev/null +++ b/internal/utils/strings_stream.go @@ -0,0 +1,67 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . + +package utils + +import ( + "github.com/iwind/TeaGo/lists" + "strings" +) + +func FilterNotEmpty(item string) bool { + return len(item) > 0 +} + +func MapAddPrefixFunc(prefix string) func(item string) string { + return func(item string) string { + if !strings.HasPrefix(item, prefix) { + return prefix + item + } + return item + } +} + +type StringsStream struct { + s []string +} + +func NewStringsStream(s []string) *StringsStream { + return &StringsStream{s: s} +} + +func (this *StringsStream) Map(f ...func(item string) string) *StringsStream { + for index, item := range this.s { + for _, f1 := range f { + item = f1(item) + } + this.s[index] = item + } + return this +} + +func (this *StringsStream) Filter(f ...func(item string) bool) *StringsStream { + for _, f1 := range f { + var newStrings = []string{} + for _, item := range this.s { + if f1(item) { + newStrings = append(newStrings, item) + } + } + this.s = newStrings + } + return this +} + +func (this *StringsStream) Unique() *StringsStream { + var newStrings = []string{} + for _, item := range this.s { + if !lists.ContainsString(newStrings, item) { + newStrings = append(newStrings, item) + } + } + this.s = newStrings + return this +} + +func (this *StringsStream) Result() []string { + return this.s +} diff --git a/internal/utils/strings_stream_test.go b/internal/utils/strings_stream_test.go new file mode 100644 index 00000000..39e9c956 --- /dev/null +++ b/internal/utils/strings_stream_test.go @@ -0,0 +1,25 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . + +package utils_test + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/utils" + "strings" + "testing" +) + +func TestStringsStream_Filter(t *testing.T) { + var stream = utils.NewStringsStream([]string{"a", "b", "1", "2", "", "png", "a"}) + stream.Filter(func(item string) bool { + return len(item) > 0 + }) + t.Log(stream.Result()) + stream.Map(func(item string) string { + return "." + item + }) + t.Log(stream.Result()) + stream.Unique() + t.Log(stream.Result()) + stream.Map(strings.ToUpper, strings.ToLower) + t.Log(stream.Result()) +} diff --git a/internal/web/actions/default/servers/server/settings/access/createPopup.go b/internal/web/actions/default/servers/server/settings/access/createPopup.go index 81758bb0..06005153 100644 --- a/internal/web/actions/default/servers/server/settings/access/createPopup.go +++ b/internal/web/actions/default/servers/server/settings/access/createPopup.go @@ -1,13 +1,16 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. +//go:build !plus package access import ( "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/utils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/iwind/TeaGo/actions" + "strings" ) type CreatePopupAction struct { @@ -37,6 +40,9 @@ func (this *CreatePopupAction) RunPost(params struct { SubRequestMethod string SubRequestFollowRequest bool + Exts []string + DomainsJSON []byte + Must *actions.Must CSRF *actionutils.CSRF }) { @@ -44,14 +50,42 @@ func (this *CreatePopupAction) RunPost(params struct { Field("name", params.Name). Require("请输入名称"). Field("type", params.Type). - Require("请输入认证类型") + Require("请输入鉴权类型") var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true} - var paramsJSON []byte + + // 扩展名 + var exts = utils.NewStringsStream(params.Exts). + Map(strings.TrimSpace, strings.ToLower). + Filter(utils.FilterNotEmpty). + Map(utils.MapAddPrefixFunc(".")). + Unique(). + Result() + + // 域名 + var domains = []string{} + if len(params.DomainsJSON) > 0 { + var rawDomains = []string{} + err := json.Unmarshal(params.DomainsJSON, &rawDomains) + if err != nil { + this.ErrorPage(err) + return + } + + // TODO 如果用户填写了一个网址,应该分析域名并填入 + + domains = utils.NewStringsStream(rawDomains). + Map(strings.TrimSpace, strings.ToLower). + Filter(utils.FilterNotEmpty). + Unique(). + Result() + } + + var method serverconfigs.HTTPAuthMethodInterface switch params.Type { case serverconfigs.HTTPAuthTypeBasicAuth: - users := []*serverconfigs.HTTPAuthBasicMethodUser{} + var users = []*serverconfigs.HTTPAuthBasicMethodUser{} err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users) if err != nil { this.ErrorPage(err) @@ -60,40 +94,39 @@ func (this *CreatePopupAction) RunPost(params struct { if len(users) == 0 { this.Fail("请添加至少一个用户") } - method := &serverconfigs.HTTPAuthBasicMethod{ + method = &serverconfigs.HTTPAuthBasicMethod{ Users: users, Realm: params.BasicAuthRealm, Charset: params.BasicAuthCharset, } - methodJSON, err := json.Marshal(method) - if err != nil { - this.ErrorPage(err) - return - } - - paramsJSON = methodJSON case serverconfigs.HTTPAuthTypeSubRequest: params.Must.Field("subRequestURL", params.SubRequestURL). Require("请输入子请求URL") if params.SubRequestFollowRequest { params.SubRequestMethod = "" } - method := &serverconfigs.HTTPAuthSubRequestMethod{ + method = &serverconfigs.HTTPAuthSubRequestMethod{ URL: params.SubRequestURL, Method: params.SubRequestMethod, } - methodJSON, err := json.Marshal(method) - if err != nil { - this.ErrorPage(err) - return - } - paramsJSON = methodJSON default: - this.Fail("不支持的认证类型'" + params.Type + "'") + this.Fail("不支持的鉴权类型'" + params.Type + "'") + } + + if method == nil { + this.Fail("无法找到对应的鉴权方式") + } + method.SetExts(exts) + method.SetDomains(domains) + + paramsJSON, err := json.Marshal(method) + if err != nil { + this.ErrorPage(err) + return } var paramsMap map[string]interface{} - err := json.Unmarshal(paramsJSON, ¶msMap) + err = json.Unmarshal(paramsJSON, ¶msMap) if err != nil { this.ErrorPage(err) return @@ -108,7 +141,7 @@ func (this *CreatePopupAction) RunPost(params struct { this.ErrorPage(err) return } - defer this.CreateLogInfo("创建HTTP认证 %d", createResp.HttpAuthPolicyId) + defer this.CreateLogInfo("创建HTTP鉴权 %d", createResp.HttpAuthPolicyId) ref.AuthPolicyId = createResp.HttpAuthPolicyId ref.AuthPolicy = &serverconfigs.HTTPAuthPolicy{ Id: createResp.HttpAuthPolicyId, diff --git a/internal/web/actions/default/servers/server/settings/access/index.go b/internal/web/actions/default/servers/server/settings/access/index.go index 9de863b4..4ee60844 100644 --- a/internal/web/actions/default/servers/server/settings/access/index.go +++ b/internal/web/actions/default/servers/server/settings/access/index.go @@ -7,6 +7,7 @@ import ( "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/iwind/TeaGo/actions" + "github.com/iwind/TeaGo/lists" ) type IndexAction struct { @@ -28,6 +29,26 @@ func (this *IndexAction) RunGet(params struct { } this.Data["webId"] = webConfig.Id + + // 移除不存在的鉴权方法 + var allTypes = []string{} + for _, def := range serverconfigs.FindAllHTTPAuthTypes() { + allTypes = append(allTypes, def.Code) + } + + var refs = webConfig.Auth.PolicyRefs + var realRefs = []*serverconfigs.HTTPAuthPolicyRef{} + for _, ref := range refs { + if ref.AuthPolicy == nil { + continue + } + if !lists.ContainsString(allTypes, ref.AuthPolicy.Type) { + continue + } + realRefs = append(realRefs, ref) + } + webConfig.Auth.PolicyRefs = realRefs + this.Data["authConfig"] = webConfig.Auth this.Show() @@ -40,7 +61,7 @@ func (this *IndexAction) RunPost(params struct { Must *actions.Must CSRF *actionutils.CSRF }) { - defer this.CreateLogInfo("修改Web %d 的认证设置", params.WebId) + defer this.CreateLogInfo("修改Web %d 的鉴权设置", params.WebId) var authConfig = &serverconfigs.HTTPAuthConfig{} err := json.Unmarshal(params.AuthJSON, authConfig) @@ -53,7 +74,7 @@ func (this *IndexAction) RunPost(params struct { this.Fail("配置校验失败:" + err.Error()) } - // 保存之前删除多于的配置信息 + // 保存之前删除多余的配置信息 for _, ref := range authConfig.PolicyRefs { ref.AuthPolicy = nil } diff --git a/internal/web/actions/default/servers/server/settings/access/init.go b/internal/web/actions/default/servers/server/settings/access/init.go index 588a6cd7..2684875a 100644 --- a/internal/web/actions/default/servers/server/settings/access/init.go +++ b/internal/web/actions/default/servers/server/settings/access/init.go @@ -16,6 +16,7 @@ func init() { GetPost("", new(IndexAction)). GetPost("/createPopup", new(CreatePopupAction)). GetPost("/updatePopup", new(UpdatePopupAction)). + Post("/random", new(RandomAction)). EndAll() }) } diff --git a/internal/web/actions/default/servers/server/settings/access/random.go b/internal/web/actions/default/servers/server/settings/access/random.go new file mode 100644 index 00000000..f03ce7c9 --- /dev/null +++ b/internal/web/actions/default/servers/server/settings/access/random.go @@ -0,0 +1,18 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . + +package access + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/iwind/TeaGo/rands" +) + +type RandomAction struct { + actionutils.ParentAction +} + +func (this *RandomAction) RunPost(params struct{}) { + this.Data["random"] = rands.HexString(32) + + this.Success() +} diff --git a/internal/web/actions/default/servers/server/settings/access/updatePopup.go b/internal/web/actions/default/servers/server/settings/access/updatePopup.go index 0453c314..dbfdf081 100644 --- a/internal/web/actions/default/servers/server/settings/access/updatePopup.go +++ b/internal/web/actions/default/servers/server/settings/access/updatePopup.go @@ -1,14 +1,17 @@ // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. +//go:build !plus package access import ( "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/utils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/maps" + "strings" ) type UpdatePopupAction struct { @@ -70,17 +73,20 @@ func (this *UpdatePopupAction) RunPost(params struct { SubRequestMethod string SubRequestFollowRequest bool + Exts []string + DomainsJSON []byte + Must *actions.Must CSRF *actionutils.CSRF }) { - defer this.CreateLogInfo("修改HTTP认证 %d", params.PolicyId) + defer this.CreateLogInfo("修改HTTP鉴权 %d", params.PolicyId) policyResp, err := this.RPC().HTTPAuthPolicyRPC().FindEnabledHTTPAuthPolicy(this.AdminContext(), &pb.FindEnabledHTTPAuthPolicyRequest{HttpAuthPolicyId: params.PolicyId}) if err != nil { this.ErrorPage(err) return } - policy := policyResp.HttpAuthPolicy + var policy = policyResp.HttpAuthPolicy if policy == nil { this.NotFound("httpAuthPolicy", params.PolicyId) return @@ -91,12 +97,40 @@ func (this *UpdatePopupAction) RunPost(params struct { Field("name", params.Name). Require("请输入名称") + // 扩展名 + var exts = utils.NewStringsStream(params.Exts). + Map(strings.TrimSpace, strings.ToLower). + Filter(utils.FilterNotEmpty). + Map(utils.MapAddPrefixFunc(".")). + Unique(). + Result() + + // 域名 + var domains = []string{} + if len(params.DomainsJSON) > 0 { + var rawDomains = []string{} + err := json.Unmarshal(params.DomainsJSON, &rawDomains) + if err != nil { + this.ErrorPage(err) + return + } + + // TODO 如果用户填写了一个网址,应该分析域名并填入 + + domains = utils.NewStringsStream(rawDomains). + Map(strings.TrimSpace, strings.ToLower). + Filter(utils.FilterNotEmpty). + Unique(). + Result() + } + var ref = &serverconfigs.HTTPAuthPolicyRef{IsOn: true} - var paramsJSON []byte + + var method serverconfigs.HTTPAuthMethodInterface switch policyType { case serverconfigs.HTTPAuthTypeBasicAuth: - users := []*serverconfigs.HTTPAuthBasicMethodUser{} + var users = []*serverconfigs.HTTPAuthBasicMethodUser{} err := json.Unmarshal(params.HttpAuthBasicAuthUsersJSON, &users) if err != nil { this.ErrorPage(err) @@ -105,36 +139,35 @@ func (this *UpdatePopupAction) RunPost(params struct { if len(users) == 0 { this.Fail("请添加至少一个用户") } - method := &serverconfigs.HTTPAuthBasicMethod{ + method = &serverconfigs.HTTPAuthBasicMethod{ Users: users, Realm: params.BasicAuthRealm, Charset: params.BasicAuthCharset, } - methodJSON, err := json.Marshal(method) - if err != nil { - this.ErrorPage(err) - return - } - - paramsJSON = methodJSON case serverconfigs.HTTPAuthTypeSubRequest: params.Must.Field("subRequestURL", params.SubRequestURL). Require("请输入子请求URL") if params.SubRequestFollowRequest { params.SubRequestMethod = "" } - method := &serverconfigs.HTTPAuthSubRequestMethod{ + method = &serverconfigs.HTTPAuthSubRequestMethod{ URL: params.SubRequestURL, Method: params.SubRequestMethod, } - methodJSON, err := json.Marshal(method) - if err != nil { - this.ErrorPage(err) - return - } - paramsJSON = methodJSON default: - this.Fail("不支持的认证类型'" + policyType + "'") + this.Fail("不支持的鉴权类型'" + policyType + "'") + } + + if method == nil { + this.Fail("无法找到对应的鉴权方式") + } + method.SetExts(exts) + method.SetDomains(domains) + + paramsJSON, err := json.Marshal(method) + if err != nil { + this.ErrorPage(err) + return } var paramsMap map[string]interface{} diff --git a/web/public/js/components.js b/web/public/js/components.js index fdd1a61e..f4f6e865 100644 --- a/web/public/js/components.js +++ b/web/public/js/components.js @@ -2485,13 +2485,13 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
系统总是会先执行记录日志、标签等不会修改请求的动作,再执行阻止、验证码等可能改变请求的动作。
-`}),Vue.component("http-auth-config-box",{props:["v-auth-config","v-is-location"],data:function(){let e=this.vAuthConfig;return null==(e=null==e?{isPrior:!1,isOn:!1}:e).policyRefs&&(e.policyRefs=[]),{authConfig:e}},methods:{isOn:function(){return(!this.vIsLocation||this.authConfig.isPrior)&&this.authConfig.isOn},add:function(){let t=this;teaweb.popup("/servers/server/settings/access/createPopup",{callback:function(e){t.authConfig.policyRefs.push(e.data.policyRef)},height:"28em"})},update:function(e,t){teaweb.popup("/servers/server/settings/access/updatePopup?policyId="+t,{callback:function(e){teaweb.success("保存成功",function(){teaweb.reload()})},height:"28em"})},remove:function(e){this.authConfig.policyRefs.$remove(e)},methodName:function(e){switch(e){case"basicAuth":return"BasicAuth";case"subRequest":return"子请求"}return""}},template:`| 启用认证 | +启用鉴权 |
@@ -2502,14 +2502,14 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
| 名称 | -认证方法 | +鉴权方法 | 参数 | 状态 | 操作 | @@ -2527,6 +2527,15 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio [{{ref.authPolicy.params.method}}] {{ref.authPolicy.params.url}} + {{ref.authPolicy.params.signParamName}}/有效期{{ref.authPolicy.params.life}}秒 + 有效期{{ref.authPolicy.params.life}}秒 + 有效期{{ref.authPolicy.params.life}}秒 + {{ref.authPolicy.params.signParamName}}/{{ref.authPolicy.params.timestampParamName}}/有效期{{ref.authPolicy.params.life}}秒 + +
|
|---|
| 名称 | -认证方法 | +鉴权方法 | 参数 | 状态 | 操作 | @@ -7527,6 +7544,15 @@ Vue.component("http-auth-config-box", { [{{ref.authPolicy.params.method}}] {{ref.authPolicy.params.url}} + {{ref.authPolicy.params.signParamName}}/有效期{{ref.authPolicy.params.life}}秒 + 有效期{{ref.authPolicy.params.life}}秒 + 有效期{{ref.authPolicy.params.life}}秒 + {{ref.authPolicy.params.signParamName}}/{{ref.authPolicy.params.timestampParamName}}/有效期{{ref.authPolicy.params.life}}秒 + +
|
|---|
| 名称 | -认证方法 | +鉴权方法 | 参数 | 状态 | 操作 | @@ -95,6 +112,15 @@ Vue.component("http-auth-config-box", { [{{ref.authPolicy.params.method}}] {{ref.authPolicy.params.url}} + {{ref.authPolicy.params.signParamName}}/有效期{{ref.authPolicy.params.life}}秒 + 有效期{{ref.authPolicy.params.life}}秒 + 有效期{{ref.authPolicy.params.life}}秒 + {{ref.authPolicy.params.signParamName}}/{{ref.authPolicy.params.timestampParamName}}/有效期{{ref.authPolicy.params.life}}秒 + +
|
|---|
只能包含字母、数字,长度不超过40。[随机生成]
+链接有效时间。
+只能包含字母、数字,长度不超过40。[随机生成]
+链接有效时间。
+只能包含字母、数字,长度不超过40。[随机生成]
+链接有效时间。
+只能包含字母、数字,长度不超过40。[随机生成]
+链接有效时间。
+如果不为空,则表示只有这些扩展名的文件才需要鉴权;扩展名需要包含点符号(.),比如
如果不为空,则表示只有这些域名的文件才需要鉴权。
+