diff --git a/apps/server/src/modules/backends/smb/smb-backend.ts b/apps/server/src/modules/backends/smb/smb-backend.ts index 7dbc7ce..b4a7b54 100644 --- a/apps/server/src/modules/backends/smb/smb-backend.ts +++ b/apps/server/src/modules/backends/smb/smb-backend.ts @@ -1,12 +1,12 @@ import * as fs from "node:fs/promises"; import * as os from "node:os"; import { BACKEND_STATUS, type BackendConfig } from "@ironmount/schemas"; -import type { VolumeBackend } from "../backend"; -import { logger } from "../../../utils/logger"; -import { withTimeout } from "../../../utils/timeout"; import { OPERATION_TIMEOUT } from "../../../core/constants"; import { toMessage } from "../../../utils/errors"; +import { logger } from "../../../utils/logger"; import { getMountForPath } from "../../../utils/mountinfo"; +import { withTimeout } from "../../../utils/timeout"; +import type { VolumeBackend } from "../backend"; import { createTestFile, executeMount, executeUnmount } from "../utils/backend-utils"; const mount = async (config: BackendConfig, path: string) => { diff --git a/apps/server/src/utils/errors.ts b/apps/server/src/utils/errors.ts index 4907db7..1166051 100644 --- a/apps/server/src/utils/errors.ts +++ b/apps/server/src/utils/errors.ts @@ -1,17 +1,19 @@ import { ConflictError, NotFoundError } from "http-errors-enhanced"; +import { sanitizeSensitiveData } from "./sanitize"; export const handleServiceError = (error: unknown) => { if (error instanceof ConflictError) { - return { message: error.message, status: 409 as const }; + return { message: sanitizeSensitiveData(error.message), status: 409 as const }; } if (error instanceof NotFoundError) { - return { message: error.message, status: 404 as const }; + return { message: sanitizeSensitiveData(error.message), status: 404 as const }; } - return { message: toMessage(error), status: 500 as const }; + return { message: sanitizeSensitiveData(toMessage(error)), status: 500 as const }; }; export const toMessage = (err: unknown): string => { - return err instanceof Error ? err.message : String(err); + const message = err instanceof Error ? err.message : String(err); + return sanitizeSensitiveData(message); }; diff --git a/apps/server/src/utils/logger.ts b/apps/server/src/utils/logger.ts index 3a08502..c5b77ad 100644 --- a/apps/server/src/utils/logger.ts +++ b/apps/server/src/utils/logger.ts @@ -1,4 +1,5 @@ import { createLogger, format, transports } from "winston"; +import { sanitizeSensitiveData } from "./sanitize"; const { printf, combine, colorize } = format; @@ -14,14 +15,14 @@ const winstonLogger = createLogger({ const log = (level: "info" | "warn" | "error" | "debug", messages: unknown[]) => { const stringMessages = messages.flatMap((m) => { if (m instanceof Error) { - return [m.message, m.stack]; + return [sanitizeSensitiveData(m.message), m.stack ? sanitizeSensitiveData(m.stack) : undefined].filter(Boolean); } if (typeof m === "object") { - return JSON.stringify(m, null, 2); + return sanitizeSensitiveData(JSON.stringify(m, null, 2)); } - return m; + return sanitizeSensitiveData(String(m)); }); winstonLogger.log(level, stringMessages.join(" ")); diff --git a/apps/server/src/utils/sanitize.ts b/apps/server/src/utils/sanitize.ts new file mode 100644 index 0000000..698d716 --- /dev/null +++ b/apps/server/src/utils/sanitize.ts @@ -0,0 +1,18 @@ +/** + * Sanitizes sensitive information from strings + * This removes passwords and credentials from logs and error messages + */ +export const sanitizeSensitiveData = (text: string): string => { + let sanitized = text.replace(/\b(pass|password)=([^\s,]+)/gi, "$1=***"); + + sanitized = sanitized.replace(/\/\/([^:@\s]+):([^@\s]+)@/g, "//$1:***@"); + + sanitized = sanitized.replace(/(\S+)\s+(\S+)\s+(\S+)/g, (match, url, user, _pass) => { + if (url.startsWith("http://") || url.startsWith("https://")) { + return `${url} ${user} ***`; + } + return match; + }); + + return sanitized; +};