78 lines
2.7 KiB
TypeScript
78 lines
2.7 KiB
TypeScript
import { FreshContext } from '$fresh/server.ts'
|
|
import { SessionStore } from ':src/session/mod.ts'
|
|
import { getCookies, setCookie } from '@std/http/cookie'
|
|
|
|
export async function handler(request: Request, ctx: FreshContext) {
|
|
// Update fresh context state with session
|
|
ctx.state = { ...ctx.state, session: SessionStore.getFromRequest(request) }
|
|
|
|
// Get response
|
|
const response = await ctx.next()
|
|
|
|
//Add security headers
|
|
// See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/TLS#http_strict_transport_security
|
|
response.headers.set('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload')
|
|
response.headers.set('Content-Security-Policy', "frame-ancestors 'none'; upgrade-insecure-requests")
|
|
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/Referrer_policy
|
|
response.headers.set('Referrer-Policy', 'no-referrer, strict-origin-when-cross-origin')
|
|
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/MIME_types
|
|
response.headers.set('X-Content-Type-Options', 'nosniff')
|
|
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/Clickjacking
|
|
response.headers.set('X-Frame-Options', 'DENY')
|
|
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CORP
|
|
response.headers.set('Cross-Origin-Resource-Policy', 'same-origin')
|
|
//See https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
|
|
//? SRI plugin for non local resources only ?
|
|
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP
|
|
//? fresh useCSP https://fresh.deno.dev/docs/examples/using-csp
|
|
|
|
// Allow service worker to serve root scope
|
|
if (ctx.url.pathname.endsWith('island-startserviceworker.js')) {
|
|
response.headers.set('Service-Worker-Allowed', '/')
|
|
}
|
|
|
|
// Start session
|
|
if (SessionStore.getFromRequest(request) === undefined) {
|
|
// Clear outdated cookies
|
|
for (const cookie in getCookies(request.headers)) {
|
|
setCookie(response.headers, {
|
|
name: cookie,
|
|
value: '',
|
|
path: '/',
|
|
expires: 0,
|
|
})
|
|
}
|
|
|
|
// Create new session
|
|
const session = SessionStore.createSession()
|
|
ctx.state = { ...ctx.state, session }
|
|
|
|
// Set session cookie
|
|
setCookie(response.headers, {
|
|
name: '__Secure-SESSION',
|
|
value: session.uuid,
|
|
httpOnly: true,
|
|
sameSite: 'Strict',
|
|
secure: true,
|
|
path: '/',
|
|
expires: SessionStore.maxAge,
|
|
})
|
|
|
|
// Set csrf
|
|
const csrf = crypto.randomUUID()
|
|
session.set('_csrf', csrf)
|
|
|
|
setCookie(response.headers, {
|
|
name: '__Host-CSRF',
|
|
value: csrf,
|
|
httpOnly: false,
|
|
sameSite: 'Strict',
|
|
secure: true,
|
|
path: '/',
|
|
expires: SessionStore.maxAge,
|
|
})
|
|
}
|
|
|
|
return response
|
|
}
|