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}
`;
}