@nanggo/social-preview
Version:
Generate beautiful social media preview images from any URL
324 lines (323 loc) • 13.5 kB
JavaScript
;
/**
* 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,
};