From e5b167dcbdbe5e13948edc0d3574f1fc1ec47efe Mon Sep 17 00:00:00 2001 From: Matteo Di Lorenzi Date: Wed, 21 Oct 2026 13:45:55 +0200 Subject: [PATCH 1/2] feat(openvpn): enforce required validation for public IPs and endpoints --- .../openvpn_rw/CreateOrEditRWServerDrawer.vue | 3 ++- .../openvpn_tunnel/CreateOrEditTunnelDrawer.vue | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/standalone/openvpn_rw/CreateOrEditRWServerDrawer.vue b/src/components/standalone/openvpn_rw/CreateOrEditRWServerDrawer.vue index 26285885b..f6becfd42 100644 --- a/src/components/standalone/openvpn_rw/CreateOrEditRWServerDrawer.vue +++ b/src/components/standalone/openvpn_rw/CreateOrEditRWServerDrawer.vue @@ -248,7 +248,7 @@ function resetForm() { vpnNetwork.value = serverData?.server ?? '' dynamicRangeIpStart.value = serverData?.ifconfig_pool?.length ? serverData.ifconfig_pool[0]! : '' dynamicRangeIpEnd.value = serverData?.ifconfig_pool?.length ? serverData.ifconfig_pool[1]! : '' - publicIpOrHostname.value = serverData?.ns_public_ip ?? [] + publicIpOrHostname.value = serverData?.ns_public_ip?.length ? serverData.ns_public_ip : [''] protocol.value = serverData?.proto ?? 'udp' port.value = serverData?.port ?? '' tunMtu.value = serverData?.tun_mtu ?? '' @@ -649,6 +649,7 @@ watch( :title="t('standalone.openvpn_rw.public_ip_hostname_unit')" :invalid-messages="publicIpOrHostnameValidationErrors" :general-invalid-message="t(validationErrorBag.getFirstI18nKeyFor('ns_public_ip'))" + :required="true" />
diff --git a/src/components/standalone/openvpn_tunnel/CreateOrEditTunnelDrawer.vue b/src/components/standalone/openvpn_tunnel/CreateOrEditTunnelDrawer.vue index ac18a0a82..a06b003e1 100644 --- a/src/components/standalone/openvpn_tunnel/CreateOrEditTunnelDrawer.vue +++ b/src/components/standalone/openvpn_tunnel/CreateOrEditTunnelDrawer.vue @@ -316,7 +316,9 @@ async function resetForm() { remoteNetworks.value = serverTunnelData.remote ?? [''] localNetworks.value = serverTunnelData.local?.map((x) => ({ id: x, label: x })) ?? [] localNetworksOptions.value = serverTunnelData.local?.map((x) => ({ id: x, label: x })) ?? [] - publicEndpoints.value = serverTunnelData.ns_public_ip ?? [] + publicEndpoints.value = serverTunnelData.ns_public_ip?.length + ? serverTunnelData.ns_public_ip + : [''] vpnNetwork.value = serverTunnelData.server ?? '' } } else { @@ -354,7 +356,7 @@ async function resetForm() { if (!props.isClientTunnel) { vpnNetwork.value = defaultsPayload.server - publicEndpoints.value = defaultsPayload.remote + publicEndpoints.value = defaultsPayload.remote?.length ? defaultsPayload.remote : [''] const initialNetworkOptions = defaultsPayload.route.map((localNetwork) => ({ id: localNetwork, label: localNetwork @@ -496,6 +498,10 @@ function validate() { // public endpoints validation let validPublicEndpoints = true + if (publicEndpoints.value.length == 0) { + validationErrorBag.value.set('publicEndpoints', [t('error.required')]) + validPublicEndpoints = false + } for (const [index, publicEndpoint] of publicEndpoints.value.entries()) { const validators = [validateRequired(publicEndpoint), validateIpAddressOrFQDN(publicEndpoint)] for (const validator of validators) { @@ -694,6 +700,8 @@ watch( :add-item-label="t('standalone.openvpn_tunnel.add_endpoint')" :title="t('standalone.openvpn_tunnel.public_endpoints')" :invalid-messages="publicEndpointsValidationErrors" + :general-invalid-message="validationErrorBag.getFirstFor('publicEndpoints')" + :required="true" >