Files
MNQ-Catering-y-Evento/src/middleware.ts
T
manuyasm87 d17f75c423 fix(seo): add baseline security headers; unify brand name to singular
- src/middleware.ts now sets HSTS, X-Content-Type-Options, X-Frame-Options,
  Referrer-Policy, and Permissions-Policy on every response -- all were
  absent per the 2026-09-15 audit. CSP deliberately left out: the site
  uses unnoned inline scripts, inline style attributes throughout, and a
  runtime-configured analytics script host, so a real CSP needs its own
  pass with live testing rather than a guess.
- SiteHeader.astro and SiteFooter.astro logo alt/aria-label said 'MNQ
  Catering y Eventos' (plural) while every title tag, the JSON-LD name,
  og:site_name, and package.json all say 'MNQ Catering y Evento'
  (singular) -- unified to the singular form used everywhere else.
2026-09-15 10:31:33 +02:00

47 lines
2.3 KiB
TypeScript

import { defineMiddleware } from 'astro:middleware';
const CANONICAL_HOST = 'www.mnqeventos.es';
/**
* SEO: enforce the canonical host at the application layer. www.mnqeventos.es
* is the real, registered, live production domain. mnqcatering.com was an
* intended rename that was never actually registered (confirmed via WHOIS —
* no match) — do NOT set CANONICAL_HOST back to it unless that domain is
* actually purchased and its DNS points at this server, or this redirect
* will send every visitor to a host that doesn't resolve.
*
* NOTE: this must also be verified at the reverse-proxy/hosting layer — host
* detection here depends on how the Host header (or X-Forwarded-Host, when
* behind a proxy) actually arrives in production. If the proxy doesn't
* forward the original host, this check will see the wrong value.
*/
export const onRequest = defineMiddleware(async (context, next) => {
const requestHost = context.url.host;
if (requestHost !== CANONICAL_HOST) {
const redirectUrl = new URL(context.url.pathname + context.url.search, `https://${CANONICAL_HOST}`);
return context.redirect(redirectUrl.toString(), 301);
}
const response = await next();
// Baseline security headers (flagged missing in the 2026-09-15 SEO/security
// audit — no HSTS, X-Content-Type-Options, X-Frame-Options, or
// Referrer-Policy were present on any response).
//
// Deliberately NOT setting Content-Security-Policy here: the site relies on
// inline <script> blocks (no nonce/hash setup), inline style="" attributes
// throughout every page, and an optional analytics script loaded from a
// runtime-configured host (PUBLIC_UMAMI_URL). A CSP tight enough to matter
// would need nonces wired through every inline script/style or it will
// silently break rendering/interactivity in production. Needs its own pass
// with live testing, not a guess baked in here.
response.headers.set('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload');
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
response.headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
return response;
});