diff --git a/internal/web/actions/default/servers/certs/certPopup.go b/internal/web/actions/default/servers/certs/certPopup.go index 0090fa47..c2b270e1 100644 --- a/internal/web/actions/default/servers/certs/certPopup.go +++ b/internal/web/actions/default/servers/certs/certPopup.go @@ -26,14 +26,14 @@ func (this *CertPopupAction) RunGet(params struct { return } - certConfig := &sslconfigs.SSLCertConfig{} + var certConfig = &sslconfigs.SSLCertConfig{} err = json.Unmarshal(certResp.SslCertJSON, certConfig) if err != nil { this.ErrorPage(err) return } - reverseCommonNames := []string{} + var reverseCommonNames = []string{} for i := len(certConfig.CommonNames) - 1; i >= 0; i-- { reverseCommonNames = append(reverseCommonNames, certConfig.CommonNames[i]) } @@ -62,7 +62,7 @@ func (this *CertPopupAction) RunGet(params struct { this.ErrorPage(err) return } - serverMaps := []maps.Map{} + var serverMaps = []maps.Map{} for _, server := range serversResp.Servers { serverMaps = append(serverMaps, maps.Map{ "id": server.Id, diff --git a/internal/web/actions/default/servers/certs/helper.go b/internal/web/actions/default/servers/certs/helper.go index ce54fa82..5dccc1dd 100644 --- a/internal/web/actions/default/servers/certs/helper.go +++ b/internal/web/actions/default/servers/certs/helper.go @@ -1,8 +1,11 @@ package certs import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/maps" + "github.com/iwind/TeaGo/types" "net/http" ) @@ -13,14 +16,29 @@ func NewHelper() *Helper { return &Helper{} } -func (this *Helper) BeforeAction(action *actions.ActionObject) { +func (this *Helper) BeforeAction(actionWrapper actions.ActionWrapper) { + var action = actionWrapper.Object() if action.Request.Method != http.MethodGet { return } action.Data["teaMenu"] = "servers" - action.Data["leftMenuItems"] = []maps.Map{ + var countOCSP int64 = 0 + parentAction, ok := actionWrapper.(actionutils.ActionInterface) + if ok { + countOCSPResp, err := parentAction.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(parentAction.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{}) + if err == nil { + countOCSP = countOCSPResp.Count + } + } + + var ocspMenuName = "OCSP日志" + if countOCSP > 0 { + ocspMenuName += "(" + types.String(countOCSP) + ")" + } + + var menu = []maps.Map{ { "name": "证书", "url": "/servers/certs", @@ -31,5 +49,11 @@ func (this *Helper) BeforeAction(action *actions.ActionObject) { "url": "/servers/certs/acme", "isActive": action.Data.GetString("leftMenuItem") == "acme", }, + { + "name": ocspMenuName, + "url": "/servers/certs/ocsp", + "isActive": action.Data.GetString("leftMenuItem") == "ocsp", + }, } + action.Data["leftMenuItems"] = menu } diff --git a/internal/web/actions/default/servers/certs/index.go b/internal/web/actions/default/servers/certs/index.go index b53f10d7..52441ba3 100644 --- a/internal/web/actions/default/servers/certs/index.go +++ b/internal/web/actions/default/servers/certs/index.go @@ -25,12 +25,12 @@ func (this *IndexAction) RunGet(params struct { this.Data["type"] = params.Type this.Data["keyword"] = params.Keyword - countAll := int64(0) - countCA := int64(0) - countAvailable := int64(0) - countExpired := int64(0) - count7Days := int64(0) - count30Days := int64(0) + var countAll = int64(0) + var countCA = int64(0) + var countAvailable = int64(0) + var countExpired = int64(0) + var count7Days = int64(0) + var count30Days = int64(0) // 计算数量 { @@ -147,7 +147,7 @@ func (this *IndexAction) RunGet(params struct { return } - certConfigs := []*sslconfigs.SSLCertConfig{} + var certConfigs = []*sslconfigs.SSLCertConfig{} err = json.Unmarshal(listResp.SslCertsJSON, &certConfigs) if err != nil { this.ErrorPage(err) @@ -155,8 +155,8 @@ func (this *IndexAction) RunGet(params struct { } this.Data["certs"] = certConfigs - certMaps := []maps.Map{} - nowTime := time.Now().Unix() + var certMaps = []maps.Map{} + var nowTime = time.Now().Unix() for _, certConfig := range certConfigs { countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{SslCertId: certConfig.Id}) if err != nil { diff --git a/internal/web/actions/default/servers/certs/init.go b/internal/web/actions/default/servers/certs/init.go index c7f47a95..8f5f5aee 100644 --- a/internal/web/actions/default/servers/certs/init.go +++ b/internal/web/actions/default/servers/certs/init.go @@ -5,6 +5,7 @@ import ( "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/accounts" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/acme/users" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs/ocsp" "github.com/TeaOSLab/EdgeAdmin/internal/web/helpers" "github.com/iwind/TeaGo" ) @@ -55,6 +56,14 @@ func init() { GetPost("/updatePopup", new(accounts.UpdatePopupAction)). Post("/delete", new(accounts.DeleteAction)). + // OCSP + Prefix("/servers/certs/ocsp"). + Data("leftMenuItem", "ocsp"). + Get("", new(ocsp.IndexAction)). + Post("/reset", new(ocsp.ResetAction)). + Post("/resetAll", new(ocsp.ResetAllAction)). + Post("/ignore", new(ocsp.IgnoreAction)). + // EndAll() }) diff --git a/internal/web/actions/default/servers/certs/ocsp/ignore.go b/internal/web/actions/default/servers/certs/ocsp/ignore.go new file mode 100644 index 00000000..8e564d8b --- /dev/null +++ b/internal/web/actions/default/servers/certs/ocsp/ignore.go @@ -0,0 +1,26 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package ocsp + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +type IgnoreAction struct { + actionutils.ParentAction +} + +func (this *IgnoreAction) RunPost(params struct { + CertIds []int64 +}) { + defer this.CreateLogInfo("忽略一组证书的OCSP状态") + + _, err := this.RPC().SSLCertRPC().IgnoreSSLCertsWithOCSPError(this.AdminContext(), &pb.IgnoreSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/servers/certs/ocsp/index.go b/internal/web/actions/default/servers/certs/ocsp/index.go new file mode 100644 index 00000000..51611b5b --- /dev/null +++ b/internal/web/actions/default/servers/certs/ocsp/index.go @@ -0,0 +1,65 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package ocsp + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/iwind/TeaGo/maps" + timeutil "github.com/iwind/TeaGo/utils/time" + "time" +) + +type IndexAction struct { + actionutils.ParentAction +} + +func (this *IndexAction) Init() { + this.SecondMenu("ocsp") +} + +func (this *IndexAction) RunGet(params struct { + Keyword string +}) { + this.Data["keyword"] = params.Keyword + + countResp, err := this.RPC().SSLCertRPC().CountAllSSLCertsWithOCSPError(this.AdminContext(), &pb.CountAllSSLCertsWithOCSPErrorRequest{Keyword: params.Keyword}) + if err != nil { + this.ErrorPage(err) + return + } + var count = countResp.Count + var page = this.NewPage(count) + this.Data["page"] = page.AsHTML() + + certsResp, err := this.RPC().SSLCertRPC().ListSSLCertsWithOCSPError(this.AdminContext(), &pb.ListSSLCertsWithOCSPErrorRequest{ + Keyword: params.Keyword, + Offset: page.Offset, + Size: page.Size, + }) + if err != nil { + this.ErrorPage(err) + return + } + var certMaps = []maps.Map{} + for _, cert := range certsResp.SslCerts { + certMaps = append(certMaps, maps.Map{ + "id": cert.Id, + "isOn": cert.IsOn, + "dnsNames": cert.DnsNames, + "commonNames": cert.CommonNames, + "hasOCSP": len(cert.Ocsp) > 0, + "ocspIsUpdated": cert.OcspIsUpdated, + "ocspError": cert.OcspError, + "isCA": cert.IsCA, + "isACME": cert.IsACME, + "name": cert.Name, + "isExpired": cert.TimeEndAt < time.Now().Unix(), + "beginDay": timeutil.FormatTime("Y-m-d", cert.TimeBeginAt), + "endDay": timeutil.FormatTime("Y-m-d", cert.TimeEndAt), + }) + } + this.Data["certs"] = certMaps + + this.Show() +} diff --git a/internal/web/actions/default/servers/certs/ocsp/reset.go b/internal/web/actions/default/servers/certs/ocsp/reset.go new file mode 100644 index 00000000..963b8fc4 --- /dev/null +++ b/internal/web/actions/default/servers/certs/ocsp/reset.go @@ -0,0 +1,26 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package ocsp + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +type ResetAction struct { + actionutils.ParentAction +} + +func (this *ResetAction) RunPost(params struct { + CertIds []int64 +}) { + defer this.CreateLogInfo("重置一组证书的OCSP状态") + + _, err := this.RPC().SSLCertRPC().ResetSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetSSLCertsWithOCSPErrorRequest{SslCertIds: params.CertIds}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/internal/web/actions/default/servers/certs/ocsp/resetAll.go b/internal/web/actions/default/servers/certs/ocsp/resetAll.go new file mode 100644 index 00000000..606e8eb8 --- /dev/null +++ b/internal/web/actions/default/servers/certs/ocsp/resetAll.go @@ -0,0 +1,24 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. + +package ocsp + +import ( + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" +) + +type ResetAllAction struct { + actionutils.ParentAction +} + +func (this *ResetAllAction) RunPost(params struct{}) { + defer this.CreateLogInfo("忽略所有证书的OCSP状态") + + _, err := this.RPC().SSLCertRPC().ResetAllSSLCertsWithOCSPError(this.AdminContext(), &pb.ResetAllSSLCertsWithOCSPErrorRequest{}) + if err != nil { + this.ErrorPage(err) + return + } + + this.Success() +} diff --git a/web/public/js/components/common/checkbox.js b/web/public/js/components/common/checkbox.js index b5bbab2e..6c130bee 100644 --- a/web/public/js/components/common/checkbox.js +++ b/web/public/js/components/common/checkbox.js @@ -14,9 +14,9 @@ Vue.component("checkbox", { } let checkedValue = this.value - if (checkedValue == null && this.checked == "checked") { - checkedValue = elementValue - } + if (checkedValue == null && this.checked == "checked") { + checkedValue = elementValue + } return { elementId: elementId, @@ -27,15 +27,24 @@ Vue.component("checkbox", { methods: { change: function () { this.$emit("input", this.newValue) + }, + check: function () { + this.newValue = this.elementValue + }, + uncheck: function () { + this.newValue = "" + }, + isChecked: function () { + return this.newValue == this.elementValue + } + }, + watch: { + value: function (v) { + if (typeof v == "boolean") { + this.newValue = v + } } }, - watch: { - value: function (v) { - if (typeof v == "boolean") { - this.newValue = v - } - } - }, template: `
diff --git a/web/views/@default/servers/certs/ocsp/index.html b/web/views/@default/servers/certs/ocsp/index.html new file mode 100644 index 00000000..ae096432 --- /dev/null +++ b/web/views/@default/servers/certs/ocsp/index.html @@ -0,0 +1,84 @@ +{$layout} +{$template "/left_menu_top"} + +
+
+ +
+
+
+ +
+
+ +   [清除条件] +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+ +

暂时没有OCSP日志。

+ + + + + + + + + + + + + + + + + + + + + + + + +
证书说明顶级发行组织域名错误信息状态操作
{{cert.name}} +
+ CA +
+
+ ACME +
+
+ {{cert.commonNames[cert.commonNames.length-1]}} + +
+ {{dnsName}} +
+
+ {{cert.ocspError}} + + 未启用 + 已过期 + 有效中 + + 详情   +
+ +
+
\ No newline at end of file diff --git a/web/views/@default/servers/certs/ocsp/index.js b/web/views/@default/servers/certs/ocsp/index.js new file mode 100644 index 00000000..f2281590 --- /dev/null +++ b/web/views/@default/servers/certs/ocsp/index.js @@ -0,0 +1,62 @@ +Tea.context(function () { + this.certIds = [] + this.allChecked = false + + this.$delay(function () { + let that = this + this.$watch("allChecked", function (b) { + let boxes = that.$refs.certCheckboxes + boxes.forEach(function (box) { + if (b) { + box.check() + } else { + box.uncheck() + } + that.changeCerts() + }) + }) + }) + + this.changeCerts = function () { + let boxes = this.$refs.certCheckboxes + let that = this + this.certIds = [] + boxes.forEach(function (box) { + if (box.isChecked()) { + let boxId = box.id + that.certIds.push(parseInt(boxId.split("_")[1])) + } + }) + } + + this.resetAllCerts = function () { + this.$post(".resetAll") + .success(function () { + teaweb.successRefresh("重置成功") + }) + } + + this.resetCerts = function () { + this.$post(".reset") + .params({ certIds: this.certIds }) + .success(function () { + teaweb.successRefresh("重置成功") + }) + } + + this.ignoreCerts = function () { + this.$post(".ignore") + .params({ certIds: this.certIds }) + .success(function () { + teaweb.successRefresh("忽略成功") + }) + } + + // 查看证书详情 + this.viewCert = function (certId) { + teaweb.popup("/servers/certs/certPopup?certId=" + certId, { + height: "28em", + width: "48em" + }) + } +}) \ No newline at end of file