feat: add theme toggle component and theme store for light/dark mode support
- Implemented ThemeToggle component for switching between light, dark, and system themes. - Created themeStore for managing theme state and persisting user preferences in localStorage. - Added utility functions for error message sanitization to prevent sensitive data leakage. - Developed proxy utility functions for API requests, including template variable replacement. - Enhanced layout with dark mode styles and smooth transitions for theme changes. - Updated main layout and page components to integrate theme toggle and improve accessibility. - Added server-side proxy handling with validation and error sanitization for API requests.
This commit is contained in:
80
src/lib/utils/error-sanitizer.ts
Normal file
80
src/lib/utils/error-sanitizer.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Error message sanitization utility
|
||||
* Prevents sensitive information leakage in error messages
|
||||
*/
|
||||
|
||||
// Patterns that might indicate sensitive information
|
||||
const SENSITIVE_PATTERNS = [
|
||||
// Password/secret related
|
||||
/password|passwd|pwd|secret|token|api[_-]?key|private[_-]?key|auth/i,
|
||||
// File paths
|
||||
/[a-z]:[\\/][^\s]*/i, // Windows paths
|
||||
/\/(?:home|usr|var|etc|root)[\\/][^\s]*/i, // Unix paths
|
||||
// Stack trace patterns
|
||||
/\s+at\s+.*\s+\(\s*[^)]+\s*\)/,
|
||||
/from\s+[^\/\s]+\/[^\/\s]+\.js/,
|
||||
// Internal server details
|
||||
/localhost|127\.0\.0\.1|0\.0\.0\.0|::1/i,
|
||||
// Database connection strings
|
||||
/mongodb|mysql|postgres|redis|sqlite[:+]/i,
|
||||
/aws_access_key_id|aws_secret_access_key/i
|
||||
];
|
||||
|
||||
/**
|
||||
* Sanitizes an error message to prevent sensitive information leakage
|
||||
*
|
||||
* @param message - The raw error message
|
||||
* @returns A sanitized error message safe to show to users
|
||||
*/
|
||||
export function sanitizeErrorMessage(message: string): string {
|
||||
if (!message || typeof message !== 'string') {
|
||||
return 'An error occurred';
|
||||
}
|
||||
|
||||
let sanitized = message;
|
||||
|
||||
// Remove or mask sensitive patterns
|
||||
for (const pattern of SENSITIVE_PATTERNS) {
|
||||
sanitized = sanitized.replace(pattern, '[REDACTED]');
|
||||
}
|
||||
|
||||
// Limit length to prevent excessive error messages
|
||||
const MAX_LENGTH = 200;
|
||||
if (sanitized.length > MAX_LENGTH) {
|
||||
sanitized = sanitized.slice(0, MAX_LENGTH) + '...';
|
||||
}
|
||||
|
||||
// Ensure we have a non-empty message
|
||||
if (!sanitized.trim()) {
|
||||
return 'An error occurred while processing your request';
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a safe error object for API responses
|
||||
*
|
||||
* @param error - The original error
|
||||
* @returns A sanitized error object
|
||||
*/
|
||||
export function createSafeError(error: unknown): { error: string; code?: string } {
|
||||
if (error instanceof Error) {
|
||||
return {
|
||||
error: sanitizeErrorMessage(error.message),
|
||||
code: error.name || 'ERROR'
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof error === 'string') {
|
||||
return {
|
||||
error: sanitizeErrorMessage(error),
|
||||
code: 'ERROR'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
error: 'An unexpected error occurred',
|
||||
code: 'UNKNOWN_ERROR'
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user