@nanggo/social-preview
Version:
Generate beautiful social media preview images from any URL
133 lines (132 loc) • 6.24 kB
JavaScript
;
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;
}