From e3e39e24e09cf53a5cbe48ea150445e9e7a17efc Mon Sep 17 00:00:00 2001 From: cv5ch <176032962+cv5ch@users.noreply.github.com> Date: Tue, 2 Sep 2025 08:14:36 +0200 Subject: [PATCH] Enhance URL Validator to allow only http: and https: as URL protocols --- src/app/core/_validators/url.validator.ts | 39 ++++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/app/core/_validators/url.validator.ts b/src/app/core/_validators/url.validator.ts index def19b5b..e47c4299 100644 --- a/src/app/core/_validators/url.validator.ts +++ b/src/app/core/_validators/url.validator.ts @@ -1,22 +1,45 @@ // url.validator.ts import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; +/** + * List of allowed URL protocols. + * Modify this array to add or remove allowed protocols. + */ +const allowedProtocols = ['http:', 'https:']; + /** * Creates an Angular ValidatorFn that validates whether a control's value is a valid URL. * This validator attempts to parse the value using the browser's native URL API. * @returns A ValidatorFn function to use in Angular Reactive Forms. */ export function urlValidator(): ValidatorFn { + // Build regex dynamically from allowedProtocols to enforce "//" + const protocolPattern = allowedProtocols.map((protocol) => protocol.replace(':', '')).join('|'); + const doubleSlashRegex = new RegExp(`^(${protocolPattern})://.+`, 'i'); + return (control: AbstractControl): ValidationErrors | null => { - const rawValue = control.value?.trim(); - if (!rawValue) { - // Don't validate empty values; leave that to Validators.required - return null; + const value: string | null = control.value?.trim(); + if (!value) { + return null; // Let empty values be handled by Validators.required } - if (URL.canParse(rawValue)) { - const { hostname } = new URL(rawValue); - return hostname ? null : { invalidUrl: { value: rawValue } }; + + // Ensure "//" is present + if (!doubleSlashRegex.test(value)) { + return { invalidUrl: { value } }; + } + + // Use the native URL API for validation + try { + const url = new URL(value); + + // Validate protocol + if (allowedProtocols.includes(url.protocol)) { + return null; // valid URL + } else { + return { invalidUrl: { value } }; + } + } catch { + return { invalidUrl: { value } }; } - return { invalidUrl: { value: rawValue } }; }; }