Newer
Older
express-blog / src / routes / index.js
// src/routes/index.js
const express = require("express");
const router = express.Router();
const { marked } = require("marked");
const fs = require("fs").promises;
const path = require("path");
const matter = require("gray-matter");

const getBaseContext = require("../utils/baseContext");

router.get("/post/:year/:month/:name", async (req, res, next) => {
  const { year, month, name } = req.params;

  // Validate year: 4 digits only
  if (!/^\d{4}$/.test(year)) {
    const error = new Error("Invalid year parameter.");
    error.statusCode = 400;
    return next(error);
  }

  // Validate month: 01-12 only
  if (!/^(0[1-9]|1[0-2])$/.test(month)) {
    const error = new Error("Invalid month parameter.");
    error.statusCode = 400;
    return next(error);
  }

  // Validate name: allow alphanumeric, dash, underscore only (no dots, no slashes)
  if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
    const error = new Error("Invalid post name parameter.");
    error.statusCode = 400;
    return next(error);
  }

  const mdPath = path.join(__dirname, "../../posts", year, month, `${name}.md`);

  try {
    const fileContent = await fs.readFile(mdPath, "utf8");
    const { data: frontmatter, content } = matter(fileContent);
    const htmlContent = marked(content);
    const context = await getBaseContext({
      title: frontmatter.title,
      date: frontmatter.date,
      author: frontmatter.author,
      content: htmlContent,
    });
    res.render("pages/post", context);
  } catch (err) {
    const error = new Error("The requested blog post could not be found.");
    error.statusCode = 404;
    next(error);
  }
});

router.get("/", async (req, res) => {
  const context = getBaseContext({
    title: "Blog Home",
    content: "Welcome to the blog.",
  });

  res.render("pages/home", context);
});

module.exports = router;