diff --git a/src/middleware/authentication.js b/src/middleware/authentication.js index 47d8412..b15ee3e 100644 --- a/src/middleware/authentication.js +++ b/src/middleware/authentication.js @@ -1,6 +1,6 @@ // middleware/authCheck.js const fetch = require("node-fetch"); -const VERIFY_URL = "https://auth.jasonpoage.com/api/verify"; +const VERIFY_URL = process.env.AUTH_VERIFY; module.exports = async (req, res, next) => { const cookie = req.headers["cookie"] || ""; @@ -15,15 +15,7 @@ credentials: "include", }); - // const body = await resVerify.text(); - req.isAuthenticated = resVerify.status === 200; - - // req.log.debug("[AuthCheck] Response status:", resVerify.status); - // req.log.debug("[AuthCheck] Response headers:", Object.fromEntries(resVerify.headers.entries())); - // req.log.debug("[AuthCheck] Response body:", body); - - req.log.info("Authenticated Result", req.isAuthenticated); } catch (err) { req.isAuthenticated = false; req.log.error("[AuthCheck] Fetch error:", err); diff --git a/src/middleware/baseContext.js b/src/middleware/baseContext.js index 03df026..e8cb659 100644 --- a/src/middleware/baseContext.js +++ b/src/middleware/baseContext.js @@ -3,7 +3,6 @@ module.exports = async function baseContextMiddleware(req, res, next) { const isAuthenticated = req.isAuthenticated; - console.log("test remote-user", req.isAuthenticated) const baseContext = await getBaseContext(isAuthenticated); res.locals.baseContext = baseContext; diff --git a/src/routes/logs.js b/src/routes/logs.js index 8b80008..f52ed01 100644 --- a/src/routes/logs.js +++ b/src/routes/logs.js @@ -19,7 +19,8 @@ const db = new Database(dbPath, { readonly: true }); router.get("/logs", secured, (req, res) => { - res.render("pages/logs", { layout: "logs" }); + // res.render("pages/logs", { layout: "logs" }); + res.renderWithBaseContext("pages/logs", { showSidebar: false, showFooter: false }); }); router.post("/logs", secured, (req, res) => { diff --git a/src/routes/newsletter.js b/src/routes/newsletter.js index 0b3d72e..70f2156 100644 --- a/src/routes/newsletter.js +++ b/src/routes/newsletter.js @@ -4,8 +4,9 @@ const { saveEmail } = require("../services/newsletterService"); const formLimiter = require("../utils/formLimiter"); -const getBaseContext = require("../utils/baseContext"); const { qualifyLink } = require("../utils/qualifyLinks"); +const HttpError = require("../utils/HttpError"); +const { Http } = require("winston/lib/winston/transports"); router.get("/newsletter", async (req, res) => { const context = { @@ -26,14 +27,34 @@ router.post("/newsletter", formLimiter, async (req, res, next) => { const { email } = req.body; - if (!email) { - return res.status(400).send("Email is required"); + // Basic validation + if (!email || typeof email !== 'string') { + return next(new HttpError("Email is required", 400)) } + // Sanitize and validate email + const sanitizedEmail = validator.normalizeEmail(email.trim()); + if (!sanitizedEmail || !validator.isEmail(sanitizedEmail)) { + return next(new HttpError("Invalid email format", 400)) + } + + // Length check + if (sanitizedEmail.length > 320) { // RFC 5321 limit + return next(new HttpError("Email too long", 400)) + } + try { - saveEmail(email); + await saveEmail(email); await sendNewsletterSubscriptionMail({ email }); res.redirect("/newsletter/success"); } catch (err) { + // Log the error but don't expose internal details + console.error('Newsletter subscription error:', err); + + // Generic response to avoid information disclosure + if (err.code === 'DUPLICATE_EMAIL') { + // Still redirect to success to avoid enumeration + return res.redirect("/newsletter/success"); + } next(err); } }); diff --git a/src/utils/baseContext.js b/src/utils/baseContext.js index 46653e9..7f7e7d4 100644 --- a/src/utils/baseContext.js +++ b/src/utils/baseContext.js @@ -20,6 +20,8 @@ years: menu, formatMonth, baseUrl, - isAuthenticated + isAuthenticated, + showSidebar: true, + showFooter: true }, overrides); }; diff --git a/src/utils/validateEmail.js b/src/utils/validateEmail.js new file mode 100644 index 0000000..5ae0b4f --- /dev/null +++ b/src/utils/validateEmail.js @@ -0,0 +1,30 @@ +const validator = require("validator"); + +// Email validation function +const validateEmail = (email) => { + if (!email || typeof email !== 'string') { + return { valid: false, message: "Email is required" }; + } + + // Trim and normalize + email = email.trim().toLowerCase(); + + // Length check + if (email.length > 254) { + return { valid: false, message: "Email address is too long" }; + } + + // Basic validation + if (!validator.isEmail(email)) { + return { valid: false, message: "Please enter a valid email address" }; + } + + // Additional checks for suspicious patterns + if (email.includes('..') || email.startsWith('.') || email.endsWith('.')) { + return { valid: false, message: "Please enter a valid email address" }; + } + + return { valid: true, email }; +}; + +module.exports = validateEmail; diff --git a/src/views/layouts/main.handlebars b/src/views/layouts/main.handlebars index a7c27f3..0f3d434 100644 --- a/src/views/layouts/main.handlebars +++ b/src/views/layouts/main.handlebars @@ -16,18 +16,22 @@
{{> headers}}