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 @@
新网站服务主要信息:
- | 所属用户 |
+ 所属用户 |
|
- | 选择套餐 |
+ 选择套餐 |
|
- | 部署的集群 * |
+ 部署的集群 * |
@@ -47,7 +47,7 @@
|
| {{tlsProtocolName.toUpperCase()}}证书 |
-
+
|
@@ -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
| |