diff --git a/internal/rpc/rpc_client.go b/internal/rpc/rpc_client.go index f8e06c83..0bb6b5fb 100644 --- a/internal/rpc/rpc_client.go +++ b/internal/rpc/rpc_client.go @@ -16,56 +16,18 @@ import ( "time" ) +// RPC客户端 type RPCClient struct { - apiConfig *configs.APIConfig - adminClients []pb.AdminServiceClient - nodeClients []pb.NodeServiceClient - nodeGrantClients []pb.NodeGrantServiceClient - nodeClusterClients []pb.NodeClusterServiceClient - nodeIPAddressClients []pb.NodeIPAddressServiceClient - serverClients []pb.ServerServiceClient - apiNodeClients []pb.APINodeServiceClient - originClients []pb.OriginServiceClient - httpWebClients []pb.HTTPWebServiceClient - reverseProxyClients []pb.ReverseProxyServiceClient - httpGzipClients []pb.HTTPGzipServiceClient - httpHeaderPolicyClients []pb.HTTPHeaderPolicyServiceClient - httpHeaderClients []pb.HTTPHeaderServiceClient - httpPageClients []pb.HTTPPageServiceClient - httpAccessLogPolicyClients []pb.HTTPAccessLogPolicyServiceClient - httpCachePolicyClients []pb.HTTPCachePolicyServiceClient - httpFirewallPolicyClients []pb.HTTPFirewallPolicyServiceClient - httpLocationClients []pb.HTTPLocationServiceClient - httpWebsocketClients []pb.HTTPWebsocketServiceClient - httpRewriteRuleClients []pb.HTTPRewriteRuleServiceClient + apiConfig *configs.APIConfig + conns []*grpc.ClientConn } +// 构造新的RPC客户端 func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { if apiConfig == nil { return nil, errors.New("api config should not be nil") } - adminClients := []pb.AdminServiceClient{} - nodeClients := []pb.NodeServiceClient{} - nodeGrantClients := []pb.NodeGrantServiceClient{} - nodeClusterClients := []pb.NodeClusterServiceClient{} - nodeIPAddressClients := []pb.NodeIPAddressServiceClient{} - serverClients := []pb.ServerServiceClient{} - apiNodeClients := []pb.APINodeServiceClient{} - originClients := []pb.OriginServiceClient{} - httpWebClients := []pb.HTTPWebServiceClient{} - reverseProxyClients := []pb.ReverseProxyServiceClient{} - httpGzipClients := []pb.HTTPGzipServiceClient{} - httpHeaderPolicyClients := []pb.HTTPHeaderPolicyServiceClient{} - httpHeaderClients := []pb.HTTPHeaderServiceClient{} - httpPageClients := []pb.HTTPPageServiceClient{} - httpAccessLogPolicyClients := []pb.HTTPAccessLogPolicyServiceClient{} - httpCachePolicyClients := []pb.HTTPCachePolicyServiceClient{} - httpFirewallPolicyClients := []pb.HTTPFirewallPolicyServiceClient{} - httpLocationClients := []pb.HTTPLocationServiceClient{} - httpWebsocketClients := []pb.HTTPWebsocketServiceClient{} - httpRewriteRuleClients := []pb.HTTPRewriteRuleServiceClient{} - conns := []*grpc.ClientConn{} for _, endpoint := range apiConfig.RPC.Endpoints { conn, err := grpc.Dial(endpoint, grpc.WithInsecure()) @@ -78,195 +40,97 @@ func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) { return nil, errors.New("[RPC]no available endpoints") } - // node clients - for _, conn := range conns { - adminClients = append(adminClients, pb.NewAdminServiceClient(conn)) - nodeClients = append(nodeClients, pb.NewNodeServiceClient(conn)) - nodeGrantClients = append(nodeGrantClients, pb.NewNodeGrantServiceClient(conn)) - nodeClusterClients = append(nodeClusterClients, pb.NewNodeClusterServiceClient(conn)) - nodeIPAddressClients = append(nodeIPAddressClients, pb.NewNodeIPAddressServiceClient(conn)) - serverClients = append(serverClients, pb.NewServerServiceClient(conn)) - apiNodeClients = append(apiNodeClients, pb.NewAPINodeServiceClient(conn)) - originClients = append(originClients, pb.NewOriginServiceClient(conn)) - httpWebClients = append(httpWebClients, pb.NewHTTPWebServiceClient(conn)) - reverseProxyClients = append(reverseProxyClients, pb.NewReverseProxyServiceClient(conn)) - httpGzipClients = append(httpGzipClients, pb.NewHTTPGzipServiceClient(conn)) - httpHeaderPolicyClients = append(httpHeaderPolicyClients, pb.NewHTTPHeaderPolicyServiceClient(conn)) - httpHeaderClients = append(httpHeaderClients, pb.NewHTTPHeaderServiceClient(conn)) - httpPageClients = append(httpPageClients, pb.NewHTTPPageServiceClient(conn)) - httpAccessLogPolicyClients = append(httpAccessLogPolicyClients, pb.NewHTTPAccessLogPolicyServiceClient(conn)) - httpCachePolicyClients = append(httpCachePolicyClients, pb.NewHTTPCachePolicyServiceClient(conn)) - httpFirewallPolicyClients = append(httpFirewallPolicyClients, pb.NewHTTPFirewallPolicyServiceClient(conn)) - httpLocationClients = append(httpLocationClients, pb.NewHTTPLocationServiceClient(conn)) - httpWebsocketClients = append(httpWebsocketClients, pb.NewHTTPWebsocketServiceClient(conn)) - httpRewriteRuleClients = append(httpRewriteRuleClients, pb.NewHTTPRewriteRuleServiceClient(conn)) - } - return &RPCClient{ - apiConfig: apiConfig, - adminClients: adminClients, - nodeClients: nodeClients, - nodeGrantClients: nodeGrantClients, - nodeClusterClients: nodeClusterClients, - nodeIPAddressClients: nodeIPAddressClients, - serverClients: serverClients, - apiNodeClients: apiNodeClients, - originClients: originClients, - httpWebClients: httpWebClients, - reverseProxyClients: reverseProxyClients, - httpGzipClients: httpGzipClients, - httpHeaderPolicyClients: httpHeaderPolicyClients, - httpHeaderClients: httpHeaderClients, - httpPageClients: httpPageClients, - httpAccessLogPolicyClients: httpAccessLogPolicyClients, - httpCachePolicyClients: httpCachePolicyClients, - httpFirewallPolicyClients: httpFirewallPolicyClients, - httpLocationClients: httpLocationClients, - httpWebsocketClients: httpWebsocketClients, - httpRewriteRuleClients: httpRewriteRuleClients, + apiConfig: apiConfig, + conns: conns, }, nil } func (this *RPCClient) AdminRPC() pb.AdminServiceClient { - if len(this.adminClients) > 0 { - return this.adminClients[rands.Int(0, len(this.adminClients)-1)] - } - return nil + return pb.NewAdminServiceClient(this.pickConn()) } func (this *RPCClient) NodeRPC() pb.NodeServiceClient { - if len(this.nodeClients) > 0 { - return this.nodeClients[rands.Int(0, len(this.nodeClients)-1)] - } - return nil + return pb.NewNodeServiceClient(this.pickConn()) } func (this *RPCClient) NodeGrantRPC() pb.NodeGrantServiceClient { - if len(this.nodeGrantClients) > 0 { - return this.nodeGrantClients[rands.Int(0, len(this.nodeGrantClients)-1)] - } - return nil + return pb.NewNodeGrantServiceClient(this.pickConn()) } func (this *RPCClient) NodeClusterRPC() pb.NodeClusterServiceClient { - if len(this.nodeClusterClients) > 0 { - return this.nodeClusterClients[rands.Int(0, len(this.nodeClusterClients)-1)] - } - return nil + return pb.NewNodeClusterServiceClient(this.pickConn()) } func (this *RPCClient) NodeIPAddressRPC() pb.NodeIPAddressServiceClient { - if len(this.nodeIPAddressClients) > 0 { - return this.nodeIPAddressClients[rands.Int(0, len(this.nodeIPAddressClients)-1)] - } - return nil + return pb.NewNodeIPAddressServiceClient(this.pickConn()) } func (this *RPCClient) ServerRPC() pb.ServerServiceClient { - if len(this.serverClients) > 0 { - return this.serverClients[rands.Int(0, len(this.serverClients)-1)] - } - return nil + return pb.NewServerServiceClient(this.pickConn()) } func (this *RPCClient) APINodeRPC() pb.APINodeServiceClient { - if len(this.apiNodeClients) > 0 { - return this.apiNodeClients[rands.Int(0, len(this.apiNodeClients)-1)] - } - return nil + return pb.NewAPINodeServiceClient(this.pickConn()) } func (this *RPCClient) OriginRPC() pb.OriginServiceClient { - if len(this.originClients) > 0 { - return this.originClients[rands.Int(0, len(this.originClients)-1)] - } - return nil + return pb.NewOriginServiceClient(this.pickConn()) } func (this *RPCClient) HTTPWebRPC() pb.HTTPWebServiceClient { - if len(this.httpWebClients) > 0 { - return this.httpWebClients[rands.Int(0, len(this.httpWebClients)-1)] - } - return nil + return pb.NewHTTPWebServiceClient(this.pickConn()) } func (this *RPCClient) ReverseProxyRPC() pb.ReverseProxyServiceClient { - if len(this.reverseProxyClients) > 0 { - return this.reverseProxyClients[rands.Int(0, len(this.reverseProxyClients)-1)] - } - return nil + return pb.NewReverseProxyServiceClient(this.pickConn()) } func (this *RPCClient) HTTPGzipRPC() pb.HTTPGzipServiceClient { - if len(this.httpGzipClients) > 0 { - return this.httpGzipClients[rands.Int(0, len(this.httpGzipClients)-1)] - } - return nil + return pb.NewHTTPGzipServiceClient(this.pickConn()) } func (this *RPCClient) HTTPHeaderRPC() pb.HTTPHeaderServiceClient { - if len(this.httpHeaderClients) > 0 { - return this.httpHeaderClients[rands.Int(0, len(this.httpHeaderClients)-1)] - } - return nil + return pb.NewHTTPHeaderServiceClient(this.pickConn()) } func (this *RPCClient) HTTPHeaderPolicyRPC() pb.HTTPHeaderPolicyServiceClient { - if len(this.httpHeaderPolicyClients) > 0 { - return this.httpHeaderPolicyClients[rands.Int(0, len(this.httpHeaderPolicyClients)-1)] - } - return nil + return pb.NewHTTPHeaderPolicyServiceClient(this.pickConn()) } func (this *RPCClient) HTTPPageRPC() pb.HTTPPageServiceClient { - if len(this.httpPageClients) > 0 { - return this.httpPageClients[rands.Int(0, len(this.httpPageClients)-1)] - } - return nil + return pb.NewHTTPPageServiceClient(this.pickConn()) } func (this *RPCClient) HTTPAccessLogPolicyRPC() pb.HTTPAccessLogPolicyServiceClient { - if len(this.httpAccessLogPolicyClients) > 0 { - return this.httpAccessLogPolicyClients[rands.Int(0, len(this.httpAccessLogPolicyClients)-1)] - } - return nil + return pb.NewHTTPAccessLogPolicyServiceClient(this.pickConn()) } func (this *RPCClient) HTTPCachePolicyRPC() pb.HTTPCachePolicyServiceClient { - if len(this.httpCachePolicyClients) > 0 { - return this.httpCachePolicyClients[rands.Int(0, len(this.httpCachePolicyClients)-1)] - } - return nil + return pb.NewHTTPCachePolicyServiceClient(this.pickConn()) } func (this *RPCClient) HTTPFirewallPolicyRPC() pb.HTTPFirewallPolicyServiceClient { - if len(this.httpFirewallPolicyClients) > 0 { - return this.httpFirewallPolicyClients[rands.Int(0, len(this.httpFirewallPolicyClients)-1)] - } - return nil + return pb.NewHTTPFirewallPolicyServiceClient(this.pickConn()) } func (this *RPCClient) HTTPLocationRPC() pb.HTTPLocationServiceClient { - if len(this.httpLocationClients) > 0 { - return this.httpLocationClients[rands.Int(0, len(this.httpLocationClients)-1)] - } - return nil + return pb.NewHTTPLocationServiceClient(this.pickConn()) } func (this *RPCClient) HTTPWebsocketRPC() pb.HTTPWebsocketServiceClient { - if len(this.httpWebsocketClients) > 0 { - return this.httpWebsocketClients[rands.Int(0, len(this.httpWebsocketClients)-1)] - } - return nil + return pb.NewHTTPWebsocketServiceClient(this.pickConn()) } func (this *RPCClient) HTTPRewriteRuleRPC() pb.HTTPRewriteRuleServiceClient { - if len(this.httpRewriteRuleClients) > 0 { - return this.httpRewriteRuleClients[rands.Int(0, len(this.httpRewriteRuleClients)-1)] - } - return nil + return pb.NewHTTPRewriteRuleServiceClient(this.pickConn()) } +func (this *RPCClient) SSLCertRPC() pb.SSLCertServiceClient { + return pb.NewSSLCertServiceClient(this.pickConn()) +} + +// 构造上下文 func (this *RPCClient) Context(adminId int64) context.Context { ctx := context.Background() m := maps.Map{ @@ -288,3 +152,11 @@ func (this *RPCClient) Context(adminId int64) context.Context { ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token) return ctx } + +// 随机选择一个连接 +func (this *RPCClient) pickConn() *grpc.ClientConn { + if len(this.conns) == 0 { + return nil + } + return this.conns[rands.Int(0, len(this.conns)-1)] +} diff --git a/internal/web/actions/default/servers/components/componentutils/component_helper.go b/internal/web/actions/default/servers/components/componentutils/component_helper.go index 9e5b3929..2fe7a902 100644 --- a/internal/web/actions/default/servers/components/componentutils/component_helper.go +++ b/internal/web/actions/default/servers/components/componentutils/component_helper.go @@ -18,7 +18,7 @@ func (this *ComponentHelper) BeforeAction(action *actions.ActionObject) { if action.Request.Method != http.MethodGet { return } - action.Data["teaMenu"] = "server" + action.Data["teaMenu"] = "servers" action.Data["mainTab"] = "component" // 顶部标签栏 diff --git a/internal/web/actions/default/servers/components/ssl/certPopup.go b/internal/web/actions/default/servers/components/ssl/certPopup.go new file mode 100644 index 00000000..88f6fef0 --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/certPopup.go @@ -0,0 +1,77 @@ +package ssl + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" + "github.com/iwind/TeaGo/maps" + timeutil "github.com/iwind/TeaGo/utils/time" + "time" +) + +type CertPopupAction struct { + actionutils.ParentAction +} + +func (this *CertPopupAction) Init() { +} + +func (this *CertPopupAction) RunGet(params struct { + CertId int64 +}) { + certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + + certConfig := &sslconfigs.SSLCertConfig{} + err = json.Unmarshal(certResp.CertJSON, certConfig) + if err != nil { + this.ErrorPage(err) + return + } + + reverseCommonNames := []string{} + for i := len(certConfig.CommonNames) - 1; i >= 0; i-- { + reverseCommonNames = append(reverseCommonNames, certConfig.CommonNames[i]) + } + + this.Data["info"] = maps.Map{ + "id": certConfig.Id, + "name": certConfig.Name, + "description": certConfig.Description, + "isOn": certConfig.IsOn, + "isAvailable": certConfig.TimeEndAt >= time.Now().Unix(), + "commonNames": reverseCommonNames, + "dnsNames": certConfig.DNSNames, + + // TODO 检查是否为7天或30天内过期 + "beginTime": timeutil.FormatTime("Y-m-d H:i:s", certConfig.TimeBeginAt), + "endTime": timeutil.FormatTime("Y-m-d H:i:s", certConfig.TimeEndAt), + + "isCA": certConfig.IsCA, + "certString": string(certConfig.CertData), + "keyString": string(certConfig.KeyData), + } + + // 引入的服务 + serversResp, err := this.RPC().ServerRPC().FindAllServersWithSSLCertId(this.AdminContext(), &pb.FindAllServersWithSSLCertIdRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + serverMaps := []maps.Map{} + for _, server := range serversResp.Servers { + serverMaps = append(serverMaps, maps.Map{ + "id": server.Id, + "isOn": server.IsOn, + "name": server.Name, + "type": server.Type, + }) + } + this.Data["servers"] = serverMaps + + this.Show() +} diff --git a/internal/web/actions/default/servers/components/ssl/delete.go b/internal/web/actions/default/servers/components/ssl/delete.go new file mode 100644 index 00000000..e9e1d4ab --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/delete.go @@ -0,0 +1,32 @@ +package ssl + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +type DeleteAction struct { + actionutils.ParentAction +} + +func (this *DeleteAction) RunPost(params struct { + CertId int64 +}) { + // 是否正在被使用 + countResp, err := this.RPC().ServerRPC().CountServersWithSSLCertId(this.AdminContext(), &pb.CountServersWithSSLCertIdRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + if countResp.Count > 0 { + this.Fail("此证书正在被某些服务引用,请先修改服务后再删除。") + } + + _, err = this.RPC().SSLCertRPC().DeleteSSLCert(this.AdminContext(), &pb.DeleteSSLCertRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/servers/components/ssl/downloadCert.go b/internal/web/actions/default/servers/components/ssl/downloadCert.go new file mode 100644 index 00000000..8f9fd922 --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/downloadCert.go @@ -0,0 +1,37 @@ +package ssl + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" + "strconv" +) + +type DownloadCertAction struct { + actionutils.ParentAction +} + +func (this *DownloadCertAction) Init() { + this.Nav("", "", "") +} + +func (this *DownloadCertAction) RunGet(params struct { + CertId int64 +}) { + certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + + certConfig := &sslconfigs.SSLCertConfig{} + err = json.Unmarshal(certResp.CertJSON, certConfig) + if err != nil { + this.ErrorPage(err) + return + } + + this.AddHeader("Content-Disposition", "attachment; filename=\"cert-"+strconv.FormatInt(params.CertId, 10)+".pem\";") + this.Write(certConfig.CertData) +} diff --git a/internal/web/actions/default/servers/components/ssl/downloadKey.go b/internal/web/actions/default/servers/components/ssl/downloadKey.go new file mode 100644 index 00000000..8d2a805c --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/downloadKey.go @@ -0,0 +1,37 @@ +package ssl + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" + "strconv" +) + +type DownloadKeyAction struct { + actionutils.ParentAction +} + +func (this *DownloadKeyAction) Init() { + this.Nav("", "", "") +} + +func (this *DownloadKeyAction) RunGet(params struct { + CertId int64 +}) { + certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + + certConfig := &sslconfigs.SSLCertConfig{} + err = json.Unmarshal(certResp.CertJSON, certConfig) + if err != nil { + this.ErrorPage(err) + return + } + + this.AddHeader("Content-Disposition", "attachment; filename=\"key-"+strconv.FormatInt(params.CertId, 10)+".pem\";") + this.Write(certConfig.KeyData) +} diff --git a/internal/web/actions/default/servers/components/ssl/downloadZip.go b/internal/web/actions/default/servers/components/ssl/downloadZip.go new file mode 100644 index 00000000..4e29d2cb --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/downloadZip.go @@ -0,0 +1,80 @@ +package ssl + +import ( + "archive/zip" + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" + "strconv" +) + +type DownloadZipAction struct { + actionutils.ParentAction +} + +func (this *DownloadZipAction) Init() { + this.Nav("", "", "") +} + +func (this *DownloadZipAction) RunGet(params struct { + CertId int64 +}) { + certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + + certConfig := &sslconfigs.SSLCertConfig{} + err = json.Unmarshal(certResp.CertJSON, certConfig) + if err != nil { + this.ErrorPage(err) + return + } + + z := zip.NewWriter(this.ResponseWriter) + defer func() { + _ = z.Close() + }() + + this.AddHeader("Content-Disposition", "attachment; filename=\"cert-"+strconv.FormatInt(params.CertId, 10)+".zip\";") + + // cert + { + w, err := z.Create("cert.pem") + if err != nil { + this.ErrorPage(err) + return + } + _, err = w.Write(certConfig.CertData) + if err != nil { + this.ErrorPage(err) + return + } + err = z.Flush() + if err != nil { + this.ErrorPage(err) + return + } + } + + // key + if !certConfig.IsCA { + w, err := z.Create("key.pem") + if err != nil { + this.ErrorPage(err) + return + } + _, err = w.Write(certConfig.KeyData) + if err != nil { + this.ErrorPage(err) + return + } + err = z.Flush() + if err != nil { + this.ErrorPage(err) + return + } + } +} diff --git a/internal/web/actions/default/servers/components/ssl/index.go b/internal/web/actions/default/servers/components/ssl/index.go index 32e15927..c6b69bbc 100644 --- a/internal/web/actions/default/servers/components/ssl/index.go +++ b/internal/web/actions/default/servers/components/ssl/index.go @@ -1,7 +1,13 @@ package ssl import ( + "encoding/json" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" + "github.com/iwind/TeaGo/maps" + timeutil "github.com/iwind/TeaGo/utils/time" + "time" ) type IndexAction struct { @@ -12,7 +18,146 @@ func (this *IndexAction) Init() { this.FirstMenu("index") } -func (this *IndexAction) RunGet(params struct{}) { +func (this *IndexAction) RunGet(params struct { + Type string +}) { + this.Data["type"] = params.Type + + countAll := int64(0) + countCA := int64(0) + countAvailable := int64(0) + countExpired := int64(0) + count7Days := int64(0) + count30Days := int64(0) + + // 计算数量 + { + // all + resp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + countAll = resp.Count + + // CA + resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{ + IsCA: true, + }) + if err != nil { + this.ErrorPage(err) + return + } + countCA = resp.Count + + // available + resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{ + IsAvailable: true, + }) + if err != nil { + this.ErrorPage(err) + return + } + countAvailable = resp.Count + + // expired + resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{ + IsExpired: true, + }) + if err != nil { + this.ErrorPage(err) + return + } + countExpired = resp.Count + + // expire in 7 days + resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{ + ExpiringDays: 7, + }) + if err != nil { + this.ErrorPage(err) + return + } + count7Days = resp.Count + + // expire in 30 days + resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{ + ExpiringDays: 30, + }) + if err != nil { + this.ErrorPage(err) + return + } + count30Days = resp.Count + } + + this.Data["countAll"] = countAll + this.Data["countCA"] = countCA + this.Data["countAvailable"] = countAvailable + this.Data["countExpired"] = countExpired + this.Data["count7Days"] = count7Days + this.Data["count30Days"] = count30Days + + // 分页 + var page *actionutils.Page + var listResp *pb.ListSSLCertsResponse + var err error + switch params.Type { + case "": + page = this.NewPage(countAll) + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{Offset: page.Offset, Size: page.Size}) + case "ca": + page = this.NewPage(countCA) + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{IsCA: true, Offset: page.Offset, Size: page.Size}) + case "available": + page = this.NewPage(countAvailable) + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{IsAvailable: true, Offset: page.Offset, Size: page.Size}) + case "expired": + page = this.NewPage(countExpired) + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{IsExpired: true, Offset: page.Offset, Size: page.Size}) + case "7days": + page = this.NewPage(count7Days) + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{ExpiringDays: 7, Offset: page.Offset, Size: page.Size}) + case "30days": + page = this.NewPage(count30Days) + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{ExpiringDays: 30, Offset: page.Offset, Size: page.Size}) + default: + page = this.NewPage(countAll) + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{}) + } + if err != nil { + this.ErrorPage(err) + return + } + + certConfigs := []*sslconfigs.SSLCertConfig{} + err = json.Unmarshal(listResp.CertsJSON, &certConfigs) + if err != nil { + this.ErrorPage(err) + return + } + this.Data["certs"] = certConfigs + + certMaps := []maps.Map{} + nowTime := time.Now().Unix() + for _, certConfig := range certConfigs { + countServersResp, err := this.RPC().ServerRPC().CountServersWithSSLCertId(this.AdminContext(), &pb.CountServersWithSSLCertIdRequest{CertId: certConfig.Id}) + if err != nil { + this.ErrorPage(err) + return + } + + certMaps = append(certMaps, maps.Map{ + "beginDay": timeutil.FormatTime("Y-m-d", certConfig.TimeBeginAt), + "endDay": timeutil.FormatTime("Y-m-d", certConfig.TimeEndAt), + "isExpired": nowTime > certConfig.TimeEndAt, + "isAvailable": nowTime <= certConfig.TimeEndAt, + "countServers": countServersResp.Count, + }) + } + this.Data["certInfos"] = certMaps + + this.Data["page"] = page.AsHTML() this.Show() } diff --git a/internal/web/actions/default/servers/components/ssl/init.go b/internal/web/actions/default/servers/components/ssl/init.go index 300f5638..b89b9695 100644 --- a/internal/web/actions/default/servers/components/ssl/init.go +++ b/internal/web/actions/default/servers/components/ssl/init.go @@ -14,6 +14,15 @@ func init() { Helper(componentutils.NewComponentHelper()). Prefix("/servers/components/ssl"). Get("", new(IndexAction)). + GetPost("/uploadPopup", new(UploadPopupAction)). + Post("/delete", new(DeleteAction)). + GetPost("/updatePopup", new(UpdatePopupAction)). + Get("/certPopup", new(CertPopupAction)). + Get("/viewKey", new(ViewKeyAction)). + Get("/viewCert", new(ViewCertAction)). + Get("/downloadKey", new(DownloadKeyAction)). + Get("/downloadCert", new(DownloadCertAction)). + Get("/downloadZip", new(DownloadZipAction)). EndAll() }) } diff --git a/internal/web/actions/default/servers/components/ssl/updatePopup.go b/internal/web/actions/default/servers/components/ssl/updatePopup.go new file mode 100644 index 00000000..39a4246e --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/updatePopup.go @@ -0,0 +1,15 @@ +package ssl + +import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + +type UpdatePopupAction struct { + actionutils.ParentAction +} + +func (this *UpdatePopupAction) Init() { + this.Nav("", "", "") +} + +func (this *UpdatePopupAction) RunGet(params struct{}) { + this.Show() +} diff --git a/internal/web/actions/default/servers/components/ssl/uploadPopup.go b/internal/web/actions/default/servers/components/ssl/uploadPopup.go new file mode 100644 index 00000000..72635f19 --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/uploadPopup.go @@ -0,0 +1,95 @@ +package ssl + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" + "github.com/iwind/TeaGo/actions" +) + +type UploadPopupAction struct { + actionutils.ParentAction +} + +func (this *UploadPopupAction) Init() { + this.Nav("", "", "") +} + +func (this *UploadPopupAction) RunGet(params struct{}) { + this.Show() +} + +func (this *UploadPopupAction) RunPost(params struct { + Name string + IsCA bool + Description string + IsOn bool + + CertFile *actions.File + KeyFile *actions.File + + Must *actions.Must +}) { + params.Must. + Field("name", params.Name). + Require("请输入证书说明") + + certData := []byte{} + keyData := []byte{} + + if params.CertFile == nil { + this.Fail("请选择要上传的证书文件") + } + var err error + certData, err = params.CertFile.Read() + if err != nil { + this.Fail("读取证书文件内容错误,请重新上传") + } + + if !params.IsCA { + if params.KeyFile == nil { + this.Fail("请选择要上传的私钥文件") + } else { + keyData, err = params.KeyFile.Read() + if err != nil { + this.Fail("读取密钥文件内容错误,请重新上传") + } + } + } + + // 校验 + sslConfig := &sslconfigs.SSLCertConfig{ + IsCA: params.IsCA, + CertData: certData, + KeyData: keyData, + } + err = sslConfig.Init() + if err != nil { + if params.IsCA { + this.Fail("证书校验错误:" + err.Error()) + } else { + this.Fail("证书或密钥校验错误:" + err.Error()) + } + } + + // 保存 + _, err = this.RPC().SSLCertRPC().CreateSSLCert(this.AdminContext(), &pb.CreateSSLCertRequest{ + IsOn: params.IsOn, + Name: params.Name, + Description: params.Description, + ServerName: "", + IsCA: params.IsCA, + CertData: certData, + KeyData: keyData, + TimeBeginAt: sslConfig.TimeBeginAt, + TimeEndAt: sslConfig.TimeEndAt, + DnsNames: sslConfig.DNSNames, + CommonNames: sslConfig.CommonNames, + }) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/servers/components/ssl/viewCert.go b/internal/web/actions/default/servers/components/ssl/viewCert.go new file mode 100644 index 00000000..59484639 --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/viewCert.go @@ -0,0 +1,34 @@ +package ssl + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" +) + +type ViewCertAction struct { + actionutils.ParentAction +} + +func (this *ViewCertAction) Init() { + this.Nav("", "", "") +} + +func (this *ViewCertAction) RunGet(params struct { + CertId int64 +}) { + certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + + certConfig := &sslconfigs.SSLCertConfig{} + err = json.Unmarshal(certResp.CertJSON, certConfig) + if err != nil { + this.ErrorPage(err) + return + } + this.Write(certConfig.CertData) +} diff --git a/internal/web/actions/default/servers/components/ssl/viewKey.go b/internal/web/actions/default/servers/components/ssl/viewKey.go new file mode 100644 index 00000000..facee9a9 --- /dev/null +++ b/internal/web/actions/default/servers/components/ssl/viewKey.go @@ -0,0 +1,34 @@ +package ssl + +import ( + "encoding/json" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" +) + +type ViewKeyAction struct { + actionutils.ParentAction +} + +func (this *ViewKeyAction) Init() { + this.Nav("", "", "") +} + +func (this *ViewKeyAction) RunGet(params struct { + CertId int64 +}) { + certResp, err := this.RPC().SSLCertRPC().FindEnabledSSLCertConfig(this.AdminContext(), &pb.FindEnabledSSLCertConfigRequest{CertId: params.CertId}) + if err != nil { + this.ErrorPage(err) + return + } + + certConfig := &sslconfigs.SSLCertConfig{} + err = json.Unmarshal(certResp.CertJSON, certConfig) + if err != nil { + this.ErrorPage(err) + return + } + this.Write(certConfig.KeyData) +} diff --git a/web/public/js/components/common/labels.js b/web/public/js/components/common/labels.js index a6a23848..521231cc 100644 --- a/web/public/js/components/common/labels.js +++ b/web/public/js/components/common/labels.js @@ -1,4 +1,4 @@ Vue.component("label-on", { props: ["v-is-on"], - template: '
| 证书说明 | +{{info.name}} | +
| 详细说明 | +{{info.decription}} | +
| 证书状态 | ++ 有效中 + 已过期 + | +
| 发行信息 | +
+
+
+
+ {{commonName}}
+
+ |
+
| 域名 | ++ {{dnsName}} + | +
| 有效期 | +{{info.beginTime}} - {{info.endTime}} | +
| 引用服务 | +
+ 暂时没有引用此证书的服务。
+
+ {{server.name}}
+
+ |
+
| 证书文件下载 | ++ [ZIP下载] + [证书下载] + [私钥下载] + | +
| 证书预览 | +
+ {{info.certString}}
+
+ [浏览器新窗口打开]
+
+ |
+
| 私钥预览 | +{{info.keyString}}
+
+ [浏览器新窗口打开]
+
+ |
+
暂时还没有相关的证书。
+| 证书说明 | +顶级发行组织 | +域名 | +生效日期 | +过期日期 | +引用服务 | +状态 | +操作 | +
|---|---|---|---|---|---|---|---|
| {{cert.name}} | ++ {{cert.commonNames[cert.commonNames.length-1]}} + | +
+
+ {{dnsName}}
+
+ |
+ {{certInfos[index].beginDay}} | +{{certInfos[index].endDay}} | +{{certInfos[index].countServers}} | ++ 已过期 + 有效中 + | ++ 详情 + 修改 + 删除 + | +
提醒:HTTP2、证书等信息修改后,可能需要清空浏览器缓存后才能浏览效果。