diff --git a/src/controllers/helpers/contactHelpers.js b/src/controllers/helpers/contactHelpers.js new file mode 100644 index 0000000..c44be4a --- /dev/null +++ b/src/controllers/helpers/contactHelpers.js @@ -0,0 +1,126 @@ +// src/routes/helpers/contactHelpers.js +const SecurityEvent = require("#src/utils/SecurityEvent.js"); +const { captureSecurityData } = require("../../utils/securityForensics"); + +function isReasonableLength(str, maxLen) { + return ( + typeof str === "string" && str.trim().length > 0 && str.length <= maxLen + ); +} + +function isValidInput(name, subject, message, emailResult) { + return ( + emailResult.valid && + isReasonableLength(name, 100) && + isReasonableLength(subject, 150) && + isReasonableLength(message, 2000) + ); +} + +/** + * Handle invalid input with consistent security logging + */ +async function handleInvalidInput(req, next, formData, emailResult) { + SecurityEvent.handleValidationFailure( + req, + formData, + emailResult.message || "invalid_input", + next + ); +} + +/** + * Build security data for logging + */ +function buildSecurityData( + req, + { formData, captchaProvided, clientData, step } +) { + return captureSecurityData(req, { + formData, + captchaProvided, + clientData, + processingStep: step, + }); +} + +/** + * Log successful form submission + */ +async function logSubmission(securityData, threatAnalysis, formData) { + await SecurityEvent.logEvent("CONTACT_SUCCESS", { + ...securityData, + threatAnalysis, + formData: { + name: formData.name, + email: formData.email, + hasMessage: !!formData.message, + hasSubject: !!formData.subject, + }, + }); +} + +/** + * Handle CAPTCHA failure with consistent logging + */ +async function handleCaptchaFailure(req, threatAnalysis, next, reason) { + SecurityEvent.handleCaptchaFailure(req, reason, threatAnalysis, next); +} + +/** + * Block high threat submissions + */ +async function blockHighThreat(req, threatAnalysis) { + return await SecurityEvent.blockThreat(req, threatAnalysis); +} + +/** + * Prepare email content with security flags if needed + */ +function prepareEmail({ name, email, message, subject }, threatAnalysis) { + const base = { name, email, message, subject }; + + if (threatAnalysis.level === "medium") { + base.securityFlag = `[SECURITY REVIEW REQUIRED - Score: ${threatAnalysis.score}]`; + } + + return base; +} + +/** + * Log successful email sending + */ +async function logSuccess(securityData, threatAnalysis) { + await SecurityEvent.logEvent("CONTACT_SUCCESS", { + ...securityData, + threatAnalysis, + processingResult: "success", + emailSent: true, + }); +} + +/** + * Log unhandled errors with security context + */ +async function logUnhandledError(req, err) { + SecurityEvent.fromRequest(req, "CONTACT_ERROR", { + error: { + message: err.message, + stack: err.stack, + name: err.name, + }, + processingStep: "error_handling", + }); +} + +module.exports = { + isValidInput, + handleInvalidInput, + buildSecurityData, + logSubmission, + handleCaptchaFailure, + blockHighThreat, + prepareEmail, + logSuccess, + logUnhandledError, +}; diff --git a/src/controllers/heplers/contactHelpers.js b/src/controllers/heplers/contactHelpers.js deleted file mode 100644 index c44be4a..0000000 --- a/src/controllers/heplers/contactHelpers.js +++ /dev/null @@ -1,126 +0,0 @@ -// src/routes/helpers/contactHelpers.js -const SecurityEvent = require("#src/utils/SecurityEvent.js"); -const { captureSecurityData } = require("../../utils/securityForensics"); - -function isReasonableLength(str, maxLen) { - return ( - typeof str === "string" && str.trim().length > 0 && str.length <= maxLen - ); -} - -function isValidInput(name, subject, message, emailResult) { - return ( - emailResult.valid && - isReasonableLength(name, 100) && - isReasonableLength(subject, 150) && - isReasonableLength(message, 2000) - ); -} - -/** - * Handle invalid input with consistent security logging - */ -async function handleInvalidInput(req, next, formData, emailResult) { - SecurityEvent.handleValidationFailure( - req, - formData, - emailResult.message || "invalid_input", - next - ); -} - -/** - * Build security data for logging - */ -function buildSecurityData( - req, - { formData, captchaProvided, clientData, step } -) { - return captureSecurityData(req, { - formData, - captchaProvided, - clientData, - processingStep: step, - }); -} - -/** - * Log successful form submission - */ -async function logSubmission(securityData, threatAnalysis, formData) { - await SecurityEvent.logEvent("CONTACT_SUCCESS", { - ...securityData, - threatAnalysis, - formData: { - name: formData.name, - email: formData.email, - hasMessage: !!formData.message, - hasSubject: !!formData.subject, - }, - }); -} - -/** - * Handle CAPTCHA failure with consistent logging - */ -async function handleCaptchaFailure(req, threatAnalysis, next, reason) { - SecurityEvent.handleCaptchaFailure(req, reason, threatAnalysis, next); -} - -/** - * Block high threat submissions - */ -async function blockHighThreat(req, threatAnalysis) { - return await SecurityEvent.blockThreat(req, threatAnalysis); -} - -/** - * Prepare email content with security flags if needed - */ -function prepareEmail({ name, email, message, subject }, threatAnalysis) { - const base = { name, email, message, subject }; - - if (threatAnalysis.level === "medium") { - base.securityFlag = `[SECURITY REVIEW REQUIRED - Score: ${threatAnalysis.score}]`; - } - - return base; -} - -/** - * Log successful email sending - */ -async function logSuccess(securityData, threatAnalysis) { - await SecurityEvent.logEvent("CONTACT_SUCCESS", { - ...securityData, - threatAnalysis, - processingResult: "success", - emailSent: true, - }); -} - -/** - * Log unhandled errors with security context - */ -async function logUnhandledError(req, err) { - SecurityEvent.fromRequest(req, "CONTACT_ERROR", { - error: { - message: err.message, - stack: err.stack, - name: err.name, - }, - processingStep: "error_handling", - }); -} - -module.exports = { - isValidInput, - handleInvalidInput, - buildSecurityData, - logSubmission, - handleCaptchaFailure, - blockHighThreat, - prepareEmail, - logSuccess, - logUnhandledError, -};