feat(client): add authorized WireGuard device enrollment and desktop connection

This commit is contained in:
opsx committed 2026-10-21 14:53:55 +08:00
1 parent d2f1f5040e
commit 6dd3c7dd45
25 files changed
+3274 -131

No files matched your search

+5 -4
View File
@@ -38,7 +38,7 @@
<el-table-column prop="source" :label="$t('common.source')" width="90" />
<el-table-column :label="$t('vpnUsers.otpMfa')" width="130">
<template #default="{ row }">
<template v-if="isOpenVPN(row.tunnel_id)">
<template v-if="supportsMFA(row.tunnel_id)">
<el-tag :type="row.mfa_enabled ? 'success' : 'info'" size="small">
{{ row.mfa_enabled ? $t('vpnUsers.bound') : $t('vpnUsers.unbound') }}
</el-tag>
@@ -61,8 +61,8 @@
</el-table-column>
<el-table-column :label="$t('common.operation')" width="280">
<template #default="{ row }">
<el-button link size="small" @click="download(row)">{{ $t('vpnUsers.downloadConfig') }}</el-button>
<el-button v-if="isOpenVPN(row.tunnel_id)" link size="small" type="primary" @click="openOTPManager(row)">{{ $t('vpnUsers.otpManagement') }}</el-button>
<el-button v-if="tunnels.find(x => x.id === row.tunnel_id)?.protocol !== 'wireguard'" link size="small" @click="download(row)">{{ $t('vpnUsers.downloadConfig') }}</el-button>
<el-button v-if="supportsMFA(row.tunnel_id)" link size="small" type="primary" @click="openOTPManager(row)">{{ $t('vpnUsers.otpManagement') }}</el-button>
<el-button link size="small" @click="toggle(row)">{{ row.enabled ? $t('common.disabled') : $t('common.enabled') }}</el-button>
<el-button type="danger" link size="small" @click="remove(row)">{{ $t('common.delete') }}</el-button>
</template>
@@ -201,6 +201,7 @@ const tunnelProto = id => {
return tun ? t(protocolDisplay(tun.protocol)) : ''
}
const isOpenVPN = id => tunnels.value.find(x => x.id === id)?.protocol === 'openvpn'
const supportsMFA = id => ['openvpn', 'wireguard'].includes(tunnels.value.find(x => x.id === id)?.protocol)
const isLocked = row => row.mfa_locked_until && new Date(row.mfa_locked_until) > new Date()
const filteredUsers = computed(() => users.value.filter(user => {
const matchKeyword = !keyword.value || [user.username, user.display_name, user.email].some(v => (v || '').toLowerCase().includes(keyword.value.toLowerCase()))
@@ -212,7 +213,7 @@ async function load() {
try {
const [u, all] = await Promise.all([api.get('/vpn-users'), api.get('/tunnels')])
users.value = u.data || []
tunnels.value = (all.data || []).filter(tun => ['openvpn', 'l2tp', 'ikev2'].includes(tun.protocol))
tunnels.value = (all.data || []).filter(tun => ['openvpn', 'l2tp', 'ikev2', 'wireguard'].includes(tun.protocol))
} finally { loading.value = false }
}