Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | /** * Vue 3 Security Plugin * * Integrates client-side security monitoring with Vue.js application */ import securityMonitor from '../utils/security-monitor.js'; import { getApiBaseUrl } from '../config/api'; import { recordError } from '../faro'; const SecurityPlugin = { install(app, options = {}) { // Enable the security monitor securityMonitor.enable(); // Make security monitor available globally app.config.globalProperties.$security = securityMonitor; app.provide('security', securityMonitor); // Set up Vue-specific error handling const originalErrorHandler = app.config.errorHandler; app.config.errorHandler = (err, instance, info) => { const componentName = instance?.$options?.name || instance?.$?.type?.name || 'Unknown'; // Report Vue errors to security monitor securityMonitor.reportCustomEvent('vue_error', 'medium', { error: { message: err.message, stack: err.stack, name: err.name, }, componentInfo: info, componentName, location: window.location.href, }); // Record error metric for OTEL recordError('vue_error', { component: componentName, severity: 'medium', }); // Call original handler if it exists if (originalErrorHandler) { originalErrorHandler(err, instance, info); } else { console.error('Vue Error:', err, info); } }; // Set up Content Security Policy headers monitoring if (options.csp !== false) { this.setupCSPHeaders(); } // Set up performance monitoring for Vue components if (options.performanceMonitoring !== false) { this.setupVuePerformanceMonitoring(app); } }, setupCSPHeaders() { // Add CSP meta tag if not present if (!document.querySelector('meta[http-equiv="Content-Security-Policy"]')) { const cspMeta = document.createElement('meta'); cspMeta.setAttribute('http-equiv', 'Content-Security-Policy'); cspMeta.setAttribute('content', this.getCSPPolicy()); document.head.appendChild(cspMeta); } }, getCSPPolicy() { // Define a strict CSP policy // Use runtime API detection const apiUrl = getApiBaseUrl(); const policy = [ "default-src 'self'", "script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://unpkg.com", "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net", "font-src 'self' https://fonts.gstatic.com", `img-src 'self' data: https: ${apiUrl.startsWith('http://') ? 'http://127.0.0.1:*' : ''}`, `connect-src 'self' ${apiUrl} https://api.github.com https://*.grafana.net ws: wss:`, "frame-src 'none'", "object-src 'none'", "base-uri 'self'", "form-action 'self'", "frame-ancestors 'none'", 'block-all-mixed-content', 'upgrade-insecure-requests', ].join('; '); return policy; }, setupVuePerformanceMonitoring(app) { // Monitor component render times const originalMount = app.mount; app.mount = function (...args) { const start = performance.now(); const result = originalMount.apply(this, args); const duration = performance.now() - start; if (duration > 1000) { // Slow mount (> 1 second) securityMonitor.reportCustomEvent('slow_component_mount', 'low', { duration, component: 'app_root', type: 'mount_performance', }); } return result; }; }, }; export default SecurityPlugin; |