feat(tls): manage ACME domain and add desktop client settings
This commit is contained in:
1 parent
003f755b37
commit
00f6c876cf
85 files changed
+7276
-1
No files matched your search
@@ -43,6 +43,32 @@
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :lg="14" v-if="auth.isAdmin()">
|
||||
<el-card class="page-card" shadow="never" style="margin-bottom:16px">
|
||||
<template #header><b>{{ $t('tls.title') }}</b></template>
|
||||
<el-alert type="info" :closable="false" :title="$t('tls.description')" style="margin-bottom:16px" />
|
||||
<el-form @submit.prevent="saveTLSDomain" label-position="top">
|
||||
<el-form-item :label="$t('tls.domain')">
|
||||
<el-input v-model.trim="tlsDomain" placeholder="test-link.appx365.com" maxlength="253" />
|
||||
</el-form-item>
|
||||
<el-button type="primary" :loading="tlsSaving" @click="saveTLSDomain">{{ $t('tls.saveDomain') }}</el-button>
|
||||
</el-form>
|
||||
<el-alert v-if="tlsStatus?.restart_required" type="warning" :closable="false" :title="$t('tls.restartRequired')" style="margin:12px 0" />
|
||||
<el-descriptions :column="1" size="small" border v-if="tlsStatus">
|
||||
<el-descriptions-item :label="$t('tls.domain')">{{ tlsStatus.configured_domain || $t('tls.notConfigured') }}</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('tls.activeDomain')">{{ tlsStatus.domain || $t('tls.notConfigured') }}</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('tls.dns')">{{ tlsStatus.dns?.join(', ') || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('tls.certificate')">
|
||||
<el-tag :type="tlsStatus.certificate_valid ? 'success' : 'warning'">{{ tlsStatus.certificate_valid ? $t('tls.valid') : tlsStatus.enabled ? $t('tls.pending') : $t('tls.notConfigured') }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="tlsStatus.certificate_cached" :label="$t('tls.issuer')">{{ tlsStatus.issuer || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="tlsStatus.certificate_cached" :label="$t('tls.expires')">{{ new Date(tlsStatus.not_after).toLocaleString() }}</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('tls.renewal')">{{ tlsStatus.enabled ? $t('tls.automatic') : '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('tls.ports')">{{ tlsStatus.http_address || ':80' }} / {{ tlsStatus.https_address || ':443' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<p class="tls-hint">{{ $t('tls.setupHint') }}</p>
|
||||
<el-button :loading="tlsLoading" @click="loadTLS">{{ $t('tls.refresh') }}</el-button>
|
||||
<el-button v-if="tlsStatus?.enabled" type="primary" tag="a" :href="`https://${tlsStatus.domain}/api/health`" target="_blank" rel="noopener noreferrer">{{ $t('tls.openHttps') }}</el-button>
|
||||
</el-card>
|
||||
<el-card class="page-card" shadow="never">
|
||||
<template #header><b>{{ $t('settings.auditTitle') }}</b></template>
|
||||
<el-empty :description="$t('settings.auditMigrated')">
|
||||
@@ -82,6 +108,30 @@ const mfaCanvas = ref(null)
|
||||
const mfaLoading = ref(false)
|
||||
const backupVisible = ref(false)
|
||||
const backupCodes = ref([])
|
||||
const tlsStatus = ref(null)
|
||||
const tlsLoading = ref(false)
|
||||
const tlsSaving = ref(false)
|
||||
const tlsDomain = ref('')
|
||||
|
||||
async function loadTLS() {
|
||||
tlsLoading.value = true
|
||||
try {
|
||||
const { data } = await api.get('/system/tls')
|
||||
tlsStatus.value = data
|
||||
tlsDomain.value = data.configured_domain || data.domain || ''
|
||||
} catch (e) { ElMessage.error(e.response?.data?.error || t('tls.loadFailed')) }
|
||||
finally { tlsLoading.value = false }
|
||||
}
|
||||
|
||||
async function saveTLSDomain() {
|
||||
tlsSaving.value = true
|
||||
try {
|
||||
const { data } = await api.put('/system/tls/domain', { domain: tlsDomain.value })
|
||||
tlsStatus.value = data.status
|
||||
ElMessage.success(data.restart_required ? t('tls.restartRequired') : t('tls.saved'))
|
||||
} catch (e) { ElMessage.error(e.response?.data?.error || t('tls.saveFailed')) }
|
||||
finally { tlsSaving.value = false }
|
||||
}
|
||||
|
||||
async function changePwd() {
|
||||
if (pwd.value.new_password !== pwd.value.confirm) return ElMessage.warning(t('settings.passwordMismatch'))
|
||||
@@ -98,6 +148,7 @@ async function changePwd() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (auth.isAdmin() && !auth.mustChange) loadTLS()
|
||||
try {
|
||||
const status = await api.get('/mfa/status')
|
||||
mfa.value.enabled = status.data.enabled
|
||||
@@ -148,4 +199,5 @@ function copyBackup() {
|
||||
color: var(--text-primary); text-align: center; padding: 6px;
|
||||
background: var(--bg-card); border-radius: 4px;
|
||||
}
|
||||
.tls-hint { color: var(--text-secondary); line-height: 1.6; font-size: 13px; }
|
||||
</style>
|
||||
Reference in new issue
Block a user