-
Notifications
You must be signed in to change notification settings - Fork 2
/
middleware.js
145 lines (131 loc) · 6.69 KB
/
middleware.js
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* ====================================
headers handling . . .
based on https://stackoverflow.com/questions/11560101/caching-json-with-cloudflare/56069077#56069077
as of 2021-05-01
nonce for CSP . . .
based on https://github.com/moveyourdigital/cloudflare-worker-csp-nonce
as of 2021-08-25
Also useful . . .
https://gist.github.com/RiFi2k/c3c65d59ca7f225e1d7d56929e0275ad
as of 2021-10-17
==================================== */
function dec2hex(dec) {
return ("0" + dec.toString(16)).substr(-2)
}
function generateNonce() {
const arr = new Uint8Array(12)
crypto.getRandomValues(arr)
const values = Array.from(arr, dec2hex)
return [
btoa(values.slice(0, 5).join("")).substr(0, 14),
btoa(values.slice(5).join("")),
].join("/")
}
export default async function handleRequest(request) {
const nonce = generateNonce()
try { // try-catch so a function crash doesn't crash the site
let response = await fetch(request)
let imageResponse = await fetch(request)
let type = imageResponse.headers.get("Content-Type") || ""
if (!type.startsWith("text/")) {
// Not text. Don't modify.
let newHeaders = new Headers(imageResponse.headers)
newHeaders.set("Cache-Control", "public, max-age=15768000, immutable")
newHeaders.set("CDN-Cache-Control", "public, max-age=15768000, immutable")
newHeaders.set("x-Non-Text-Item", "Non-text item - headers successfully edited")
// newHeaders.set("Permissions-Policy", "interest-cohort=()")
newHeaders.set("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
newHeaders.set("X-Frame-Options", "SAMEORIGIN")
newHeaders.set("X-Content-Type-Options", "nosniff")
newHeaders.set("Referrer-Policy", "no-referrer, strict-origin-when-cross-origin")
return new Response(imageResponse.body, {
status: imageResponse.status,
statusText: imageResponse.statusText,
headers: newHeaders
})
}
const html = (await response.text())
.replace(/DhcnhD3khTMePgXw/gi, nonce)
.replace(
'src="https://ajax.cloudflare.com',
`nonce="${nonce}" src="https://ajax.cloudflare.com`
)
.replace( // single opening quotation mark
`src='https://static.cloudflareinsights.com`,
`nonce="${nonce}" src='https://static.cloudflareinsights.com`
)
.replace( // double opening quotation mark
`src="https://static.cloudflareinsights.com`,
`nonce="${nonce}" src="https://static.cloudflareinsights.com`
)
.replace( // if using CF's addy obfuscation
'cloudflare-static/email-decode.min.js"',
`cloudflare-static/email-decode.min.js" nonce="${nonce}"`
)
.replace(
'rel="stylesheet"',
`rel="stylesheet" nonce="${nonce}"`
)
.replace(/<link rel="preload"/g, `<link nonce="${nonce}" rel="preload"`)
.replace(
'cdn.usefathom.com/script.js"',
`cdn.usefathom.com/script.js" nonce="${nonce}"`
)
.replace(
'src="/assets/js/lite-yt-embed_',
`nonce="${nonce}" src="/assets/js/lite-yt-embed_`
)
.replace(/<style/g, `<style nonce="${nonce}"`)
let ttl = undefined
// let cache = caches.default
let url = new URL(request.url)
// let shouldCache = false
let jsStuff = false
let svgStuff = false
const filesRegex = /(.*\.(ac3|avi|bmp|br|bz2|css|cue|dat|doc|docx|dts|eot|exe|flv|gif|gz|ico|img|iso|jpeg|jpg|js|json|map|mkv|mp3|mp4|mpeg|mpg|ogg|pdf|png|ppt|pptx|qt|rar|rm|svg|swf|tar|tgz|ttf|txt|wav|webp|webm|webmanifest|woff|woff2|xls|xlsx|xml|zip))$/
const jsRegex = /(.*\.(js))$/
const svgRegex = /(.*\.(svg))$/
if (url.pathname.match(filesRegex)) {
// shouldCache = true
ttl = 31536000
}
if (url.pathname.match(jsRegex)) {
jsStuff = true
}
if (url.pathname.match(svgRegex)) {
svgStuff = true
}
let newHeaders = new Headers(response.headers)
// newHeaders.set("Permissions-Policy", "interest-cohort=()")
newHeaders.set("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
newHeaders.set("X-Frame-Options", "SAMEORIGIN")
newHeaders.set("X-Content-Type-Options", "nosniff")
newHeaders.set("Referrer-Policy", "no-referrer, strict-origin-when-cross-origin")
if (ttl) {
newHeaders.set("Cache-Control", "public, max-age=" + ttl + ", immutable")
newHeaders.set("CDN-Cache-Control", "public, max-age=" + ttl + ", immutable")
newHeaders.set("X-TTL-Setting", ttl)
newHeaders.set("X-CSS-Test", "Test header works")
} else {
newHeaders.set("Cache-Control", "public, max-age=0, must-revalidate")
newHeaders.set("Content-Security-Policy", `base-uri 'self' https://*.brycewray.com; connect-src 'self' https://*.brycewray.com https://*.cloudinary.com https://*.cloudflareinsights.com https://cloudflareinsights.com https://*.ytimg.com https://*.youtube-nocookie.com https://*.mastodon.social https://cdn.masto.host https://*.zachleat.com https://*.usefathom.com; default-src 'self'; frame-ancestors 'self' https://*.brycewray.com https://*.youtube-nocookie.com; font-src 'self' https://*.brycewray.com data: https://giscus.app https://fonts.gstatic.com; form-action 'self' mailto: https://*.duckduckgo.com https://duckduckgo.com; frame-src 'self' https://*.brycewray.com https://*.youtube-nocookie.com https://giscus.app; img-src 'self' https://*.brycewray.com https://*.usefathom.com https://*.cloudinary.com https://*.ytimg.com https://*.youtube-nocookie.com https://*.twimg.com https://*.mastodon.social https://*.fosstodon.org https://cdn.masto.host https://*.zachleat.com https://*.google.com https://translate.googleapis.com data:; media-src 'self' https://*.brycewray.com https://*.cloudinary.com https://*.ytimg.com https://*.youtube-nocookie.com https://*.twimg.com https://*.mastodon.social https://*.fosstodon.org https://cdn.masto.host https://*.zachleat.com data:; object-src 'none'; script-src 'self' 'nonce-${nonce}' https://giscus.app 'unsafe-inline' 'unsafe-eval'; script-src-elem 'self' 'nonce-${nonce}' https://giscus.app; style-src 'self' 'unsafe-inline' https://*.brycewray.com https://*.youtube-nocookie.com data: https://*.google.com https://translate.googleapis.com https://giscus.app https://fonts.googleapis.com; report-uri https://brycewray.report-uri.com/r/d/csp/reportOnly;`)
newHeaders.set("Report-To", "{'group':'default','max_age':31536000,'endpoints':[{'url':'https://brycewray.report-uri.com/a/d/g'}],'include_subdomains':true}")
newHeaders.set("X-XSS-Protection", "1")
newHeaders.set("Permissions-Policy", "fullscreen=*, picture-in-picture=*, xr-spatial-tracking=*")
}
newHeaders.set("CF-nonce-generator", "HIT")
if (jsStuff) {
newHeaders.set("Content-Type", "application/javascript; charset=utf-8")
}
if (svgStuff) {
newHeaders.set("Content-Type", "image/svg+xml; charset=utf-8")
}
return new Response(html, {
status: response.status,
statusText: response.statusText,
headers: newHeaders
})
} catch (error) {
console.log(error)
}
}