chore: offload retrieval of environment variables from jwt.ts to env.ts

This commit is contained in:
2026-01-02 22:57:03 +01:00
parent f86630c51e
commit 4bf39c7fdf
5 changed files with 48 additions and 47 deletions

View File

@@ -5,7 +5,7 @@ import * as ms from '../schemas/miscSchema';
import * as ls from '../schemas/linkSchema'; import * as ls from '../schemas/linkSchema';
import { LinkService } from '../services/linkService'; import { LinkService } from '../services/linkService';
import { UserService } from '../services/userService'; import { UserService } from '../services/userService';
import * as jwt from '../tools/jwt'; import * as env from '../tools/env';
import { generateSentenceString, generateShortString } from '../tools/wordlist'; import { generateSentenceString, generateShortString } from '../tools/wordlist';
/** /**
@@ -32,7 +32,7 @@ export async function generateShortLinkHandler(
); );
let generatedSubdomain: string | null = null; 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]'); generatedSubdomain = generateSentenceString('[subdomain]');
const userResponse: ls.LinkResponseDTO = { const userResponse: ls.LinkResponseDTO = {
@@ -65,7 +65,7 @@ export async function generateSentenceLinkHandler(
let generatedSentenceString: string = generateSentenceString(); let generatedSentenceString: string = generateSentenceString();
let generatedSubdomain: string | null = null; 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]'); generatedSubdomain = generateSentenceString('[subdomain]');
const userResponse: ls.LinkResponseDTO = { const userResponse: ls.LinkResponseDTO = {

View File

@@ -1,5 +1,6 @@
import z from 'zod'; import z from 'zod';
// GET /api/v1/link/short
const shortLinkRequestSchemaQuery = z.object({ const shortLinkRequestSchemaQuery = z.object({
// https://zod.dev/v4?id=stringbool // https://zod.dev/v4?id=stringbool
length: z.coerce length: z.coerce
@@ -20,6 +21,7 @@ export const shortLinkRequestSchema = z.object({
}); });
export type ShortLinkRequestDTO = z.TypeOf<typeof shortLinkRequestSchema>; export type ShortLinkRequestDTO = z.TypeOf<typeof shortLinkRequestSchema>;
// GET /api/v1/link/fromWordlist
const sentenceLinkRequestSchemaQuery = z.object({ const sentenceLinkRequestSchemaQuery = z.object({
// https://zod.dev/v4?id=stringbool // https://zod.dev/v4?id=stringbool
withSubdomain: z.stringbool('WithSubdomain must be a boolean') withSubdomain: z.stringbool('WithSubdomain must be a boolean')
@@ -31,6 +33,7 @@ export const sentenceLinkRequestSchema = z.object({
}); });
export type SentenceLinkRequestDTO = z.TypeOf<typeof sentenceLinkRequestSchema>; export type SentenceLinkRequestDTO = z.TypeOf<typeof sentenceLinkRequestSchema>;
// response for both /api/v1/link/short and /api/v1/link/fromWordlist
/** /**
* @swagger * @swagger

View File

@@ -1,8 +1,5 @@
import * as dotenv from 'dotenv'; import * as env from './env';
dotenv.config({ quiet: true });
let cors = require('cors'); let cors = require('cors');
import { getEnvString } from './jwt';
/** /**
* Returns user-trusted origins from the .env file. * Returns user-trusted origins from the .env file.
@@ -12,7 +9,7 @@ import { getEnvString } from './jwt';
*/ */
export function getTrustedOrigins(): string[] { export function getTrustedOrigins(): string[] {
let trustedOrigins: string[] = ['http://localhost:6568']; let trustedOrigins: string[] = ['http://localhost:6568'];
const configOriginsString: string | undefined = getEnvString('trustedOrigins', true); const configOriginsString: string | undefined = env.getString('trustedOrigins', true);
// No config available. // No config available.
if (configOriginsString === undefined) { if (configOriginsString === undefined) {

37
src/tools/env.ts Normal file
View File

@@ -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];
}

View File

@@ -1,10 +1,8 @@
// Heavily based on: // Heavily based on:
// https://github.com/TomDoesTech/REST-API-Tutorial-Updated/blob/7b5f040e1acd94d267df585516b33ee7e3b75f70/src/utils/jwt.utils.ts // 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 jwt from 'jsonwebtoken';
import { DEFAULT_TOKEN_LIFETIME } from '../schemas/authSchema'; import { DEFAULT_TOKEN_LIFETIME } from '../schemas/authSchema';
import * as env from './env';
type JwtStatus = { type JwtStatus = {
valid: boolean; valid: boolean;
@@ -12,40 +10,6 @@ type JwtStatus = {
decoded: string | jwt.JwtPayload | null; 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. * Sign a JWT containing sub (number), role (number, 0/1), iat/exp (unix timestamp) claims.
* *
@@ -66,7 +30,7 @@ export function signJwt(
// 'base64' // 'base64'
// ).toString('utf8'); // ).toString('utf8');
const secret: string = getEnvString(keyName, true)!; const secret: string = env.getString(keyName, true)!;
// Use the default expiration time of 24 hours. // Use the default expiration time of 24 hours.
if (options === undefined) if (options === undefined)
@@ -97,7 +61,7 @@ export function verifyJwt(
// 'base64' // 'base64'
// ).toString('utf8'); // ).toString('utf8');
const secret: string = getEnvString(keyName, true)!; const secret: string = env.getString(keyName, true)!;
try { try {
const decoded: string | jwt.JwtPayload = jwt.verify(token, secret); const decoded: string | jwt.JwtPayload = jwt.verify(token, secret);