chore: Centralize env parsing, validation, defaults, and deprecation notices (#3487)

* chore: Centralize env parsing, defaults, deprecation

* wip

* test

* test

* tsc

* docs, more validation

* fix: Allow empty REDIS_URL (defaults to localhost)

* test

* fix: SLACK_MESSAGE_ACTIONS not bool

* fix: Add SMTP port validation
This commit is contained in:
Tom Moor
2022-05-19 08:05:11 -07:00
committed by GitHub
parent 51001cfac1
commit 3c002f82cc
66 changed files with 783 additions and 341 deletions

View File

@@ -1,4 +1,5 @@
import TestServer from "fetch-test-server";
import env from "@server/env";
import webService from "@server/services/web";
import { buildUser, buildTeam } from "@server/test/factories";
import { flushdb } from "@server/test/support";
@@ -57,7 +58,7 @@ describe("#auth.config", () => {
});
it("should return available providers for team subdomain", async () => {
process.env.URL = "http://localoutline.com";
env.URL = "http://localoutline.com";
await buildTeam({
guestSignin: false,
subdomain: "example",
@@ -102,7 +103,7 @@ describe("#auth.config", () => {
});
it("should return email provider for team when guest signin enabled", async () => {
process.env.URL = "http://localoutline.com";
env.URL = "http://localoutline.com";
await buildTeam({
guestSignin: true,
subdomain: "example",
@@ -126,7 +127,7 @@ describe("#auth.config", () => {
});
it("should not return provider when disabled", async () => {
process.env.URL = "http://localoutline.com";
env.URL = "http://localoutline.com";
await buildTeam({
guestSignin: false,
subdomain: "example",
@@ -149,7 +150,7 @@ describe("#auth.config", () => {
});
describe("self hosted", () => {
it("should return available providers for team", async () => {
process.env.DEPLOYMENT = "";
env.DEPLOYMENT = "";
await buildTeam({
guestSignin: false,
authenticationProviders: [
@@ -166,7 +167,7 @@ describe("#auth.config", () => {
expect(body.data.providers[0].name).toBe("Slack");
});
it("should return email provider for team when guest signin enabled", async () => {
process.env.DEPLOYMENT = "";
env.DEPLOYMENT = "";
await buildTeam({
guestSignin: true,
authenticationProviders: [

View File

@@ -2,6 +2,7 @@ import invariant from "invariant";
import Router from "koa-router";
import { find } from "lodash";
import { parseDomain, isCustomSubdomain } from "@shared/utils/domains";
import env from "@server/env";
import auth from "@server/middlewares/authentication";
import { Team, TeamDomain } from "@server/models";
import { presentUser, presentTeam, presentPolicies } from "@server/presenters";
@@ -10,7 +11,7 @@ import providers from "../auth/providers";
const router = new Router();
function filterProviders(team: Team) {
function filterProviders(team?: Team) {
return providers
.sort((provider) => (provider.id === "email" ? 1 : -1))
.filter((provider) => {
@@ -39,7 +40,7 @@ router.post("auth.config", async (ctx) => {
// If self hosted AND there is only one team then that team becomes the
// brand for the knowledge base and it's guest signin option is used for the
// root login page.
if (process.env.DEPLOYMENT !== "hosted") {
if (env.DEPLOYMENT !== "hosted") {
const teams = await Team.scope("withAuthenticationProviders").findAll();
if (teams.length === 1) {
@@ -76,7 +77,7 @@ router.post("auth.config", async (ctx) => {
// If subdomain signin page then we return minimal team details to allow
// for a custom screen showing only relevant signin options for that team.
if (
process.env.SUBDOMAINS_ENABLED === "true" &&
env.SUBDOMAINS_ENABLED &&
isCustomSubdomain(ctx.request.hostname) &&
!isCustomDomain(ctx.request.hostname)
) {
@@ -103,7 +104,6 @@ router.post("auth.config", async (ctx) => {
// Otherwise, we're requesting from the standard root signin page
ctx.body = {
data: {
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1 arguments, but got 0.
providers: filterProviders(),
},
};

View File

@@ -1,5 +1,6 @@
import { Context } from "koa";
import Router from "koa-router";
import env from "@server/env";
import { AuthenticationError } from "@server/errors";
import CleanupDeletedDocumentsTask from "@server/queues/tasks/CleanupDeletedDocumentsTask";
import CleanupDeletedTeamsTask from "@server/queues/tasks/CleanupDeletedTeamsTask";
@@ -11,7 +12,7 @@ const router = new Router();
const cronHandler = async (ctx: Context) => {
const { token, limit = 500 } = ctx.body as { token?: string; limit: number };
if (process.env.UTILS_SECRET !== token) {
if (env.UTILS_SECRET !== token) {
throw AuthenticationError("Invalid secret token");
}

View File

@@ -1,4 +1,5 @@
import TestServer from "fetch-test-server";
import env from "@server/env";
import { IntegrationAuthentication, SearchQuery } from "@server/models";
import webService from "@server/services/web";
import { buildDocument, buildIntegration } from "@server/test/factories";
@@ -24,7 +25,7 @@ describe("#hooks.unfurl", () => {
});
const res = await server.post("/api/hooks.unfurl", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
team_id: "TXXXXXXXX",
api_app_id: "AXXXXXXXXX",
event: {
@@ -51,7 +52,7 @@ describe("#hooks.slack", () => {
const { user, team } = await seed();
const res = await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: user.authentications[0].providerId,
team_id: team.authenticationProviders[0].providerId,
text: "dsfkndfskndsfkn",
@@ -71,7 +72,7 @@ describe("#hooks.slack", () => {
});
const res = await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: user.authentications[0].providerId,
team_id: team.authenticationProviders[0].providerId,
text: "contains",
@@ -93,7 +94,7 @@ describe("#hooks.slack", () => {
});
const res = await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: user.authentications[0].providerId,
team_id: team.authenticationProviders[0].providerId,
text: "*contains",
@@ -113,7 +114,7 @@ describe("#hooks.slack", () => {
});
const res = await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: user.authentications[0].providerId,
team_id: team.authenticationProviders[0].providerId,
text: "contains",
@@ -132,7 +133,7 @@ describe("#hooks.slack", () => {
const { user, team } = await seed();
await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: user.authentications[0].providerId,
team_id: team.authenticationProviders[0].providerId,
text: "contains",
@@ -160,7 +161,7 @@ describe("#hooks.slack", () => {
const { user, team } = await seed();
const res = await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: user.authentications[0].providerId,
team_id: team.authenticationProviders[0].providerId,
text: "help",
@@ -175,7 +176,7 @@ describe("#hooks.slack", () => {
const { user, team } = await seed();
const res = await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: user.authentications[0].providerId,
team_id: team.authenticationProviders[0].providerId,
text: "",
@@ -202,7 +203,7 @@ describe("#hooks.slack", () => {
});
const res = await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: "unknown-slack-user-id",
team_id: team.authenticationProviders[0].providerId,
text: "contains",
@@ -234,7 +235,7 @@ describe("#hooks.slack", () => {
});
const res = await server.post("/api/hooks.slack", {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user_id: "unknown-slack-user-id",
team_id: serviceTeamId,
text: "contains",
@@ -273,7 +274,7 @@ describe("#hooks.interactive", () => {
teamId: user.teamId,
});
const payload = JSON.stringify({
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user: {
id: user.authentications[0].providerId,
},
@@ -302,7 +303,7 @@ describe("#hooks.interactive", () => {
teamId: user.teamId,
});
const payload = JSON.stringify({
token: process.env.SLACK_VERIFICATION_TOKEN,
token: env.SLACK_VERIFICATION_TOKEN,
user: {
id: "unknown-slack-user-id",
},

View File

@@ -1,6 +1,7 @@
import invariant from "invariant";
import Router from "koa-router";
import { escapeRegExp } from "lodash";
import env from "@server/env";
import { AuthenticationError, InvalidRequestError } from "@server/errors";
import Logger from "@server/logging/logger";
import {
@@ -26,7 +27,7 @@ router.post("hooks.unfurl", async (ctx) => {
return (ctx.body = ctx.body.challenge);
}
if (token !== process.env.SLACK_VERIFICATION_TOKEN) {
if (token !== env.SLACK_VERIFICATION_TOKEN) {
throw AuthenticationError("Invalid token");
}
@@ -89,7 +90,7 @@ router.post("hooks.interactive", async (ctx) => {
assertPresent(token, "token is required");
assertPresent(callback_id, "callback_id is required");
if (token !== process.env.SLACK_VERIFICATION_TOKEN) {
if (token !== env.SLACK_VERIFICATION_TOKEN) {
throw AuthenticationError("Invalid verification token");
}
@@ -127,7 +128,7 @@ router.post("hooks.slack", async (ctx) => {
assertPresent(team_id, "team_id is required");
assertPresent(user_id, "user_id is required");
if (token !== process.env.SLACK_VERIFICATION_TOKEN) {
if (token !== env.SLACK_VERIFICATION_TOKEN) {
throw AuthenticationError("Invalid verification token");
}
@@ -289,7 +290,7 @@ router.post("hooks.slack", async (ctx) => {
result.document.collection,
team,
queryIsInTitle ? undefined : result.context,
process.env.SLACK_MESSAGE_ACTIONS
env.SLACK_MESSAGE_ACTIONS
? [
{
name: "post",

View File

@@ -1,4 +1,5 @@
import Router from "koa-router";
import env from "@server/env";
import auth from "@server/middlewares/authentication";
import { Team, NotificationSetting } from "@server/models";
import { authorize } from "@server/policies";
@@ -75,7 +76,7 @@ router.post("notificationSettings.unsubscribe", async (ctx) => {
return;
}
ctx.redirect(`${process.env.URL}?notice=invalid-auth`);
ctx.redirect(`${env.URL}?notice=invalid-auth`);
});
export default router;

View File

@@ -5,6 +5,7 @@ import userInviter from "@server/commands/userInviter";
import userSuspender from "@server/commands/userSuspender";
import { sequelize } from "@server/database/sequelize";
import InviteEmail from "@server/emails/templates/InviteEmail";
import env from "@server/env";
import { ValidationError } from "@server/errors";
import logger from "@server/logging/logger";
import auth from "@server/middlewares/authentication";
@@ -338,11 +339,11 @@ router.post("users.resendInvite", auth(), async (ctx) => {
user.incrementFlag(UserFlag.InviteSent);
await user.save({ transaction });
if (process.env.NODE_ENV === "development") {
if (env.ENVIRONMENT === "development") {
logger.info(
"email",
`Sign in immediately: ${
process.env.URL
env.URL
}/auth/email.callback?token=${user.getEmailSigninToken()}`
);
}