From 047bd907f0da252bb45c8942e37400b1f9dc1b4e Mon Sep 17 00:00:00 2001 From: zhengkunwang223 Date: Tue, 6 Dec 2022 11:42:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0CC=E9=98=B2=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/website.go | 28 ++++ backend/app/dto/nginx.go | 1 - backend/app/dto/website.go | 6 + backend/app/request/website.go | 13 ++ backend/app/service/website.go | 65 ++++++++- backend/router/ro_website.go | 2 + frontend/src/api/interface/website.ts | 18 +++ frontend/src/api/modules/website.ts | 8 ++ frontend/src/lang/modules/zh.ts | 6 + .../config/basic/default-doc/index.vue | 6 +- .../website/config/safety/ccdeny/index.vue | 131 ++++++++++++++++++ .../website/website/config/safety/index.vue | 7 +- 12 files changed, 280 insertions(+), 11 deletions(-) create mode 100644 backend/app/request/website.go create mode 100644 frontend/src/views/website/website/config/safety/ccdeny/index.vue diff --git a/backend/app/api/v1/website.go b/backend/app/api/v1/website.go index c221b7cc5..5d45d17d1 100644 --- a/backend/app/api/v1/website.go +++ b/backend/app/api/v1/website.go @@ -4,6 +4,7 @@ import ( "errors" "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "github.com/1Panel-dev/1Panel/backend/app/dto" + "github.com/1Panel-dev/1Panel/backend/app/request" "github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/global" "github.com/gin-gonic/gin" @@ -268,3 +269,30 @@ func (b *BaseApi) CreateWebsiteCheck(c *gin.Context) { } helper.SuccessWithData(c, data) } + +func (b *BaseApi) GetWebsiteWafConfig(c *gin.Context) { + var req request.WebsiteWafReq + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + data, err := websiteService.GetWafConfig(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, data) +} + +func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) { + var req request.WebsiteWafUpdate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := websiteService.UpdateWafConfig(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} diff --git a/backend/app/dto/nginx.go b/backend/app/dto/nginx.go index 287874956..7a364a633 100644 --- a/backend/app/dto/nginx.go +++ b/backend/app/dto/nginx.go @@ -76,6 +76,5 @@ var StaticFileKeyMap = map[NginxKey]struct { type NginxParam struct { UpdateScope string `json:"scope"` Name string `json:"name"` - SecondKey string `json:"secondKey"` Params []string `json:"params"` } diff --git a/backend/app/dto/website.go b/backend/app/dto/website.go index 553e74468..44f507277 100644 --- a/backend/app/dto/website.go +++ b/backend/app/dto/website.go @@ -121,3 +121,9 @@ type WebsitePreInstallCheck struct { type WebsiteInstallCheckReq struct { InstallIds []uint `json:"InstallIds"` } + +type WebsiteWafConfig struct { + Enable bool `json:"enable"` + FilePath string `json:"filePath"` + Content string `json:"content"` +} diff --git a/backend/app/request/website.go b/backend/app/request/website.go new file mode 100644 index 000000000..a5dee51c4 --- /dev/null +++ b/backend/app/request/website.go @@ -0,0 +1,13 @@ +package request + +type WebsiteWafReq struct { + WebsiteID uint `json:"websiteId" validate:"required"` + Key string `json:"key" validate:"required"` + Rule string `json:"rule" validate:"required"` +} + +type WebsiteWafUpdate struct { + WebsiteID uint `json:"websiteId" validate:"required"` + Key string `json:"key" validate:"required"` + Enable bool `json:"enable" validate:"required"` +} diff --git a/backend/app/service/website.go b/backend/app/service/website.go index 90d575da7..da8ece63e 100644 --- a/backend/app/service/website.go +++ b/backend/app/service/website.go @@ -6,6 +6,7 @@ import ( "encoding/json" "encoding/pem" "fmt" + "github.com/1Panel-dev/1Panel/backend/app/request" "github.com/1Panel-dev/1Panel/backend/buserr" "os" "path" @@ -33,6 +34,18 @@ type IWebsiteService interface { RecoverByUpload(req dto.WebSiteRecoverByFile) error UpdateWebsite(req dto.WebSiteUpdate) error DeleteWebSite(req dto.WebSiteDel) error + GetWebsite(id uint) (dto.WebsiteDTO, error) + CreateWebsiteDomain(create dto.WebSiteDomainCreate) (model.WebSiteDomain, error) + GetWebsiteDomain(websiteId uint) ([]model.WebSiteDomain, error) + DeleteWebsiteDomain(domainId uint) error + GetNginxConfigByScope(req dto.NginxConfigReq) (*dto.WebsiteNginxConfig, error) + UpdateNginxConfigByScope(req dto.NginxConfigReq) error + GetWebsiteNginxConfig(websiteId uint) (dto.FileInfo, error) + GetWebsiteHTTPS(websiteId uint) (dto.WebsiteHTTPS, error) + OpWebsiteHTTPS(req dto.WebsiteHTTPSOp) (dto.WebsiteHTTPS, error) + PreInstallCheck(req dto.WebsiteInstallCheckReq) ([]dto.WebsitePreInstallCheck, error) + GetWafConfig(req request.WebsiteWafReq) (dto.WebsiteWafConfig, error) + UpdateWafConfig(req request.WebsiteWafUpdate) error } func NewWebsiteService() IWebsiteService { @@ -54,7 +67,6 @@ func (w WebsiteService) PageWebSite(req dto.WebSiteReq) (int64, []dto.WebSiteDTO } func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error { - if exist, _ := websiteRepo.GetBy(websiteRepo.WithDomain(create.PrimaryDomain)); len(exist) > 0 { return buserr.New(constant.ErrNameIsExist) } @@ -229,7 +241,6 @@ func (w WebsiteService) GetWebsite(id uint) (dto.WebsiteDTO, error) { } func (w WebsiteService) DeleteWebSite(req dto.WebSiteDel) error { - website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID)) if err != nil { return err @@ -296,7 +307,6 @@ func (w WebsiteService) GetWebsiteDomain(websiteId uint) ([]model.WebSiteDomain, } func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error { - webSiteDomain, err := websiteDomainRepo.GetFirst(commonRepo.WithByID(domainId)) if err != nil { return err @@ -328,7 +338,6 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error { } func (w WebsiteService) GetNginxConfigByScope(req dto.NginxConfigReq) (*dto.WebsiteNginxConfig, error) { - keys, ok := dto.ScopeKeyMap[req.Scope] if !ok || len(keys) == 0 { return nil, nil @@ -350,7 +359,6 @@ func (w WebsiteService) GetNginxConfigByScope(req dto.NginxConfigReq) (*dto.Webs } func (w WebsiteService) UpdateNginxConfigByScope(req dto.NginxConfigReq) error { - keys, ok := dto.ScopeKeyMap[req.Scope] if !ok || len(keys) == 0 { return nil @@ -554,3 +562,50 @@ func (w WebsiteService) PreInstallCheck(req dto.WebsiteInstallCheckReq) ([]dto.W return nil, nil } } + +func (w WebsiteService) GetWafConfig(req request.WebsiteWafReq) (dto.WebsiteWafConfig, error) { + var res dto.WebsiteWafConfig + website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID)) + if err != nil { + return res, nil + } + + params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"set"}, &website) + if err != nil { + return res, nil + } + for _, param := range params { + if param.Params[0] == req.Key { + res.Enable = len(param.Params) > 1 && param.Params[1] == "on" + break + } + } + nginxFull, err := getNginxFull(&website) + if err != nil { + return res, nil + } + + filePath := path.Join(nginxFull.SiteDir, "sites", website.Alias, "waf", "rules", req.Rule) + content, err := os.ReadFile(filePath) + if err != nil { + return res, nil + } + res.FilePath = filePath + res.Content = string(content) + + return res, nil +} + +func (w WebsiteService) UpdateWafConfig(req request.WebsiteWafUpdate) error { + website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID)) + if err != nil { + return nil + } + updateValue := "on" + if !req.Enable { + updateValue = "off" + } + return updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{ + {Name: "set", Params: []string{req.Key, updateValue}}, + }, &website) +} diff --git a/backend/router/ro_website.go b/backend/router/ro_website.go index 3a02b15b6..b2574f1bb 100644 --- a/backend/router/ro_website.go +++ b/backend/router/ro_website.go @@ -33,5 +33,7 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) { groupRouter.POST("/config/update", baseApi.UpdateNginxConfig) groupRouter.GET("/:id/https", baseApi.GetHTTPSConfig) groupRouter.POST("/:id/https", baseApi.UpdateHTTPSConfig) + groupRouter.POST("/waf/config", baseApi.GetWebsiteWafConfig) + groupRouter.POST("/waf/update", baseApi.UpdateWebsiteWafConfig) } } diff --git a/frontend/src/api/interface/website.ts b/frontend/src/api/interface/website.ts index 20fd3a4db..1f40e855c 100644 --- a/frontend/src/api/interface/website.ts +++ b/frontend/src/api/interface/website.ts @@ -212,4 +212,22 @@ export namespace WebSite { version: string; appName: string; } + + export interface WafReq { + websiteId: number; + key: string; + rule: string; + } + + export interface WafRes { + enable: boolean; + filePath: string; + content: string; + } + + export interface WafUpdate { + enable: boolean; + websiteId: number; + key: string; + } } diff --git a/frontend/src/api/modules/website.ts b/frontend/src/api/modules/website.ts index 1dfb39f4b..a71831500 100644 --- a/frontend/src/api/modules/website.ts +++ b/frontend/src/api/modules/website.ts @@ -148,3 +148,11 @@ export const UpdateHTTPSConfig = (req: WebSite.HTTPSReq) => { export const PreCheck = (req: WebSite.CheckReq) => { return http.post(`/websites/check`, req); }; + +export const GetWafConfig = (req: WebSite.WafReq) => { + return http.post(`/websites/waf/config`, req); +}; + +export const UpdateWafEnable = (req: WebSite.WafUpdate) => { + return http.post(`/websites/waf/update`, req); +}; diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 0d9c86ef1..ab16ff82b 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -850,6 +850,12 @@ export default { default: '默认', deleteHelper: '相关应用状态不正常,请检查', toApp: '去已安装列表', + enableCC: '开启CC攻击防护', + cycle: '周期', + frequency: '频率', + ccHelper: '{0} 秒内累计请求同一URL超过 {1} 次,触发CC防御,封锁此IP', + seconds: '秒', + count: '次', }, nginx: { serverNamesHashBucketSizeHelper: '服务器名字的hash表大小', diff --git a/frontend/src/views/website/website/config/basic/default-doc/index.vue b/frontend/src/views/website/website/config/basic/default-doc/index.vue index 1dc2befd6..caa9a6035 100644 --- a/frontend/src/views/website/website/config/basic/default-doc/index.vue +++ b/frontend/src/views/website/website/config/basic/default-doc/index.vue @@ -73,10 +73,10 @@ const search = (req: WebSite.NginxConfigReq) => { loading.value = true; GetNginxConfig(req) .then((res) => { - if (res.data && res.data.length > 0) { - const indexParam = res.data[0]; + if (res.data && res.data.params.length > 0) { + const params = res.data.params[0].params; let values = ''; - for (const param of indexParam.params) { + for (const param of params) { values = values + param + '\n'; } defaultModel.value.index = values; diff --git a/frontend/src/views/website/website/config/safety/ccdeny/index.vue b/frontend/src/views/website/website/config/safety/ccdeny/index.vue new file mode 100644 index 000000000..11df02ed2 --- /dev/null +++ b/frontend/src/views/website/website/config/safety/ccdeny/index.vue @@ -0,0 +1,131 @@ + + + diff --git a/frontend/src/views/website/website/config/safety/index.vue b/frontend/src/views/website/website/config/safety/index.vue index 46162b3f1..9a6bc85de 100644 --- a/frontend/src/views/website/website/config/safety/index.vue +++ b/frontend/src/views/website/website/config/safety/index.vue @@ -1,6 +1,8 @@