feat: fips inside (checkpoint)

This commit is contained in:
Daniel Hougaard
2025-07-07 09:47:02 +04:00
parent 9aa3c14bf2
commit d4652e69ce
8 changed files with 131 additions and 106 deletions

View File

@@ -26,15 +26,18 @@ export default {
transformMode: "ssr", transformMode: "ssr",
async setup() { async setup() {
const logger = initLogger(); const logger = initLogger();
const envConfig = initEnvConfig(logger); const { envCfg, updateRootEncryptionKey } = initEnvConfig(logger);
const db = initDbConnection({ const db = initDbConnection({
dbConnectionUri: envConfig.DB_CONNECTION_URI, dbConnectionUri: envCfg.DB_CONNECTION_URI,
dbRootCert: envConfig.DB_ROOT_CERT dbRootCert: envCfg.DB_ROOT_CERT
}); });
const superAdminDAL = superAdminDALFactory(db); const superAdminDAL = superAdminDALFactory(db);
await crypto.initialize(superAdminDAL); const fipsEnabled = await crypto.initialize(superAdminDAL);
if (fipsEnabled) {
updateRootEncryptionKey(envCfg.ENCRYPTION_KEY);
}
const redis = buildRedisFromConfig(envConfig); const redis = buildRedisFromConfig(envCfg);
await redis.flushdb("SYNC"); await redis.flushdb("SYNC");
try { try {
@@ -59,10 +62,10 @@ export default {
}); });
const smtp = mockSmtpServer(); const smtp = mockSmtpServer();
const queue = queueServiceFactory(envConfig, { dbConnectionUrl: envConfig.DB_CONNECTION_URI }); const queue = queueServiceFactory(envCfg, { dbConnectionUrl: envCfg.DB_CONNECTION_URI });
const keyStore = keyStoreFactory(envConfig); const keyStore = keyStoreFactory(envCfg);
const hsmModule = initializeHsmModule(envConfig); const hsmModule = initializeHsmModule(envCfg);
hsmModule.initialize(); hsmModule.initialize();
const server = await main({ const server = await main({
@@ -74,7 +77,7 @@ export default {
hsmModule: hsmModule.getModule(), hsmModule: hsmModule.getModule(),
superAdminDAL, superAdminDAL,
redis, redis,
envConfig envConfig: envCfg
}); });
// @ts-expect-error type // @ts-expect-error type
@@ -91,8 +94,8 @@ export default {
organizationId: seedData1.organization.id, organizationId: seedData1.organization.id,
accessVersion: 1 accessVersion: 1
}, },
envConfig.AUTH_SECRET, envCfg.AUTH_SECRET,
{ expiresIn: envConfig.JWT_AUTH_LIFETIME } { expiresIn: envCfg.JWT_AUTH_LIFETIME }
); );
} catch (error) { } catch (error) {
// eslint-disable-next-line // eslint-disable-next-line

View File

@@ -353,8 +353,23 @@ export const initEnvConfig = (logger?: CustomLogger) => {
process.exit(-1); process.exit(-1);
} }
envCfg = Object.freeze(parsedEnv.data); const updateRootEncryptionKey = (key?: string) => {
return envCfg; if (!key) {
throw new Error("Failed to update root encryption key. Key is unset.");
}
const newEnvCfg = {
...envCfg
};
newEnvCfg.ROOT_ENCRYPTION_KEY = key;
delete newEnvCfg.ENCRYPTION_KEY;
envCfg = Object.freeze(newEnvCfg);
return envCfg;
};
return { envCfg, updateRootEncryptionKey };
}; };
export const formatSmtpConfig = () => { export const formatSmtpConfig = () => {

View File

@@ -5,6 +5,7 @@ import { SymmetricKeyAlgorithm, TSymmetricEncryptionFns } from "./types";
const IV_LENGTH = 12; const IV_LENGTH = 12;
const TAG_LENGTH = 16; const TAG_LENGTH = 16;
// todo(daniel): Decide if we should move this into the cryptography module
export const symmetricCipherService = ( export const symmetricCipherService = (
type: SymmetricKeyAlgorithm.AES_GCM_128 | SymmetricKeyAlgorithm.AES_GCM_256 type: SymmetricKeyAlgorithm.AES_GCM_128 | SymmetricKeyAlgorithm.AES_GCM_256
): TSymmetricEncryptionFns => { ): TSymmetricEncryptionFns => {

View File

@@ -11,7 +11,9 @@ import { SecretEncryptionAlgo, SecretKeyEncoding } from "@app/db/schemas";
import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal"; import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
import { ADMIN_CONFIG_DB_UUID } from "@app/services/super-admin/super-admin-service"; import { ADMIN_CONFIG_DB_UUID } from "@app/services/super-admin/super-admin-service";
import { isBase64 } from "../base64";
import { getConfig } from "../config/env"; import { getConfig } from "../config/env";
import { CryptographyError } from "../errors";
import { logger } from "../logger"; import { logger } from "../logger";
enum DigestType { enum DigestType {
@@ -59,6 +61,8 @@ type TDecryptAsymmetricInput = {
privateKey: string; privateKey: string;
}; };
const bytesToBits = (bytes: number) => bytes * 8;
const IV_BYTES_SIZE = 12; const IV_BYTES_SIZE = 12;
const BLOCK_SIZE_BYTES_16 = 16; const BLOCK_SIZE_BYTES_16 = 16;
@@ -294,6 +298,33 @@ const cryptographyFactory = () => {
return $fipsEnabled; return $fipsEnabled;
}; };
const $setFipsModeEnabled = (enabled: boolean) => { const $setFipsModeEnabled = (enabled: boolean) => {
// If FIPS is enabled, we need to validate that the ENCRYPTION_KEY is in a base64 format, and is a 256-bit key.
if (enabled) {
const appCfg = getConfig();
if (appCfg.ENCRYPTION_KEY) {
// we need to validate that the ENCRYPTION_KEY is a base64 encoded 256-bit key
if (!isBase64(appCfg.ENCRYPTION_KEY)) {
throw new CryptographyError({
message:
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not a base64 encoded 256-bit key.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
});
}
if (bytesToBits(Buffer.from(appCfg.ENCRYPTION_KEY, "base64").length) !== 256) {
throw new CryptographyError({
message:
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not a 256-bit key.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
});
}
} else {
throw new CryptographyError({
message:
"FIPS mode is enabled, but the ENCRYPTION_KEY environment variable is not set.\nYou can generate a 256-bit key using the following command: `openssl rand -base64 32`"
});
}
}
$fipsEnabled = enabled; $fipsEnabled = enabled;
$isInitialized = true; $isInitialized = true;
}; };
@@ -337,52 +368,22 @@ const cryptographyFactory = () => {
const asymmetric = () => { const asymmetric = () => {
const generateKeyPair = () => { const generateKeyPair = () => {
if (isFipsModeEnabled()) { if (isFipsModeEnabled()) {
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is enabled.");
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is enabled.");
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is enabled.");
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is enabled.");
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is enabled.");
return generateAsymmetricKeyPairFipsValidated(); return generateAsymmetricKeyPairFipsValidated();
} }
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is DISABLED.");
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is DISABLED.");
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is DISABLED.");
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is DISABLED.");
logger.info("[FIPS]: Generating asymmetric key pair. FIPS mode is DISABLED.");
return generateAsymmetricKeyPairNoFipsValidation(); return generateAsymmetricKeyPairNoFipsValidation();
}; };
const encrypt = (data: string, publicKey: string, privateKey: string) => { const encrypt = (data: string, publicKey: string, privateKey: string) => {
if (isFipsModeEnabled()) { if (isFipsModeEnabled()) {
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is enabled.");
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is enabled.");
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is enabled.");
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is enabled.");
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is enabled.");
return encryptAsymmetricFipsValidated(data, publicKey, privateKey); return encryptAsymmetricFipsValidated(data, publicKey, privateKey);
} }
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is DISABLED.");
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is DISABLED.");
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is DISABLED.");
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is DISABLED.");
logger.info("[FIPS]: Encrypting asymmetric data. FIPS mode is DISABLED.");
return encryptAsymmetricNoFipsValidation(data, publicKey, privateKey); return encryptAsymmetricNoFipsValidation(data, publicKey, privateKey);
}; };
const decrypt = ({ ciphertext, nonce, publicKey, privateKey }: TDecryptAsymmetricInput) => { const decrypt = ({ ciphertext, nonce, publicKey, privateKey }: TDecryptAsymmetricInput) => {
if (isFipsModeEnabled()) { if (isFipsModeEnabled()) {
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is enabled.");
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is enabled.");
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is enabled.");
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is enabled.");
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is enabled.");
return decryptAsymmetricFipsValidated({ ciphertext, nonce, publicKey, privateKey }); return decryptAsymmetricFipsValidated({ ciphertext, nonce, publicKey, privateKey });
} }
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is DISABLED.");
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is DISABLED.");
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is DISABLED.");
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is DISABLED.");
logger.info("[FIPS]: Decrypting asymmetric data. FIPS mode is DISABLED.");
return decryptAsymmetricNoFipsValidation({ ciphertext, nonce, publicKey, privateKey }); return decryptAsymmetricNoFipsValidation({ ciphertext, nonce, publicKey, privateKey });
}; };
@@ -397,6 +398,12 @@ const cryptographyFactory = () => {
let decipher; let decipher;
if (keySize === SymmetricKeySize.Bits128) { if (keySize === SymmetricKeySize.Bits128) {
if (isFipsModeEnabled()) {
throw new CryptographyError({
message: "128-bit symmetric key is not supported in FIPS mode of operation."
});
}
// Not ideal: 128-bit hex key (32 chars) gets interpreted as 32 UTF-8 bytes (256 bits) // Not ideal: 128-bit hex key (32 chars) gets interpreted as 32 UTF-8 bytes (256 bits)
// This works but reduces effective key entropy from 256 to 128 bits // This works but reduces effective key entropy from 256 to 128 bits
// Note: Never use this for FIPS mode of operation. // Note: Never use this for FIPS mode of operation.
@@ -418,6 +425,12 @@ const cryptographyFactory = () => {
let cipher; let cipher;
if (keySize === SymmetricKeySize.Bits128) { if (keySize === SymmetricKeySize.Bits128) {
if (isFipsModeEnabled()) {
throw new CryptographyError({
message: "128-bit symmetric key is not supported in FIPS mode of operation."
});
}
iv = crypto.randomBytes(BLOCK_SIZE_BYTES_16); iv = crypto.randomBytes(BLOCK_SIZE_BYTES_16);
cipher = crypto.createCipheriv(SecretEncryptionAlgo.AES_256_GCM, key, iv); cipher = crypto.createCipheriv(SecretEncryptionAlgo.AES_256_GCM, key, iv);
} else { } else {
@@ -478,21 +491,6 @@ const cryptographyFactory = () => {
}: Omit<TDecryptSymmetricInput, "key" | "keySize"> & { }: Omit<TDecryptSymmetricInput, "key" | "keySize"> & {
keyEncoding: SecretKeyEncoding; keyEncoding: SecretKeyEncoding;
}) => { }) => {
logger.info(
`[FIPS]: decryptWithRootEncryptionKey -> Decrypting symmetric data. FIPS mode is: ${isFipsModeEnabled()}`
);
logger.info(
`[FIPS]: decryptWithRootEncryptionKey -> Decrypting symmetric data. FIPS mode is: ${isFipsModeEnabled()}`
);
logger.info(
`[FIPS]: decryptWithRootEncryptionKey -> Decrypting symmetric data. FIPS mode is: ${isFipsModeEnabled()}`
);
logger.info(
`[FIPS]: decryptWithRootEncryptionKey -> Decrypting symmetric data. FIPS mode is: ${isFipsModeEnabled()}`
);
logger.info(
`[FIPS]: decryptWithRootEncryptionKey -> Decrypting symmetric data. FIPS mode is: ${isFipsModeEnabled()}`
);
const appCfg = getConfig(); const appCfg = getConfig();
// the or gate is used used in migration // the or gate is used used in migration
const rootEncryptionKey = appCfg?.ROOT_ENCRYPTION_KEY || process.env.ROOT_ENCRYPTION_KEY; const rootEncryptionKey = appCfg?.ROOT_ENCRYPTION_KEY || process.env.ROOT_ENCRYPTION_KEY;
@@ -530,11 +528,6 @@ const cryptographyFactory = () => {
* @deprecated Do not use MD5 unless you absolutely have to. It is considered an unsafe hashing algorithm, and should only be used if absolutely necessary. * @deprecated Do not use MD5 unless you absolutely have to. It is considered an unsafe hashing algorithm, and should only be used if absolutely necessary.
*/ */
const md5 = (message: string, digest: DigestType = DigestType.Hex) => { const md5 = (message: string, digest: DigestType = DigestType.Hex) => {
logger.info(`[FIPS]: md5 -> Hashing message. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: md5 -> Hashing message. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: md5 -> Hashing message. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: md5 -> Hashing message. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: md5 -> Hashing message. FIPS mode is: ${isFipsModeEnabled()}`);
// If FIPS is enabled and we need MD5, we use the crypto-js implementation. // If FIPS is enabled and we need MD5, we use the crypto-js implementation.
// Avoid this at all costs unless strictly necessary, like for mongo atlas digest auth. // Avoid this at all costs unless strictly necessary, like for mongo atlas digest auth.
if (isFipsModeEnabled()) { if (isFipsModeEnabled()) {
@@ -544,12 +537,6 @@ const cryptographyFactory = () => {
}; };
const createHash = async (password: string, saltRounds: number) => { const createHash = async (password: string, saltRounds: number) => {
logger.info(`[FIPS]: createHash -> Hashing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: createHash -> Hashing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: createHash -> Hashing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: createHash -> Hashing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: createHash -> Hashing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: createHash -> Hashing password. FIPS mode is: ${isFipsModeEnabled()}`);
if (isFipsModeEnabled()) { if (isFipsModeEnabled()) {
const hasher = hasherFipsValidated(); const hasher = hasherFipsValidated();
@@ -566,12 +553,6 @@ const cryptographyFactory = () => {
}; };
const compareHash = async (password: string, hash: string) => { const compareHash = async (password: string, hash: string) => {
logger.info(`[FIPS]: compareHash -> Comparing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: compareHash -> Comparing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: compareHash -> Comparing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: compareHash -> Comparing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: compareHash -> Comparing password. FIPS mode is: ${isFipsModeEnabled()}`);
logger.info(`[FIPS]: compareHash -> Comparing password. FIPS mode is: ${isFipsModeEnabled()}`);
if (isFipsModeEnabled()) { if (isFipsModeEnabled()) {
const isValid = await hasherFipsValidated().compare(password, hash); const isValid = await hasherFipsValidated().compare(password, hash);
return isValid; return isValid;

View File

@@ -171,3 +171,15 @@ export class OidcAuthError extends Error {
this.error = error; this.error = error;
} }
} }
export class CryptographyError extends Error {
name: string;
error: unknown;
constructor({ name, error, message }: { message?: string; name?: string; error?: unknown }) {
super(message || "Cryptographic operation failed");
this.name = name || "CryptographyError";
this.error = error;
}
}

View File

@@ -75,27 +75,29 @@ const initTelemetryInstrumentation = ({
}; };
const setupTelemetry = () => { const setupTelemetry = () => {
const appCfg = initEnvConfig(); const { envCfg } = initEnvConfig();
if (appCfg.OTEL_TELEMETRY_COLLECTION_ENABLED) { console.log("envCfg", envCfg);
if (envCfg.OTEL_TELEMETRY_COLLECTION_ENABLED) {
console.log("Initializing telemetry instrumentation"); console.log("Initializing telemetry instrumentation");
initTelemetryInstrumentation({ initTelemetryInstrumentation({
otlpURL: appCfg.OTEL_EXPORT_OTLP_ENDPOINT, otlpURL: envCfg.OTEL_EXPORT_OTLP_ENDPOINT,
otlpUser: appCfg.OTEL_COLLECTOR_BASIC_AUTH_USERNAME, otlpUser: envCfg.OTEL_COLLECTOR_BASIC_AUTH_USERNAME,
otlpPassword: appCfg.OTEL_COLLECTOR_BASIC_AUTH_PASSWORD, otlpPassword: envCfg.OTEL_COLLECTOR_BASIC_AUTH_PASSWORD,
otlpPushInterval: appCfg.OTEL_OTLP_PUSH_INTERVAL, otlpPushInterval: envCfg.OTEL_OTLP_PUSH_INTERVAL,
exportType: appCfg.OTEL_EXPORT_TYPE exportType: envCfg.OTEL_EXPORT_TYPE
}); });
} }
if (appCfg.SHOULD_USE_DATADOG_TRACER) { if (envCfg.SHOULD_USE_DATADOG_TRACER) {
console.log("Initializing Datadog tracer"); console.log("Initializing Datadog tracer");
tracer.init({ tracer.init({
profiling: appCfg.DATADOG_PROFILING_ENABLED, profiling: envCfg.DATADOG_PROFILING_ENABLED,
version: appCfg.INFISICAL_PLATFORM_VERSION, version: envCfg.INFISICAL_PLATFORM_VERSION,
env: appCfg.DATADOG_ENV, env: envCfg.DATADOG_ENV,
service: appCfg.DATADOG_SERVICE, service: envCfg.DATADOG_SERVICE,
hostname: appCfg.DATADOG_HOSTNAME hostname: envCfg.DATADOG_HOSTNAME
}); });
} }
}; };

View File

@@ -22,26 +22,29 @@ dotenv.config();
const run = async () => { const run = async () => {
const logger = initLogger(); const logger = initLogger();
const envConfig = initEnvConfig(logger); const { envCfg, updateRootEncryptionKey } = initEnvConfig(logger);
await removeTemporaryBaseDirectory(); await removeTemporaryBaseDirectory();
const db = initDbConnection({ const db = initDbConnection({
dbConnectionUri: envConfig.DB_CONNECTION_URI, dbConnectionUri: envCfg.DB_CONNECTION_URI,
dbRootCert: envConfig.DB_ROOT_CERT, dbRootCert: envCfg.DB_ROOT_CERT,
readReplicas: envConfig.DB_READ_REPLICAS?.map((el) => ({ readReplicas: envCfg.DB_READ_REPLICAS?.map((el) => ({
dbRootCert: el.DB_ROOT_CERT, dbRootCert: el.DB_ROOT_CERT,
dbConnectionUri: el.DB_CONNECTION_URI dbConnectionUri: el.DB_CONNECTION_URI
})) }))
}); });
const superAdminDAL = superAdminDALFactory(db); const superAdminDAL = superAdminDALFactory(db);
await crypto.initialize(superAdminDAL); const fipsEnabled = await crypto.initialize(superAdminDAL);
if (fipsEnabled) {
updateRootEncryptionKey(envCfg.ENCRYPTION_KEY);
}
const auditLogDb = envConfig.AUDIT_LOGS_DB_CONNECTION_URI const auditLogDb = envCfg.AUDIT_LOGS_DB_CONNECTION_URI
? initAuditLogDbConnection({ ? initAuditLogDbConnection({
dbConnectionUri: envConfig.AUDIT_LOGS_DB_CONNECTION_URI, dbConnectionUri: envCfg.AUDIT_LOGS_DB_CONNECTION_URI,
dbRootCert: envConfig.AUDIT_LOGS_DB_ROOT_CERT dbRootCert: envCfg.AUDIT_LOGS_DB_ROOT_CERT
}) })
: undefined; : undefined;
@@ -49,17 +52,17 @@ const run = async () => {
const smtp = smtpServiceFactory(formatSmtpConfig()); const smtp = smtpServiceFactory(formatSmtpConfig());
const queue = queueServiceFactory(envConfig, { const queue = queueServiceFactory(envCfg, {
dbConnectionUrl: envConfig.DB_CONNECTION_URI, dbConnectionUrl: envCfg.DB_CONNECTION_URI,
dbRootCert: envConfig.DB_ROOT_CERT dbRootCert: envCfg.DB_ROOT_CERT
}); });
await queue.initialize(); await queue.initialize();
const keyStore = keyStoreFactory(envConfig); const keyStore = keyStoreFactory(envCfg);
const redis = buildRedisFromConfig(envConfig); const redis = buildRedisFromConfig(envCfg);
const hsmModule = initializeHsmModule(envConfig); const hsmModule = initializeHsmModule(envCfg);
hsmModule.initialize(); hsmModule.initialize();
const server = await main({ const server = await main({
@@ -72,7 +75,7 @@ const run = async () => {
queue, queue,
keyStore, keyStore,
redis, redis,
envConfig envConfig: envCfg
}); });
const bootstrap = await bootstrapCheck({ db }); const bootstrap = await bootstrapCheck({ db });
@@ -96,7 +99,7 @@ const run = async () => {
process.exit(0); process.exit(0);
}); });
if (!envConfig.isDevelopmentMode) { if (!envCfg.isDevelopmentMode) {
process.on("uncaughtException", (error) => { process.on("uncaughtException", (error) => {
logger.error(error, "CRITICAL ERROR: Uncaught Exception"); logger.error(error, "CRITICAL ERROR: Uncaught Exception");
}); });
@@ -107,8 +110,8 @@ const run = async () => {
} }
await server.listen({ await server.listen({
port: envConfig.PORT, port: envCfg.PORT,
host: envConfig.HOST, host: envCfg.HOST,
listenTextResolver: (address) => { listenTextResolver: (address) => {
void bootstrap(); void bootstrap();
return address; return address;

View File

@@ -7,6 +7,7 @@ import { ZodError } from "zod";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { import {
BadRequestError, BadRequestError,
CryptographyError,
DatabaseError, DatabaseError,
ForbiddenRequestError, ForbiddenRequestError,
GatewayTimeoutError, GatewayTimeoutError,
@@ -147,6 +148,13 @@ export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider
message: error.message, message: error.message,
error: error.name error: error.name
}); });
} else if (error instanceof CryptographyError) {
void res.status(HttpStatusCodes.BadRequest).send({
reqId: req.id,
statusCode: HttpStatusCodes.BadRequest,
message: error.message,
error: error.name
});
} else if (error instanceof jwt.JsonWebTokenError) { } else if (error instanceof jwt.JsonWebTokenError) {
let errorMessage = error.message; let errorMessage = error.message;