mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
feat: display info of multiple certificates in server tab.
This commit is contained in:
parent
ada02323d8
commit
e1a5521f4a
9 changed files with 54 additions and 61 deletions
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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"
|
||||
/>
|
||||
|
|
|
@ -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 />
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -12,7 +12,7 @@ import type { CertificateInfo } from '@/api/cert'
|
|||
withDefaults(defineProps<{
|
||||
enabled: boolean
|
||||
certInfo?: {
|
||||
[key: number]: CertificateInfo
|
||||
[key: number]: CertificateInfo[]
|
||||
}
|
||||
context: 'http' | 'stream'
|
||||
}>(), {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue