UNPKG

@nanggo/social-preview

Version:

Generate beautiful social media preview images from any URL

324 lines (323 loc) 13.5 kB
"use strict"; /** * Centralized Security Constants - Phase 1.5 Advanced Security * All security-related limits and configurations in one place */ Object.defineProperty(exports, "__esModule", { value: true }); exports.SECURITY_LIMITS = exports.ALLOWED_TEMPLATES = exports.QUALITY_LIMITS = exports.DIMENSION_LIMITS = exports.SECURITY_CONFIG = exports.MAX_DNS_CACHE_SIZE = exports.DNS_CACHE_TTL = exports.MAX_CONCURRENT_CONNECTIONS = exports.HTTP_TIMEOUT = exports.SUSPICIOUS_URL_PARAMS = exports.SHARP_SECURITY_CONFIG = exports.SHARP_CACHE_CONFIG = exports.ALLOWED_SVG_NAMESPACES = exports.ALLOWED_SVG_URI_PATTERN = exports.FORBIDDEN_SVG_ATTRIBUTES = exports.ALLOWED_SVG_ATTRIBUTES = exports.FORBIDDEN_SVG_TAGS = exports.ALLOWED_SVG_TAGS = exports.DANGEROUS_UNICODE_CHARS = exports.ZERO_WIDTH_CHARS = exports.BIDI_CONTROL_CHARS = exports.EXTENDED_ASCII_CONTROL_CHARS = exports.ASCII_CONTROL_CHARS = exports.SUSPICIOUS_PATTERNS = exports.DANGEROUS_CSS_PATTERNS = exports.DANGEROUS_HTML_PATTERNS = exports.MAX_URL_LENGTH = exports.MAX_COLOR_LENGTH = exports.MAX_TEXT_LENGTH = exports.MAX_DPI = exports.ALLOWED_IMAGE_FORMATS = exports.PROCESSING_TIMEOUT = exports.MAX_SVG_SIZE = exports.MAX_FILE_SIZE = exports.MAX_IMAGE_HEIGHT = exports.MAX_IMAGE_WIDTH = exports.MAX_INPUT_PIXELS = exports.BLOCKED_PROTOCOLS = exports.ALLOWED_PROTOCOLS = exports.BLOCKED_IPV6_RANGES = exports.BLOCKED_IP_RANGES = void 0; // ============================================================================= // NETWORK SECURITY CONSTANTS // ============================================================================= /** Private IP ranges to block for SSRF protection */ exports.BLOCKED_IP_RANGES = [ // IPv4 Private ranges { start: '0.0.0.0', end: '0.255.255.255', description: 'Current network' }, { start: '10.0.0.0', end: '10.255.255.255', description: 'Private Class A' }, { start: '127.0.0.0', end: '127.255.255.255', description: 'Loopback' }, { start: '169.254.0.0', end: '169.254.255.255', description: 'Link-local' }, { start: '172.16.0.0', end: '172.31.255.255', description: 'Private Class B' }, { start: '192.0.0.0', end: '192.0.0.255', description: 'IETF Protocol Assignments' }, { start: '192.0.2.0', end: '192.0.2.255', description: 'TEST-NET-1' }, { start: '192.88.99.0', end: '192.88.99.255', description: '6to4 Relay' }, { start: '192.168.0.0', end: '192.168.255.255', description: 'Private Class C' }, { start: '198.18.0.0', end: '198.19.255.255', description: 'Network Testing' }, { start: '198.51.100.0', end: '198.51.100.255', description: 'TEST-NET-2' }, { start: '203.0.113.0', end: '203.0.113.255', description: 'TEST-NET-3' }, { start: '224.0.0.0', end: '255.255.255.255', description: 'Multicast/Reserved' }, // Carrier-Grade NAT (RFC 6598) { start: '100.64.0.0', end: '100.127.255.255', description: 'Carrier-Grade NAT' }, ]; /** Blocked IPv6 ranges */ exports.BLOCKED_IPV6_RANGES = [ '::1/128', // Loopback '::/128', // Unspecified 'fc00::/7', // Unique Local 'fe80::/10', // Link-local 'ff00::/8', // Multicast ]; /** Allowed protocols for URLs */ exports.ALLOWED_PROTOCOLS = ['http:', 'https:']; /** Blocked protocols (security threats) */ exports.BLOCKED_PROTOCOLS = [ 'javascript:', 'data:', 'vbscript:', 'file:', 'ftp:', 'blob:', 'about:', ]; // ============================================================================= // IMAGE PROCESSING SECURITY CONSTANTS // ============================================================================= /** Maximum allowed pixels for image processing (64 megapixels) */ exports.MAX_INPUT_PIXELS = 64 * 1024 * 1024; /** Maximum image dimensions */ exports.MAX_IMAGE_WIDTH = 8192; exports.MAX_IMAGE_HEIGHT = 8192; /** Maximum file size (15MB) */ exports.MAX_FILE_SIZE = 15 * 1024 * 1024; /** Maximum SVG content size (1MB) */ exports.MAX_SVG_SIZE = 1 * 1024 * 1024; /** Sharp processing timeout (30 seconds) */ exports.PROCESSING_TIMEOUT = 30_000; /** Allowed image formats (whitelist approach) */ exports.ALLOWED_IMAGE_FORMATS = new Set([ 'jpeg', 'jpg', 'png', 'webp', 'gif', 'bmp', 'tiff' ]); /** Maximum DPI to prevent memory exhaustion */ exports.MAX_DPI = 600; // ============================================================================= // TEXT VALIDATION SECURITY CONSTANTS // ============================================================================= /** Maximum text content length */ exports.MAX_TEXT_LENGTH = 10_000; /** Maximum color value length */ exports.MAX_COLOR_LENGTH = 100; /** Maximum URL length */ exports.MAX_URL_LENGTH = 2048; /** Dangerous HTML/Script patterns to block */ exports.DANGEROUS_HTML_PATTERNS = [ // Script injection /<script/gi, /<\/script>/gi, /javascript:/gi, /vbscript:/gi, // HTML injection /<iframe/gi, /<object/gi, /<embed/gi, /<applet/gi, /<meta/gi, /<link/gi, /<style/gi, // Event handlers /on\w+\s*=/gi, // Expression patterns /expression\(/gi, /eval\(/gi, /function\s*\(/gi, // URL encoded patterns /%3Cscript/gi, /javascript%3A/gi, ]; /** Dangerous CSS patterns to block */ exports.DANGEROUS_CSS_PATTERNS = [ /[<>]/g, // HTML tags /javascript:/gi, // JavaScript protocol /expression\(/gi, // CSS expressions (IE) /data:/gi, // Data URIs /url\(/gi, // URL functions /import/gi, // CSS imports /@/g, // CSS at-rules /\/\*/g, // CSS comments /\*\//g, // CSS comment ends /;/g, // CSS statement terminators /\}/g, // CSS block terminators /\{/g, // CSS block starters /\\/g, // Escape sequences ]; /** Suspicious keyword patterns */ exports.SUSPICIOUS_PATTERNS = [ /script/gi, /eval/gi, /function/gi, /return/gi, /alert/gi, /prompt/gi, /confirm/gi, /document/gi, /window/gi, /console/gi, /xhr/gi, /fetch/gi, ]; // ============================================================================= // UNICODE SECURITY CONSTANTS // ============================================================================= /** ASCII control characters to remove (except \t, \n, \r) */ // eslint-disable-next-line no-control-regex exports.ASCII_CONTROL_CHARS = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g; /** Extended ASCII control characters */ exports.EXTENDED_ASCII_CONTROL_CHARS = /[\x80-\x9f]/g; /** Unicode Bidirectional Text Control Characters (Bidi attack prevention) */ exports.BIDI_CONTROL_CHARS = { RIGHT_TO_LEFT_OVERRIDE: /\u202E/g, LEFT_TO_RIGHT_OVERRIDE: /\u202D/g, LEFT_TO_RIGHT_MARK: /\u200E/g, RIGHT_TO_LEFT_MARK: /\u200F/g, ARABIC_LETTER_MARK: /\u061C/g, LEFT_TO_RIGHT_ISOLATE: /\u2066/g, RIGHT_TO_LEFT_ISOLATE: /\u2067/g, FIRST_STRONG_ISOLATE: /\u2068/g, POP_DIRECTIONAL_ISOLATE: /\u2069/g, }; /** Zero-width and formatting characters */ exports.ZERO_WIDTH_CHARS = { ZERO_WIDTH_SPACE: /\u200B/g, ZERO_WIDTH_NON_JOINER: /\u200C/g, ZERO_WIDTH_JOINER: /\u200D/g, ZERO_WIDTH_NO_BREAK_SPACE: /\uFEFF/g, SOFT_HYPHEN: /\u00AD/g, COMBINING_GRAPHEME_JOINER: /\u034F/g, }; /** Other dangerous Unicode characters */ exports.DANGEROUS_UNICODE_CHARS = { MONGOLIAN_VOWEL_SEPARATOR: /\u180E/g, LINE_SEPARATOR: /\u2028/g, PARAGRAPH_SEPARATOR: /\u2029/g, VARIATION_SELECTORS: /[\uFE00-\uFE0F]/g, }; // ============================================================================= // SVG SECURITY CONSTANTS // ============================================================================= /** SVG tags allowed for security (whitelist) */ exports.ALLOWED_SVG_TAGS = [ 'svg', 'g', 'path', 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'text', 'tspan', 'defs', 'linearGradient', 'radialGradient', 'stop', 'title', 'desc', ]; /** SVG tags forbidden for security (blacklist) */ exports.FORBIDDEN_SVG_TAGS = [ 'script', 'object', 'embed', 'iframe', 'frame', 'frameset', 'link', 'meta', 'base', 'form', 'input', 'button', 'select', 'textarea', 'video', 'audio', 'source', 'track', 'canvas', 'applet', 'param', 'foreignObject', // Animation and interaction tags 'animate', 'animateTransform', 'animateMotion', 'set', // External reference tags 'use', 'image', 'textPath', 'marker', 'symbol', // CSS injection vectors 'style', ]; /** SVG attributes allowed for security (whitelist) */ exports.ALLOWED_SVG_ATTRIBUTES = [ // Basic identification (safe) 'id', 'class', // Geometric positioning and sizing (safe) 'x', 'y', 'x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'r', 'rx', 'ry', 'width', 'height', 'd', 'points', // Safe styling attributes 'fill', 'stroke', 'stroke-width', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'fill-opacity', 'stroke-opacity', 'opacity', 'visibility', 'display', // Transform (geometric only, no external refs) 'transform', // SVG viewport (safe) 'viewBox', 'preserveAspectRatio', // Namespace declarations (required for valid SVG) 'xmlns', // Gradient-specific safe attributes 'gradientUnits', 'gradientTransform', 'spreadMethod', 'stop-color', 'stop-opacity', 'offset', // Text positioning and styling (safe) 'text-anchor', 'dominant-baseline', 'font-family', 'font-size', 'font-weight', 'font-style', 'text-decoration', 'letter-spacing', 'word-spacing', 'dx', 'dy', 'rotate', 'textLength', 'lengthAdjust', ]; /** SVG attributes forbidden for security (blacklist) */ exports.FORBIDDEN_SVG_ATTRIBUTES = [ // CSS injection vectors 'style', // External resource loading 'href', 'xlink:href', 'src', 'data', 'action', // External namespace declarations 'xmlns:xlink', // Dangerous reference attributes 'clip-path', 'mask', 'filter', ]; /** Allowed SVG URI pattern (only fragment identifiers) */ exports.ALLOWED_SVG_URI_PATTERN = /^#/; /** Allowed SVG namespaces */ exports.ALLOWED_SVG_NAMESPACES = ['http://www.w3.org/2000/svg']; // ============================================================================= // SHARP SECURITY CONSTANTS // ============================================================================= /** Sharp memory cache settings */ exports.SHARP_CACHE_CONFIG = { memory: 150, // 150MB memory cache files: 30, // 30 files cache items: 300, // 300 operations cache }; /** Sharp security configuration */ exports.SHARP_SECURITY_CONFIG = { limitInputPixels: exports.MAX_INPUT_PIXELS, sequentialRead: true, density: 300, failOnError: true, // Security: fail fast on corrupted/malicious images stripMetadata: true, }; // ============================================================================= // URL VALIDATION CONSTANTS // ============================================================================= /** Suspicious URL query parameters */ exports.SUSPICIOUS_URL_PARAMS = [ 'callback', 'jsonp', 'eval', 'script', ]; // ============================================================================= // NETWORK/CONNECTION SECURITY CONSTANTS // ============================================================================= /** HTTP/HTTPS connection timeouts */ exports.HTTP_TIMEOUT = 30_000; // 30 seconds /** Maximum concurrent connections per agent */ exports.MAX_CONCURRENT_CONNECTIONS = 50; /** DNS cache TTL in milliseconds */ exports.DNS_CACHE_TTL = 5 * 60 * 1000; // 5 minutes /** Maximum DNS cache size */ exports.MAX_DNS_CACHE_SIZE = 1000; /** Security configuration object */ exports.SECURITY_CONFIG = { HTTP_TIMEOUT: exports.HTTP_TIMEOUT, MAX_CONCURRENT_CONNECTIONS: exports.MAX_CONCURRENT_CONNECTIONS, DNS_CACHE_TTL: exports.DNS_CACHE_TTL, MAX_DNS_CACHE_SIZE: exports.MAX_DNS_CACHE_SIZE, PROCESSING_TIMEOUT: exports.PROCESSING_TIMEOUT, MAX_INPUT_PIXELS: exports.MAX_INPUT_PIXELS, }; // ============================================================================= // VALIDATION LIMITS // ============================================================================= /** Dimension validation limits */ exports.DIMENSION_LIMITS = { MIN_WIDTH: 100, MIN_HEIGHT: 100, MAX_WIDTH: 4096, MAX_HEIGHT: 4096, }; /** Quality validation limits */ exports.QUALITY_LIMITS = { MIN: 1, MAX: 100, }; /** Template validation */ exports.ALLOWED_TEMPLATES = ['modern', 'classic', 'minimal']; // ============================================================================= // SECURITY EXPORT // ============================================================================= /** Combined security limits for easy access */ exports.SECURITY_LIMITS = { // Network MAX_URL_LENGTH: exports.MAX_URL_LENGTH, ALLOWED_PROTOCOLS: exports.ALLOWED_PROTOCOLS, BLOCKED_PROTOCOLS: exports.BLOCKED_PROTOCOLS, // Images MAX_INPUT_PIXELS: exports.MAX_INPUT_PIXELS, MAX_IMAGE_WIDTH: exports.MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT: exports.MAX_IMAGE_HEIGHT, MAX_FILE_SIZE: exports.MAX_FILE_SIZE, MAX_SVG_SIZE: exports.MAX_SVG_SIZE, MAX_DPI: exports.MAX_DPI, PROCESSING_TIMEOUT: exports.PROCESSING_TIMEOUT, ALLOWED_IMAGE_FORMATS: Array.from(exports.ALLOWED_IMAGE_FORMATS), // Text MAX_TEXT_LENGTH: exports.MAX_TEXT_LENGTH, MAX_COLOR_LENGTH: exports.MAX_COLOR_LENGTH, // Templates ALLOWED_TEMPLATES: [...exports.ALLOWED_TEMPLATES], // Dimensions ...exports.DIMENSION_LIMITS, // Quality ...exports.QUALITY_LIMITS, };