From e2523c1cc0673882bfbab038b7ef05932968e114 Mon Sep 17 00:00:00 2001 From: kaizerCodes <114164516+kaizercodes@users.noreply.github.com> Date: Tue, 29 Sep 2026 19:17:38 +0100 Subject: [PATCH 1/4] security: Test mailer transport selection and fallbacks (#1295) --- src/lib/mailer.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/lib/mailer.ts b/src/lib/mailer.ts index 31dc622f..325726fc 100644 --- a/src/lib/mailer.ts +++ b/src/lib/mailer.ts @@ -1,5 +1,9 @@ import { logger } from '../logger.js'; +export interface MailerTransport { + sendMail(options: { from: string; to: string; subject: string; text: string }): Promise; +} + export interface MailerOptions { enabled: boolean; from: string; @@ -24,6 +28,12 @@ let mailerOptions: MailerOptions = { transport: (process.env.MAILER_TRANSPORT as 'console' | 'smtp') ?? 'console', }; +let transportFactory: ((options: MailerOptions) => MailerTransport) | undefined; + +export function setTransportFactory(factory: ((options: MailerOptions) => MailerTransport) | undefined): void { + transportFactory = factory; +} + export function configureMailer(options: Partial): void { mailerOptions = { ...mailerOptions, ...options }; } @@ -41,6 +51,17 @@ export async function sendMail(payload: MailPayload): Promise { }); if (mailerOptions.transport === 'smtp') { + if (transportFactory) { + const transporter = transportFactory(mailerOptions); + await transporter.sendMail({ + from: mailerOptions.from, + to: payload.to, + subject: payload.subject, + text: payload.text, + }); + return; + } + let nodemailer: any; try { nodemailer = await import('nodemailer'); From d794be22738fa71c3eefe37fb09659fe88f096b0 Mon Sep 17 00:00:00 2001 From: kaizerCodes <114164516+kaizercodes@users.noreply.github.com> Date: Tue, 29 Sep 2026 19:19:10 +0100 Subject: [PATCH 2/4] security: Test mailer transport selection and fallbacks (#1295) --- src/lib/mailer.ts | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/src/lib/mailer.ts b/src/lib/mailer.ts index 325726fc..0cddf4af 100644 --- a/src/lib/mailer.ts +++ b/src/lib/mailer.ts @@ -1,9 +1,5 @@ import { logger } from '../logger.js'; -export interface MailerTransport { - sendMail(options: { from: string; to: string; subject: string; text: string }): Promise; -} - export interface MailerOptions { enabled: boolean; from: string; @@ -22,22 +18,22 @@ export interface MailPayload { text: string; } -let mailerOptions: MailerOptions = { +const defaultMailerOptions: MailerOptions = { enabled: process.env.MAILER_ENABLED === 'true', from: process.env.MAILER_FROM ?? 'noreply@callora.com', transport: (process.env.MAILER_TRANSPORT as 'console' | 'smtp') ?? 'console', }; -let transportFactory: ((options: MailerOptions) => MailerTransport) | undefined; - -export function setTransportFactory(factory: ((options: MailerOptions) => MailerTransport) | undefined): void { - transportFactory = factory; -} +let mailerOptions: MailerOptions = { ...defaultMailerOptions }; export function configureMailer(options: Partial): void { mailerOptions = { ...mailerOptions, ...options }; } +export function resetMailer(): void { + mailerOptions = { ...defaultMailerOptions }; +} + export async function sendMail(payload: MailPayload): Promise { if (!mailerOptions.enabled) { logger.info('[mailer] Mailer disabled, skipping email', { to: payload.to, subject: payload.subject }); @@ -51,17 +47,6 @@ export async function sendMail(payload: MailPayload): Promise { }); if (mailerOptions.transport === 'smtp') { - if (transportFactory) { - const transporter = transportFactory(mailerOptions); - await transporter.sendMail({ - from: mailerOptions.from, - to: payload.to, - subject: payload.subject, - text: payload.text, - }); - return; - } - let nodemailer: any; try { nodemailer = await import('nodemailer'); From f029dbb121dc13e7249c75be20bf7ab628bd4814 Mon Sep 17 00:00:00 2001 From: kaizerCodes <114164516+kaizercodes@users.noreply.github.com> Date: Tue, 29 Sep 2026 22:49:31 +0100 Subject: [PATCH 3/4] security: Test mailer transport selection and fallbacks (#1295) --- src/lib/mailer.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/lib/mailer.ts b/src/lib/mailer.ts index 0cddf4af..68d498e4 100644 --- a/src/lib/mailer.ts +++ b/src/lib/mailer.ts @@ -1,4 +1,4 @@ -import { logger } from '../logger.js'; +import { logger } from '../logger'; export interface MailerOptions { enabled: boolean; @@ -18,22 +18,16 @@ export interface MailPayload { text: string; } -const defaultMailerOptions: MailerOptions = { +let mailerOptions: MailerOptions = { enabled: process.env.MAILER_ENABLED === 'true', from: process.env.MAILER_FROM ?? 'noreply@callora.com', transport: (process.env.MAILER_TRANSPORT as 'console' | 'smtp') ?? 'console', }; -let mailerOptions: MailerOptions = { ...defaultMailerOptions }; - export function configureMailer(options: Partial): void { mailerOptions = { ...mailerOptions, ...options }; } -export function resetMailer(): void { - mailerOptions = { ...defaultMailerOptions }; -} - export async function sendMail(payload: MailPayload): Promise { if (!mailerOptions.enabled) { logger.info('[mailer] Mailer disabled, skipping email', { to: payload.to, subject: payload.subject }); @@ -73,7 +67,7 @@ export async function sendMail(payload: MailPayload): Promise { logToConsole(payload); } -function logToConsole(payload: MailPayload): void { +export function logToConsole(payload: MailPayload): void { logger.info('[mailer] Email notification', { from: mailerOptions.from, to: payload.to, From 5458f1d3457805467b7b086102303814c7626691 Mon Sep 17 00:00:00 2001 From: kaizerCodes <114164516+kaizercodes@users.noreply.github.com> Date: Tue, 29 Sep 2026 22:53:34 +0100 Subject: [PATCH 4/4] security: Test mailer transport selection and fallbacks (#1295) --- src/lib/mailer.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/lib/mailer.ts b/src/lib/mailer.ts index 68d498e4..dec4f149 100644 --- a/src/lib/mailer.ts +++ b/src/lib/mailer.ts @@ -1,4 +1,5 @@ -import { logger } from '../logger'; +import { logger } from '../logger.js'; +import { logger } from '../logger.js'; export interface MailerOptions { enabled: boolean; @@ -24,6 +25,10 @@ let mailerOptions: MailerOptions = { transport: (process.env.MAILER_TRANSPORT as 'console' | 'smtp') ?? 'console', }; +export function getMailerOptions(): MailerOptions { + return { ...mailerOptions }; +} + export function configureMailer(options: Partial): void { mailerOptions = { ...mailerOptions, ...options }; } @@ -64,14 +69,17 @@ export async function sendMail(payload: MailPayload): Promise { return; } - logToConsole(payload); + logToConsole(payload, mailerOptions.transport === 'console' && process.env.NODE_ENV === 'production'); } -export function logToConsole(payload: MailPayload): void { - logger.info('[mailer] Email notification', { +function logToConsole(payload: MailPayload, omitBody = false): void { + const entry: Record = { from: mailerOptions.from, to: payload.to, subject: payload.subject, - body: payload.text, - }); + }; + if (!omitBody) { + entry.body = payload.text; + } + logger.info('[mailer] Email notification', entry); }