|
@@ -0,0 +1,1071 @@
|
|
|
+package waf
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "net"
|
|
|
+
|
|
|
+ v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
|
|
|
+ "github.com/go-nunu/nunu-layout-advanced/internal/model"
|
|
|
+ "github.com/go-nunu/nunu-layout-advanced/internal/repository/api/waf"
|
|
|
+ "github.com/go-nunu/nunu-layout-advanced/internal/service"
|
|
|
+ "github.com/go-nunu/nunu-layout-advanced/internal/service/api/flexCdn"
|
|
|
+)
|
|
|
+
|
|
|
+// AidedWebService Web转发辅助服务接口
|
|
|
+type AidedWebService interface {
|
|
|
+ // 验证相关
|
|
|
+ ValidateAddRequest(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) error
|
|
|
+ ValidateEditRequest(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse, oldData *model.WebForwarding) error
|
|
|
+ ValidateDeletePermission(oldData *model.WebForwarding, hostId int) error
|
|
|
+
|
|
|
+ // CDN网站管理
|
|
|
+ CreateCdnWebsite(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse, formData v1.Website) (int64, error)
|
|
|
+ UpdateCdnConfiguration(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse, formData v1.Website) error
|
|
|
+ DeleteCdnServer(ctx context.Context, cdnWebId int) error
|
|
|
+
|
|
|
+ // 源站管理
|
|
|
+ AddOriginsToWebsite(ctx context.Context, req *v1.WebForwardingRequest, webId int64) (map[string]int64, error)
|
|
|
+ UpdateOriginServers(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, ipData *model.WebForwardingRule) error
|
|
|
+
|
|
|
+ // 功能配置管理
|
|
|
+ ConfigureWebsocket(ctx context.Context, webId int64) error
|
|
|
+ ConfigureProxyProtocol(ctx context.Context, req *v1.WebForwardingRequest, webId int64) error
|
|
|
+ ConfigureCCProtection(ctx context.Context, req *v1.WebForwardingRequest, webId int64) error
|
|
|
+ ConfigureWafFirewall(ctx context.Context, webId int64, groupId int) error
|
|
|
+
|
|
|
+ // 异步任务处理
|
|
|
+ ProcessAsyncTasks(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse)
|
|
|
+ ProcessIpWhitelistChanges(ctx context.Context, req *v1.WebForwardingRequest, ipData *model.WebForwardingRule) error
|
|
|
+ ProcessDeleteIpWhitelist(ctx context.Context, id int) error
|
|
|
+ ProcessDomainWhitelistChanges(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse) error
|
|
|
+ ProcessDeleteDomainWhitelist(ctx context.Context, oldData *model.WebForwarding, uid int) error
|
|
|
+
|
|
|
+ // 数据库操作
|
|
|
+ SaveToDatabase(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse, webId int64, cdnOriginIds map[string]int64) (int, error)
|
|
|
+ UpdateDatabaseRecords(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse, ipData *model.WebForwardingRule) error
|
|
|
+ CleanupDatabaseRecords(ctx context.Context, id int) error
|
|
|
+
|
|
|
+ // SSL证书管理
|
|
|
+ ProcessSSLCertificate(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse, formData v1.Website) error
|
|
|
+ ProcessSSLCertificateUpdate(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse) error
|
|
|
+ CleanupSSLCertificate(ctx context.Context, oldData *model.WebForwarding) error
|
|
|
+
|
|
|
+ // 数据准备辅助函数
|
|
|
+ PrepareWafData(ctx context.Context, req *v1.WebForwardingRequest) (RequireResponse, v1.Website, error)
|
|
|
+ BuildProxyConfig(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) (v1.TypeJSON, error)
|
|
|
+ BulidFormData(ctx context.Context, formData v1.Website) (v1.WebsiteSend, error)
|
|
|
+
|
|
|
+ // 协议判断辅助函数
|
|
|
+ GetProtocolType(isHttps int) string
|
|
|
+ IsHttpsProtocol(isHttps int) bool
|
|
|
+
|
|
|
+ // 模型构建辅助函数
|
|
|
+ BuildWebForwardingModel(req *v1.WebForwardingDataRequest, ruleId int, require RequireResponse) *model.WebForwarding
|
|
|
+ BuildWebRuleModel(reqData *v1.WebForwardingDataRequest, require RequireResponse, localDbId int, cdnOriginIds map[string]int64) *model.WebForwardingRule
|
|
|
+
|
|
|
+ // 列表差异处理辅助函数
|
|
|
+ FindDifferenceList(oldList, newList []v1.BackendList) (added, removed []v1.BackendList)
|
|
|
+ WashDifferentIp(newIpList []string, oldIpList []string) (addedDenyIps []string, removedDenyIps []string)
|
|
|
+
|
|
|
+ // 日志配置辅助函数
|
|
|
+ EditLog(ctx context.Context, webId int64) error
|
|
|
+
|
|
|
+ // 废弃的方法(保持向后兼容)
|
|
|
+ Require(ctx context.Context, req v1.GlobalRequire) (v1.GlobalRequire, error)
|
|
|
+ ValidateWebForwardingRequest(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) error
|
|
|
+ CreateOriginServers(ctx context.Context, req *v1.WebForwardingRequest) (map[string]int64, error)
|
|
|
+}
|
|
|
+
|
|
|
+func NewAidedWebService(
|
|
|
+ service *service.Service,
|
|
|
+ webForwardingRepository waf.WebForwardingRepository,
|
|
|
+ wafformatter WafFormatterService,
|
|
|
+ sslCert flexCdn.SslCertService,
|
|
|
+ cdn flexCdn.CdnService,
|
|
|
+ proxy flexCdn.ProxyService,
|
|
|
+ websocket flexCdn.WebsocketService,
|
|
|
+ cc CcService,
|
|
|
+ ccIpList CcIpListService,
|
|
|
+ gatewayIp GatewayipService,
|
|
|
+ globalLimitRep waf.GlobalLimitRepository,
|
|
|
+) AidedWebService {
|
|
|
+ return &aidedWebService{
|
|
|
+ Service: service,
|
|
|
+ webForwardingRepository: webForwardingRepository,
|
|
|
+ wafformatter: wafformatter,
|
|
|
+ sslCert: sslCert,
|
|
|
+ cdn: cdn,
|
|
|
+ proxy: proxy,
|
|
|
+ websocket: websocket,
|
|
|
+ cc: cc,
|
|
|
+ ccIpList: ccIpList,
|
|
|
+ gatewayIp: gatewayIp,
|
|
|
+ globalLimitRep: globalLimitRep,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+type aidedWebService struct {
|
|
|
+ *service.Service
|
|
|
+ webForwardingRepository waf.WebForwardingRepository
|
|
|
+ wafformatter WafFormatterService
|
|
|
+ sslCert flexCdn.SslCertService
|
|
|
+ cdn flexCdn.CdnService
|
|
|
+ proxy flexCdn.ProxyService
|
|
|
+ websocket flexCdn.WebsocketService
|
|
|
+ cc CcService
|
|
|
+ ccIpList CcIpListService
|
|
|
+ gatewayIp GatewayipService
|
|
|
+ globalLimitRep waf.GlobalLimitRepository
|
|
|
+}
|
|
|
+
|
|
|
+const (
|
|
|
+ // 协议类型常量
|
|
|
+ isHttps = 1
|
|
|
+ isHttp = 0
|
|
|
+ protocolHttps = "https"
|
|
|
+ protocolHttp = "http"
|
|
|
+
|
|
|
+ // 默认配置常量
|
|
|
+ defaultNodeClusterId = 2
|
|
|
+ proxyProtocolVersion = 1
|
|
|
+)
|
|
|
+
|
|
|
+// Require 验证函数(原require函数)
|
|
|
+func (s *aidedWebService) Require(ctx context.Context, req v1.GlobalRequire) (v1.GlobalRequire, error) {
|
|
|
+ var res v1.GlobalRequire
|
|
|
+ //g, gCtx := errgroup.WithContext(ctx)
|
|
|
+
|
|
|
+ //g.Go(func() error {
|
|
|
+ // result, e := s.wafformatter.require(gCtx, req, "web")
|
|
|
+ // if e != nil {
|
|
|
+ // return e
|
|
|
+ // }
|
|
|
+ // res = result
|
|
|
+ // return nil
|
|
|
+ //})
|
|
|
+
|
|
|
+ //g.Go(func() error {
|
|
|
+ // e := s.wafformatter.validateWafDomainCount(gCtx, req)
|
|
|
+ // if e != nil {
|
|
|
+ // return e
|
|
|
+ // }
|
|
|
+ // return nil
|
|
|
+ //})
|
|
|
+ //if err = g.Wait(); err != nil {
|
|
|
+ // return v1.GlobalRequire{}, err
|
|
|
+ //}
|
|
|
+ return res, nil
|
|
|
+}
|
|
|
+
|
|
|
+// BuildWebForwardingModel 辅助函数,用于构建通用的 WebForwarding 模型
|
|
|
+// ruleId 是从 WAF 系统获取的 ID
|
|
|
+func (s *aidedWebService) BuildWebForwardingModel(req *v1.WebForwardingDataRequest, ruleId int, require RequireResponse) *model.WebForwarding {
|
|
|
+ return &model.WebForwarding{
|
|
|
+ HostId: require.HostId,
|
|
|
+ CdnWebId: ruleId,
|
|
|
+ Port: req.Port,
|
|
|
+ Domain: req.Domain,
|
|
|
+ IsHttps: req.IsHttps,
|
|
|
+ Comment: req.Comment,
|
|
|
+ HttpsCert: req.HttpsCert,
|
|
|
+ HttpsKey: req.HttpsKey,
|
|
|
+ SslCertId: int(req.SslCertId),
|
|
|
+ SslPolicyId: int(req.SslPolicyId),
|
|
|
+ Cc: req.CcConfig.IsOn,
|
|
|
+ ThresholdMethod: req.CcConfig.ThresholdMethod,
|
|
|
+ Level: req.CcConfig.Level,
|
|
|
+ Limit5s: req.CcConfig.Limit5s,
|
|
|
+ Limit60s: req.CcConfig.Limit60s,
|
|
|
+ Limit300s: req.CcConfig.Limit300s,
|
|
|
+ Proxy: req.Proxy,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// BuildWebRuleModel 构建WebForwardingRule模型
|
|
|
+func (s *aidedWebService) BuildWebRuleModel(reqData *v1.WebForwardingDataRequest, require RequireResponse, localDbId int, cdnOriginIds map[string]int64) *model.WebForwardingRule {
|
|
|
+ return &model.WebForwardingRule{
|
|
|
+ Uid: require.Uid,
|
|
|
+ HostId: require.HostId,
|
|
|
+ WebId: localDbId,
|
|
|
+ CdnOriginIds: cdnOriginIds,
|
|
|
+ BackendList: reqData.BackendList,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// PrepareWafData 准备WAF数据
|
|
|
+// 职责:协调整个流程,负责获取前置配置和组装最终的 formData。
|
|
|
+func (s *aidedWebService) PrepareWafData(ctx context.Context, req *v1.WebForwardingRequest) (RequireResponse, v1.Website, error) {
|
|
|
+ // 1. 获取基础配置
|
|
|
+ require, err := s.wafformatter.Require(ctx, v1.GlobalRequire{
|
|
|
+ HostId: req.HostId,
|
|
|
+ Uid: req.Uid,
|
|
|
+ Comment: req.WebForwardingData.Comment,
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return RequireResponse{}, v1.Website{}, fmt.Errorf("获取WAF前置配置失败: %w", err)
|
|
|
+ }
|
|
|
+ if require.Uid == 0 {
|
|
|
+ return RequireResponse{}, v1.Website{}, fmt.Errorf("请先配置实例")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 调用辅助函数,构建核心的代理配置 (将复杂逻辑封装起来)
|
|
|
+ byteData, err := s.BuildProxyConfig(ctx, req, require)
|
|
|
+ if err != nil {
|
|
|
+ return RequireResponse{}, v1.Website{}, err // 错误信息在辅助函数中已经包装好了
|
|
|
+ }
|
|
|
+ type serverNames struct {
|
|
|
+ ServerNames string `json:"name" form:"name"`
|
|
|
+ Type string `json:"type" form:"type"`
|
|
|
+ }
|
|
|
+ var serverName []serverNames
|
|
|
+ var serverJson []byte
|
|
|
+ if req.WebForwardingData.Domain != "" {
|
|
|
+ serverName = append(serverName, serverNames{
|
|
|
+ ServerNames: req.WebForwardingData.Domain,
|
|
|
+ Type: "full",
|
|
|
+ })
|
|
|
+ serverJson, err = json.Marshal(serverName)
|
|
|
+ if err != nil {
|
|
|
+ return RequireResponse{}, v1.Website{}, err
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 组装最终的 WAF 表单数据
|
|
|
+ formData := v1.Website{
|
|
|
+ UserId: int64(require.CdnUid),
|
|
|
+ Type: "httpProxy",
|
|
|
+ Name: require.Tag,
|
|
|
+ ServerNamesJSON: serverJson,
|
|
|
+ Description: req.WebForwardingData.Comment,
|
|
|
+ ServerGroupIds: []int64{int64(require.GroupId)},
|
|
|
+ NodeClusterId: defaultNodeClusterId,
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 根据协议类型,填充 HttpJSON 和 HttpsJSON 字段
|
|
|
+ if req.WebForwardingData.IsHttps == isHttps {
|
|
|
+ formData.HttpJSON = v1.TypeJSON{IsOn: false}
|
|
|
+ formData.HttpsJSON = byteData
|
|
|
+ } else {
|
|
|
+ formData.HttpJSON = byteData
|
|
|
+ formData.HttpsJSON = v1.TypeJSON{IsOn: false}
|
|
|
+ }
|
|
|
+
|
|
|
+ return require, formData, nil
|
|
|
+}
|
|
|
+
|
|
|
+// BuildProxyConfig 构建代理配置
|
|
|
+// 职责:专门负责处理 HTTP/HTTPS 的差异,并生成对应的 JSON 配置。
|
|
|
+func (s *aidedWebService) BuildProxyConfig(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) (v1.TypeJSON, error) {
|
|
|
+ var (
|
|
|
+ jsonData v1.TypeJSON
|
|
|
+ apiType string
|
|
|
+ )
|
|
|
+
|
|
|
+ jsonData.IsOn = true
|
|
|
+ apiType = protocolHttps
|
|
|
+ jsonData.SslPolicyRef.SslPolicyId = req.WebForwardingData.SslPolicyId
|
|
|
+ // 判断协议类型,并处理 HTTPS 的特殊逻辑(证书)
|
|
|
+ if req.WebForwardingData.IsHttps == isHttps {
|
|
|
+ // 处理证书信息
|
|
|
+ if jsonData.SslPolicyRef.SslPolicyId == 0 {
|
|
|
+ sslPolicyId, err := s.sslCert.AddSslPolicy(ctx, nil)
|
|
|
+ if err != nil {
|
|
|
+ return v1.TypeJSON{}, err
|
|
|
+ }
|
|
|
+ jsonData.SslPolicyRef.SslPolicyId = sslPolicyId
|
|
|
+ }
|
|
|
+ jsonData.SslPolicyRef.IsOn = true
|
|
|
+ } else {
|
|
|
+ apiType = protocolHttp
|
|
|
+ jsonData.SslPolicyRef = v1.SslPolicyRef{
|
|
|
+ IsOn: false,
|
|
|
+ SslPolicyId: req.WebForwardingData.SslCertId,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 填充通用的 Listen 配置
|
|
|
+ for _, v := range require.GatewayIps {
|
|
|
+ jsonData.Listen = append(jsonData.Listen, v1.Listen{
|
|
|
+ Protocol: apiType,
|
|
|
+ Host: v,
|
|
|
+ Port: req.WebForwardingData.Port,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return jsonData, nil
|
|
|
+}
|
|
|
+
|
|
|
+// FindDifferenceList 查找两个列表的差异
|
|
|
+func (s *aidedWebService) FindDifferenceList(oldList, newList []v1.BackendList) (added, removed []v1.BackendList) {
|
|
|
+ diff := make(map[v1.BackendList]int)
|
|
|
+
|
|
|
+ // 1. 遍历旧列表,为每个元素计数 +1
|
|
|
+ for _, item := range oldList {
|
|
|
+ diff[item]++
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 遍历新列表,为每个元素计数 -1
|
|
|
+ for _, item := range newList {
|
|
|
+ diff[item]--
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 遍历 diff map 来找出差异
|
|
|
+ for item, count := range diff {
|
|
|
+ if count > 0 {
|
|
|
+ // 如果 count > 0,说明这个元素在 oldList 中但不在 newList 中
|
|
|
+ removed = append(removed, item)
|
|
|
+ } else if count < 0 {
|
|
|
+ // 如果 count < 0,说明这个元素在 newList 中但不在 oldList 中
|
|
|
+ added = append(added, item)
|
|
|
+ }
|
|
|
+ // 如果 count == 0,说明元素在两个列表中都存在,不做任何操作
|
|
|
+ }
|
|
|
+
|
|
|
+ return added, removed
|
|
|
+}
|
|
|
+
|
|
|
+// WashDifferentIp 清洗IP差异
|
|
|
+func (s *aidedWebService) WashDifferentIp(newIpList []string, oldIpList []string) (addedDenyIps []string, removedDenyIps []string) {
|
|
|
+ var newAllowIps []string
|
|
|
+ var oldAllowIps []string
|
|
|
+ if len(oldIpList) > 0 {
|
|
|
+ for _, v := range oldIpList {
|
|
|
+ if net.ParseIP(v) != nil {
|
|
|
+ oldAllowIps = append(oldAllowIps, v)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if len(newIpList) > 0 {
|
|
|
+ for _, v := range newIpList {
|
|
|
+ if net.ParseIP(v) != nil {
|
|
|
+ newAllowIps = append(newAllowIps, v)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ addedDenyIps, removedDenyIps = s.wafformatter.findIpDifferences(oldAllowIps, newAllowIps)
|
|
|
+ return addedDenyIps, removedDenyIps
|
|
|
+}
|
|
|
+
|
|
|
+// EditLog 修改日志配置
|
|
|
+func (s *aidedWebService) EditLog(ctx context.Context, webId int64) error {
|
|
|
+ webConfigId, err := s.webForwardingRepository.GetWebConfigId(ctx, webId)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := s.cdn.EditWebLog(ctx, webConfigId, v1.WebLog{
|
|
|
+ IsPrior: false,
|
|
|
+ IsOn: true,
|
|
|
+ Fields: []int64{1, 2, 6, 7},
|
|
|
+ Status1: true,
|
|
|
+ Status2: true,
|
|
|
+ Status3: true,
|
|
|
+ Status4: true,
|
|
|
+ Status5: true,
|
|
|
+ FirewallOnly: false,
|
|
|
+ EnableClientClosed: false,
|
|
|
+ }); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// BulidFormData 构建表单数据
|
|
|
+func (s *aidedWebService) BulidFormData(ctx context.Context, formData v1.Website) (v1.WebsiteSend, error) {
|
|
|
+ httpJSON, err := json.Marshal(formData.HttpJSON)
|
|
|
+ if err != nil {
|
|
|
+ return v1.WebsiteSend{}, err
|
|
|
+ }
|
|
|
+ httpsJSON, err := json.Marshal(formData.HttpsJSON)
|
|
|
+ if err != nil {
|
|
|
+ return v1.WebsiteSend{}, err
|
|
|
+ }
|
|
|
+ formDataSend := v1.WebsiteSend{
|
|
|
+ UserId: formData.UserId,
|
|
|
+ AdminId: formData.AdminId,
|
|
|
+ Type: formData.Type,
|
|
|
+ Name: formData.Name,
|
|
|
+ Description: formData.Description,
|
|
|
+ ServerNamesJSON: formData.ServerNamesJSON,
|
|
|
+ HttpJSON: httpJSON,
|
|
|
+ HttpsJSON: httpsJSON,
|
|
|
+ TcpJSON: formData.TcpJSON,
|
|
|
+ TlsJSON: formData.TlsJSON,
|
|
|
+ UdpJSON: formData.UdpJSON,
|
|
|
+ WebId: formData.WebId,
|
|
|
+ ReverseProxyJSON: formData.ReverseProxyJSON,
|
|
|
+ ServerGroupIds: formData.ServerGroupIds,
|
|
|
+ UserPlanId: formData.UserPlanId,
|
|
|
+ NodeClusterId: formData.NodeClusterId,
|
|
|
+ IncludeNodesJSON: formData.IncludeNodesJSON,
|
|
|
+ ExcludeNodesJSON: formData.ExcludeNodesJSON,
|
|
|
+ }
|
|
|
+ return formDataSend, nil
|
|
|
+}
|
|
|
+
|
|
|
+// ValidateWebForwardingRequest 验证Web转发请求
|
|
|
+func (s *aidedWebService) ValidateWebForwardingRequest(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) error {
|
|
|
+ // 验证域名限制
|
|
|
+ if err := s.wafformatter.validateWafDomainCount(ctx, v1.GlobalRequire{
|
|
|
+ HostId: req.HostId,
|
|
|
+ Domain: req.WebForwardingData.Domain,
|
|
|
+ Comment: req.WebForwardingData.Comment,
|
|
|
+ Uid: req.Uid,
|
|
|
+ }); err != nil {
|
|
|
+ return fmt.Errorf("域名数量验证失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证端口数量限制
|
|
|
+ if err := s.wafformatter.validateWafPortCount(ctx, require.HostId); err != nil {
|
|
|
+ return fmt.Errorf("端口数量验证失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证端口重复
|
|
|
+ protocol := s.GetProtocolType(req.WebForwardingData.IsHttps)
|
|
|
+ if err := s.wafformatter.VerifyPort(ctx, protocol, int64(req.WebForwardingData.Id), req.WebForwardingData.Port, int64(require.HostId), req.WebForwardingData.Domain); err != nil {
|
|
|
+ return fmt.Errorf("端口 %d 验证失败: %w", req.WebForwardingData.Port, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ProcessSSLCertificate 处理SSL证书
|
|
|
+func (s *aidedWebService) ProcessSSLCertificate(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse, formData v1.Website) error {
|
|
|
+ if !s.IsHttpsProtocol(req.WebForwardingData.IsHttps) {
|
|
|
+ return nil // 非HTTPS协议不需要处理SSL证书
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加SSL证书
|
|
|
+ sslCertId, err := s.sslCert.AddSSLCert(ctx, v1.SSL{
|
|
|
+ Name: req.WebForwardingData.Domain,
|
|
|
+ Domain: req.WebForwardingData.Domain,
|
|
|
+ CertData: req.WebForwardingData.HttpsCert,
|
|
|
+ KeyData: req.WebForwardingData.HttpsKey,
|
|
|
+ CdnUserId: require.CdnUid,
|
|
|
+ Description: req.WebForwardingData.Comment,
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("添加SSL证书失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新请求中的证书ID
|
|
|
+ req.WebForwardingData.SslCertId = sslCertId
|
|
|
+ req.WebForwardingData.SslPolicyId = formData.HttpsJSON.SslPolicyRef.SslPolicyId
|
|
|
+
|
|
|
+ // 编辑SSL策略
|
|
|
+ if err := s.sslCert.EditSslPolicy(ctx, formData.HttpsJSON.SslPolicyRef.SslPolicyId, []int64{sslCertId}, "add"); err != nil {
|
|
|
+ return fmt.Errorf("编辑SSL策略失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// CreateOriginServers 创建源站服务器
|
|
|
+func (s *aidedWebService) CreateOriginServers(ctx context.Context, req *v1.WebForwardingRequest) (map[string]int64, error) {
|
|
|
+ cdnOriginIds := make(map[string]int64)
|
|
|
+
|
|
|
+ for _, backend := range req.WebForwardingData.BackendList {
|
|
|
+ apiType := s.GetProtocolType(backend.IsHttps)
|
|
|
+
|
|
|
+ id, err := s.wafformatter.AddOrigin(ctx, v1.WebJson{
|
|
|
+ ApiType: apiType,
|
|
|
+ BackendList: backend.Addr,
|
|
|
+ Host: backend.CustomHost,
|
|
|
+ Comment: req.WebForwardingData.Comment,
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("添加源站 %s 失败: %w", backend.Addr, err)
|
|
|
+ }
|
|
|
+ cdnOriginIds[backend.Addr] = id
|
|
|
+ }
|
|
|
+
|
|
|
+ return cdnOriginIds, nil
|
|
|
+}
|
|
|
+
|
|
|
+// GetProtocolType 获取协议类型字符串
|
|
|
+func (s *aidedWebService) GetProtocolType(isHttps int) string {
|
|
|
+ if s.IsHttpsProtocol(isHttps) {
|
|
|
+ return protocolHttps
|
|
|
+ }
|
|
|
+ return protocolHttp
|
|
|
+}
|
|
|
+
|
|
|
+// IsHttpsProtocol 判断是否为HTTPS协议
|
|
|
+func (s *aidedWebService) IsHttpsProtocol(httpsFlag int) bool {
|
|
|
+ return httpsFlag == isHttps
|
|
|
+}
|
|
|
+
|
|
|
+// ValidateAddRequest 验证添加请求
|
|
|
+func (s *aidedWebService) ValidateAddRequest(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) error {
|
|
|
+ if err := s.wafformatter.validateWafDomainCount(ctx, v1.GlobalRequire{
|
|
|
+ HostId: req.HostId,
|
|
|
+ Domain: req.WebForwardingData.Domain,
|
|
|
+ Comment: req.WebForwardingData.Comment,
|
|
|
+ Uid: req.Uid,
|
|
|
+ }); err != nil {
|
|
|
+ return fmt.Errorf("域名数量验证失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := s.wafformatter.validateWafPortCount(ctx, require.HostId); err != nil {
|
|
|
+ return fmt.Errorf("端口数量验证失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ protocol := s.GetProtocolType(req.WebForwardingData.IsHttps)
|
|
|
+ if err := s.wafformatter.VerifyPort(ctx, protocol, int64(req.WebForwardingData.Id), req.WebForwardingData.Port, int64(require.HostId), req.WebForwardingData.Domain); err != nil {
|
|
|
+ return fmt.Errorf("端口 %d 验证失败: %w", req.WebForwardingData.Port, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ValidateEditRequest 验证编辑请求
|
|
|
+func (s *aidedWebService) ValidateEditRequest(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse, oldData *model.WebForwarding) error {
|
|
|
+ if err := s.wafformatter.validateWafDomainCount(ctx, v1.GlobalRequire{
|
|
|
+ HostId: req.HostId,
|
|
|
+ Domain: req.WebForwardingData.Domain,
|
|
|
+ Comment: req.WebForwardingData.Comment,
|
|
|
+ Uid: req.Uid,
|
|
|
+ }); err != nil {
|
|
|
+ return fmt.Errorf("域名数量验证失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ protocol := s.GetProtocolType(req.WebForwardingData.IsHttps)
|
|
|
+ if err := s.wafformatter.VerifyPort(ctx, protocol, int64(req.WebForwardingData.Id), req.WebForwardingData.Port, int64(require.HostId), req.WebForwardingData.Domain); err != nil {
|
|
|
+ return fmt.Errorf("端口 %d 验证失败: %w", req.WebForwardingData.Port, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ValidateDeletePermission 验证删除权限
|
|
|
+func (s *aidedWebService) ValidateDeletePermission(oldData *model.WebForwarding, hostId int) error {
|
|
|
+ if oldData.HostId != hostId {
|
|
|
+ return fmt.Errorf("用户权限不足")
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// CreateCdnWebsite 创建CDN网站
|
|
|
+func (s *aidedWebService) CreateCdnWebsite(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse, formData v1.Website) (int64, error) {
|
|
|
+ formDataSend, err := s.BulidFormData(ctx, formData)
|
|
|
+ if err != nil {
|
|
|
+ return 0, fmt.Errorf("构建表单数据失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ webId, err := s.cdn.CreateWebsite(ctx, formDataSend)
|
|
|
+ if err != nil {
|
|
|
+ return 0, fmt.Errorf("创建CDN网站失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return webId, nil
|
|
|
+}
|
|
|
+
|
|
|
+// UpdateCdnConfiguration 更新CDN配置
|
|
|
+func (s *aidedWebService) UpdateCdnConfiguration(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse, formData v1.Website) error {
|
|
|
+ // 修改网站端口、协议或证书
|
|
|
+ if oldData.Port != req.WebForwardingData.Port || oldData.IsHttps != req.WebForwardingData.IsHttps ||
|
|
|
+ oldData.HttpsCert != req.WebForwardingData.HttpsCert || oldData.HttpsKey != req.WebForwardingData.HttpsKey {
|
|
|
+
|
|
|
+ if err := s.updateWebsiteProtocolAndCert(ctx, req, oldData, require, formData); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 修改网站域名
|
|
|
+ if oldData.Domain != req.WebForwardingData.Domain {
|
|
|
+ if err := s.updateWebsiteDomain(ctx, req, oldData); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 修改网站名字
|
|
|
+ if oldData.Comment != req.WebForwardingData.Comment {
|
|
|
+ if err := s.updateWebsiteBasicInfo(ctx, oldData, require); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// DeleteCdnServer 删除CDN服务器
|
|
|
+func (s *aidedWebService) DeleteCdnServer(ctx context.Context, cdnWebId int) error {
|
|
|
+ if err := s.cdn.DelServer(ctx, int64(cdnWebId)); err != nil {
|
|
|
+ return fmt.Errorf("删除CDN服务器失败: %w", err)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// updateWebsiteProtocolAndCert 更新网站协议和证书
|
|
|
+func (s *aidedWebService) updateWebsiteProtocolAndCert(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse, formData v1.Website) error {
|
|
|
+ // 修改证书
|
|
|
+ if oldData.HttpsCert != req.WebForwardingData.HttpsCert || oldData.HttpsKey != req.WebForwardingData.HttpsKey {
|
|
|
+ if err := s.sslCert.EditSSLCert(ctx, v1.SSL{
|
|
|
+ Name: req.WebForwardingData.Domain,
|
|
|
+ CertId: oldData.SslCertId,
|
|
|
+ CertData: req.WebForwardingData.HttpsCert,
|
|
|
+ KeyData: req.WebForwardingData.HttpsKey,
|
|
|
+ CdnUserId: require.CdnUid,
|
|
|
+ Domain: req.WebForwardingData.Domain,
|
|
|
+ Description: req.WebForwardingData.Comment,
|
|
|
+ }); err != nil {
|
|
|
+ return fmt.Errorf("修改SSL证书失败: %w", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 切换协议
|
|
|
+ var typeConfig, closeConfig v1.TypeJSON
|
|
|
+ var apiType, closeType string
|
|
|
+
|
|
|
+ if s.IsHttpsProtocol(req.WebForwardingData.IsHttps) {
|
|
|
+ typeConfig = formData.HttpsJSON
|
|
|
+ closeConfig = formData.HttpJSON
|
|
|
+ apiType = s.GetProtocolType(req.WebForwardingData.IsHttps)
|
|
|
+ closeType = s.GetProtocolType(0) // HTTP
|
|
|
+ } else {
|
|
|
+ typeConfig = formData.HttpJSON
|
|
|
+ closeConfig = formData.HttpsJSON
|
|
|
+ apiType = s.GetProtocolType(req.WebForwardingData.IsHttps)
|
|
|
+ closeType = s.GetProtocolType(1) // HTTPS
|
|
|
+ }
|
|
|
+
|
|
|
+ typeJson, err := json.Marshal(typeConfig)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("序列化协议配置失败: %w", err)
|
|
|
+ }
|
|
|
+ closeJson, err := json.Marshal(closeConfig)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("序列化关闭协议配置失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 切换协议
|
|
|
+ if err := s.cdn.EditServerType(ctx, v1.EditWebsite{
|
|
|
+ Id: int64(oldData.CdnWebId),
|
|
|
+ TypeJSON: typeJson,
|
|
|
+ }, apiType); err != nil {
|
|
|
+ return fmt.Errorf("切换到%s协议失败: %w", apiType, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := s.cdn.EditServerType(ctx, v1.EditWebsite{
|
|
|
+ Id: int64(oldData.CdnWebId),
|
|
|
+ TypeJSON: closeJson,
|
|
|
+ }, closeType); err != nil {
|
|
|
+ return fmt.Errorf("关闭%s协议失败: %w", closeType, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// updateWebsiteDomain 更新网站域名
|
|
|
+func (s *aidedWebService) updateWebsiteDomain(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding) error {
|
|
|
+ type serverName struct {
|
|
|
+ Name string `json:"name" form:"name"`
|
|
|
+ Type string `json:"type" form:"type"`
|
|
|
+ }
|
|
|
+ var serverData []serverName
|
|
|
+ serverData = append(serverData, serverName{
|
|
|
+ Name: req.WebForwardingData.Domain,
|
|
|
+ Type: "full",
|
|
|
+ })
|
|
|
+ serverJson, err := json.Marshal(serverData)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("序列化服务器名称失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := s.cdn.EditServerName(ctx, v1.EditServerNames{
|
|
|
+ ServerId: int64(oldData.CdnWebId),
|
|
|
+ ServerNamesJSON: serverJson,
|
|
|
+ }); err != nil {
|
|
|
+ return fmt.Errorf("更新服务器名称失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// updateWebsiteBasicInfo 更新网站基本信息
|
|
|
+func (s *aidedWebService) updateWebsiteBasicInfo(ctx context.Context, oldData *model.WebForwarding, require RequireResponse) error {
|
|
|
+ // 通过globalLimitRep获取节点ID,这是项目中现有的方法
|
|
|
+ nodeId, err := s.globalLimitRep.GetNodeId(ctx, oldData.CdnWebId)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("获取节点ID失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := s.cdn.EditServerBasic(ctx, int64(oldData.CdnWebId), require.Tag, nodeId); err != nil {
|
|
|
+ return fmt.Errorf("更新服务器基本信息失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// AddOriginsToWebsite 添加源站到网站
|
|
|
+func (s *aidedWebService) AddOriginsToWebsite(ctx context.Context, req *v1.WebForwardingRequest, webId int64) (map[string]int64, error) {
|
|
|
+ cdnOriginIds, err := s.CreateOriginServers(ctx, req)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("创建源站服务器失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加源站到网站
|
|
|
+ for _, originId := range cdnOriginIds {
|
|
|
+ if err := s.cdn.AddServerOrigin(ctx, webId, originId); err != nil {
|
|
|
+ return nil, fmt.Errorf("添加源站到网站失败: %w", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return cdnOriginIds, nil
|
|
|
+}
|
|
|
+
|
|
|
+// UpdateOriginServers 更新源站服务器
|
|
|
+func (s *aidedWebService) UpdateOriginServers(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, ipData *model.WebForwardingRule) error {
|
|
|
+ addOrigins, delOrigins := s.FindDifferenceList(ipData.BackendList, req.WebForwardingData.BackendList)
|
|
|
+ addedIds := make(map[string]int64)
|
|
|
+
|
|
|
+ // 添加新源站
|
|
|
+ for _, v := range addOrigins {
|
|
|
+ apiType := s.GetProtocolType(v.IsHttps)
|
|
|
+ id, err := s.wafformatter.AddOrigin(ctx, v1.WebJson{
|
|
|
+ ApiType: apiType,
|
|
|
+ BackendList: v.Addr,
|
|
|
+ Host: v.CustomHost,
|
|
|
+ Comment: req.WebForwardingData.Comment,
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("添加源站 %s 失败: %w", v.Addr, err)
|
|
|
+ }
|
|
|
+ addedIds[v.Addr] = id
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将新源站添加到网站
|
|
|
+ for _, v := range addedIds {
|
|
|
+ if err := s.cdn.AddServerOrigin(ctx, int64(oldData.CdnWebId), v); err != nil {
|
|
|
+ return fmt.Errorf("添加源站到网站失败: %w", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 删除旧源站
|
|
|
+ for k, v := range ipData.CdnOriginIds {
|
|
|
+ for _, ip := range delOrigins {
|
|
|
+ if k == ip.Addr {
|
|
|
+ if err := s.cdn.DelServerOrigin(ctx, int64(oldData.CdnWebId), v); err != nil {
|
|
|
+ return fmt.Errorf("删除源站失败: %w", err)
|
|
|
+ }
|
|
|
+ delete(ipData.CdnOriginIds, k)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合并新的源站ID
|
|
|
+ for k, v := range addedIds {
|
|
|
+ ipData.CdnOriginIds[k] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ConfigureWebsocket 配置WebSocket
|
|
|
+func (s *aidedWebService) ConfigureWebsocket(ctx context.Context, webId int64) error {
|
|
|
+ websocketId, err := s.websocket.AddWebsocket(ctx)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("添加WebSocket失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := s.websocket.EnableOrDisable(ctx, webId, websocketId, true, false); err != nil {
|
|
|
+ return fmt.Errorf("启用WebSocket失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ConfigureProxyProtocol 配置代理协议
|
|
|
+func (s *aidedWebService) ConfigureProxyProtocol(ctx context.Context, req *v1.WebForwardingRequest, webId int64) error {
|
|
|
+ if req.WebForwardingData.Proxy {
|
|
|
+ if err := s.proxy.EditProxy(ctx, webId, v1.ProxyProtocolJSON{
|
|
|
+ IsOn: true,
|
|
|
+ Version: proxyProtocolVersion,
|
|
|
+ }); err != nil {
|
|
|
+ return fmt.Errorf("启用代理协议失败: %w", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ConfigureCCProtection 配置CC防护
|
|
|
+func (s *aidedWebService) ConfigureCCProtection(ctx context.Context, req *v1.WebForwardingRequest, webId int64) error {
|
|
|
+ if req.WebForwardingData.CcConfig.IsOn {
|
|
|
+ if err := s.cc.EditCcConfig(ctx, webId, req.WebForwardingData.CcConfig); err != nil {
|
|
|
+ return fmt.Errorf("配置CC防护失败: %w", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ConfigureWafFirewall 配置WAF防火墙
|
|
|
+func (s *aidedWebService) ConfigureWafFirewall(ctx context.Context, webId int64, groupId int) error {
|
|
|
+ if err := s.ccIpList.AddCcIpListPolicy(ctx, webId, int64(groupId)); err != nil {
|
|
|
+ return fmt.Errorf("配置WAF防火墙失败: %w", err)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ProcessAsyncTasks 处理异步任务
|
|
|
+func (s *aidedWebService) ProcessAsyncTasks(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) {
|
|
|
+ // 域名白名单处理
|
|
|
+ if req.WebForwardingData.Domain != "" {
|
|
|
+ go func() {
|
|
|
+ doMain, err := s.wafformatter.ConvertToWildcardDomain(ctx, req.WebForwardingData.Domain)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if len(require.GatewayIps) == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ firstIp, err := s.gatewayIp.GetGatewayipByHostIdFirst(ctx, int64(require.HostId), int64(require.Uid))
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ s.wafformatter.PublishDomainWhitelistTask(doMain, firstIp, "add")
|
|
|
+ }()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 源站IP白名单处理
|
|
|
+ if req.WebForwardingData.BackendList != nil {
|
|
|
+ go func() {
|
|
|
+ var ips []string
|
|
|
+ for _, v := range req.WebForwardingData.BackendList {
|
|
|
+ ip, _, err := net.SplitHostPort(v.Addr)
|
|
|
+ if err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ ips = append(ips, ip)
|
|
|
+ }
|
|
|
+ if len(ips) > 0 {
|
|
|
+ s.wafformatter.PublishIpWhitelistTask(ips, "add", "", "white")
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ProcessIpWhitelistChanges 处理IP白名单变更
|
|
|
+func (s *aidedWebService) ProcessIpWhitelistChanges(ctx context.Context, req *v1.WebForwardingRequest, ipData *model.WebForwardingRule) error {
|
|
|
+ var oldIps, newIps []string
|
|
|
+
|
|
|
+ // 提取旧IP列表
|
|
|
+ for _, v := range ipData.BackendList {
|
|
|
+ ip, _, err := net.SplitHostPort(v.Addr)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("解析旧IP地址失败: %w", err)
|
|
|
+ }
|
|
|
+ oldIps = append(oldIps, ip)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取新IP列表
|
|
|
+ for _, v := range req.WebForwardingData.BackendList {
|
|
|
+ ip, _, err := net.SplitHostPort(v.Addr)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("解析新IP地址失败: %w", err)
|
|
|
+ }
|
|
|
+ newIps = append(newIps, ip)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查找IP差异
|
|
|
+ addedIps, removedIps := s.wafformatter.findIpDifferences(oldIps, newIps)
|
|
|
+
|
|
|
+ // 异步处理添加的IP
|
|
|
+ if len(addedIps) > 0 {
|
|
|
+ go s.wafformatter.PublishIpWhitelistTask(addedIps, "add", "", "white")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 异步处理删除的IP
|
|
|
+ if len(removedIps) > 0 {
|
|
|
+ go func() {
|
|
|
+ ipsToDelist, err := s.wafformatter.WashDelIps(ctx, removedIps)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if len(ipsToDelist) > 0 {
|
|
|
+ s.wafformatter.PublishIpWhitelistTask(ipsToDelist, "del", "0", "white")
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ProcessDeleteIpWhitelist 处理删除IP白名单
|
|
|
+func (s *aidedWebService) ProcessDeleteIpWhitelist(ctx context.Context, id int) error {
|
|
|
+ ipData, err := s.webForwardingRepository.GetWebForwardingIpsByID(ctx, id)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("获取IP数据失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if ipData != nil && len(ipData.BackendList) > 0 {
|
|
|
+ var ips []string
|
|
|
+ for _, v := range ipData.BackendList {
|
|
|
+ ip, _, err := net.SplitHostPort(v.Addr)
|
|
|
+ if err != nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ ips = append(ips, ip)
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(ips) > 0 {
|
|
|
+ go func() {
|
|
|
+ ipsToDelist, err := s.wafformatter.WashDelIps(ctx, ips)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if len(ipsToDelist) > 0 {
|
|
|
+ s.wafformatter.PublishIpWhitelistTask(ipsToDelist, "del", "0", "white")
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ProcessDomainWhitelistChanges 处理域名白名单变更
|
|
|
+func (s *aidedWebService) ProcessDomainWhitelistChanges(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse) error {
|
|
|
+ if oldData.Domain != req.WebForwardingData.Domain {
|
|
|
+ firstIp, err := s.gatewayIp.GetGatewayipByHostIdFirst(ctx, int64(req.HostId), int64(req.Uid))
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("获取网关IP失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ newDomain, err := s.wafformatter.ConvertToWildcardDomain(ctx, req.WebForwardingData.Domain)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("转换新域名失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ oldDomain, err := s.wafformatter.ConvertToWildcardDomain(ctx, oldData.Domain)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("转换旧域名失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(require.GatewayIps) == 0 {
|
|
|
+ return fmt.Errorf("网关组不存在")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查旧域名使用数量
|
|
|
+ count, err := s.webForwardingRepository.GetDomainCount(ctx, req.HostId, oldData.Domain)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("获取域名使用数量失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 异步处理域名白名单变更
|
|
|
+ go func() {
|
|
|
+ if count < 2 {
|
|
|
+ s.wafformatter.PublishDomainWhitelistTask(oldDomain, firstIp, "del")
|
|
|
+ }
|
|
|
+ s.wafformatter.PublishDomainWhitelistTask(newDomain, firstIp, "add")
|
|
|
+ }()
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ProcessDeleteDomainWhitelist 处理删除域名白名单
|
|
|
+func (s *aidedWebService) ProcessDeleteDomainWhitelist(ctx context.Context, oldData *model.WebForwarding, uid int) error {
|
|
|
+ if oldData.Domain != "" {
|
|
|
+ firstIp, err := s.gatewayIp.GetGatewayipByHostIdFirst(ctx, int64(oldData.HostId), int64(uid))
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("获取网关IP失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ doMain, err := s.wafformatter.ConvertToWildcardDomain(ctx, oldData.Domain)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("转换域名失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ go s.wafformatter.PublishDomainWhitelistTask(doMain, firstIp, "del")
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// SaveToDatabase 保存到数据库
|
|
|
+func (s *aidedWebService) SaveToDatabase(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse, webId int64, cdnOriginIds map[string]int64) (int, error) {
|
|
|
+ webModel := s.BuildWebForwardingModel(&req.WebForwardingData, int(webId), require)
|
|
|
+
|
|
|
+ id, err := s.webForwardingRepository.AddWebForwarding(ctx, webModel)
|
|
|
+ if err != nil {
|
|
|
+ return 0, fmt.Errorf("添加Web转发记录失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ webRuleModel := s.BuildWebRuleModel(&req.WebForwardingData, require, id, cdnOriginIds)
|
|
|
+ if _, err = s.webForwardingRepository.AddWebForwardingIps(ctx, *webRuleModel); err != nil {
|
|
|
+ return 0, fmt.Errorf("添加Web转发规则失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return id, nil
|
|
|
+}
|
|
|
+
|
|
|
+// UpdateDatabaseRecords 更新数据库记录
|
|
|
+func (s *aidedWebService) UpdateDatabaseRecords(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse, ipData *model.WebForwardingRule) error {
|
|
|
+ webModel := s.BuildWebForwardingModel(&req.WebForwardingData, req.WebForwardingData.CdnWebId, require)
|
|
|
+ webModel.Id = req.WebForwardingData.Id
|
|
|
+
|
|
|
+ if err := s.webForwardingRepository.EditWebForwarding(ctx, webModel); err != nil {
|
|
|
+ return fmt.Errorf("更新Web转发记录失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ webRuleModel := s.BuildWebRuleModel(&req.WebForwardingData, require, req.WebForwardingData.Id, ipData.CdnOriginIds)
|
|
|
+ if err := s.webForwardingRepository.EditWebForwardingIps(ctx, *webRuleModel); err != nil {
|
|
|
+ return fmt.Errorf("更新Web转发规则失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// CleanupDatabaseRecords 清理数据库记录
|
|
|
+func (s *aidedWebService) CleanupDatabaseRecords(ctx context.Context, id int) error {
|
|
|
+ if err := s.webForwardingRepository.DeleteWebForwarding(ctx, int64(id)); err != nil {
|
|
|
+ return fmt.Errorf("删除Web转发记录失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := s.webForwardingRepository.DeleteWebForwardingIpsById(ctx, id); err != nil {
|
|
|
+ return fmt.Errorf("删除Web转发规则失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// ProcessSSLCertificateUpdate 处理SSL证书更新
|
|
|
+func (s *aidedWebService) ProcessSSLCertificateUpdate(ctx context.Context, req *v1.WebForwardingRequest, oldData *model.WebForwarding, require RequireResponse) error {
|
|
|
+ if !s.IsHttpsProtocol(req.WebForwardingData.IsHttps) {
|
|
|
+ return nil // 非HTTPS协议不需要处理SSL证书
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果证书内容有变化
|
|
|
+ if oldData.HttpsCert != req.WebForwardingData.HttpsCert || oldData.HttpsKey != req.WebForwardingData.HttpsKey {
|
|
|
+ if err := s.sslCert.EditSSLCert(ctx, v1.SSL{
|
|
|
+ Name: req.WebForwardingData.Domain,
|
|
|
+ CertId: oldData.SslCertId,
|
|
|
+ CertData: req.WebForwardingData.HttpsCert,
|
|
|
+ KeyData: req.WebForwardingData.HttpsKey,
|
|
|
+ CdnUserId: require.CdnUid,
|
|
|
+ Domain: req.WebForwardingData.Domain,
|
|
|
+ Description: req.WebForwardingData.Comment,
|
|
|
+ }); err != nil {
|
|
|
+ return fmt.Errorf("更新SSL证书失败: %w", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// CleanupSSLCertificate 清理SSL证书
|
|
|
+func (s *aidedWebService) CleanupSSLCertificate(ctx context.Context, oldData *model.WebForwarding) error {
|
|
|
+ if oldData.SslCertId != 0 {
|
|
|
+ if err := s.cdn.DelSSLCert(ctx, int64(oldData.SslCertId)); err != nil {
|
|
|
+ return fmt.Errorf("删除SSL证书失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := s.sslCert.EditSslPolicy(ctx, int64(oldData.SslPolicyId), []int64{int64(oldData.SslCertId)}, "del"); err != nil {
|
|
|
+ return fmt.Errorf("删除SSL策略失败: %w", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|