feat: display info of multiple certificates in server tab.

This commit is contained in:
Jacky 2024-07-24 16:33:45 +08:00
parent ada02323d8
commit e1a5521f4a
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D
9 changed files with 54 additions and 61 deletions

View file

@ -66,7 +66,6 @@ func GetDomains(c *gin.Context) {
func GetDomain(c *gin.Context) {
rewriteName, ok := c.Get("rewriteConfigFileName")
name := c.Param("name")
// for modify filename
@ -84,14 +83,12 @@ func GetDomain(c *gin.Context) {
}
enabled := true
if _, err := os.Stat(nginx.GetConfPath("sites-enabled", name)); os.IsNotExist(err) {
enabled = false
}
g := query.ChatGPTLog
chatgpt, err := g.Where(g.Name.Eq(path)).FirstOrCreate()
if err != nil {
api.ErrHandler(c, err)
return
@ -103,14 +100,12 @@ func GetDomain(c *gin.Context) {
s := query.Site
site, err := s.Where(s.Path.Eq(path)).FirstOrInit()
if err != nil {
api.ErrHandler(c, err)
return
}
certModel, err := model.FirstCert(name)
if err != nil {
logger.Warn(err)
}
@ -136,28 +131,21 @@ func GetDomain(c *gin.Context) {
}
nginxConfig, err := nginx.ParseNgxConfig(path)
if err != nil {
api.ErrHandler(c, err)
return
}
certInfoMap := make(map[int]*cert.Info)
certInfoMap := make(map[int][]*cert.Info)
for serverIdx, server := range nginxConfig.Servers {
for _, directive := range server.Directives {
if directive.Directive == "ssl_certificate" {
pubKey, err := cert.GetCertInfo(directive.Params)
if err != nil {
logger.Error("Failed to get certificate information", err)
break
continue
}
certInfoMap[serverIdx] = pubKey
break
certInfoMap[serverIdx] = append(certInfoMap[serverIdx], pubKey)
}
}
}
@ -291,9 +279,8 @@ func EnableDomain(c *gin.Context) {
}
}
// Test nginx config, if not pass then disable the site.
// Test nginx config, if not pass, then disable the site.
output := nginx.TestConf()
if nginx.GetLogLevel(output) > nginx.Warn {
_ = os.Remove(enabledConfigFilePath)
c.JSON(http.StatusInternalServerError, gin.H{
@ -318,16 +305,13 @@ func EnableDomain(c *gin.Context) {
func DisableDomain(c *gin.Context) {
enabledConfigFilePath := nginx.GetConfPath("sites-enabled", c.Param("name"))
_, err := os.Stat(enabledConfigFilePath)
if err != nil {
api.ErrHandler(c, err)
return
}
err = os.Remove(enabledConfigFilePath)
if err != nil {
api.ErrHandler(c, err)
return
@ -342,7 +326,6 @@ func DisableDomain(c *gin.Context) {
}
output := nginx.Reload()
if nginx.GetLogLevel(output) > nginx.Warn {
c.JSON(http.StatusInternalServerError, gin.H{
"message": output,
@ -360,7 +343,6 @@ func DeleteDomain(c *gin.Context) {
name := c.Param("name")
availablePath := nginx.GetConfPath("sites-available", name)
enabledPath := nginx.GetConfPath("sites-enabled", name)
if _, err = os.Stat(availablePath); os.IsNotExist(err) {
c.JSON(http.StatusNotFound, gin.H{
"message": "site not found",
@ -379,7 +361,6 @@ func DeleteDomain(c *gin.Context) {
_ = certModel.Remove()
err = os.Remove(availablePath)
if err != nil {
api.ErrHandler(c, err)
return

View file

@ -16,6 +16,6 @@ type Site struct {
AutoCert bool `json:"auto_cert"`
ChatGPTMessages []openai.ChatCompletionMessage `json:"chatgpt_messages,omitempty"`
Tokenized *nginx.NgxConfig `json:"tokenized,omitempty"`
CertInfo map[int]*cert.Info `json:"cert_info,omitempty"`
CertInfo map[int][]*cert.Info `json:"cert_info,omitempty"`
Filepath string `json:"filepath"`
}

View file

@ -15,9 +15,7 @@ export interface Site {
auto_cert: boolean
chatgpt_messages: ChatComplicationMessage[]
tokenized?: NgxConfig
cert_info?: {
[key: number]: CertificateInfo
}
cert_info?: Record<number, CertificateInfo[]>
}
export interface AutoCertRequest {

View file

@ -126,7 +126,10 @@ const isManaged = computed(() => {
layout="vertical"
>
<AFormItem :label="$gettext('Certificate Status')">
<CertInfo :cert="data.certificate_info" />
<CertInfo
:cert="data.certificate_info"
class="max-w-96"
/>
</AFormItem>
</AForm>

View file

@ -29,7 +29,7 @@ const ngx_config: NgxConfig = reactive({
servers: [],
})
const cert_info_map: Record<string, CertificateInfo> = reactive({})
const certInfoMap: Ref<Record<number, CertificateInfo[]>> = ref({})
const auto_cert = ref(false)
const enabled = ref(false)
@ -62,9 +62,6 @@ function handle_response(r: Site) {
if (r.advanced)
advance_mode.value = true
Object.keys(cert_info_map).forEach((v: string) => {
delete cert_info_map[v]
})
parse_error_status.value = false
parse_error_message.value = ''
filename.value = r.name
@ -74,8 +71,8 @@ function handle_response(r: Site) {
auto_cert.value = r.auto_cert
history_chatgpt_record.value = r.chatgpt_messages
data.value = r
certInfoMap.value = r.cert_info || {}
Object.assign(ngx_config, r.tokenized)
Object.assign(cert_info_map, r.cert_info)
}
function init() {
@ -230,7 +227,7 @@ provide('data', data)
>
<NgxConfigEditor
v-model:auto-cert="auto_cert"
:cert-info="cert_info_map"
:cert-info="certInfoMap"
:enabled="enabled"
@callback="save"
/>

View file

@ -8,7 +8,7 @@ const props = defineProps<{
configName: string
enabled: boolean
currentServerIndex: number
certInfo?: CertificateInfo
certInfo?: CertificateInfo[]
}>()
const emit = defineEmits(['update:enabled'])
@ -25,13 +25,23 @@ const enabled = computed({
<template>
<div>
<h2>
<h3>
{{ $gettext('Certificate Status') }}
</h2>
<CertInfo
:cert="certInfo"
</h3>
<ARow
:gutter="[16, 16]"
class="mb-4"
/>
>
<ACol
v-for="(c, index) in certInfo"
:key="index"
:xs="24"
:sm="12"
>
<CertInfo :cert="c" />
</ACol>
</ARow>
<ChangeCert />

View file

@ -1,42 +1,46 @@
<script setup lang="ts">
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons-vue'
import dayjs from 'dayjs'
import type { CertificateInfo } from '@/api/cert'
defineProps<{
const props = defineProps<{
cert?: CertificateInfo
}>()
const isValid = computed(() => dayjs().isAfter(props.cert?.not_before) && dayjs().isBefore(props.cert?.not_after))
</script>
<template>
<div
<ACard
v-if="cert"
class="cert-info"
size="small"
>
<template #title>
{{ cert.subject_name }}
<ATag
v-if="isValid"
color="success"
class="ml-2"
>
{{ $gettext('Valid') }}
</ATag>
<ATag
v-else
color="error"
class="ml-2"
>
{{ $gettext('Expired') }}
</ATag>
</template>
<p>
{{ $gettext('Intermediate Certification Authorities: %{issuer}', { issuer: cert.issuer_name }) }}
</p>
<p>
{{ $gettext('Subject Name: %{subject}', { subject: cert.subject_name }) }}
</p>
<p>
{{ $gettext('Expired At: %{date}', { date: dayjs(cert.not_after).format('YYYY-MM-DD HH:mm:ss').toString() }) }}
</p>
<p>
<p class="mb-0">
{{ $gettext('Not Valid Before: %{date}', { date: dayjs(cert.not_before).format('YYYY-MM-DD HH:mm:ss').toString() }) }}
</p>
<div class="status">
<template v-if="dayjs().isBefore(cert.not_before) || dayjs().isAfter(cert.not_after)">
<CloseCircleOutlined class="text-red-600" />
<span class="ml-2">{{ $gettext('Certificate has expired') }}</span>
</template>
<template v-else>
<CheckCircleOutlined class="text-green-500" />
<span class="ml-2">{{ $gettext('Certificate is valid') }}</span>
</template>
</div>
</div>
</ACard>
</template>
<style lang="less" scoped>

View file

@ -12,7 +12,7 @@ import type { CheckedType } from '@/types'
const props = withDefaults(defineProps<{
autoCert?: boolean
enabled: boolean
certInfo?: Record<number, CertificateInfo>
certInfo?: Record<number, CertificateInfo[]>
context?: 'http' | 'stream'
}>(), {
autoCert: false,

View file

@ -12,7 +12,7 @@ import type { CertificateInfo } from '@/api/cert'
withDefaults(defineProps<{
enabled: boolean
certInfo?: {
[key: number]: CertificateInfo
[key: number]: CertificateInfo[]
}
context: 'http' | 'stream'
}>(), {