From 4bf39c7fdf7ef82be41bf5524482ff822147de26 Mon Sep 17 00:00:00 2001 From: sherl Date: Fri, 2 Jan 2026 22:57:03 +0100 Subject: [PATCH] chore: offload retrieval of environment variables from jwt.ts to env.ts --- src/controllers/linkController.ts | 6 ++--- src/schemas/linkSchema.ts | 3 +++ src/tools/cors.ts | 7 ++---- src/tools/env.ts | 37 +++++++++++++++++++++++++++ src/tools/jwt.ts | 42 +++---------------------------- 5 files changed, 48 insertions(+), 47 deletions(-) create mode 100644 src/tools/env.ts diff --git a/src/controllers/linkController.ts b/src/controllers/linkController.ts index 356200d..9bc65b6 100644 --- a/src/controllers/linkController.ts +++ b/src/controllers/linkController.ts @@ -5,7 +5,7 @@ import * as ms from '../schemas/miscSchema'; import * as ls from '../schemas/linkSchema'; import { LinkService } from '../services/linkService'; import { UserService } from '../services/userService'; -import * as jwt from '../tools/jwt'; +import * as env from '../tools/env'; import { generateSentenceString, generateShortString } from '../tools/wordlist'; /** @@ -32,7 +32,7 @@ export async function generateShortLinkHandler( ); let generatedSubdomain: string | null = null; - if (val.query['withSubdomain'] === true && jwt.getEnvString('useSubdomains', true) === 'true') + if (val.query['withSubdomain'] === true && env.getString('useSubdomains', true) === 'true') generatedSubdomain = generateSentenceString('[subdomain]'); const userResponse: ls.LinkResponseDTO = { @@ -65,7 +65,7 @@ export async function generateSentenceLinkHandler( let generatedSentenceString: string = generateSentenceString(); let generatedSubdomain: string | null = null; - if (val.query['withSubdomain'] === true && jwt.getEnvString('useSubdomains', true) === 'true') + if (val.query['withSubdomain'] === true && env.getString('useSubdomains', true) === 'true') generatedSubdomain = generateSentenceString('[subdomain]'); const userResponse: ls.LinkResponseDTO = { diff --git a/src/schemas/linkSchema.ts b/src/schemas/linkSchema.ts index af6b0eb..83a9c02 100644 --- a/src/schemas/linkSchema.ts +++ b/src/schemas/linkSchema.ts @@ -1,5 +1,6 @@ import z from 'zod'; +// GET /api/v1/link/short const shortLinkRequestSchemaQuery = z.object({ // https://zod.dev/v4?id=stringbool length: z.coerce @@ -20,6 +21,7 @@ export const shortLinkRequestSchema = z.object({ }); export type ShortLinkRequestDTO = z.TypeOf; +// GET /api/v1/link/fromWordlist const sentenceLinkRequestSchemaQuery = z.object({ // https://zod.dev/v4?id=stringbool withSubdomain: z.stringbool('WithSubdomain must be a boolean') @@ -31,6 +33,7 @@ export const sentenceLinkRequestSchema = z.object({ }); export type SentenceLinkRequestDTO = z.TypeOf; +// response for both /api/v1/link/short and /api/v1/link/fromWordlist /** * @swagger diff --git a/src/tools/cors.ts b/src/tools/cors.ts index db6a17a..86b8002 100644 --- a/src/tools/cors.ts +++ b/src/tools/cors.ts @@ -1,8 +1,5 @@ -import * as dotenv from 'dotenv'; -dotenv.config({ quiet: true }); - +import * as env from './env'; let cors = require('cors'); -import { getEnvString } from './jwt'; /** * Returns user-trusted origins from the .env file. @@ -12,7 +9,7 @@ import { getEnvString } from './jwt'; */ export function getTrustedOrigins(): string[] { let trustedOrigins: string[] = ['http://localhost:6568']; - const configOriginsString: string | undefined = getEnvString('trustedOrigins', true); + const configOriginsString: string | undefined = env.getString('trustedOrigins', true); // No config available. if (configOriginsString === undefined) { diff --git a/src/tools/env.ts b/src/tools/env.ts new file mode 100644 index 0000000..464d752 --- /dev/null +++ b/src/tools/env.ts @@ -0,0 +1,37 @@ +import * as dotenv from 'dotenv'; +dotenv.config({ quiet: true }); + +/** + * Get the environmental string from .env. + * Supports rewriting names to UPPER_SNAKE_CASE if isGlobal is set. + * + * @param {string} key The key + * @param {boolean} [isGlobal=true] Indicates if global + * @return {(string|undefined)} The environment string. + */ +export function getString( + key: string, + isGlobal: boolean = true +): string | undefined { + let keyName: string = ''; + + if (isGlobal) { + // Global values are DECLARED_LIKE_THIS=... + for (let i: number = 0; i < key.length; i++) { + if (key[i].toLowerCase() === key[i]) { + // If is lowercase, skip. + keyName += key[i]; + } else { + // If is uppercase, convert to snake case. + keyName += `_${key[i].toLowerCase()}`; + } + } + keyName = keyName.toUpperCase(); + } else { + // Non-global keys are parsed as passed + keyName = key; + } + + return process.env[keyName]; +} + diff --git a/src/tools/jwt.ts b/src/tools/jwt.ts index 16c6db8..9c733c6 100644 --- a/src/tools/jwt.ts +++ b/src/tools/jwt.ts @@ -1,10 +1,8 @@ // Heavily based on: // https://github.com/TomDoesTech/REST-API-Tutorial-Updated/blob/7b5f040e1acd94d267df585516b33ee7e3b75f70/src/utils/jwt.utils.ts -import * as dotenv from 'dotenv'; -dotenv.config({ quiet: true }); - import jwt from 'jsonwebtoken'; import { DEFAULT_TOKEN_LIFETIME } from '../schemas/authSchema'; +import * as env from './env'; type JwtStatus = { valid: boolean; @@ -12,40 +10,6 @@ type JwtStatus = { decoded: string | jwt.JwtPayload | null; }; -/** - * Get the environmental string from .env. - * Supports rewriting names to UPPER_SNAKE_CASE if isGlobal is set. - * - * @param {string} key The key - * @param {boolean} [isGlobal=true] Indicates if global - * @return {(string|undefined)} The environment string. - */ -export function getEnvString( - key: string, - isGlobal: boolean = true -): string | undefined { - let keyName: string = ''; - - if (isGlobal) { - // Global values are DECLARED_LIKE_THIS=... - for (let i: number = 0; i < key.length; i++) { - if (key[i].toLowerCase() === key[i]) { - // If is lowercase, skip. - keyName += key[i]; - } else { - // If is uppercase, convert to snake case. - keyName += `_${key[i].toLowerCase()}`; - } - } - keyName = keyName.toUpperCase(); - } else { - // Non-global keys are parsed as passed - keyName = key; - } - - return process.env[keyName]; -} - /** * Sign a JWT containing sub (number), role (number, 0/1), iat/exp (unix timestamp) claims. * @@ -66,7 +30,7 @@ export function signJwt( // 'base64' // ).toString('utf8'); - const secret: string = getEnvString(keyName, true)!; + const secret: string = env.getString(keyName, true)!; // Use the default expiration time of 24 hours. if (options === undefined) @@ -97,7 +61,7 @@ export function verifyJwt( // 'base64' // ).toString('utf8'); - const secret: string = getEnvString(keyName, true)!; + const secret: string = env.getString(keyName, true)!; try { const decoded: string | jwt.JwtPayload = jwt.verify(token, secret);