/** * Video Embed Validation Utilities * * Security: Only YouTube and Vimeo embeds are allowed. * This module validates video URLs and builds safe embed URLs. */ // ============================================================================ // Video Provider Definitions // ============================================================================ export interface VideoProvider { name: string; patterns: RegExp[]; embedTemplate: (videoId: string, hash?: string) => string; validateId: (id: string) => boolean; } export const VIDEO_PROVIDERS: Record = { youtube: { name: 'YouTube', patterns: [ // Standard watch URL: https://www.youtube.com/watch?v=VIDEO_ID /^https:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/, // Short URL: https://youtu.be/VIDEO_ID /^https:\/\/youtu\.be\/([a-zA-Z0-9_-]{11})/, // Embed URL: https://www.youtube.com/embed/VIDEO_ID /^https:\/\/(?:www\.)?youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/, // Nocookie embed: https://www.youtube-nocookie.com/embed/VIDEO_ID /^https:\/\/(?:www\.)?youtube-nocookie\.com\/embed\/([a-zA-Z0-9_-]{11})/, ], embedTemplate: (videoId: string) => `https://www.youtube-nocookie.com/embed/${videoId}`, validateId: (id: string) => /^[a-zA-Z0-9_-]{11}$/.test(id), }, vimeo: { name: 'Vimeo', patterns: [ // Standard URL: https://vimeo.com/VIDEO_ID /^https:\/\/(?:www\.)?vimeo\.com\/(\d+)(?:\/([a-zA-Z0-9]+))?/, // Player URL: https://player.vimeo.com/video/VIDEO_ID /^https:\/\/player\.vimeo\.com\/video\/(\d+)/, ], embedTemplate: (videoId: string, hash?: string) => hash ? `https://player.vimeo.com/video/${videoId}?h=${hash}` : `https://player.vimeo.com/video/${videoId}`, validateId: (id: string) => /^\d+$/.test(id), }, }; // ============================================================================ // Validation Result Types // ============================================================================ export interface VideoValidationResult { isValid: boolean; provider?: 'youtube' | 'vimeo'; videoId?: string; hash?: string; error?: string; } export interface ParsedVideo { provider: 'youtube' | 'vimeo'; videoId: string; hash?: string; } // ============================================================================ // URL Sanitization // ============================================================================ /** * Check if a string contains potentially dangerous content */ function containsDangerousContent(str: string): boolean { if (!str) return false; const dangerousPatterns = [ /