import sanitizeHtml from 'sanitize-html'; import type { AuthenticationChatOption, LoadPreviousSessionChatOption } from './types'; function sanitizeUserInput(input: string): string { // Sanitize HTML tags and entities let sanitized = sanitizeHtml(input, { allowedTags: [], allowedAttributes: {}, }); // Remove dangerous protocols sanitized = sanitized.replace(/javascript:/gi, ''); sanitized = sanitized.replace(/data:/gi, ''); sanitized = sanitized.replace(/vbscript:/gi, ''); return sanitized; } export function getSanitizedInitialMessages(initialMessages: string): string[] { const sanitizedString = sanitizeUserInput(initialMessages); return sanitizedString .split('\n') .map((line) => line.trim()) .filter((line) => line !== ''); } export function getSanitizedI18nConfig(config: Record): Record { const sanitized: Record = {}; for (const [key, value] of Object.entries(config)) { sanitized[key] = sanitizeUserInput(value); } return sanitized; } export function createPage({ instanceId, webhookUrl, showWelcomeScreen, loadPreviousSession, i18n: { en }, initialMessages, authentication, allowFileUploads, allowedFilesMimeTypes, customCss, enableStreaming, }: { instanceId: string; webhookUrl?: string; showWelcomeScreen?: boolean; loadPreviousSession?: LoadPreviousSessionChatOption; i18n: { en: Record; }; initialMessages: string; mode: 'test' | 'production'; authentication: AuthenticationChatOption; allowFileUploads?: boolean; allowedFilesMimeTypes?: string; customCss?: string; enableStreaming?: boolean; }) { const validAuthenticationOptions: AuthenticationChatOption[] = [ 'none', 'basicAuth', 'n8nUserAuth', ]; const validLoadPreviousSessionOptions: LoadPreviousSessionChatOption[] = [ 'manually', 'memory', 'notSupported', ]; const sanitizedAuthentication = validAuthenticationOptions.includes(authentication) ? authentication : 'none'; const sanitizedShowWelcomeScreen = !!showWelcomeScreen; const sanitizedAllowFileUploads = !!allowFileUploads; const sanitizedAllowedFilesMimeTypes = allowedFilesMimeTypes?.toString() ?? ''; const sanitizedCustomCss = sanitizeHtml(``, { allowedTags: ['style'], allowedAttributes: false, }); const sanitizedLoadPreviousSession = validLoadPreviousSessionOptions.includes( loadPreviousSession as LoadPreviousSessionChatOption, ) ? loadPreviousSession : 'notSupported'; const sanitizedInitialMessages = getSanitizedInitialMessages(initialMessages); const sanitizedI18nConfig = getSanitizedI18nConfig(en || {}); return ` Chat ${sanitizedCustomCss} `; }