Files
habitica/website/server/middlewares/index.js
Kalista Payne af7114dee8 Squashed commit of the following:
commit cc6a35e61d
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 17:27:50 2025 -0600

    fix(CSP): more Amazon domains

commit 985b86c29a
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 17:18:08 2025 -0600

    fix(csp): more loggly allowance

commit 166bd31527
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 17:12:00 2025 -0600

    fix(csp): data, inline, some refactoring

commit 1a0a6c1806
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 17:05:44 2025 -0600

    fix(CSP): override default script-src

commit 023d9886c8
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 16:56:24 2025 -0600

    fix(CSP): unsafe-eval in default-src

commit f51f0a0c93
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 16:52:14 2025 -0600

    fix(CSP): move trusted list to default-src

commit 83b2ba7688
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 16:38:05 2025 -0600

    fix(CSP): explicit habitica/aws in script-src

commit d5ca5172d5
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 16:31:38 2025 -0600

    fix(CSP): need escaped single quotes

commit c677a1ffef
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 16:27:46 2025 -0600

    fix(CSP): unsafe-eval

commit 6ef35c3f72
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 16:15:07 2025 -0600

    fix(CSP): might need to skip entirely in dev but try no 'self'

commit 5759fb37d8
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 12 15:51:26 2025 -0600

    fix(csp): permit AWS in default-src

commit 9f238abf93
Author: Kalista Payne <kalista@habitica.com>
Date:   Fri Dec 5 17:22:25 2025 -0600

    fix(csp): update helmet version to latest

commit 9462e90f4f
Author: Kalista Payne <kalista@habitica.com>
Date:   Tue Nov 25 09:27:05 2025 -0600

    feat(security): implement CSP

commit 72539f9ba3
Author: Kalista Payne <kalista@habitica.com>
Date:   Wed Dec 10 14:16:53 2025 -0600

    5.42.2

commit dabd466719
Author: Kalista Payne <kalista@habitica.com>
Date:   Wed Dec 10 14:16:48 2025 -0600

    Revert "Chat optimization (#15545)"

    This reverts commit 2917955ef0.

commit 8bf2304330
Author: Kalista Payne <kalista@habitica.com>
Date:   Wed Dec 10 14:15:48 2025 -0600

    chore(event): G1G1 date tweaks

commit 6937dc4e4e
Author: Kalista Payne <kalista@habitica.com>
Date:   Mon Dec 8 16:37:04 2025 -0600

    fix(subscription): couple more layout tweaks
2025-12-12 17:31:02 -06:00

173 lines
5.0 KiB
JavaScript

// This module is only used to attach middlewares to the express app
import bodyParser from 'body-parser';
import nconf from 'nconf';
import morgan from 'morgan';
import cookieSession from 'cookie-session';
import mongoose from 'mongoose';
import compression from 'compression';
import methodOverride from 'method-override';
import passport from 'passport';
import basicAuth from 'express-basic-auth';
import helmet from 'helmet';
import setupExpress from '../libs/setupExpress';
import errorHandler from './errorHandler';
import notFoundHandler from './notFound';
import cors from './cors';
import staticMiddleware from './static';
import domainMiddleware from './domain';
// import favicon from 'serve-favicon';
// import path from 'path';
import maintenanceMode from './maintenanceMode';
import { ENABLE_CLUSTER } from '../libs/config';
import {
forceSSL,
forceHabitica,
} from './redirects';
import blocker from './blocker';
import v1 from './v1';
import v2 from './v2';
import appRoutes from './appRoutes';
import responseHandler from './response';
import {
attachTranslateFunction,
} from './language';
import {
logRequestData,
logSlowRequests,
} from './requestLogHandler';
const IS_PROD = nconf.get('IS_PROD');
const DISABLE_LOGGING = nconf.get('DISABLE_REQUEST_LOGGING') === 'true';
const ENABLE_HTTP_AUTH = nconf.get('SITE_HTTP_AUTH_ENABLED') === 'true';
const LOG_REQUESTS_EXCESSIVE_MODE = nconf.get('LOG_REQUESTS_EXCESSIVE_MODE') === 'true';
const SLOW_REQUEST_THRESHOLD = nconf.get('SLOW_REQUEST_THRESHOLD');
// const PUBLIC_DIR = path.join(__dirname, '/../../client');
const SESSION_SECRET = nconf.get('SESSION_SECRET');
const TEN_YEARS = 1000 * 60 * 60 * 24 * 365 * 10;
export default function attachMiddlewares (app, server) {
setupExpress(app);
if (LOG_REQUESTS_EXCESSIVE_MODE) {
app.use(logRequestData);
}
if (SLOW_REQUEST_THRESHOLD > 0) {
app.use(logSlowRequests);
}
if (ENABLE_CLUSTER) {
app.use(domainMiddleware(server, mongoose));
}
if (!IS_PROD && !DISABLE_LOGGING) app.use(morgan('dev'));
// See https://helmetjs.github.io/ for the list of headers enabled by default
app.use(helmet({
// New middlewares added by default in Helmet 4 are disabled
contentSecurityPolicy: {
directives: {
defaultSrc: [
'*.habitica.com',
'*.amazon.com',
'*.amazonaws.com',
'*.loggly.com',
'*.payments-amazon.com',
'*.stripe.com',
'*.stripe.network',
],
imgSrc: [
'*',
'data:',
],
scriptSrc: [
'\'unsafe-eval\'',
'\'unsafe-inline\'',
'*.habitica.com',
'*.amazon.com',
'*.amazonaws.com',
'*.loggly.com',
'*.payments-amazon.com',
'*.stripe.com',
'*.stripe.network',
],
upgradeInsecureRequests: IS_PROD ? [] : null,
},
},
expectCt: false,
permittedCrossDomainPolicies: false,
referrerPolicy: false,
}));
// add res.respond and res.t
app.use(responseHandler);
app.use(attachTranslateFunction);
app.use(compression());
// app.use(favicon(`${PUBLIC_DIR}/favicon.ico`));
app.use(maintenanceMode);
app.use(blocker);
app.use(cors);
app.use(forceSSL);
app.use(forceHabitica);
app.use(bodyParser.urlencoded({
extended: true, // Uses 'qs' library as old connect middleware
limit: '10mb',
}));
app.use(function bodyMiddleware (req, res, next) { // eslint-disable-line prefer-arrow-callback
if (req.path === '/stripe/webhooks') {
// Do not parse the body for `/stripe/webhooks`
// See https://stripe.com/docs/webhooks/signatures#verify-official-libraries
bodyParser.raw({ type: 'application/json' })(req, res, next);
} else {
bodyParser.json({ limit: '10mb' })(req, res, next);
}
});
app.use(methodOverride());
app.use(cookieSession({
name: 'connect:sess', // Used to keep backward compatibility with Express 3 cookies
secret: SESSION_SECRET,
httpOnly: true, // so cookies are not accessible with browser JS
// TODO what about https only (secure) ?
maxAge: TEN_YEARS,
}));
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
// The site can require basic HTTP authentication to be accessed
if (ENABLE_HTTP_AUTH) {
const httpBasicAuthUsers = {};
const usernames = nconf.get('SITE_HTTP_AUTH_USERNAMES').split(',');
const passwords = nconf.get('SITE_HTTP_AUTH_PASSWORDS').split(',');
usernames.forEach((user, index) => {
httpBasicAuthUsers[user] = passwords[index];
});
app.use(basicAuth({
users: httpBasicAuthUsers,
challenge: true,
realm: 'Habitica',
}));
}
app.use('/api/v2', v2);
app.use('/api/v1', v1);
app.use(appRoutes); // the main app, also setup top-level routes
staticMiddleware(app);
app.use(notFoundHandler);
// Error handler middleware, define as the last one.
app.use(errorHandler);
}