diff --git a/src/components/standalone/ipsec_tunnel/CreateOrEditTunnelDrawer.vue b/src/components/standalone/ipsec_tunnel/CreateOrEditTunnelDrawer.vue
index 45d6e74f9..bc22431ac 100644
--- a/src/components/standalone/ipsec_tunnel/CreateOrEditTunnelDrawer.vue
+++ b/src/components/standalone/ipsec_tunnel/CreateOrEditTunnelDrawer.vue
@@ -8,6 +8,7 @@ import {
MessageBag,
validateHost,
validateIp4Cidr,
+ validateNoCurlyBraces,
validatePositiveInteger,
validateRequired,
validateRequiredOption,
@@ -355,12 +356,10 @@ function validateFormByStep(step: number): boolean {
if (presharedKeyMode.value === 'generate') {
return true
} else {
- const validator = validateRequired(presharedKey.value)
- if (!validator.valid) {
- validationErrorBag.value.set('presharedKey', [t(validator.errMessage as string)])
- return false
- }
- return true
+ return runValidators(
+ [validateRequired(presharedKey.value), validateNoCurlyBraces(presharedKey.value)],
+ 'presharedKey'
+ )
}
} else {
const step3Validators: [validationOutput[], string][] = [
@@ -611,7 +610,15 @@ watch(
v-model="presharedKey"
:invalid-message="validationErrorBag.getFirstFor('presharedKey')"
:label="id ? t('standalone.ipsec_tunnel.pre_shared_key') : ''"
- />
+ >
+
+
+
+ {{ t('standalone.ipsec_tunnel.pre_shared_key_invalid_chars_tooltip') }}
+
+
+
+
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 8a07b0f16..0f68f40e5 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -84,6 +84,7 @@
"required": "Required",
"unique": "Enter a unique value",
"invalid": "Field has incorrect value",
+ "curly_braces_not_allowed": "Curly brace characters are not allowed",
"invalid_format": "File is not a valid PEM format",
"expired": "Certificate has expired",
"key_mismatch": "Private key does not match the certificate",
@@ -2182,6 +2183,7 @@
"choose_wan": "Choose WAN",
"add_network": "Add network",
"pre_shared_key": "Pre-shared key",
+ "pre_shared_key_invalid_chars_tooltip": "The characters '\\{' and '\\}' are not allowed in the pre-shared key",
"use_generated_key": "Use generated key",
"use_custom_key": "Use custom key",
"dpd_dead_peer_detection": "DPD (dead peer detection)",
diff --git a/src/i18n/it.json b/src/i18n/it.json
index 630ce0304..ba07f7ebe 100644
--- a/src/i18n/it.json
+++ b/src/i18n/it.json
@@ -82,6 +82,7 @@
"http_404": "Risorsa non trovata",
"http_500": "Errore del server",
"required": "Obbligatorio",
+ "curly_braces_not_allowed": "I caratteri di parentesi graffe non sono consentiti",
"invalid_hostname": "Nome host non valido",
"hostname_is_too_long": "Il nome host ha troppi caratteri",
"cannot_save_configuration": "Impossibile salvare la configurazione",
@@ -1563,6 +1564,7 @@
"wan_ip_address": "Indirizzo IP WAN",
"enable": "Abilita",
"pre_shared_key": "Chiave condivisa",
+ "pre_shared_key_invalid_chars_tooltip": "I caratteri '\\{' e '\\}' non sono consentiti nella chiave condivisa",
"remote_ip_address_tooltip": "Inserire l'indirizzo IP pubblico o l'host del server remoto. Se il server remoto ha un indirizzo IP dinamico, รจ sufficiente inserire 'qualsiasi'",
"edit_ipsec_tunnel": "Modifica tunnel IPsec",
"ike_version": "Versione IKE",
diff --git a/src/lib/__tests__/validateNoCurlyBraces.spec.ts b/src/lib/__tests__/validateNoCurlyBraces.spec.ts
new file mode 100644
index 000000000..9cda7c350
--- /dev/null
+++ b/src/lib/__tests__/validateNoCurlyBraces.spec.ts
@@ -0,0 +1,23 @@
+import { describe, expect, it } from 'vitest'
+import { validateNoCurlyBraces } from '@/lib/validation'
+
+describe('validateNoCurlyBraces', () => {
+ it('accepts an empty string', () => {
+ expect(validateNoCurlyBraces('').valid).toBe(true)
+ })
+
+ it('accepts whitespace-only values', () => {
+ expect(validateNoCurlyBraces(' ').valid).toBe(true)
+ })
+
+ it.each(['{secret', 'secret}', 'sec{ret}', '{}'])('rejects "%s"', (input) => {
+ const result = validateNoCurlyBraces(input)
+
+ expect(result.valid).toBe(false)
+ expect(result.errMessage).toBeDefined()
+ })
+
+ it('accepts special characters other than curly braces', () => {
+ expect(validateNoCurlyBraces('p@ssw0rd![]()').valid).toBe(true)
+ })
+})
diff --git a/src/lib/validation.ts b/src/lib/validation.ts
index 9ff202d92..3e5ff5a1c 100644
--- a/src/lib/validation.ts
+++ b/src/lib/validation.ts
@@ -733,6 +733,17 @@ export function validateNoSpaces(value: string): validationOutput {
return { valid: true }
}
+/**
+ * Validate if the string doesn't have curly braces.
+ * @param value
+ */
+export function validateNoCurlyBraces(value: string): validationOutput {
+ if (value.includes('{') || value.includes('}')) {
+ return { valid: false, errMessage: 'error.curly_braces_not_allowed' }
+ }
+ return { valid: true }
+}
+
/**
* Validate a 6-digit code
*