🔒️ Add security headers for cloudflare (#100)

* 🔒️ Add security headers for cloudflare

add security headers for cloudflare

* 🔧 Add plugin to quartz config to include custom headers

add plugin to quartz config to include custom headers on build

* ♻️ Csp update to allow stylesheets

csp update to allow stylesheets

* 🔒️ Unblocks KaTeX fonts

unblocks KaTeX fonts

* ♻️ Adds function to include quartz/static in addition to static directory at root

adds back function to include quartz/static in addition to new static directory at root
This commit is contained in:
Eri Barrett 2025-04-29 17:30:34 -04:00 committed by GitHub
parent 1f5c5417b4
commit 19f239dfae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 65 additions and 0 deletions

View File

@ -1,5 +1,61 @@
import { QuartzConfig } from "./quartz/cfg"
import * as Plugin from "./quartz/plugins"
import { Argv, BuildCtx } from "./quartz/util/ctx"
import fs from "fs"
import path from "path"
import { FilePath } from "./quartz/util/path"
import { glob } from "./quartz/util/glob"
// Custom plugin to copy all files from static/ to the root of public/
const CopyStatic = () => ({
name: "CopyStatic",
getQuartzComponents() {
return []
},
async emit({ argv, cfg }: BuildCtx): Promise<FilePath[]> {
const staticPath = "static"
const publicPath = argv.output
try {
// Ensure static path exists
if (!fs.existsSync(staticPath)) {
console.log("Static directory does not exist, skipping copy.")
return []
}
// Use glob to find all files in static directory, respecting ignore patterns
const files = await glob("**/*", staticPath, cfg.configuration.ignorePatterns)
const outputFiles: FilePath[] = []
for (const file of files) {
const sourceFilePath = path.join(staticPath, file) as FilePath
// Skip if it's a directory (glob might return directories)
if ((await fs.promises.lstat(sourceFilePath)).isDirectory()) {
continue;
}
const destFilePath = path.join(publicPath, file) as FilePath
const destDir = path.dirname(destFilePath)
// Ensure destination directory exists
await fs.promises.mkdir(destDir, { recursive: true })
// Copy file
await fs.promises.copyFile(sourceFilePath, destFilePath)
outputFiles.push(destFilePath)
}
if (outputFiles.length > 0) {
console.log(`Successfully copied ${outputFiles.length} files from static/ to public/`)
}
return outputFiles
} catch (err) {
console.error("Error copying static files:", err)
return []
}
}
})
/**
* Quartz 4.0 Configuration
@ -85,6 +141,7 @@ const config: QuartzConfig = {
enableRSS: true,
}),
Plugin.Assets(),
CopyStatic(),
Plugin.Static(),
Plugin.NotFoundPage(),
],

8
static/_headers Normal file
View File

@ -0,0 +1,8 @@
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.posthog.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://fonts.googleapis.com; img-src 'self' data: blob: https:; font-src 'self' data: https://fonts.gstatic.com https://cdnjs.cloudflare.com; worker-src 'self' blob:; connect-src 'self' https://*.posthog.com; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; upgrade-insecure-requests; block-all-mixed-content