From 5d8aeb8b41b2e568a89ce5c358888b02ae9020b5 Mon Sep 17 00:00:00 2001 From: Giacomo Sanchietti Date: Wed, 4 Feb 2026 16:45:42 +0100 Subject: [PATCH] feat(ovpntunnel): show all cert expirations Display the expiration of all involved certificates: - client - server - CA --- .../openvpn_tunnel/TunnelInfoModal.vue | 120 +++++++++++++----- .../openvpn_tunnel/TunnelManager.vue | 11 +- .../standalone/openvpn_tunnel/TunnelTable.vue | 69 +++++----- src/i18n/en.json | 15 +-- src/i18n/it.json | 15 +-- 5 files changed, 142 insertions(+), 88 deletions(-) diff --git a/src/components/standalone/openvpn_tunnel/TunnelInfoModal.vue b/src/components/standalone/openvpn_tunnel/TunnelInfoModal.vue index 5942ed2be..ff0bc8abe 100644 --- a/src/components/standalone/openvpn_tunnel/TunnelInfoModal.vue +++ b/src/components/standalone/openvpn_tunnel/TunnelInfoModal.vue @@ -6,7 +6,7 @@ import { NeModal } from '@nethesis/vue-components' import { useI18n } from 'vue-i18n' import type { ServerTunnel, ClientTunnel } from './TunnelManager.vue' -import { watch, ref, computed } from 'vue' +import { watch, ref } from 'vue' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { getCertificateStatus } from './TunnelTable.vue' @@ -33,14 +33,10 @@ function isClientTunnel(item: ServerTunnel | ClientTunnel): item is ClientTunnel return 'remote_host' in item } -const certificateStatus = computed(() => { - if (!_itemToShow.value?.cert_expiry_ts) return { show: false } - return getCertificateStatus( - _itemToShow.value.cert_expiry_ts, - isClientTunnel(_itemToShow.value), - true - ) -}) +function getCertStatus(expirationTimestamp: number) { + if (!_itemToShow.value?.certificates) return { show: false } + return getCertificateStatus({ cert: expirationTimestamp }) +} - -

- {{ - isClientTunnel(_itemToShow!) - ? t('standalone.openvpn_tunnel.client_cert_expiry') - : t('standalone.openvpn_tunnel.cert_expiry') - }} -

-
-

- {{ - _itemToShow.cert_expiry_ts - ? new Date(_itemToShow.cert_expiry_ts * 1000).toLocaleString(locale) - : '' - }} + + + +

diff --git a/src/components/standalone/openvpn_tunnel/TunnelManager.vue b/src/components/standalone/openvpn_tunnel/TunnelManager.vue index 24400badc..6a2bcc4fb 100644 --- a/src/components/standalone/openvpn_tunnel/TunnelManager.vue +++ b/src/components/standalone/openvpn_tunnel/TunnelManager.vue @@ -27,7 +27,11 @@ import { getProductName } from '@/lib/config' export type ServerTunnel = { /* always available */ - cert_expiry_ts: number + certificates: { + server: number + client: number + CA: number + } connected: boolean enabled: boolean id: string @@ -47,7 +51,10 @@ export type ServerTunnel = { export type ClientTunnel = { /* always available */ - cert_expiry_ts: number + certificates: { + client: number + CA: number + } connected: boolean enabled: boolean id: string diff --git a/src/components/standalone/openvpn_tunnel/TunnelTable.vue b/src/components/standalone/openvpn_tunnel/TunnelTable.vue index 79fc67026..68847ea44 100644 --- a/src/components/standalone/openvpn_tunnel/TunnelTable.vue +++ b/src/components/standalone/openvpn_tunnel/TunnelTable.vue @@ -28,40 +28,49 @@ export function isCertificatesExpired(expiryTimestamp: number): boolean { return expiryTimestamp <= Date.now() / 1000 } -export function getCertificateStatus( - expiryTimestamp: number, - isClientTunnel: boolean = false, - tunnelDetailModal: boolean = false -): CertificateStatusResult { - if (isCertificatesExpired(expiryTimestamp)) { +export function getCertificateStatus(certificates: { + [key: string]: number +}): CertificateStatusResult { + // Determine which certificate to check (client for client tunnels, server for server tunnels) + + // Check if any certificate is expired + let isExpired = false + for (const cert of Object.values(certificates)) { + if (isCertificatesExpired(cert)) { + isExpired = true + break + } + } + + if (isExpired) { return { show: true, icon: faCircleExclamation, colorClass: 'text-red-700 dark:text-red-500', - messageKey: tunnelDetailModal - ? isClientTunnel - ? 'standalone.openvpn_tunnel.client_cert_expired_complete_message' - : 'standalone.openvpn_tunnel.cert_expired_complete_message' - : isClientTunnel - ? 'standalone.openvpn_tunnel.client_cert_expired_message' - : 'standalone.openvpn_tunnel.cert_expired_message' + messageKey: 'standalone.openvpn_tunnel.cert_expired_message' + } + } + + let isExpiring = false + for (const cert of Object.values(certificates)) { + if (shouldShowCertExpiryBadge(cert)) { + isExpiring = true + break } } - if (shouldShowCertExpiryBadge(expiryTimestamp)) { + if (isExpiring) { + // Get the minimum days until expiry among all certificates + const daysUntilExpiry = Math.min( + ...Object.values(certificates).map((cert) => getDaysUntilExpiry(cert)) + ) return { show: true, icon: faTriangleExclamation, colorClass: 'text-amber-700 dark:text-amber-500', - messageKey: tunnelDetailModal - ? isClientTunnel - ? 'standalone.openvpn_tunnel.client_cert_expiring_complete_message' - : 'standalone.openvpn_tunnel.cert_expiring_complete_message' - : isClientTunnel - ? 'standalone.openvpn_tunnel.client_cert_expiring_message' - : 'standalone.openvpn_tunnel.cert_expiring_message', + messageKey: 'standalone.openvpn_tunnel.cert_expiring_message', messageParams: { - days: getDaysUntilExpiry(expiryTimestamp) + days: daysUntilExpiry } } } @@ -219,19 +228,13 @@ function checkIsClientTunnel(item: ServerTunnel | ClientTunnel): item is ClientT

{{ item.ns_name }}

@@ -239,8 +242,8 @@ function checkIsClientTunnel(item: ServerTunnel | ClientTunnel): item is ClientT

{{ t( - getCertificateStatus(item.cert_expiry_ts, checkIsClientTunnel(item)) - .messageKey! + getCertificateStatus(item.certificates).messageKey!, + getCertificateStatus(item.certificates).messageParams! ) }}

diff --git a/src/i18n/en.json b/src/i18n/en.json index 3d66c6f2a..6eea54fd6 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -2086,18 +2086,13 @@ "regenerate_cert_button": "Regenerate", "tunnel_name_max_length": "Maximum 10 characters allowed", "tunnel_details": "Tunnel details", - "cert_expiring_message": "Certificates expiring soon", - "client_cert_expiring_message": "Certificate expiring soon", - "cert_expiring_complete_message": "The certificates will expire in {days} days", - "client_cert_expiring_complete_message": "The client certificate will expire in {days} days", - "cert_expired_message": "Certificates are expired", - "client_cert_expired_message": "Certificate is expired", - "cert_expired_complete_message": "The certificates are expired", - "client_cert_expired_complete_message": "The client certificate is expired", + "cert_expiring_message": "The certificate will expire in {days} days", + "cert_expired_message": "The certificate is expired", "bytes_received": "Bytes received", "bytes_sent": "Bytes sent", - "client_cert_expiry": "Client certificate expire", - "cert_expiry": "Certificates expire", + "server_cert_expiration": "Server certificate expiration", + "client_cert_expiration": "Client certificate expiration", + "ca_cert_expiration": "CA certificate expiration", "tunnel_id": "Tunnel ID", "real_address": "Real address", "since": "Connection start", diff --git a/src/i18n/it.json b/src/i18n/it.json index ecf97f19b..c729e2cf3 100644 --- a/src/i18n/it.json +++ b/src/i18n/it.json @@ -1477,18 +1477,13 @@ "regenerate_cert_button": "Rigenera", "tunnel_name_max_length": "Massimo 10 caratteri", "tunnel_details": "Dettagli tunnel", - "cert_expiring_message": "Certificati in scadenza", - "client_cert_expiring_message": "Certificato in scadenza", - "cert_expiring_complete_message": "I certificati scadranno tra {days} giorni", - "client_cert_expiring_complete_message": "Il certificato del client scadrà tra {days} giorni", - "cert_expired_message": "Certificati scaduti", - "client_cert_expired_message": "Certificato scaduto", - "cert_expired_complete_message": "I certificati sono scaduti", - "client_cert_expired_complete_message": "Il certificato del client è scaduto", + "cert_expiring_message": "Il certificato scadrà tra {days} giorni", + "cert_expired_message": "Il certificato è scaduto", "bytes_received": "Bytes ricevuti", "bytes_sent": "Bytes inviati", - "client_cert_expiry": "Scadenza certificato client", - "cert_expiry": "Scadenza certificati", + "server_cert_expiration": "Scadenza certificato server", + "client_cert_expiration": "Scadenza certificato client", + "ca_cert_expiration": "Scadenza certificato CA", "tunnel_id": "ID Tunnel", "real_address": "Indirizzo reale", "since": "Inizio connessione",