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) {
|
func GetDomain(c *gin.Context) {
|
||||||
rewriteName, ok := c.Get("rewriteConfigFileName")
|
rewriteName, ok := c.Get("rewriteConfigFileName")
|
||||||
|
|
||||||
name := c.Param("name")
|
name := c.Param("name")
|
||||||
|
|
||||||
// for modify filename
|
// for modify filename
|
||||||
|
@ -84,14 +83,12 @@ func GetDomain(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
enabled := true
|
enabled := true
|
||||||
|
|
||||||
if _, err := os.Stat(nginx.GetConfPath("sites-enabled", name)); os.IsNotExist(err) {
|
if _, err := os.Stat(nginx.GetConfPath("sites-enabled", name)); os.IsNotExist(err) {
|
||||||
enabled = false
|
enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
g := query.ChatGPTLog
|
g := query.ChatGPTLog
|
||||||
chatgpt, err := g.Where(g.Name.Eq(path)).FirstOrCreate()
|
chatgpt, err := g.Where(g.Name.Eq(path)).FirstOrCreate()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.ErrHandler(c, err)
|
api.ErrHandler(c, err)
|
||||||
return
|
return
|
||||||
|
@ -103,14 +100,12 @@ func GetDomain(c *gin.Context) {
|
||||||
|
|
||||||
s := query.Site
|
s := query.Site
|
||||||
site, err := s.Where(s.Path.Eq(path)).FirstOrInit()
|
site, err := s.Where(s.Path.Eq(path)).FirstOrInit()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.ErrHandler(c, err)
|
api.ErrHandler(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
certModel, err := model.FirstCert(name)
|
certModel, err := model.FirstCert(name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn(err)
|
logger.Warn(err)
|
||||||
}
|
}
|
||||||
|
@ -136,28 +131,21 @@ func GetDomain(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nginxConfig, err := nginx.ParseNgxConfig(path)
|
nginxConfig, err := nginx.ParseNgxConfig(path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.ErrHandler(c, err)
|
api.ErrHandler(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
certInfoMap := make(map[int]*cert.Info)
|
certInfoMap := make(map[int][]*cert.Info)
|
||||||
|
|
||||||
for serverIdx, server := range nginxConfig.Servers {
|
for serverIdx, server := range nginxConfig.Servers {
|
||||||
for _, directive := range server.Directives {
|
for _, directive := range server.Directives {
|
||||||
if directive.Directive == "ssl_certificate" {
|
if directive.Directive == "ssl_certificate" {
|
||||||
|
|
||||||
pubKey, err := cert.GetCertInfo(directive.Params)
|
pubKey, err := cert.GetCertInfo(directive.Params)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to get certificate information", err)
|
logger.Error("Failed to get certificate information", err)
|
||||||
break
|
continue
|
||||||
}
|
}
|
||||||
|
certInfoMap[serverIdx] = append(certInfoMap[serverIdx], pubKey)
|
||||||
certInfoMap[serverIdx] = pubKey
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
output := nginx.TestConf()
|
||||||
|
|
||||||
if nginx.GetLogLevel(output) > nginx.Warn {
|
if nginx.GetLogLevel(output) > nginx.Warn {
|
||||||
_ = os.Remove(enabledConfigFilePath)
|
_ = os.Remove(enabledConfigFilePath)
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
@ -318,16 +305,13 @@ func EnableDomain(c *gin.Context) {
|
||||||
|
|
||||||
func DisableDomain(c *gin.Context) {
|
func DisableDomain(c *gin.Context) {
|
||||||
enabledConfigFilePath := nginx.GetConfPath("sites-enabled", c.Param("name"))
|
enabledConfigFilePath := nginx.GetConfPath("sites-enabled", c.Param("name"))
|
||||||
|
|
||||||
_, err := os.Stat(enabledConfigFilePath)
|
_, err := os.Stat(enabledConfigFilePath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.ErrHandler(c, err)
|
api.ErrHandler(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.Remove(enabledConfigFilePath)
|
err = os.Remove(enabledConfigFilePath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.ErrHandler(c, err)
|
api.ErrHandler(c, err)
|
||||||
return
|
return
|
||||||
|
@ -342,7 +326,6 @@ func DisableDomain(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
output := nginx.Reload()
|
output := nginx.Reload()
|
||||||
|
|
||||||
if nginx.GetLogLevel(output) > nginx.Warn {
|
if nginx.GetLogLevel(output) > nginx.Warn {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"message": output,
|
"message": output,
|
||||||
|
@ -360,7 +343,6 @@ func DeleteDomain(c *gin.Context) {
|
||||||
name := c.Param("name")
|
name := c.Param("name")
|
||||||
availablePath := nginx.GetConfPath("sites-available", name)
|
availablePath := nginx.GetConfPath("sites-available", name)
|
||||||
enabledPath := nginx.GetConfPath("sites-enabled", name)
|
enabledPath := nginx.GetConfPath("sites-enabled", name)
|
||||||
|
|
||||||
if _, err = os.Stat(availablePath); os.IsNotExist(err) {
|
if _, err = os.Stat(availablePath); os.IsNotExist(err) {
|
||||||
c.JSON(http.StatusNotFound, gin.H{
|
c.JSON(http.StatusNotFound, gin.H{
|
||||||
"message": "site not found",
|
"message": "site not found",
|
||||||
|
@ -379,7 +361,6 @@ func DeleteDomain(c *gin.Context) {
|
||||||
_ = certModel.Remove()
|
_ = certModel.Remove()
|
||||||
|
|
||||||
err = os.Remove(availablePath)
|
err = os.Remove(availablePath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.ErrHandler(c, err)
|
api.ErrHandler(c, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -16,6 +16,6 @@ type Site struct {
|
||||||
AutoCert bool `json:"auto_cert"`
|
AutoCert bool `json:"auto_cert"`
|
||||||
ChatGPTMessages []openai.ChatCompletionMessage `json:"chatgpt_messages,omitempty"`
|
ChatGPTMessages []openai.ChatCompletionMessage `json:"chatgpt_messages,omitempty"`
|
||||||
Tokenized *nginx.NgxConfig `json:"tokenized,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"`
|
Filepath string `json:"filepath"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,7 @@ export interface Site {
|
||||||
auto_cert: boolean
|
auto_cert: boolean
|
||||||
chatgpt_messages: ChatComplicationMessage[]
|
chatgpt_messages: ChatComplicationMessage[]
|
||||||
tokenized?: NgxConfig
|
tokenized?: NgxConfig
|
||||||
cert_info?: {
|
cert_info?: Record<number, CertificateInfo[]>
|
||||||
[key: number]: CertificateInfo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AutoCertRequest {
|
export interface AutoCertRequest {
|
||||||
|
|
|
@ -126,7 +126,10 @@ const isManaged = computed(() => {
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
>
|
>
|
||||||
<AFormItem :label="$gettext('Certificate Status')">
|
<AFormItem :label="$gettext('Certificate Status')">
|
||||||
<CertInfo :cert="data.certificate_info" />
|
<CertInfo
|
||||||
|
:cert="data.certificate_info"
|
||||||
|
class="max-w-96"
|
||||||
|
/>
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
</AForm>
|
</AForm>
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ const ngx_config: NgxConfig = reactive({
|
||||||
servers: [],
|
servers: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const cert_info_map: Record<string, CertificateInfo> = reactive({})
|
const certInfoMap: Ref<Record<number, CertificateInfo[]>> = ref({})
|
||||||
|
|
||||||
const auto_cert = ref(false)
|
const auto_cert = ref(false)
|
||||||
const enabled = ref(false)
|
const enabled = ref(false)
|
||||||
|
@ -62,9 +62,6 @@ function handle_response(r: Site) {
|
||||||
if (r.advanced)
|
if (r.advanced)
|
||||||
advance_mode.value = true
|
advance_mode.value = true
|
||||||
|
|
||||||
Object.keys(cert_info_map).forEach((v: string) => {
|
|
||||||
delete cert_info_map[v]
|
|
||||||
})
|
|
||||||
parse_error_status.value = false
|
parse_error_status.value = false
|
||||||
parse_error_message.value = ''
|
parse_error_message.value = ''
|
||||||
filename.value = r.name
|
filename.value = r.name
|
||||||
|
@ -74,8 +71,8 @@ function handle_response(r: Site) {
|
||||||
auto_cert.value = r.auto_cert
|
auto_cert.value = r.auto_cert
|
||||||
history_chatgpt_record.value = r.chatgpt_messages
|
history_chatgpt_record.value = r.chatgpt_messages
|
||||||
data.value = r
|
data.value = r
|
||||||
|
certInfoMap.value = r.cert_info || {}
|
||||||
Object.assign(ngx_config, r.tokenized)
|
Object.assign(ngx_config, r.tokenized)
|
||||||
Object.assign(cert_info_map, r.cert_info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
@ -230,7 +227,7 @@ provide('data', data)
|
||||||
>
|
>
|
||||||
<NgxConfigEditor
|
<NgxConfigEditor
|
||||||
v-model:auto-cert="auto_cert"
|
v-model:auto-cert="auto_cert"
|
||||||
:cert-info="cert_info_map"
|
:cert-info="certInfoMap"
|
||||||
:enabled="enabled"
|
:enabled="enabled"
|
||||||
@callback="save"
|
@callback="save"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -8,7 +8,7 @@ const props = defineProps<{
|
||||||
configName: string
|
configName: string
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
currentServerIndex: number
|
currentServerIndex: number
|
||||||
certInfo?: CertificateInfo
|
certInfo?: CertificateInfo[]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits(['update:enabled'])
|
const emit = defineEmits(['update:enabled'])
|
||||||
|
@ -25,13 +25,23 @@ const enabled = computed({
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2>
|
<h3>
|
||||||
{{ $gettext('Certificate Status') }}
|
{{ $gettext('Certificate Status') }}
|
||||||
</h2>
|
</h3>
|
||||||
<CertInfo
|
|
||||||
:cert="certInfo"
|
<ARow
|
||||||
|
:gutter="[16, 16]"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
/>
|
>
|
||||||
|
<ACol
|
||||||
|
v-for="(c, index) in certInfo"
|
||||||
|
:key="index"
|
||||||
|
:xs="24"
|
||||||
|
:sm="12"
|
||||||
|
>
|
||||||
|
<CertInfo :cert="c" />
|
||||||
|
</ACol>
|
||||||
|
</ARow>
|
||||||
|
|
||||||
<ChangeCert />
|
<ChangeCert />
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,46 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons-vue'
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import type { CertificateInfo } from '@/api/cert'
|
import type { CertificateInfo } from '@/api/cert'
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
cert?: CertificateInfo
|
cert?: CertificateInfo
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const isValid = computed(() => dayjs().isAfter(props.cert?.not_before) && dayjs().isBefore(props.cert?.not_after))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<ACard
|
||||||
v-if="cert"
|
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>
|
<p>
|
||||||
{{ $gettext('Intermediate Certification Authorities: %{issuer}', { issuer: cert.issuer_name }) }}
|
{{ $gettext('Intermediate Certification Authorities: %{issuer}', { issuer: cert.issuer_name }) }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
|
||||||
{{ $gettext('Subject Name: %{subject}', { subject: cert.subject_name }) }}
|
|
||||||
</p>
|
|
||||||
<p>
|
<p>
|
||||||
{{ $gettext('Expired At: %{date}', { date: dayjs(cert.not_after).format('YYYY-MM-DD HH:mm:ss').toString() }) }}
|
{{ $gettext('Expired At: %{date}', { date: dayjs(cert.not_after).format('YYYY-MM-DD HH:mm:ss').toString() }) }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p class="mb-0">
|
||||||
{{ $gettext('Not Valid Before: %{date}', { date: dayjs(cert.not_before).format('YYYY-MM-DD HH:mm:ss').toString() }) }}
|
{{ $gettext('Not Valid Before: %{date}', { date: dayjs(cert.not_before).format('YYYY-MM-DD HH:mm:ss').toString() }) }}
|
||||||
</p>
|
</p>
|
||||||
<div class="status">
|
</ACard>
|
||||||
<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>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -12,7 +12,7 @@ import type { CheckedType } from '@/types'
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
autoCert?: boolean
|
autoCert?: boolean
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
certInfo?: Record<number, CertificateInfo>
|
certInfo?: Record<number, CertificateInfo[]>
|
||||||
context?: 'http' | 'stream'
|
context?: 'http' | 'stream'
|
||||||
}>(), {
|
}>(), {
|
||||||
autoCert: false,
|
autoCert: false,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import type { CertificateInfo } from '@/api/cert'
|
||||||
withDefaults(defineProps<{
|
withDefaults(defineProps<{
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
certInfo?: {
|
certInfo?: {
|
||||||
[key: number]: CertificateInfo
|
[key: number]: CertificateInfo[]
|
||||||
}
|
}
|
||||||
context: 'http' | 'stream'
|
context: 'http' | 'stream'
|
||||||
}>(), {
|
}>(), {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue