import { IsBoolean, IsOptional, IsString, IsUrl, MaxLength, MinLength, } from 'class-validator'; /** * DTO for admin-managed RSS feed sources (`TenderRssFeedSource`, D-14/D-08). * * `@IsUrl` here is only a COARSE well-formedness check (http/https, * protocol required). The SUBSTANTIVE SSRF/denylist guard — rejecting * DENYLISTED_PORTALS hostnames and private/loopback hosts — is enforced in * `TenderRssFeedSourceService.assertUrlAllowed()`, NOT here (RESEARCH.md * Pitfall 3: an admin-supplied RSS feed URL is runtime data, added long * after `SourceRegistry.register()`'s DI-boot-time denylist check runs — * this DTO alone provides zero protection against a feed URL pointing at * vergabe24/aumass or an internal host). `require_tld: false` deliberately * lets IP-literal URLs pass THIS validation layer so the service-layer * check can reject them with a clear, domain-specific SSRF error message * instead of a generic "invalid URL" one. */ export class TenderRssFeedDto { @IsUrl({ protocols: ['http', 'https'], require_protocol: true, require_tld: false, }) url!: string; @IsString() @MinLength(1) @MaxLength(200) label!: string; @IsOptional() @IsBoolean() isActive?: boolean; }