import { configKeys } from '../defaultConfig.js'; import { log } from '../logger.js'; /** * Sanitizes directive objects * * @param args - Directive's JSON */ export const sanitizeDirective = (args: any): void => { log.debug('sanitizeDirective called with', args); // Return if not an object if (typeof args !== 'object' || args == null) { return; } // Sanitize each element if an array if (Array.isArray(args)) { args.forEach((arg) => sanitizeDirective(arg)); return; } // Sanitize each key if an object for (const key of Object.keys(args)) { log.debug('Checking key', key); if ( key.startsWith('__') || key.includes('proto') || key.includes('constr') || !configKeys.has(key) || args[key] == null ) { log.debug('sanitize deleting key: ', key); delete args[key]; continue; } // Recurse if an object if (typeof args[key] === 'object') { log.debug('sanitizing object', key); sanitizeDirective(args[key]); continue; } const cssMatchers = ['themeCSS', 'fontFamily', 'altFontFamily']; for (const cssKey of cssMatchers) { if (key.includes(cssKey)) { log.debug('sanitizing css option', key); args[key] = sanitizeCss(args[key]); } } } if (args.themeVariables) { for (const k of Object.keys(args.themeVariables)) { const val = args.themeVariables[k]; if (val?.match && !val.match(/^[\d "#%(),.;A-Za-z]+$/)) { args.themeVariables[k] = ''; } } } log.debug('After sanitization', args); }; export const sanitizeCss = (str: string): string => { let startCnt = 0; let endCnt = 0; for (const element of str) { if (startCnt < endCnt) { return '{ /* ERROR: Unbalanced CSS */ }'; } if (element === '{') { startCnt++; } else if (element === '}') { endCnt++; } } if (startCnt !== endCnt) { return '{ /* ERROR: Unbalanced CSS */ }'; } // Todo add more checks here return str; };