-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcdn.go
More file actions
117 lines (104 loc) · 3.91 KB
/
cdn.go
File metadata and controls
117 lines (104 loc) · 3.91 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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//go:build !localassets
// +build !localassets
// Package ui provides a set of UI components for Go web applications
package ui
import (
"fmt"
"net/http"
"strings"
)
// CDNConfig holds configuration for CDN resources used by UI components
type CDNConfig struct {
TailwindCSS string
Shoelace string
ShoelaceTheme string
HTMX string
ApexCharts string
D3 string
Helia string
Dexie string
}
// DefaultCDNConfig returns the default CDN configuration
func DefaultCDNConfig() CDNConfig {
return CDNConfig{
TailwindCSS: "https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4",
Shoelace: "https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.19.1/cdn/shoelace-autoloader.js",
ShoelaceTheme: "https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.19.1/cdn/themes/light.css",
HTMX: "https://unpkg.com/htmx.org@2.0.4",
ApexCharts: "https://cdn.jsdelivr.net/npm/apexcharts@4.3.0/dist/apexcharts.min.js",
D3: "https://cdn.jsdelivr.net/npm/d3@7",
Helia: "https://cdn.jsdelivr.net/npm/helia/dist/index.min.js",
Dexie: "https://unpkg.com/dexie@latest/dist/dexie.js",
}
}
// CDNResources represents the CDN resources as HTTP headers
type CDNResources struct {
config CDNConfig
}
// NewCDNResources creates a new CDN resources handler with default config
func NewCDNResources() *CDNResources {
return &CDNResources{
config: DefaultCDNConfig(),
}
}
// NewCDNResourcesWithConfig creates a new CDN resources handler with custom config
func NewCDNResourcesWithConfig(config CDNConfig) *CDNResources {
return &CDNResources{
config: config,
}
}
// AddPreloadHeaders adds preload headers for CDN resources to improve performance
func (c *CDNResources) AddPreloadHeaders(w http.ResponseWriter) {
// Preload critical resources
w.Header().Add("Link", "<"+c.config.TailwindCSS+">; rel=preload; as=script")
w.Header().Add("Link", "<"+c.config.Shoelace+">; rel=preload; as=script")
w.Header().Add("Link", "<"+c.config.HTMX+">; rel=preload; as=script")
w.Header().Add("Link", "<"+c.config.ShoelaceTheme+">; rel=preload; as=style")
}
// PreloadMiddleware returns middleware that adds preload headers for CDN resources
func PreloadMiddleware(next http.Handler) http.Handler {
cdn := NewCDNResources()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Only add preload headers for HTML responses
if strings.Contains(r.Header.Get("Accept"), "text/html") {
cdn.AddPreloadHeaders(w)
}
next.ServeHTTP(w, r)
})
}
// SecurityHeaders adds security headers for serving UI components
func SecurityHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Content Security Policy allowing CDN resources
csp := "default-src 'self'; " +
"script-src 'self' 'unsafe-inline' 'unsafe-eval' " +
"https://cdn.jsdelivr.net " +
"https://unpkg.com " +
"https://cdn.tailwindcss.com; " +
"style-src 'self' 'unsafe-inline' " +
"https://cdn.jsdelivr.net " +
"https://cdn.tailwindcss.com; " +
"font-src 'self' data: " +
"https://cdn.jsdelivr.net; " +
"img-src 'self' data: https:; " +
"connect-src 'self' https: wss:;"
w.Header().Set("Content-Security-Policy", csp)
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "SAMEORIGIN")
w.Header().Set("X-XSS-Protection", "1; mode=block")
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
next.ServeHTTP(w, r)
})
}
// CacheControl adds cache control headers for static assets
func CacheControl(maxAge int) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Set cache headers for static assets
if strings.HasPrefix(r.URL.Path, "/assets/") {
w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", maxAge))
}
next.ServeHTTP(w, r)
})
}
}