-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvite.config.ts
More file actions
103 lines (86 loc) · 3.24 KB
/
Copy pathvite.config.ts
File metadata and controls
103 lines (86 loc) · 3.24 KB
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
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import tailwindcss from "@tailwindcss/vite";
import basicSsl from "@vitejs/plugin-basic-ssl";
/**
* Generates Content Security Policy header
* Restrictive policy to prevent XSS and data injection attacks
*/
function getCSPHeader(): string {
// Get API URL from environment or use default
// In Vite config, we can access process.env directly
const apiUrl = process.env.VITE_API_URL || "http://localhost:3000/api";
// Extract origin from API URL, with fallback
let apiOrigin = "http://localhost:3000";
try {
apiOrigin = new URL(apiUrl).origin;
} catch (error) {
console.warn(
`Invalid VITE_API_URL: ${apiUrl}. Using default origin: ${apiOrigin}`
);
}
// Build CSP directives
const directives = [
// Default source - only allow same origin
"default-src 'self'",
// Scripts - allow same origin, inline scripts with nonce, eval for Vue dev mode, blob URLs, and data URLs (for PDF.js workers)
// In production, consider using nonce-based approach instead of 'unsafe-inline'
"script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: data:",
// Styles - allow same origin and inline styles (Tailwind may need this)
// Consider using nonce-based approach in production
"style-src 'self' 'unsafe-inline'",
// Images - allow same origin, data URLs (for base64 images), blob URLs (for PDFs), and external sources
"img-src 'self' data: blob: https:",
// Fonts - allow same origin and data URLs
"font-src 'self' data:",
// Connect - allow same origin, API backend, Microsoft OAuth endpoints, blob URLs, and data URLs (for PDF.js)
`connect-src 'self' ${apiOrigin} https://login.microsoftonline.com https://login.live.com https://graph.microsoft.com blob: data:`,
// Media - allow same origin, blob URLs (for audio/video files)
"media-src 'self' blob: data:",
// Object - restrict embedded objects
"object-src 'none'",
// Base URI - prevent base tag injection
"base-uri 'self'",
// Form action - restrict form submissions to same origin and API
`form-action 'self' ${apiOrigin} https://login.microsoftonline.com https://login.live.com`,
// Frame ancestors - prevent clickjacking
"frame-ancestors 'none'",
// Upgrade insecure requests - force HTTPS
"upgrade-insecure-requests",
// Block all mixed content
"block-all-mixed-content",
];
return directives.join("; ");
}
export default defineConfig({
plugins: [vue(), tailwindcss(), basicSsl()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
server: {
port: 5173,
strictPort: true,
headers: {
"Content-Security-Policy": getCSPHeader(),
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"X-XSS-Protection": "1; mode=block",
"Referrer-Policy": "strict-origin-when-cross-origin",
"Permissions-Policy": "geolocation=(), microphone=(), camera=()",
},
},
preview: {
port: 4173,
headers: {
"Content-Security-Policy": getCSPHeader(),
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"X-XSS-Protection": "1; mode=block",
"Referrer-Policy": "strict-origin-when-cross-origin",
"Permissions-Policy": "geolocation=(), microphone=(), camera=()",
},
},
});