From 07f9b76320759ddce3f2a88f731b42c9c819b101 Mon Sep 17 00:00:00 2001 From: devZenta Date: Tue, 25 Nov 2025 14:56:54 +0100 Subject: [PATCH] feat: implement token generation and validation for knock emails --- src/services/smtpServer.ts | 52 +++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/services/smtpServer.ts b/src/services/smtpServer.ts index 02019c9..0afc9f2 100644 --- a/src/services/smtpServer.ts +++ b/src/services/smtpServer.ts @@ -97,10 +97,15 @@ async function initSmtpServer({ } if (token === 'knock') { - // Generate a random token - // Save it to the token store with validated set to false - // Build the link to validate it - const knockLink = ``; + + const newToken = (await randomBytes(32)).toString('hex'); + + await tokenStore.set(newToken, { + pattern: fromAddress, + validated: false, + }); + + const knockLink = `${BASE_URL}/knock/${newToken}/validation`; await sendMail({ from: fromAddress, to: toAddress, @@ -113,11 +118,46 @@ async function initSmtpServer({ `💌 - Knock email sent to ${toAddress} (session: ${session.id}).`, ); - callback(); + return callback(); } - // Check the token and the email pattern + const tokenPayload = await tokenStore.get(token); + if (!tokenPayload) { + log( + 'warning', + `💌 - Rejected mail from ${fromAddress} due to invalid token (session: ${session.id}).`, + ); + return callback( + Object.assign(new Error('Invalid token'), { + responseCode: 553 + }), + ); + } + + if (!tokenPayload.validated) { + log( + 'warning', + `💌 - Rejected mail from ${fromAddress} due to unvalidated token (session: ${session.id}).`, + ); + return callback( + Object.assign(new Error('Token not validated'), { + responseCode: 553, + }), + ); + } + + if (tokenPayload.pattern !== fromAddress) { + log( + 'warning', + `💌 - Rejected mail from ${fromAddress} due to pattern mismatch (session: ${session.id}).`, + ); + return callback( + Object.assign(new Error('Email address does not match token pattern'), { + responseCode: 553, + }), + ); + } await sendMail({ from: fromAddress, to: toAddress,