UNPKG

@nanggo/social-preview

Version:

Generate beautiful social media preview images from any URL

133 lines (132 loc) 6.24 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateOptions = validateOptions; exports.validateOptionsLegacy = validateOptionsLegacy; exports.sanitizeOptions = sanitizeOptions; const types_1 = require("../../types"); const security_1 = require("../../constants/security"); const color_1 = require("./color"); const dimensions_1 = require("./dimensions"); const text_1 = require("./text"); /** * Validates all preview options including dimensions, quality, and colors. */ function validateOptions(options) { // Use the new centralized sanitization - this ensures all validation paths converge sanitizeOptions(options); } // Legacy function maintained for backward compatibility function validateOptionsLegacy(options) { // Validate dimensions if provided if (options.width !== undefined || options.height !== undefined) { const width = options.width || 1200; const height = options.height || 630; (0, dimensions_1.validateDimensions)(width, height); } // Validate quality if provided if (options.quality !== undefined) { if (!Number.isFinite(options.quality) || options.quality < security_1.QUALITY_LIMITS.MIN || options.quality > security_1.QUALITY_LIMITS.MAX) { throw new types_1.PreviewGeneratorError(types_1.ErrorType.VALIDATION_ERROR, `Quality must be between ${security_1.QUALITY_LIMITS.MIN} and ${security_1.QUALITY_LIMITS.MAX}, got: ${options.quality}`); } } // Validate colors if provided if (options.colors) { const colors = options.colors; // Validate each color property if it exists if (colors.primary) (0, color_1.validateColor)(colors.primary); if (colors.secondary) (0, color_1.validateColor)(colors.secondary); if (colors.background) (0, color_1.validateColor)(colors.background); if (colors.text) (0, color_1.validateColor)(colors.text); if (colors.accent) (0, color_1.validateColor)(colors.accent); if (colors.overlay) (0, color_1.validateColor)(colors.overlay); } // Validate template type if provided if (options.template !== undefined) { if (!security_1.ALLOWED_TEMPLATES.includes(options.template)) { throw new types_1.PreviewGeneratorError(types_1.ErrorType.VALIDATION_ERROR, `Invalid template type: ${options.template}. Allowed templates: ${security_1.ALLOWED_TEMPLATES.join(', ')}`); } } // Validate cache option if provided if (options.cache !== undefined && typeof options.cache !== 'boolean') { throw new types_1.PreviewGeneratorError(types_1.ErrorType.VALIDATION_ERROR, `Cache option must be boolean, got: ${typeof options.cache}`); } // Validate text inputs if provided if (options.fallback?.text) { (0, text_1.validateTextInput)(options.fallback.text, 'fallback text'); } } // ============================================================================= // BRAND TYPE VALIDATORS - Phase 1.5 Advanced Security // ============================================================================= /** * Central validation gateway - all external input must pass through this. */ function sanitizeOptions(options) { // Deep validation of all nested properties const sanitized = { ...options, }; // Validate colors if present - ALL color properties must be validated if (sanitized.colors) { if (sanitized.colors.background) { // Note: validateColor now returns SanitizedColor, but we need to store as string // This maintains type safety at validation boundaries while preserving runtime compatibility sanitized.colors.background = (0, color_1.validateColor)(sanitized.colors.background); } if (sanitized.colors.text) { sanitized.colors.text = (0, color_1.validateColor)(sanitized.colors.text); } if (sanitized.colors.accent) { sanitized.colors.accent = (0, color_1.validateColor)(sanitized.colors.accent); } // Critical security fix: validate previously missing color properties if (sanitized.colors.primary) { sanitized.colors.primary = (0, color_1.validateColor)(sanitized.colors.primary); } if (sanitized.colors.secondary) { sanitized.colors.secondary = (0, color_1.validateColor)(sanitized.colors.secondary); } if (sanitized.colors.overlay) { sanitized.colors.overlay = (0, color_1.validateColor)(sanitized.colors.overlay); } } // Validate dimensions if (sanitized.width !== undefined) { sanitized.width = (0, dimensions_1.validateDimension)(sanitized.width); } if (sanitized.height !== undefined) { sanitized.height = (0, dimensions_1.validateDimension)(sanitized.height); } // Validate quality if (sanitized.quality !== undefined) { if (sanitized.quality < security_1.QUALITY_LIMITS.MIN || sanitized.quality > security_1.QUALITY_LIMITS.MAX) { throw new types_1.PreviewGeneratorError(types_1.ErrorType.VALIDATION_ERROR, `Quality must be between ${security_1.QUALITY_LIMITS.MIN} and ${security_1.QUALITY_LIMITS.MAX}`); } } // Validate template type if (sanitized.template !== undefined) { if (!security_1.ALLOWED_TEMPLATES.includes(sanitized.template)) { throw new types_1.PreviewGeneratorError(types_1.ErrorType.VALIDATION_ERROR, `Invalid template type: ${sanitized.template}. Allowed templates: ${security_1.ALLOWED_TEMPLATES.join(', ')}`); } } // Validate cache option if (sanitized.cache !== undefined && typeof sanitized.cache !== 'boolean') { throw new types_1.PreviewGeneratorError(types_1.ErrorType.VALIDATION_ERROR, `Cache option must be boolean, got: ${typeof sanitized.cache}`); } // Validate text inputs from fallback if (sanitized.fallback?.text) { sanitized.fallback = { ...sanitized.fallback, text: (0, text_1.validateTextInput)(sanitized.fallback.text, 'fallback text'), }; } return sanitized; }