Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved process.env variables to a config file #702

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8b5ca84
Added env to settingsSingleton
kev306 Jun 14, 2024
a8956b0
Updated settingsSingleton to be a named export rather than default
kev306 Jun 14, 2024
fe5b394
Using config.ts instead of settings.ts for env variables
kev306 Jun 14, 2024
46bd507
replaced process.env.ENV mentions in app.ts
kev306 Jun 14, 2024
58c6e1d
Added process.env as part of config
kev306 Jun 14, 2024
e0a747c
Added s3 env variables to config
kev306 Jun 14, 2024
bd0fd22
Added google captcha
kev306 Jun 14, 2024
1ab7e67
Added patreon envs to config
kev306 Jun 14, 2024
d9d9c6b
Added nodeEnv and databaseUrl
kev306 Jun 14, 2024
ab66eea
Added email related configs
kev306 Jun 14, 2024
3d324f5
Added the discord config
kev306 Jun 14, 2024
4c6825a
Added vpn to config
kev306 Jun 14, 2024
8e7d63d
Added remaining env to config
kev306 Jun 14, 2024
0cbe508
Added a check for test environments
kev306 Jun 14, 2024
4bb1244
Refactored config.ts
kev306 Jun 14, 2024
5eebee9
Added config directory. Split out patreonConfig partially
kev306 Jun 17, 2024
260fa45
Renamed config to configOld for refactor purposes
kev306 Jun 17, 2024
c8ad6ab
Extracted patreon config variables
kev306 Jun 17, 2024
226bcdd
Minor fix
kev306 Jun 17, 2024
60264e5
Removed patreon variables from old config
kev306 Jun 17, 2024
f620ce8
Extracted Discord config
kev306 Jun 17, 2024
8836209
Extracted s3 config variables
kev306 Jun 17, 2024
4063b3a
Extracted email variables
kev306 Jun 17, 2024
605a6cd
Extracted nodeEnv
kev306 Jun 17, 2024
0007024
Extracted general config variables
kev306 Jun 17, 2024
f111894
Variable renames
kev306 Jun 17, 2024
b9767bf
Additional variable renames
kev306 Jun 17, 2024
af65349
Renamed config to index.ts
kev306 Jun 17, 2024
7f3ddab
renamed to discordConfig
kev306 Jun 17, 2024
65f35f1
Extracted vpn variables
kev306 Jun 17, 2024
d3ac29e
Added google captcha and databaseurl
kev306 Jun 17, 2024
8e4d60f
Minor update
kev306 Jun 17, 2024
f5ffd6d
Extracted env
kev306 Jun 17, 2024
9873ce4
Added ENV validation
kev306 Jun 17, 2024
0cb5053
Added required env variables for some general ones
kev306 Jun 17, 2024
41aa393
Added function for required variable
kev306 Jun 17, 2024
1df6b7b
Added required prod variables
kev306 Jun 17, 2024
a09da92
Fixed up the port/ip/secret key in app.ts
kev306 Jun 17, 2024
eea948c
Minor fix
kev306 Jun 17, 2024
92b697d
Minor update
kev306 Jun 27, 2024
5426731
Updated s3 bucket validation
kev306 Jun 27, 2024
6147795
Minor update
kev306 Jun 27, 2024
41aebad
Added port validation
kev306 Jun 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 6 additions & 15 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import socket, { Server as SocketServer } from 'socket.io';
import createProxyMiddleware from 'http-proxy-middleware';
import morgan from 'morgan';

import { config } from './config';
import { server as socketServer } from './sockets/sockets';
import User from './models/user';
import { emailVerified, isLoggedIn } from './routes/middleware';
Expand All @@ -38,16 +39,6 @@ import { SESSIONS_COLLECTION_NAME } from './constants';

const assetsPath = path.join(__dirname, '../assets');

// Die if env var isn't given in
if (
process.env.ENV !== 'local' &&
process.env.ENV !== 'staging' &&
process.env.ENV !== 'prod'
) {
console.error('Bad environment variable given.');
process.exit(1);
}

const app = express();
app.use(compression());
app.use(express.static(assetsPath, { maxAge: 518400000 })); // expires in 7 days.
Expand Down Expand Up @@ -84,16 +75,16 @@ app.use(
),
);

if (process.env.ENV === 'local') {
if (config.ENV === 'local') {
console.log('Routing dist_webpack to localhost:3010.');
app.use(
'/dist_webpack',
createProxyMiddleware({ target: 'http://localhost:3010' }),
);
}

const port = process.env.PORT || 3000;
const dbLoc = process.env.DATABASEURL;
const port = config.PORT;
const dbLoc = config.DATABASE_URL;
console.log(`Using database url: ${dbLoc}`);

mongoose.connect(dbLoc, {
Expand Down Expand Up @@ -139,7 +130,7 @@ process
});

// authentication
const secretKey = process.env.MY_SECRET_KEY || 'MySecretKey';
const secretKey = config.MY_SECRET_KEY;
app.use(
session({
secret: secretKey,
Expand Down Expand Up @@ -192,7 +183,7 @@ app.use('/lobby', lobbyRoutes);
app.use('/forum', forumRoutes);
app.use('/profile', profileRoutes);

const IP = process.env.IP || '127.0.0.1';
const IP = config.IP;
const server = app.listen(port, () => {
console.log(`Server has started on ${IP}:${port}!`);
});
Expand Down
16 changes: 9 additions & 7 deletions src/clients/discord/index.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
import Discord, { TextChannel } from 'discord.js';

import { config } from '../../config';

const client = new Discord.Client();

if (process.env.ENV === 'prod') {
client.login(process.env.discord_bot_token);
if (config.ENV === 'prod') {
client.login(config.discord.BOT_TOKEN);
}

export function sendToDiscordAdmins(message: string, ping?: boolean): void {
if (ping) {
message = `${getAdminPing()} ${message}`;
}
sendToChannel(message, process.env.discord_admin_channel_id);
sendToChannel(message, config.discord.ADMIN_CHANNEL_ID);
}

export function sendToDiscordMods(message: string, ping?: boolean): void {
if (ping) {
message = `${getModPing()} ${message}`;
}
sendToChannel(message, process.env.discord_mod_channel_id);
sendToChannel(message, config.discord.MOD_CHANNEL_ID);
}

function sendToChannel(message: string, channelId: string): void {
const channel = client.channels.cache.get(channelId) as TextChannel;

if (process.env.ENV === 'prod') {
if (config.ENV === 'prod') {
channel.send(message);
}
}

function getAdminPing(): string {
return `<@&${process.env.discord_admin_role_id}>`;
return `<@&${config.discord.ADMIN_ROLE_ID}>`;
}

function getModPing(): string {
return `<@&${process.env.discord_mod_role_id}>`;
return `<@&${config.discord.MOD_ROLE_ID}>`;
}
10 changes: 6 additions & 4 deletions src/clients/patreon/patreonController.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import uuid from 'uuid';

import { config } from '../../config';
import {
IPatreonController,
PatreonUserTokens,
PaidPatronFullDetails,
} from './patreonAgent';
import uuid from 'uuid';

const PATREON_URLS = {
AUTHORIZATION_LINK: 'https://www.patreon.com/oauth2/authorize',
Expand All @@ -12,9 +14,9 @@ const PATREON_URLS = {
};

export class PatreonController implements IPatreonController {
private clientId = process.env.patreon_client_ID;
private clientSecret = process.env.patreon_client_secret;
private redirectUri = process.env.patreon_redirectURL;
private clientId = config.patreon.CLIENT_ID;
private clientSecret = config.patreon.CLIENT_SECRET;
private redirectUri = config.patreon.REDIRECT_URL;

public async getPatreonUserTokens(code: string): Promise<PatreonUserTokens> {
const getPatreonUserTokensUrl = new URL(PATREON_URLS.GET_TOKENS);
Expand Down
10 changes: 6 additions & 4 deletions src/clients/s3/S3Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
PutObjectCommand,
S3Client,
} from '@aws-sdk/client-s3';

import { config } from '../../config';
import { IS3Controller } from './S3Agent';

export default class S3Controller implements IS3Controller {
Expand All @@ -15,12 +17,12 @@ export default class S3Controller implements IS3Controller {
private bucket: string;

constructor() {
this.publicFileLinkPrefix = process.env.S3_PUBLIC_FILE_LINK_PREFIX;
this.bucket = process.env.S3_BUCKET_NAME;
this.publicFileLinkPrefix = config.s3.PUBLIC_FILE_LINK_PREFIX;
this.bucket = config.s3.BUCKET_NAME;

this.client = new S3Client({
region: process.env.S3_REGION,
endpoint: process.env.S3_ENDPOINT,
region: config.s3.REGION,
endpoint: config.s3.ENDPOINT,
credentials: fromEnv(),
});
}
Expand Down
22 changes: 0 additions & 22 deletions src/config.ts

This file was deleted.

17 changes: 17 additions & 0 deletions src/config/discordConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getRequiredEnvVariable, getRequiredProdEnvVariable } from './utils';

export type DiscordConfigType = {
BOT_TOKEN?: string;
ADMIN_CHANNEL_ID?: string;
MOD_CHANNEL_ID?: string;
ADMIN_ROLE_ID?: string;
MOD_ROLE_ID?: string;
};

export const DiscordConfig: Readonly<DiscordConfigType> = Object.freeze({
BOT_TOKEN: getRequiredProdEnvVariable('discord_bot_token'),
ADMIN_CHANNEL_ID: getRequiredProdEnvVariable('discord_admin_channel_id'),
MOD_CHANNEL_ID: getRequiredProdEnvVariable('discord_mod_channel_id'),
ADMIN_ROLE_ID: getRequiredProdEnvVariable('discord_admin_role_id'),
MOD_ROLE_ID: getRequiredProdEnvVariable('discord_mod_role_id'),
});
17 changes: 17 additions & 0 deletions src/config/emailConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getRequiredProdEnvVariable } from './utils';

export type EmailConfigType = {
PROAVALON_EMAIL_ADDRESS_DOMAIN?: string;
PROAVALON_EMAIL_ADDRESS?: string;
MAILGUN_API_KEY?: string;
};

export const EmailConfig: Readonly<EmailConfigType> = Object.freeze({
PROAVALON_EMAIL_ADDRESS_DOMAIN: getRequiredProdEnvVariable(
'PROAVALON_EMAIL_ADDRESS_DOMAIN',
),
PROAVALON_EMAIL_ADDRESS: getRequiredProdEnvVariable(
'PROAVALON_EMAIL_ADDRESS',
),
MAILGUN_API_KEY: getRequiredProdEnvVariable('MAILGUN_API_KEY'),
});
72 changes: 72 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { PatreonConfig, PatreonConfigType } from './patreonConfig';
import { DiscordConfig, DiscordConfigType } from './discordConfig';
import { S3Config, S3ConfigType } from './s3Config';
import { EmailConfig, EmailConfigType } from './emailConfig';
import { VpnConfig, VpnConfigType } from './vpnConfig';
import { getRequiredEnvVariable } from './utils';

type ConfigNew = {
ENV: string;
NODE_ENV?: string;
SERVER_DOMAIN?: string;
PORT?: number;
IP?: string;
MY_SECRET_KEY: string;

GOOGLE_CAPTCHA_KEY?: string;
DATABASE_URL: string;

discord: DiscordConfigType;
email: EmailConfigType;
patreon: PatreonConfigType;
s3: S3ConfigType;
vpn: VpnConfigType;
};

export const config: Readonly<ConfigNew> = Object.freeze({
ENV: validateEnv(),
NODE_ENV: process.env.NODE_ENV,
SERVER_DOMAIN: process.env.SERVER_DOMAIN,
PORT: validatePort(),
IP: process.env.IP || '127.0.0.1',
MY_SECRET_KEY: process.env.MY_SECRET_KEY || 'MySecretKey',

GOOGLE_CAPTCHA_KEY: process.env.MY_SECRET_GOOGLE_CAPTCHA_KEY,
DATABASE_URL: getRequiredEnvVariable('DATABASEURL'), // TODO-kev: Consider renaming env variable

discord: DiscordConfig,
email: EmailConfig,
patreon: PatreonConfig,
s3: S3Config,
vpn: VpnConfig,
});

function validateEnv(): string {
const VALID_ENVIRONMENTS: Set<string> = new Set(['local', 'staging', 'prod']);
const ENV = getRequiredEnvVariable('ENV');

if (process.env.NODE_ENV !== 'test') {
if (!VALID_ENVIRONMENTS.has(ENV)) {
console.error(`Bad environment variable given: ${ENV}`);
process.exit(1);
}
}

return ENV;
}

function validatePort(): number {
if (!process.env.PORT) {
return 3000;
}

const port = parseInt(process.env.PORT, 10);

if (isNaN(port) || port < 1 || port > 65535) {
console.error(
`Invalid port number: ${port}. Port must be between 1 and 65535.`,
);
}

return port;
}
13 changes: 13 additions & 0 deletions src/config/patreonConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getRequiredProdEnvVariable } from './utils';

export type PatreonConfigType = {
CLIENT_ID?: string;
CLIENT_SECRET?: string;
REDIRECT_URL?: string;
};

export const PatreonConfig: Readonly<PatreonConfigType> = Object.freeze({
CLIENT_ID: getRequiredProdEnvVariable('patreon_client_ID'),
CLIENT_SECRET: getRequiredProdEnvVariable('patreon_client_secret'),
REDIRECT_URL: getRequiredProdEnvVariable('patreon_redirectURL'),
});
31 changes: 31 additions & 0 deletions src/config/s3Config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { getRequiredEnvVariable } from './utils';

export type S3ConfigType = {
PUBLIC_FILE_LINK_PREFIX: string;
BUCKET_NAME: string;
REGION: string;
ENDPOINT: string;
};

export const S3Config: Readonly<S3ConfigType> = Object.freeze({
PUBLIC_FILE_LINK_PREFIX: getRequiredEnvVariable('S3_PUBLIC_FILE_LINK_PREFIX'),
BUCKET_NAME: validateBucketName(),
REGION: getRequiredEnvVariable('S3_REGION'),
ENDPOINT: getRequiredEnvVariable('S3_ENDPOINT'),
});

function validateBucketName() {
const S3_BUCKET_NAME = getRequiredEnvVariable('S3_BUCKET_NAME');

if (
(process.env.ENV === 'prod' && S3_BUCKET_NAME !== `proavalon`) ||
(process.env.ENV === 'staging' && S3_BUCKET_NAME !== `proavalon-staging`)
) {
console.error(
`Invalid env variables: ENV=${process.env.ENV} S3_BUCKET_NAME=${S3_BUCKET_NAME}`,
);
process.exit(1);
}

return S3_BUCKET_NAME;
}
19 changes: 19 additions & 0 deletions src/config/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function getRequiredProdEnvVariable(variableName: string) {
return process.env.ENV === `prod`
? getRequiredEnvVariable(variableName)
: process.env[variableName];
}

export function getRequiredEnvVariable(variableName: string) {
const envVariable = process.env[variableName];

if (
process.env.NODE_ENV !== 'test' &&
(envVariable === undefined || envVariable === '')
) {
console.error(`Missing required environment variable: ${variableName}`);
process.exit(1);
}

return envVariable;
}
13 changes: 13 additions & 0 deletions src/config/vpnConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getRequiredProdEnvVariable } from './utils';

export type VpnConfigType = {
VPN_DETECTION_TOKEN?: string;
WHITELISTED_VPN_USERNAMES?: string;
};

export const VpnConfig: Readonly<VpnConfigType> = Object.freeze({
VPN_DETECTION_TOKEN: getRequiredProdEnvVariable('VPN_DETECTION_TOKEN'),
WHITELISTED_VPN_USERNAMES: getRequiredProdEnvVariable(
'WHITELISTED_VPN_USERNAMES',
),
});
5 changes: 3 additions & 2 deletions src/gameplay/game.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-nocheck
import _ from 'lodash';

import { config } from '../config';
import Room, { RoomConfig } from './room';
import usernamesIndexes from '../myFunctions/usernamesIndexes';
import User from '../models/user';
Expand Down Expand Up @@ -128,7 +129,7 @@ class Game extends Room {
constructor(gameConfig: GameConfig) {
super(gameConfig.roomConfig);

// Expand config
// Expand configOld
this.muteSpectators = gameConfig.muteSpectators;
this.disableVoteHistory = gameConfig.disableVoteHistory;
this.roomCreationType = gameConfig.roomCreationType;
Expand Down Expand Up @@ -1561,7 +1562,7 @@ class Game extends Room {
});
}

if (process.env.NODE_ENV !== 'test') {
if (config.NODE_ENV !== 'test') {
this.playersInGame.forEach((player) => {
User.findById(player.userId)
.populate('notifications')
Expand Down
Loading
Loading