Files
outline/server/services/web.ts
Tom Moor 53414ec3ba feat: Server side translation setup (#4657)
* Server side translation setup

* docs
2023-01-07 11:52:09 -08:00

143 lines
4.0 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-var-requires */
import Koa from "koa";
import {
contentSecurityPolicy,
dnsPrefetchControl,
referrerPolicy,
} from "koa-helmet";
import mount from "koa-mount";
import enforceHttps, { xForwardedProtoResolver } from "koa-sslify";
import env from "@server/env";
import Logger from "@server/logging/Logger";
import { initI18n } from "@server/utils/i18n";
import routes from "../routes";
import api from "../routes/api";
import auth from "../routes/auth";
const isProduction = env.ENVIRONMENT === "production";
const isTest = env.ENVIRONMENT === "test";
// Construct scripts CSP based on services in use by this installation
const defaultSrc = ["'self'"];
const scriptSrc = [
"'self'",
"'unsafe-inline'",
"'unsafe-eval'",
"gist.github.com",
"www.googletagmanager.com",
"cdn.zapier.com",
];
if (env.GOOGLE_ANALYTICS_ID) {
scriptSrc.push("www.google-analytics.com");
}
if (env.CDN_URL) {
scriptSrc.push(env.CDN_URL);
defaultSrc.push(env.CDN_URL);
}
export default function init(app: Koa = new Koa()): Koa {
initI18n();
if (isProduction) {
// Force redirect to HTTPS protocol unless explicitly disabled
if (env.FORCE_HTTPS) {
app.use(
enforceHttps({
resolver: xForwardedProtoResolver,
})
);
} else {
Logger.warn("Enforced https was disabled with FORCE_HTTPS env variable");
}
// trust header fields set by our proxy. eg X-Forwarded-For
app.proxy = true;
} else if (!isTest) {
const convert = require("koa-convert");
const webpack = require("webpack");
const devMiddleware = require("koa-webpack-dev-middleware");
const hotMiddleware = require("koa-webpack-hot-middleware");
const config = require("../../webpack.config.dev");
const compile = webpack(config);
/* eslint-enable global-require */
const middleware = devMiddleware(compile, {
// display no info to console (only warnings and errors)
noInfo: true,
// display nothing to the console
quiet: false,
watchOptions: {
poll: 1000,
ignored: ["node_modules", "flow-typed", "server", "build", "__mocks__"],
},
// Uncomment to test service worker
// headers: {
// "Service-Worker-Allowed": "/",
// },
// public path to bind the middleware to
// use the same as in webpack
publicPath: config.output.publicPath,
// options for formatting the statistics
stats: {
colors: true,
},
});
app.use(async (ctx, next) => {
ctx.webpackConfig = config;
ctx.devMiddleware = middleware;
await next();
});
app.use(convert(middleware));
app.use(
convert(
hotMiddleware(compile, {
// @ts-expect-error ts-migrate(7019) FIXME: Rest parameter 'args' implicitly has an 'any[]' ty... Remove this comment to see the full error message
log: (...args) => Logger.info("lifecycle", ...args),
path: "/__webpack_hmr",
heartbeat: 10 * 1000,
})
)
);
}
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, these are applied after auth and api so they are only returned on
// standard non-XHR accessed routes
app.use(
contentSecurityPolicy({
directives: {
defaultSrc,
scriptSrc,
styleSrc: [
"'self'",
"'unsafe-inline'",
"github.githubassets.com",
"cdn.zapier.com",
],
imgSrc: ["*", "data:", "blob:"],
frameSrc: ["*", "data:"],
connectSrc: ["*"], // 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));
return app;
}