diff --git a/internal/web/actions/default/servers/certs/selectPopup.go b/internal/web/actions/default/servers/certs/selectPopup.go index 54a9bb72..9210a58a 100644 --- a/internal/web/actions/default/servers/certs/selectPopup.go +++ b/internal/web/actions/default/servers/certs/selectPopup.go @@ -2,9 +2,11 @@ package certs import ( "encoding/json" + "errors" "github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs" "github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/maps" @@ -23,15 +25,82 @@ func (this *SelectPopupAction) Init() { } func (this *SelectPopupAction) RunGet(params struct { + ServerId int64 // 搜索的服务 + UserId int64 // 搜索的用户名 + SearchingDomains string // 搜索的域名 + SearchingType string // 搜索类型:match|all + ViewSize string SelectedCertIds string Keyword string }) { - // TODO 列出常用和最新的证书供用户选择 + // 服务相关 + if params.ServerId > 0 { + serverResp, err := this.RPC().ServerRPC().FindEnabledUserServerBasic(this.AdminContext(), &pb.FindEnabledUserServerBasicRequest{ServerId: params.ServerId}) + if err != nil { + this.ErrorPage(err) + return + } + var server = serverResp.Server + if server != nil { + if server.UserId > 0 { + params.UserId = server.UserId + } + + // 读取所有ServerNames + serverNamesResp, err := this.RPC().ServerRPC().FindServerNames(this.AdminContext(), &pb.FindServerNamesRequest{ServerId: params.ServerId}) + if err != nil { + this.ErrorPage(err) + return + } + if len(serverNamesResp.ServerNamesJSON) > 0 { + var serverNames = []*serverconfigs.ServerNameConfig{} + err = json.Unmarshal(serverNamesResp.ServerNamesJSON, &serverNames) + if err != nil { + this.ErrorPage(err) + return + } + params.SearchingDomains = strings.Join(serverconfigs.PlainServerNames(serverNames), ",") + } + } + } + + // 用户相关 + this.Data["userId"] = params.UserId + + // 域名搜索相关 + var url = this.Request.URL.Path + var query = this.Request.URL.Query() + query.Del("searchingType") + this.Data["baseURL"] = url + "?" + query.Encode() + + var searchingDomains = []string{} + if len(params.SearchingDomains) > 0 { + searchingDomains = strings.Split(params.SearchingDomains, ",") + } + const maxDomains = 2_000 // 限制搜索的域名数量 + if len(searchingDomains) > maxDomains { + searchingDomains = searchingDomains[:maxDomains] + } + this.Data["searchingDomains"] = searchingDomains this.Data["keyword"] = params.Keyword this.Data["selectedCertIds"] = params.SelectedCertIds + var searchingType = params.SearchingType + if len(searchingType) == 0 { + if len(params.SearchingDomains) == 0 { + searchingType = "all" + } else { + searchingType = "match" + } + } + if searchingType != "all" && searchingType != "match" { + this.ErrorPage(errors.New("invalid searching type '" + searchingType + "'")) + return + } + this.Data["searchingType"] = searchingType + // 已经选择的证书 var selectedCertIds = []string{} if len(params.SelectedCertIds) > 0 { @@ -43,24 +112,68 @@ func (this *SelectPopupAction) RunGet(params struct { } this.Data["viewSize"] = params.ViewSize - countResp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{ + // 全部证书数量 + countAllResp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{ + UserId: params.UserId, Keyword: params.Keyword, }) if err != nil { this.ErrorPage(err) return } + var totalAll = countAllResp.Count + this.Data["totalAll"] = totalAll - page := this.NewPage(countResp.Count) + // 已匹配证书数量 + var totalMatch int64 = 0 + if len(searchingDomains) > 0 { + countMatchResp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{ + UserId: params.UserId, + Keyword: params.Keyword, + Domains: searchingDomains, + }) + if err != nil { + this.ErrorPage(err) + return + } + totalMatch = countMatchResp.Count + } + this.Data["totalMatch"] = totalMatch + + var totalCerts int64 + if searchingType == "all" { + totalCerts = totalAll + } else if searchingType == "match" { + totalCerts = totalMatch + } + + var page = this.NewPage(totalCerts) this.Data["page"] = page.AsHTML() - listResp, err := this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{ - Keyword: params.Keyword, - Offset: page.Offset, - Size: page.Size, - }) + var listResp *pb.ListSSLCertsResponse + if searchingType == "all" { + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{ + UserId: params.UserId, + Keyword: params.Keyword, + Offset: page.Offset, + Size: page.Size, + }) + } else if searchingType == "match" { + listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{ + UserId: params.UserId, + Keyword: params.Keyword, + Domains: searchingDomains, + Offset: page.Offset, + Size: page.Size, + }) + } - certConfigs := []*sslconfigs.SSLCertConfig{} + if listResp == nil { + this.ErrorPage(errors.New("'listResp' should not be nil")) + return + } + + var certConfigs = []*sslconfigs.SSLCertConfig{} err = json.Unmarshal(listResp.SslCertsJSON, &certConfigs) if err != nil { this.ErrorPage(err) @@ -68,8 +181,8 @@ func (this *SelectPopupAction) 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/web/public/js/components/server/server-name-box.js b/web/public/js/components/server/server-name-box.js index 6970005e..6b4e79b0 100644 --- a/web/public/js/components/server/server-name-box.js +++ b/web/public/js/components/server/server-name-box.js @@ -1,78 +1,100 @@ Vue.component("server-name-box", { - props: ["v-server-names"], - data: function () { - let serverNames = this.vServerNames; - if (serverNames == null) { - serverNames = [] - } - return { - serverNames: serverNames, - isSearching: false, - keyword: "" - } - }, - methods: { - addServerName: function () { - window.UPDATING_SERVER_NAME = null - let that = this - teaweb.popup("/servers/addServerNamePopup", { - callback: function (resp) { - var serverName = resp.data.serverName - that.serverNames.push(serverName) - } - }); - }, + props: ["v-server-names"], + data: function () { + let serverNames = this.vServerNames; + if (serverNames == null) { + serverNames = [] + } + return { + serverNames: serverNames, + isSearching: false, + keyword: "" + } + }, + methods: { + addServerName: function () { + window.UPDATING_SERVER_NAME = null + let that = this + teaweb.popup("/servers/addServerNamePopup", { + callback: function (resp) { + var serverName = resp.data.serverName + that.serverNames.push(serverName) + } + }); + }, - removeServerName: function (index) { - this.serverNames.$remove(index) - }, + removeServerName: function (index) { + this.serverNames.$remove(index) + }, - updateServerName: function (index, serverName) { - window.UPDATING_SERVER_NAME = teaweb.clone(serverName) - let that = this - teaweb.popup("/servers/addServerNamePopup", { - callback: function (resp) { - var serverName = resp.data.serverName - Vue.set(that.serverNames, index, serverName) - } - }); - }, - showSearchBox: function () { - this.isSearching = !this.isSearching - if (this.isSearching) { - let that = this - setTimeout(function () { - that.$refs.keywordRef.focus() - }, 200) - } else { - this.keyword = "" - } - }, - }, - watch: { - keyword: function (v) { - this.serverNames.forEach(function (serverName) { - if (v.length == 0) { - serverName.isShowing = true - return - } - if (serverName.subNames == null || serverName.subNames.length == 0) { - if (!teaweb.match(serverName.name, v)) { - serverName.isShowing = false - } - } else { - let found = false - serverName.subNames.forEach(function (subName) { - if (teaweb.match(subName, v)) { - found = true - } - }) - serverName.isShowing = found - } - }) - } - }, - template: `
+ updateServerName: function (index, serverName) { + window.UPDATING_SERVER_NAME = teaweb.clone(serverName) + let that = this + teaweb.popup("/servers/addServerNamePopup", { + callback: function (resp) { + var serverName = resp.data.serverName + Vue.set(that.serverNames, index, serverName) + } + }); + }, + showSearchBox: function () { + this.isSearching = !this.isSearching + if (this.isSearching) { + let that = this + setTimeout(function () { + that.$refs.keywordRef.focus() + }, 200) + } else { + this.keyword = "" + } + }, + allServerNames: function () { + if (this.serverNames == null) { + return [] + } + let result = [] + this.serverNames.forEach(function (serverName) { + if (serverName.subNames != null && serverName.subNames.length > 0) { + serverName.subNames.forEach(function (subName) { + if (subName != null && subName.length > 0) { + if (!result.$contains(subName)) { + result.push(subName) + } + } + }) + } else if (serverName.name != null && serverName.name.length > 0) { + if (!result.$contains(serverName.name)) { + result.push(serverName.name) + } + } + }) + return result + } + }, + watch: { + keyword: function (v) { + this.serverNames.forEach(function (serverName) { + if (v.length == 0) { + serverName.isShowing = true + return + } + if (serverName.subNames == null || serverName.subNames.length == 0) { + if (!teaweb.match(serverName.name, v)) { + serverName.isShowing = false + } + } else { + let found = false + serverName.subNames.forEach(function (subName) { + if (teaweb.match(subName, v)) { + found = true + } + }) + serverName.isShowing = found + } + }) + } + }, + template: `
diff --git a/web/public/js/components/server/ssl-certs-box.js b/web/public/js/components/server/ssl-certs-box.js index 24ad267c..ee8a04ae 100644 --- a/web/public/js/components/server/ssl-certs-box.js +++ b/web/public/js/components/server/ssl-certs-box.js @@ -5,7 +5,8 @@ Vue.component("ssl-certs-box", { "v-protocol", // 协议:https|tls "v-view-size", // 弹窗尺寸:normal, mini "v-single-mode", // 单证书模式 - "v-description" // 描述文字 + "v-description", // 描述文字 + "v-domains" // 搜索的域名列表或者函数 ], data: function () { let certs = this.vCerts @@ -43,8 +44,8 @@ Vue.component("ssl-certs-box", { // 选择证书 selectCert: function () { let that = this - let width = "50em" - let height = "30em" + let width = "54em" + let height = "32em" let viewSize = this.vViewSize if (viewSize == null) { viewSize = "normal" @@ -53,11 +54,37 @@ Vue.component("ssl-certs-box", { width = "35em" height = "20em" } - teaweb.popup("/servers/certs/selectPopup?viewSize=" + viewSize, { + + let searchingDomains = [] + if (this.vDomains != null) { + if (typeof this.vDomains == "function") { + let resultDomains = this.vDomains() + if (resultDomains != null && typeof resultDomains == "object" && (resultDomains instanceof Array)) { + searchingDomains = resultDomains + } + } else if (typeof this.vDomains == "object" && (this.vDomains instanceof Array)) { + searchingDomains = this.vDomains + } + if (searchingDomains.length > 10000) { + searchingDomains = searchingDomains.slice(0, 10000) + } + } + + let selectedCertIds = this.certs.map(function (cert) { + return cert.id + }) + + teaweb.popup("/servers/certs/selectPopup?viewSize=" + viewSize + "&searchingDomains=" + window.encodeURIComponent(searchingDomains.join(",")) + "&selectedCertIds=" + selectedCertIds.join(","), { width: width, height: height, callback: function (resp) { - that.certs.push(resp.data.cert) + if (resp.data.cert != null) { + that.certs.push(resp.data.cert) + } + if (resp.data.certs != null) { + that.certs.$pushAll(resp.data.certs) + } + that.$forceUpdate() } }) }, diff --git a/web/public/js/components/server/ssl-config-box.js b/web/public/js/components/server/ssl-config-box.js index fa514b9c..e8ba3493 100644 --- a/web/public/js/components/server/ssl-config-box.js +++ b/web/public/js/components/server/ssl-config-box.js @@ -107,12 +107,23 @@ Vue.component("ssl-config-box", { selectedCertIds.push(cert.id.toString()) }) } - teaweb.popup("/servers/certs/selectPopup?selectedCertIds=" + selectedCertIds, { + let serverId = this.vServerId + if (serverId == null) { + serverId = 0 + } + teaweb.popup("/servers/certs/selectPopup?selectedCertIds=" + selectedCertIds + "&serverId=" + serverId, { width: "50em", height: "30em", callback: function (resp) { - that.policy.certRefs.push(resp.data.certRef) - that.policy.certs.push(resp.data.cert) + if (resp.data.cert != null && resp.data.certRef != null) { + that.policy.certRefs.push(resp.data.certRef) + that.policy.certs.push(resp.data.cert) + } + if (resp.data.certs != null && resp.data.certRefs != null) { + that.policy.certRefs.$pushAll(resp.data.certRefs) + that.policy.certs.$pushAll(resp.data.certs) + } + that.$forceUpdate() } }) }, @@ -312,8 +323,15 @@ Vue.component("ssl-config-box", { width: "50em", height: "30em", callback: function (resp) { - that.policy.clientCARefs.push(resp.data.certRef) - that.policy.clientCACerts.push(resp.data.cert) + if (resp.data.cert != null && resp.data.certRef != null) { + that.policy.clientCARefs.push(resp.data.certRef) + that.policy.clientCACerts.push(resp.data.cert) + } + if (resp.data.certs != null && resp.data.certRefs != null) { + that.policy.clientCARefs.$pushAll(resp.data.certRefs) + that.policy.clientCACerts.$pushAll(resp.data.certs) + } + that.$forceUpdate() } }) }, @@ -525,7 +543,7 @@ Vue.component("ssl-config-box", { 客户端认证CA证书
-
+
{{cert.name}} / {{cert.dnsNames}} / 有效至{{formatTime(cert.timeEndAt)}}  
diff --git a/web/views/@default/servers/certs/index.js b/web/views/@default/servers/certs/index.js index 0358e502..fc43ba4c 100644 --- a/web/views/@default/servers/certs/index.js +++ b/web/views/@default/servers/certs/index.js @@ -14,7 +14,6 @@ Tea.context(function () { // 批量上传证书 this.uploadBatch = function () { teaweb.popup("/servers/certs/uploadBatchPopup", { - height: "30em", callback: function () { window.location.reload() } diff --git a/web/views/@default/servers/certs/selectPopup.html b/web/views/@default/servers/certs/selectPopup.html index bbc072e2..8e9d5880 100644 --- a/web/views/@default/servers/certs/selectPopup.html +++ b/web/views/@default/servers/certs/selectPopup.html @@ -1,26 +1,48 @@ {$layout "layout_popup"} -

选择证书

+

选择证书 (当前服务域名:{{searchingDomains[0]}}等{{searchingDomains.length}}个域名

+ +
+
+ +
+ +
+
+ + 所有证书 ({{totalAll}}) + | + 域名匹配证书 ({{totalMatch}}) + +
+ + +
+
+ +
+ -

暂时还没有相关的证书。

+

暂时还没有跟所添加域名匹配的相关证书。

+ @@ -30,6 +52,9 @@ +
证书说明 域名 过期日期
+ + {{cert.name}} {{cert.name}} diff --git a/web/views/@default/servers/certs/selectPopup.js b/web/views/@default/servers/certs/selectPopup.js index cbc5c269..a3075da7 100644 --- a/web/views/@default/servers/certs/selectPopup.js +++ b/web/views/@default/servers/certs/selectPopup.js @@ -11,4 +11,67 @@ Tea.context(function () { } }) } + + this.encodeURL = function (arg) { + return window.encodeURIComponent(arg) + } + + /** + * 复选框 + */ + this.countChecked = 0 + + this.certs.forEach(function (cert) { + cert.isChecked = false + }) + + this.changeAll = function (b) { + let that = this + this.certs.forEach(function (cert) { + cert.isChecked = b + }) + + if (b) { + let countChecked = 0 + this.certs.forEach(function (cert, index) { + if (cert.isChecked && !that.certInfos[index].isSelected) { + countChecked++ + } + }) + this.countChecked = countChecked + } else { + this.countChecked = 0 + } + } + + this.changeCertChecked = function () { + let countChecked = 0 + this.certs.forEach(function (cert) { + if (cert.isChecked) { + countChecked++ + } + }) + this.countChecked = countChecked + } + + this.confirmChecked = function () { + let resultCerts = [] + let resultCertRefs = [] + this.certs.forEach(function (cert) { + if (cert.isChecked) { + resultCerts.push(cert) + resultCertRefs.push({ + isOn: true, + certId: cert.id + }) + } + }) + NotifyPopup({ + code: 200, + data: { + certs: resultCerts, + certRefs: resultCertRefs + } + }) + } }) \ No newline at end of file diff --git a/web/views/@default/servers/create.html b/web/views/@default/servers/create.html index a3f77abe..349ca288 100644 --- a/web/views/@default/servers/create.html +++ b/web/views/@default/servers/create.html @@ -7,14 +7,14 @@

新网站服务主要信息:

- + - + - + @@ -77,7 +77,7 @@ - + diff --git a/web/views/@default/servers/create.js b/web/views/@default/servers/create.js index 6bc432b1..eecb2b67 100644 --- a/web/views/@default/servers/create.js +++ b/web/views/@default/servers/create.js @@ -96,4 +96,11 @@ Tea.context(function () { this.plans = resp.data.plans }) } + + /** + * 证书相关 + */ + this.findServerNames = function () { + return this.$refs.serverNameBox.allServerNames() + } }) \ No newline at end of file
所属用户所属用户

当前服务所属平台用户。

选择套餐选择套餐
部署的集群 *部署的集群 *
@@ -47,7 +47,7 @@
{{tlsProtocolName.toUpperCase()}}证书 - +
绑定端口 *绑定端口 *