1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 08:19:15 +08:00

feat: 创建网站增加 waf 关联 (#4333)

This commit is contained in:
zhengkunwang 2024-03-27 18:36:08 +08:00 committed by GitHub
parent a5d853c61a
commit 9b9fe5444d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 255 additions and 29 deletions

View File

@ -69,24 +69,12 @@ type WebsiteOp struct {
Operate string `json:"operate"`
}
type WebsiteWafReq struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Rule string `json:"rule" validate:"required"`
}
type WebsiteRedirectUpdate struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Enable bool `json:"enable"`
}
type WebsiteWafUpdate struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Enable bool `json:"enable"`
}
type WebsiteRecover struct {
WebsiteName string `json:"websiteName" validate:"required"`
Type string `json:"type" validate:"required"`
@ -207,12 +195,12 @@ type WebsiteRedirectReq struct {
WebsiteID uint `json:"websiteId" validate:"required"`
}
type WebsiteWafFileUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Content string `json:"content" validate:"required"`
Type string `json:"type" validate:"required,oneof=cc ip_white ip_block url_white url_block cookie_block args_check post_check ua_check file_ext_block user_agent"`
}
type WebsiteCommonReq struct {
ID uint `json:"id" validate:"required"`
}
type WafWebsite struct {
Key string `json:"key"`
Domains []string `json:"domains"`
Host []string `json:"host"`
}

View File

@ -31,11 +31,6 @@ type WebsiteNginxConfig struct {
Params []NginxParam `json:"params"`
}
type WebsiteWafConfig struct {
Enable bool `json:"enable"`
Content string `json:"content"`
}
type WebsiteHTTPS struct {
Enable bool `json:"enable"`
HttpConfig string `json:"httpConfig"`

View File

@ -61,6 +61,7 @@ type IWebsiteService interface {
UpdateWebsite(req request.WebsiteUpdate) error
DeleteWebsite(req request.WebsiteDelete) error
GetWebsite(id uint) (response.WebsiteDTO, error)
CreateWebsiteDomain(create request.WebsiteDomainCreate) ([]model.WebsiteDomain, error)
GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error)
DeleteWebsiteDomain(domainId uint) error
@ -328,6 +329,10 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
if err = configDefaultNginx(website, domains, appInstall, runtime); err != nil {
return err
}
if err = createWafConfig(website, domains); err != nil {
return err
}
tx, ctx := helper.GetTxAndContext()
defer tx.Rollback()
if err = websiteRepo.Create(ctx, website); err != nil {
@ -420,7 +425,11 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
if err != nil {
return err
}
if err := delNginxConfig(website, req.ForceDelete); err != nil {
if err = delNginxConfig(website, req.ForceDelete); err != nil {
return err
}
if err = delWafConfig(website, req.ForceDelete); err != nil {
return err
}
@ -489,6 +498,53 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
return nil, err
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return nil, err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if fileOp.Stat(wafDataPath) {
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return nil, err
}
var websitesArray []request.WafWebsite
if content != nil {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return nil, err
}
}
for index, wafWebsite := range websitesArray {
if wafWebsite.Key == website.Alias {
wafSite := request.WafWebsite{
Key: website.Alias,
Domains: wafWebsite.Domains,
Host: wafWebsite.Host,
}
for _, domain := range domainModels {
wafSite.Domains = append(wafSite.Domains, domain.Domain)
if domain.Port != 80 && domain.Port != 443 {
wafSite.Host = append(wafSite.Host, domain.Domain+":"+string(rune(domain.Port)))
}
}
if len(wafSite.Host) == 0 {
wafSite.Host = []string{}
}
websitesArray[index] = wafSite
break
}
}
websitesContent, err := json.Marshal(websitesArray)
if err != nil {
return nil, err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return nil, err
}
}
return domainModels, websiteDomainRepo.BatchCreate(context.TODO(), domainModels)
}
@ -518,6 +574,7 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
if oldDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(webSiteDomain.WebsiteID), websiteDomainRepo.WithDomain(webSiteDomain.Domain)); len(oldDomains) == 1 {
domains = append(domains, webSiteDomain.Domain)
}
if len(ports) > 0 || len(domains) > 0 {
stringBinds := make([]string, len(ports))
for i := 0; i < len(ports); i++ {
@ -528,6 +585,63 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
}
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if fileOp.Stat(wafDataPath) {
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
var newWebsitesArray []request.WafWebsite
if content != nil {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
for _, wafWebsite := range websitesArray {
if wafWebsite.Key == website.Alias {
wafSite := wafWebsite
oldDomains := wafSite.Domains
var newDomains []string
for _, domain := range oldDomains {
if domain == webSiteDomain.Domain {
continue
}
newDomains = append(newDomains, domain)
}
wafSite.Domains = newDomains
oldHostArray := wafSite.Host
var newHostArray []string
for _, host := range oldHostArray {
if host == webSiteDomain.Domain+":"+string(rune(webSiteDomain.Port)) {
continue
}
newHostArray = append(newHostArray, host)
}
wafSite.Host = newHostArray
if len(wafSite.Host) == 0 {
wafSite.Host = []string{}
}
newWebsitesArray = append(newWebsitesArray, wafSite)
} else {
newWebsitesArray = append(newWebsitesArray, wafWebsite)
}
}
websitesContent, err := json.Marshal(newWebsitesArray)
if err != nil {
return err
}
if err = fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
}
return websiteDomainRepo.DeleteBy(context.TODO(), commonRepo.WithByID(domainId))
}

View File

@ -1,6 +1,7 @@
package service
import (
"encoding/json"
"fmt"
"log"
"os"
@ -197,7 +198,7 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website,
}
}
}
return fileOp.CopyDir(path.Join(nginxFolder, "www", "common", "waf", "rules"), path.Join(siteFolder, "waf"))
return nil
}
func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, appInstall *model.AppInstall, runtime *model.Runtime) error {
@ -233,12 +234,8 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
server.UpdateServerName(serverNames)
siteFolder := path.Join("/www", "sites", website.Alias)
commonFolder := path.Join("/www", "common")
server.UpdateDirective("access_log", []string{path.Join(siteFolder, "log", "access.log")})
server.UpdateDirective("error_log", []string{path.Join(siteFolder, "log", "error.log")})
server.UpdateDirective("access_by_lua_file", []string{path.Join(commonFolder, "waf", "access.lua")})
server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")})
server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "log")})
rootIndex := path.Join("/www/sites", website.Alias, "index")
switch website.Type {
@ -285,6 +282,92 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
return nil
}
func createWafConfig(website *model.Website, domains []model.WebsiteDomain) error {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if !fileOp.Stat(wafDataPath) {
return nil
}
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
if len(content) != 0 {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
wafWebsite := request.WafWebsite{
Key: website.Alias,
Domains: make([]string, 0),
Host: make([]string, 0),
}
for _, domain := range domains {
wafWebsite.Domains = append(wafWebsite.Domains, domain.Domain)
if domain.Port != 80 && domain.Port != 443 {
wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+string(rune(domain.Port)))
}
}
websitesArray = append(websitesArray, wafWebsite)
websitesContent, err := json.Marshal(websitesArray)
if err != nil {
return err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
var (
sitesDir = path.Join(wafDataPath, "sites")
defaultConfigPath = path.Join(wafDataPath, "conf", "siteConfig.json")
defaultRuleDir = path.Join(wafDataPath, "rules")
websiteDir = path.Join(sitesDir, website.Alias)
)
defaultConfigContent, err := fileOp.GetContent(defaultConfigPath)
if err != nil {
return err
}
if !fileOp.Stat(websiteDir) {
if err = fileOp.CreateDir(websiteDir, 0755); err != nil {
return err
}
}
defer func() {
if err != nil {
_ = fileOp.DeleteDir(websiteDir)
}
}()
if err = fileOp.SaveFileWithByte(path.Join(websiteDir, "config.json"), defaultConfigContent, 0644); err != nil {
return err
}
websiteRuleDir := path.Join(websiteDir, "rules")
if !fileOp.Stat(websiteRuleDir) {
if err := fileOp.CreateDir(websiteRuleDir, 0755); err != nil {
return err
}
}
defaultRulesName := []string{"acl", "args", "cookie", "defaultUaBlack", "defaultUrlBlack", "fileExt", "header", "methodWhite"}
for _, ruleName := range defaultRulesName {
srcPath := path.Join(defaultRuleDir, ruleName+".json")
if err = fileOp.Copy(srcPath, websiteRuleDir); err != nil {
return err
}
}
return nil
}
func delNginxConfig(website model.Website, force bool) error {
nginxApp, err := appRepo.GetFirst(appRepo.WithKey(constant.AppOpenresty))
if err != nil {
@ -322,6 +405,52 @@ func delNginxConfig(website model.Website, force bool) error {
return nil
}
func delWafConfig(website model.Website, force bool) error {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if !fileOp.Stat(wafDataPath) {
return nil
}
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
var newWebsiteArray []request.WafWebsite
if len(content) > 0 {
if err = json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
for _, wafWebsite := range websitesArray {
if wafWebsite.Key != website.Alias {
newWebsiteArray = append(newWebsiteArray, wafWebsite)
}
}
websitesContent, err := json.Marshal(newWebsiteArray)
if err != nil {
return err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
_ = fileOp.DeleteDir(path.Join(wafDataPath, "sites", website.Alias))
if err := opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
if force {
return nil
}
return err
}
return nil
}
func addListenAndServerName(website model.Website, ports []int, domains []string) error {
nginxFull, err := getNginxFull(&website)
if err != nil {