From 4bb0e40b36b57aa700068e6c6e90fe8ee9c5de4e Mon Sep 17 00:00:00 2001 From: zkldi Date: Tue, 2 Nov 2021 20:38:29 +0000 Subject: [PATCH] Refactor how NODE_ENV is used. --- server/src/external/mongo/db.ts | 2 +- server/src/lib/cdn/cdn.test.ts | 2 +- server/src/lib/email/client.ts | 4 ++-- server/src/lib/setup/config.ts | 16 +++++++++++++++- server/src/main.ts | 2 +- server/src/server/middleware/rate-limiter.ts | 4 ++-- server/src/server/router/api/v1/auth/auth.ts | 4 ++-- server/src/server/router/api/v1/auth/router.ts | 6 +++--- .../router/api/v1/oauth/clients/middleware.ts | 3 ++- .../_userID/integrations/kai/_kaiType/router.ts | 3 ++- server/src/server/server.ts | 14 +++++++------- server/src/utils/fetch.ts | 3 ++- 12 files changed, 40 insertions(+), 23 deletions(-) diff --git a/server/src/external/mongo/db.ts b/server/src/external/mongo/db.ts index bfde9ce49..d69d7d72b 100644 --- a/server/src/external/mongo/db.ts +++ b/server/src/external/mongo/db.ts @@ -47,7 +47,7 @@ const logger = CreateLogCtx(__filename); let dbName = ServerConfig.MONGO_DATABASE_NAME; /* istanbul ignore next */ -if (process.env.NODE_ENV === "test") { +if (Environment.nodeEnv === "test") { dbName = `testingdb`; } diff --git a/server/src/lib/cdn/cdn.test.ts b/server/src/lib/cdn/cdn.test.ts index d45f56a5f..a09fcc8fe 100644 --- a/server/src/lib/cdn/cdn.test.ts +++ b/server/src/lib/cdn/cdn.test.ts @@ -13,7 +13,7 @@ function getTestTxt() { } const ResetFileRoot = () => { - if (process.env.NODE_ENV !== "test") { + if (Environment.nodeEnv !== "test") { throw new Error( `Not in test, yet CDN.test.ts was triggered, which could rm -rf something important.` ); diff --git a/server/src/lib/email/client.ts b/server/src/lib/email/client.ts index 01daea050..910feb110 100644 --- a/server/src/lib/email/client.ts +++ b/server/src/lib/email/client.ts @@ -1,5 +1,5 @@ import CreateLogCtx from "lib/logger/logger"; -import { ServerConfig } from "lib/setup/config"; +import { Environment, ServerConfig } from "lib/setup/config"; import nodemailer, { SentMessageInfo, Transporter } from "nodemailer"; const logger = CreateLogCtx(__filename); @@ -34,7 +34,7 @@ if (ServerConfig.EMAIL_CONFIG) { } export function SendEmail(to: string, htmlContent: string): Promise | undefined { - if (process.env.NODE_ENV === "test") { + if (Environment.nodeEnv === "test") { logger.debug(`Stubbed out SendEmail as env was test.`); return; } diff --git a/server/src/lib/setup/config.ts b/server/src/lib/setup/config.ts index 54dc2f45c..5a06c84cf 100644 --- a/server/src/lib/setup/config.ts +++ b/server/src/lib/setup/config.ts @@ -169,10 +169,24 @@ if (!cdnRoot) { process.exit(1); } +const nodeEnv = process.env.NODE_ENV; +if (!nodeEnv) { + logger.error(`No NODE_ENV specified in environment. Terminating.`); + process.exit(1); +} + +if (!["dev", "production", "staging", "test"].includes(nodeEnv)) { + logger.error( + `Invalid NODE_ENV set in environment. Expected dev, production, test or staging. Got ${nodeEnv}.` + ); + process.exit(1); +} + export const Environment = { port, redisUrl, mongoUrl, // If node_env is test, force to ./test-cdn. - cdnRoot: process.env.NODE_ENV === "test" ? "./test-cdn" : cdnRoot, + cdnRoot: nodeEnv === "test" ? "./test-cdn" : cdnRoot, + nodeEnv, }; diff --git a/server/src/main.ts b/server/src/main.ts index 17c596b4e..8999cfbf9 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -10,7 +10,7 @@ import { InitSequenceDocs } from "external/mongo/sequence-docs"; const logger = CreateLogCtx(__filename); -logger.info(`Booting ${ServerTypeInfo.name} - ${FormatVersion()} [ENV: ${process.env.NODE_ENV}]`); +logger.info(`Booting ${ServerTypeInfo.name} - ${FormatVersion()} [ENV: ${Environment.nodeEnv}]`); logger.info(`Log level is set to ${ServerConfig.LOG_LEVEL}.`); logger.info(`Loading sequence documents...`); diff --git a/server/src/server/middleware/rate-limiter.ts b/server/src/server/middleware/rate-limiter.ts index 01f593946..e3606ecc5 100644 --- a/server/src/server/middleware/rate-limiter.ts +++ b/server/src/server/middleware/rate-limiter.ts @@ -1,5 +1,5 @@ import RateLimitRedis from "rate-limit-redis"; -import { ServerConfig } from "lib/setup/config"; +import { Environment, ServerConfig } from "lib/setup/config"; import rateLimit from "express-rate-limit"; import CreateLogCtx from "lib/logger/logger"; import { RedisClient } from "external/redis/redis"; @@ -7,7 +7,7 @@ import { RedisClient } from "external/redis/redis"; const logger = CreateLogCtx(__filename); const store = - process.env.NODE_ENV === "production" + Environment.nodeEnv === "production" || Environment.nodeEnv === "staging" ? new RateLimitRedis({ prefix: `${ServerConfig.TYPE}-RL:`, client: RedisClient }) : undefined; // undefined forces a default to an in-memory store diff --git a/server/src/server/router/api/v1/auth/auth.ts b/server/src/server/router/api/v1/auth/auth.ts index 574fd5025..87679e6a9 100644 --- a/server/src/server/router/api/v1/auth/auth.ts +++ b/server/src/server/router/api/v1/auth/auth.ts @@ -11,7 +11,7 @@ import CreateLogCtx from "lib/logger/logger"; import { FormatUserDoc } from "utils/user"; import nodeFetch from "utils/fetch"; import { Random20Hex } from "utils/misc"; -import { ServerConfig } from "lib/setup/config"; +import { Environment, ServerConfig } from "lib/setup/config"; import { CreateURLWithParams } from "utils/url"; const logger = CreateLogCtx(__filename); @@ -173,5 +173,5 @@ export function MountAuthCookie( }; req.session.cookie.maxAge = 3.154e10; - req.session.cookie.secure = process.env.NODE_ENV === "production"; + req.session.cookie.secure = Environment.nodeEnv === "production"; } diff --git a/server/src/server/router/api/v1/auth/router.ts b/server/src/server/router/api/v1/auth/router.ts index 657781fa2..cc2bdca57 100644 --- a/server/src/server/router/api/v1/auth/router.ts +++ b/server/src/server/router/api/v1/auth/router.ts @@ -25,7 +25,7 @@ import { DecrementCounterValue, GetNextCounterValue } from "utils/db"; import { SendEmail } from "lib/email/client"; import { EmailFormatResetPassword, EmailFormatVerifyEmail } from "lib/email/formats"; import { Random20Hex } from "utils/misc"; -import { ServerConfig } from "lib/setup/config"; +import { Environment, ServerConfig } from "lib/setup/config"; import { integer } from ".pnpm/tachi-common@0.2.36/node_modules/tachi-common"; const logger = CreateLogCtx(__filename); @@ -64,7 +64,7 @@ router.post( logger.verbose(`Recieved login request with username ${req.body.username} (${req.ip})`); /* istanbul ignore next */ - if (process.env.NODE_ENV === "production") { + if (Environment.nodeEnv === "production" || Environment.nodeEnv === "staging") { logger.verbose("Validating captcha..."); const validCaptcha = await ValidateCaptcha( req.body.recaptcha, @@ -177,7 +177,7 @@ router.post( logger.verbose(`Recieved register request with username ${req.body.username} (${req.ip})`); /* istanbul ignore next */ - if (process.env.NODE_ENV === "production") { + if (Environment.nodeEnv === "production" || Environment.nodeEnv === "staging") { logger.verbose("Validating captcha..."); const validCaptcha = await ValidateCaptcha( req.body.recaptcha, diff --git a/server/src/server/router/api/v1/oauth/clients/middleware.ts b/server/src/server/router/api/v1/oauth/clients/middleware.ts index 050ccdcae..502ec1533 100644 --- a/server/src/server/router/api/v1/oauth/clients/middleware.ts +++ b/server/src/server/router/api/v1/oauth/clients/middleware.ts @@ -1,6 +1,7 @@ import { RequestHandler } from "express"; import db from "external/mongo/db"; import { SYMBOL_TachiData } from "lib/constants/tachi"; +import { Environment } from "lib/setup/config"; import { OAuth2ApplicationDocument } from "tachi-common"; import { AssignToReqTachiData } from "utils/req-tachi-data"; @@ -36,7 +37,7 @@ export const RequireOwnershipOfClient: RequestHandler = (req, res, next) => { // request. To hack around this for testing, we perform this hack. // There's an open issue for this here: https://github.com/i-like-robots/express-request-mock/issues/19 /* istanbul ignore next */ - if (process.env.NODE_ENV === "test" && req.body.__terribleHackOauth2ClientDoc) { + if (Environment.nodeEnv === "test" && req.body.__terribleHackOauth2ClientDoc) { // obviously a glaring hack and security flaw - this only applies // in testing. client = req.body.__terribleHackOauth2ClientDoc; diff --git a/server/src/server/router/api/v1/users/_userID/integrations/kai/_kaiType/router.ts b/server/src/server/router/api/v1/users/_userID/integrations/kai/_kaiType/router.ts index 285c3c4fc..812beea1c 100644 --- a/server/src/server/router/api/v1/users/_userID/integrations/kai/_kaiType/router.ts +++ b/server/src/server/router/api/v1/users/_userID/integrations/kai/_kaiType/router.ts @@ -15,6 +15,7 @@ import { RequireSelfRequestFromUser } from "../../../middleware"; import { RequireKamaitachi } from "server/middleware/type-require"; import fetch from "utils/fetch"; import { Random20Hex } from "utils/misc"; +import { Environment } from "lib/setup/config"; const router: Router = Router({ mergeParams: true }); @@ -71,7 +72,7 @@ router.post( const user = req[SYMBOL_TachiData]!.requestedUser!; const kaiType = req.params.kaiType.toUpperCase() as "FLO" | "EAG" | "MIN"; - if (process.env.NODE_ENV === "dev") { + if (Environment.nodeEnv === "dev") { await db["kai-auth-tokens"].update( { userID: user.id, diff --git a/server/src/server/server.ts b/server/src/server/server.ts index 45b371460..2e3d5ab6a 100644 --- a/server/src/server/server.ts +++ b/server/src/server/server.ts @@ -12,7 +12,7 @@ const logger = CreateLogCtx(__filename); let store; -if (process.env.NODE_ENV !== "test") { +if (Environment.nodeEnv !== "test") { logger.info("Connecting ExpressSession to Redis."); const RedisStore = connectRedis(expressSession); store = new RedisStore({ @@ -27,20 +27,20 @@ const userSessionMiddleware = expressSession({ // append node_env onto the end of the session name // so we can separate tokens under the same URL. // say for staging.kamaitachi.xyz - name: `${ServerConfig.TYPE}_${process.env.NODE_ENV}_session`, + name: `${ServerConfig.TYPE}_${Environment.nodeEnv}_session`, secret: ServerConfig.SESSION_SECRET, store, resave: true, saveUninitialized: false, cookie: { - secure: process.env.NODE_ENV === "production" || ServerConfig.ENABLE_SERVER_HTTPS, + secure: Environment.nodeEnv === "production" || ServerConfig.ENABLE_SERVER_HTTPS, sameSite: "lax", // Very important. Without this, we're vulnerable to CSRF! }, }); const app: Express = express(); -if (process.env.NODE_ENV !== "production" && ServerConfig.CLIENT_DEV_SERVER) { +if (Environment.nodeEnv !== "production" && ServerConfig.CLIENT_DEV_SERVER) { logger.warn(`Enabling CORS requests from ${ServerConfig.CLIENT_DEV_SERVER}.`); // Allow CORS requests from another server (since we have our dev server hosted separately). @@ -60,7 +60,7 @@ if (process.env.NODE_ENV !== "production" && ServerConfig.CLIENT_DEV_SERVER) { app.options("*", (req, res) => res.send()); } } else { - if (process.env.NODE_ENV !== "test") { + if (Environment.nodeEnv !== "test") { logger.info("Enabling Helmet, as no CLIENT_DEV_SERVER was set, or we are in production."); } app.use(helmet()); @@ -108,11 +108,11 @@ app.use("/", mainRouter); // this is not the case (we have a dedicated nginx box for it running in a separate process). // In dev, this is a pain to setup, so we can just run it locally. if (ServerConfig.RUN_OWN_CDN) { - if (process.env.NODE_ENV === "production") { + if (Environment.nodeEnv === "production") { logger.warn( `Running OWN_CDN in production. Consider making a separate process handle your CDN for performance.` ); - } else if (process.env.NODE_ENV !== "test") { + } else if (Environment.nodeEnv !== "test") { logger.info(`Running own CDN at ${Environment.cdnRoot}.`); } diff --git a/server/src/utils/fetch.ts b/server/src/utils/fetch.ts index 8aa83bf3b..bd1ef7f8b 100644 --- a/server/src/utils/fetch.ts +++ b/server/src/utils/fetch.ts @@ -1,7 +1,8 @@ +import { Environment } from "lib/setup/config"; import nodeFetch from "node-fetch"; const fetch = - process.env.NODE_ENV === "test" + Environment.nodeEnv === "test" ? () => { throw new Error("Cannot use real fetch inside testing env!"); }