diff --git a/crates/defguard_core/src/grpc/enrollment.rs b/crates/defguard_core/src/grpc/enrollment.rs index c7a43069ba..13b0733ea5 100644 --- a/crates/defguard_core/src/grpc/enrollment.rs +++ b/crates/defguard_core/src/grpc/enrollment.rs @@ -695,6 +695,11 @@ impl EnrollmentServer { None, true, ); + if device.name.is_empty() { + return Err(Status::invalid_argument( + "Cannot add a new device with no name. You may be trying to add a new user device as a network device. Defguard CLI supports only network devices.", + )); + } let device = device.save(&mut *transaction).await.map_err(|err| { error!( "Failed to save device {}, pubkey {} for user {}({:?}): {err}", diff --git a/web/src/pages/devices/modals/AddStandaloneDeviceModal/steps/MethodStep/MethodStep.tsx b/web/src/pages/devices/modals/AddStandaloneDeviceModal/steps/MethodStep/MethodStep.tsx index a054a9150c..ef6b9f0853 100644 --- a/web/src/pages/devices/modals/AddStandaloneDeviceModal/steps/MethodStep/MethodStep.tsx +++ b/web/src/pages/devices/modals/AddStandaloneDeviceModal/steps/MethodStep/MethodStep.tsx @@ -88,11 +88,13 @@ export const MethodStep = () => { // biome-ignore lint/correctness/useExhaustiveDependencies: migration, checkMeLater useEffect(() => { if (networks) { - const options: SelectOption[] = networks.map((n) => ({ - key: n.id, - value: n.id, - label: n.name, - })); + const options: SelectOption[] = networks + .filter((n) => n.location_mfa_mode === 'disabled') + .map((n) => ({ + key: n.id, + value: n.id, + label: n.name, + })); setState({ networks, networkOptions: options, diff --git a/web/src/pages/wizard/components/WizardNetworkConfiguration/WizardNetworkConfiguration.tsx b/web/src/pages/wizard/components/WizardNetworkConfiguration/WizardNetworkConfiguration.tsx index 8d416e221e..6ecdd20349 100644 --- a/web/src/pages/wizard/components/WizardNetworkConfiguration/WizardNetworkConfiguration.tsx +++ b/web/src/pages/wizard/components/WizardNetworkConfiguration/WizardNetworkConfiguration.tsx @@ -118,7 +118,10 @@ export const WizardNetworkConfiguration = () => { .string() .trim() .min(1, LL.form.error.required()) - .refine((val) => validateIpOrDomain(val), LL.form.error.endpoint()), + .refine( + (val) => validateIpOrDomain(val, false, true), + LL.form.error.endpoint(), + ), port: z .number({ invalid_type_error: LL.form.error.invalid(), diff --git a/web/src/shared/validators.ts b/web/src/shared/validators.ts index 77df62d88a..8d99664003 100644 --- a/web/src/shared/validators.ts +++ b/web/src/shared/validators.ts @@ -1,6 +1,5 @@ import ipaddr from 'ipaddr.js'; import { z } from 'zod'; - import { patternValidDomain, patternValidWireguardKey } from './patterns'; export const validateWireguardPublicKey = (props: { @@ -24,11 +23,13 @@ export const validateIpOrDomain = ( allowMask = false, allowIPv6 = false, ): boolean => { - return ( - (allowIPv6 && validateIPv6(val, allowMask)) || - validateIPv4(val, allowMask) || - patternValidDomain.test(val) - ); + const hasLetter = /\p{L}/u.test(val); + const hasColon = /:/.test(val); + if (!hasLetter || hasColon) { + return (allowIPv6 && validateIPv6(val, allowMask)) || validateIPv4(val, allowMask); + } else { + return patternValidDomain.test(val); + } }; // Returns false when invalid @@ -41,6 +42,7 @@ export const validateIpList = ( .replace(' ', '') .split(splitWith) .every((el) => { + if (!el.includes('/') && allowMasks) return false; return validateIPv4(el, allowMasks) || validateIPv6(el, allowMasks); }); }; @@ -76,6 +78,10 @@ export const validateIPv4 = (ip: string, allowMask = false): boolean => { return ipaddr.IPv4.isValidCIDR(ip); } } + const ipv4Pattern = /^(\d{1,3}\.){3}\d{1,3}$/; + if (!ipv4Pattern.test(ip)) { + return false; + } return ipaddr.IPv4.isValid(ip); };