Support IPv4 HTTP public gateway entries
This commit is contained in:
1 parent
6f01d31f97
commit
6d5973bea3
11 files changed
+146
-32
No files matched your search
@@ -961,13 +961,13 @@
|
||||
"publicEntryTitle": "Public entry",
|
||||
"publicEntryDesc": "Scheme, host, and port define the public Base URL used by the OIDC issuer, Feishu identity, and tunnel callbacks.",
|
||||
"scheme": "Scheme",
|
||||
"host": "Host",
|
||||
"host": "Domain / IPv4 address",
|
||||
"port": "Port",
|
||||
"publicBase": "Public Base URL",
|
||||
"publicBaseHint": "OIDC issuer is Base URL + /id; tunnel callbacks inherit the same base.",
|
||||
"publicBaseHint": "Generated from scheme, address and port; no input needed. Feishu / OIDC callbacks use this address.",
|
||||
"httpRisk": "HTTP is plaintext. Prefer HTTPS in production; HTTP is for intranet or temporary ICP workarounds.",
|
||||
"saveEntry": "Save public entry",
|
||||
"hostRequired": "Host is required",
|
||||
"hostRequired": "Enter a domain or IPv4 address",
|
||||
"certListTitle": "Certificates",
|
||||
"addCert": "Add certificate",
|
||||
"replaceCert": "Replace",
|
||||
|
||||
@@ -961,13 +961,13 @@
|
||||
"publicEntryTitle": "公网入口",
|
||||
"publicEntryDesc": "协议、域名与端口决定 OIDC 发行者、飞书身份与专线对外地址;保存后各页只读继承,不再写死 https。",
|
||||
"scheme": "协议",
|
||||
"host": "域名",
|
||||
"host": "域名 / IPv4 地址",
|
||||
"port": "端口",
|
||||
"publicBase": "对外 Base URL",
|
||||
"publicBaseHint": "飞书 / OIDC 发行者为 Base URL + /id;专线回调亦由此派生。",
|
||||
"publicBaseHint": "自动由协议、地址和端口生成,无需填写;飞书 / OIDC 回调引用此地址。",
|
||||
"httpRisk": "HTTP 为明文传输,仅建议内网或未备案临时绕行场景;生产环境优先 HTTPS。",
|
||||
"saveEntry": "保存公网入口",
|
||||
"hostRequired": "请填写域名",
|
||||
"hostRequired": "请填写域名或 IPv4 地址",
|
||||
"certListTitle": "证书",
|
||||
"addCert": "添加证书",
|
||||
"replaceCert": "更换",
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
<el-form label-position="top" @submit.prevent="savePublicEntry">
|
||||
<el-form-item :label="$t('tls.scheme')">
|
||||
<el-radio-group v-model="entry.scheme" class="scheme-group" @change="onSchemeChange">
|
||||
<el-radio-button value="https">HTTPS</el-radio-button>
|
||||
<el-radio-button value="http">HTTP</el-radio-button>
|
||||
<el-radio-button value="https">HTTPS</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-alert
|
||||
@@ -27,7 +27,7 @@
|
||||
<el-row :gutter="12">
|
||||
<el-col :xs="24" :sm="16">
|
||||
<el-form-item :label="$t('tls.host')" required>
|
||||
<el-input v-model.trim="entry.host" placeholder="vpn.example.com" maxlength="253" />
|
||||
<el-input v-model.trim="entry.host" placeholder="vpn.example.com / 121.4.111.208" maxlength="253" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="8">
|
||||
@@ -37,7 +37,7 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item :label="$t('tls.publicBase')">
|
||||
<el-input :model-value="publicBase" readonly>
|
||||
<el-input :model-value="publicBase" readonly class="derived-base">
|
||||
<template #append>
|
||||
<el-button @click="copyBase">{{ $t('common.copy') }}</el-button>
|
||||
</template>
|
||||
@@ -231,10 +231,10 @@ const certDialog = ref(false)
|
||||
const certSubmitting = ref(false)
|
||||
|
||||
const entry = reactive({
|
||||
scheme: 'https',
|
||||
scheme: 'http',
|
||||
host: '',
|
||||
port: 443,
|
||||
mode: 'autocert',
|
||||
port: 80,
|
||||
mode: 'nginx',
|
||||
})
|
||||
|
||||
const certForm = reactive({
|
||||
@@ -248,10 +248,7 @@ const certForm = reactive({
|
||||
})
|
||||
|
||||
const publicBase = computed(() => {
|
||||
const local = buildPublicBase(entry)
|
||||
const remote = tlsStatus.value?.configured_public_base || tlsStatus.value?.public_base || ''
|
||||
// Prefer live form preview while editing; fall back to server after load.
|
||||
return local || remote
|
||||
return buildPublicBase(entry)
|
||||
})
|
||||
|
||||
const certRows = computed(() => {
|
||||
@@ -273,6 +270,7 @@ const certRows = computed(() => {
|
||||
|
||||
function onSchemeChange() {
|
||||
entry.port = defaultPort(entry.scheme)
|
||||
if (entry.scheme === 'http') entry.mode = 'nginx'
|
||||
}
|
||||
|
||||
function resetCertForm() {
|
||||
@@ -372,11 +370,11 @@ async function loadTLS() {
|
||||
const { data } = await api.get('/system/tls')
|
||||
tlsStatus.value = data
|
||||
entry.host = data.configured_domain || data.domain || data.host || ''
|
||||
const scheme = data.configured_scheme || data.scheme || 'https'
|
||||
const scheme = entry.host ? (data.configured_scheme || data.scheme || 'https') : 'http'
|
||||
entry.scheme = scheme === 'http' ? 'http' : 'https'
|
||||
const port = Number(data.configured_port || data.port)
|
||||
entry.port = port > 0 ? port : defaultPort(entry.scheme)
|
||||
entry.mode = data.configured_mode || data.mode || 'autocert'
|
||||
entry.mode = entry.host ? (data.configured_mode || data.mode || 'autocert') : 'nginx'
|
||||
} catch (e) { ElMessage.error(e.response?.data?.error || t('tls.loadFailed')) }
|
||||
finally { tlsLoading.value = false }
|
||||
}
|
||||
@@ -499,6 +497,8 @@ onMounted(() => { if (!auth.mustChange) refreshAll() })
|
||||
.settings-column :deep(.el-card__header) { background: #f9fbfe; color: #21344e; }
|
||||
.card-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
|
||||
.tls-hint { color: var(--text-secondary); line-height: 1.6; font-size: 13px; margin-top: 6px; }
|
||||
.derived-base :deep(.el-input__wrapper) { background: var(--el-fill-color-light); }
|
||||
.derived-base :deep(.el-input__inner) { color: var(--el-text-color-secondary); cursor: default; }
|
||||
.nginx-preview { max-height: 280px; overflow: auto; background: #172239; color: #e7eefc; border-radius: 8px; padding: 14px; font-size: 12px; line-height: 1.5; margin-top: 8px; }
|
||||
.scheme-group { width: 100%; }
|
||||
.scheme-group :deep(.el-radio-button) { flex: 1; }
|
||||
|
||||
Reference in new issue
Block a user