diff --git a/server/app.js b/server/app.js index 95c243108..c4a63669c 100644 --- a/server/app.js +++ b/server/app.js @@ -29,7 +29,6 @@ const scriptSrc = [ "'unsafe-inline'", "'unsafe-eval'", "gist.github.com", - "browser.sentry-cdn.com", ]; if (env.GOOGLE_ANALYTICS_ID) { @@ -122,8 +121,8 @@ if (process.env.SENTRY_DSN) { maxBreadcrumbs: 0, ignoreErrors: [ // emitted by Koa when bots attempt to snoop on paths such as wp-admin - // or the user submits a bad request. These are expected in normal running - // of the application + // or the user client submits a bad request. These are expected in normal + // running of the application and don't need to be reported. "BadRequestError", "UnauthorizedError", ], @@ -168,6 +167,8 @@ app.on("error", (error, ctx) => { app.use(mount("/auth", auth)); app.use(mount("/api", api)); +// Sets common security headers by default, such as no-sniff, hsts, hide powered +// by etc app.use(helmet()); app.use( contentSecurityPolicy({ @@ -178,18 +179,14 @@ app.use( imgSrc: ["*", "data:", "blob:"], frameSrc: ["*"], connectSrc: ["*"], - // Removed because connect-src: self + websockets does not work in Safari - // Ref: https://bugs.webkit.org/show_bug.cgi?id=201591 - // connectSrc: compact([ - // "'self'", - // process.env.AWS_S3_UPLOAD_BUCKET_URL.replace("s3:", "localhost:"), - // "www.google-analytics.com", - // "api.github.com", - // "sentry.io", - // ]), + // Do not use connect-src: because self + websockets does not work in + // Safari, ref: https://bugs.webkit.org/show_bug.cgi?id=201591 }, }) ); + +// Allow DNS prefetching for performance, we do not care about leaking requests +// to our own CDN's app.use(dnsPrefetchControl({ allow: true })); app.use(referrerPolicy({ policy: "no-referrer" })); app.use(mount(routes)); diff --git a/server/routes.js b/server/routes.js index 37077ccfc..2bc3e2835 100644 --- a/server/routes.js +++ b/server/routes.js @@ -7,7 +7,7 @@ import Router from "koa-router"; import sendfile from "koa-sendfile"; import serve from "koa-static"; import { languages } from "../shared/i18n"; -import environment from "./env"; +import env from "./env"; import apexRedirect from "./middlewares/apexRedirect"; import { opensearchResponse } from "./utils/opensearch"; import prefetchTags from "./utils/prefetchTags"; @@ -45,12 +45,12 @@ const renderApp = async (ctx, next) => { } const page = await readIndexFile(ctx); - const env = ` - window.env = ${JSON.stringify(environment)}; + const environment = ` + window.env = ${JSON.stringify(env)}; `; ctx.body = page .toString() - .replace(/\/\/inject-env\/\//g, env) + .replace(/\/\/inject-env\/\//g, environment) .replace(/\/\/inject-prefetch\/\//g, prefetchTags) .replace(/\/\/inject-slack-app-id\/\//g, process.env.SLACK_APP_ID || ""); }; @@ -111,7 +111,19 @@ router.get("/share/*", (ctx, next) => { // catch all for application router.get("*", renderApp); -// middleware +// In order to report all possible performance metrics to Sentry this header +// must be provided when serving the application, see: +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin +const timingOrigins = [env.URL]; +if (env.SENTRY_DSN) { + timingOrigins.push("https://sentry.io"); +} + +koa.use(async (ctx, next) => { + ctx.set("Timing-Allow-Origin", timingOrigins.join(", ")); + await next(); +}); + koa.use(apexRedirect()); koa.use(router.routes()); diff --git a/server/utils/prefetchTags.js b/server/utils/prefetchTags.js index 8fdcda291..b80103b54 100644 --- a/server/utils/prefetchTags.js +++ b/server/utils/prefetchTags.js @@ -28,6 +28,7 @@ try { // no-op } +let index = 0; Object.values(manifestData).forEach((filename) => { if (typeof filename !== "string") return; if (!env.CDN_URL) return; @@ -40,14 +41,19 @@ Object.values(manifestData).forEach((filename) => { filename.includes("/runtime") || filename.includes("/vendors"); - prefetchTags.push( - - ); + // only prefetch the first few javascript chunks or it gets out of hand fast + const shouldPrefetch = ++index <= 6; + + if (shouldPreload || shouldPrefetch) { + prefetchTags.push( + + ); + } } else if (filename.endsWith(".css")) { prefetchTags.push(