\section{Middleware}

\begin{frame}{Mi az a middleware?}
  \begin{block}{Definíció}
    Függvény, amely HTTP kérés és válasz között fut, hozzáfér \texttt{req}, \texttt{res}, \texttt{next}-hez.
  \end{block}
  
  \begin{itemize}
    \item Láncolható függvények
    \item Kérés előfeldolgozás
    \item Válasz utófeldolgozás
    \item Kérés megszakítás
  \end{itemize}
  
  \begin{exampleblock}{Express middleware}
    \texttt{function middleware(req, res, next) \{ ... \}}
  \end{exampleblock}
\end{frame}

\begin{frame}[shrink=5]{Middleware működése}
  \begin{center}
    \begin{tikzpicture}[node distance=1.5cm, auto]
      \node (browser) [rectangle, draw, text width=2cm, text centered] {Browser};
      \node (mw1) [rectangle, draw, right of=browser, xshift=1.5cm, text width=2.5cm, text centered] {Middleware 1\\(Logger)};
      \node (mw2) [rectangle, draw, right of=mw1, xshift=2cm, text width=2.5cm, text centered] {Middleware 2\\(Auth)};
      \node (route) [rectangle, draw, right of=mw2, xshift=2cm, text width=2cm, text centered] {Route Handler};
      
      \draw[->, thick] (browser) -- node[above] {Request} (mw1);
      \draw[->, thick] (mw1) -- node[above] {\texttt{next()}} (mw2);
      \draw[->, thick] (mw2) -- node[above] {\texttt{next()}} (route);
      \draw[->, thick, dashed] (route) -- node[below] {Response} (browser);
    \end{tikzpicture}
  \end{center}
  
  \begin{alertblock}{Fontos!}
    Ha nem hívod meg a \texttt{next()}-et, a kérés megáll és nem jut el a következő middleware-hez vagy route handler-hez!
  \end{alertblock}
\end{frame}

\begin{frame}[shrink=5]{Middleware típusok}
  \begin{enumerate}
    \item \textbf{Application-level}
      \begin{itemize}
        \item Egész app-ra
      \end{itemize}
    
    \item \textbf{Router-level}
      \begin{itemize}
        \item Adott routerre
      \end{itemize}
    
    \item \textbf{Error-handling}
      \begin{itemize}
        \item 4 param: \texttt{(err, req, res, next)}
      \end{itemize}
    
    \item \textbf{Built-in}
      \begin{itemize}
        \item \texttt{express.json()}
      \end{itemize}
    
    \item \textbf{Third-party}
      \begin{itemize}
        \item \texttt{cors}, \texttt{helmet}
      \end{itemize}
  \end{enumerate}
\end{frame}

\begin{frame}[fragile,shrink=10]{Egyszerű logger middleware}
  \begin{block}{Request logging - 1. rész}
    \small
    \begin{verbatim}
const express = require('express');
const app = express();

const logger = (req, res, next) => {
  const timestamp = new Date().toISOString();
  console.log(`[${timestamp}] ${req.method} ${req.url}`);
  next();
};
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile,shrink=10]{Egyszerű logger middleware (folyt.)}
  \begin{block}{Request logging - 2. rész (használat)}
    \small
    \begin{verbatim}
app.use(logger);

app.get('/', (req, res) => {
  res.json({ message: 'Hello World' });
});

app.get('/users', (req, res) => {
  res.json({ users: ['Alice', 'Bob'] });
});

app.listen(3000);

// Kimenet:
// [2026-02-23T10:30:15.000Z] GET /
// [2026-02-23T10:30:20.000Z] GET /users
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile,shrink=10]{Request timing middleware}
  \begin{block}{Válaszidő mérése}
    \small
    \begin{verbatim}
const requestTimer = (req, res, next) => {
  req.startTime = Date.now();
  
  res.on('finish', () => {
    const duration = Date.now() - req.startTime;
    console.log(`${req.method} ${req.url} - ${duration}ms`);
  });
  
  next();
};

app.use(requestTimer);

// Kimenet:
// GET /api/users - 145ms
// POST /api/login - 523ms
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Validation middleware}
  \begin{block}{Input validáció - 1. rész}
    \small
    \begin{verbatim}
// email validáló middleware
const validateEmail = (req, res, next) => {
  const { email } = req.body;
  
  if (!email) {
    return res.status(400).json({ 
      error: 'Email is required' 
    });
  }
  
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(email)) {
    return res.status(400).json({ 
      error: 'Invalid email format' 
    });
  }
  
  next();  // Validáció sikeres, tovább
};
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Validation middleware (folyt.)}
  \begin{block}{Input validáció - 2. rész (használat)}
    \small
    \begin{verbatim}
app.use(express.json());  // Body parser middleware

// Route-specific middleware
app.post('/register', validateEmail, (req, res) => {
  const { email, password } = req.body;
  
  // Email már validálva van a middleware által
  // Regisztráció logika...
  
  res.json({ message: 'User registered', email });
});

// Több middleware egyszerre
app.post('/login', 
  validateEmail, 
  validatePassword,  // Másik validator
  (req, res) => {
    // Login logika...
  }
);
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Authentikációs middleware - JWT}
  \begin{block}{Token validáció - 1. rész}
    \small
    \begin{verbatim}
const jwt = require('jsonwebtoken');

const authenticateJWT = (req, res, next) => {
  // Token a Authorization header-ből
  const authHeader = req.headers.authorization;
  
  if (!authHeader) {
    return res.status(401).json({ 
      error: 'Access token required' 
    });
  }
  
  // Bearer TOKEN formátum
  const token = authHeader.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ 
      error: 'Token not found' 
    });
  }
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Authentikációs middleware - JWT (folyt.)}
  \begin{block}{Token validáció - 2. rész}
    \small
    \begin{verbatim}
  // Token verify
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    
    // Felhasználói adat hozzáadása a request objektumhoz
    req.user = decoded;  // { userId, email, role, ... }
    
    next();  // Sikeres authentikáció
    
  } catch (error) {
    return res.status(403).json({ 
      error: 'Invalid or expired token' 
    });
  }
};

// Használat
app.get('/api/profile', authenticateJWT, (req, res) => {
  // req.user elérhető itt
  res.json({ user: req.user });
});
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Autorizációs middleware - Role-based}
  \begin{block}{Szerepkör ellenőrzés}
    \small
    \begin{verbatim}
// Role-based access control middleware factory
const requireRole = (role) => {
  return (req, res, next) => {
    // Feltételezzük, hogy az authenticateJWT már futott
    if (!req.user) {
      return res.status(401).json({ 
        error: 'Not authenticated' 
      });
    }
    
    if (req.user.role !== role) {
      return res.status(403).json({ 
        error: `Forbidden: ${role} role required` 
      });
    }
    
    next();  // Jogosultság OK
  };
};
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Autorizációs middleware (folyt.)}
  \begin{block}{Használat szerepkör ellenőrzésre}
    \small
    \begin{verbatim}
// Admin-only endpoint
app.delete('/api/users/:id', 
  authenticateJWT,          // 1. Authentikáció
  requireRole('admin'),      // 2. Autorizáció
  (req, res) => {
    // Csak admin férhet ide
    const userId = req.params.id;
    // Delete user logika...
    res.json({ message: 'User deleted' });
  }
);

// Több szerepkör támogatása
const requireAnyRole = (...roles) => {
  return (req, res, next) => {
    if (!req.user || !roles.includes(req.user.role)) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
};

app.get('/api/reports', authenticateJWT, requireAnyRole('admin', 'manager'), ...);
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Rate limiting middleware}
  \begin{block}{API hívások korlátozása}
    \small
    \begin{verbatim}
const rateLimit = require('express-rate-limit');

// Rate limiter konfiguráció
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 perc
  max: 100,                   // Max 100 kérés 15 percenként
  message: 'Too many requests, please try again later',
  standardHeaders: true,      // RateLimit-* headers
  legacyHeaders: false
});

// Application-level
app.use('/api/', limiter);

// Strict limiter login-hoz
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,  // Max 5 login kísérlet 15 percenként
  skipSuccessfulRequests: true  // Sikeres login nem számít bele
});

app.post('/api/login', loginLimiter, (req, res) => { ... });
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Error handling middleware}
  \begin{block}{Központi hibakezelés}
    \small
    \begin{verbatim}
// Error handling middleware (4 paraméter!)
const errorHandler = (err, req, res, next) => {
  // Logolás
  console.error('Error:', err);
  
  // Custom error osztályok kezelése
  if (err.statusCode) {
    return res.status(err.statusCode).json({
      error: err.name,
      message: err.message
    });
  }
  
  // Váratlan hibák
  res.status(500).json({
    error: 'InternalServerError',
    message: 'Something went wrong'
  });
};

// Error handler middleware UTOLJÁRA kell regisztrálni!
app.use(errorHandler);
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Error handling használata}
  \begin{block}{Hibák továbbítása a next()-el}
    \small
    \begin{verbatim}
// Async route handler
app.get('/api/users/:id', async (req, res, next) => {
  try {
    const user = await User.findById(req.params.id);
    
    if (!user) {
      const error = new Error('User not found');
      error.statusCode = 404;
      throw error;  // vagy: return next(error);
    }
    
    res.json({ user });
    
  } catch (error) {
    next(error);  // Error handler middleware-nek továbbítja
  }
});

// A errorHandler middleware automatikusan feldolgozza
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{CORS middleware}
  \begin{block}{Cross-Origin Resource Sharing}
    \small
    \begin{verbatim}
const cors = require('cors');

// Egyszerű CORS - minden origin engedélyezve
app.use(cors());

// Konfigurált CORS
const corsOptions = {
  origin: 'https://frontend.example.com',  // Engedélyezett origin
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,  // Cookie-k engedélyezése
  maxAge: 86400       // Preflight cache 24 óra
};

app.use(cors(corsOptions));

// Route-specific CORS
app.get('/api/public', cors(), (req, res) => {
  res.json({ message: 'Public data' });
});
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Security middleware - Helmet}
  \begin{block}{HTTP header biztonság}
    \small
    \begin{verbatim}
const helmet = require('helmet');

// Helmet middleware - biztonságos HTTP headerek
app.use(helmet());

// Helmet beállítja:
// - Content-Security-Policy
// - X-DNS-Prefetch-Control
// - X-Frame-Options (SAMEORIGIN)
// - X-Content-Type-Options (nosniff)
// - X-XSS-Protection
// stb.

// Egyedi konfiguráció
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"]
    }
  }
}));
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Middleware láncolás}
  \begin{block}{Több middleware egyidejű használata}
    \small
    \begin{verbatim}
// Middleware láncolás egy route-on
app.post('/api/posts',
  authenticateJWT,      // 1. Authentikáció
  requireRole('user'),  // 2. Autorizáció
  validatePost,         // 3. Validáció
  uploadImages,         // 4. Képfeltöltés
  (req, res) => {       // 5. Route handler
    // Post létrehozás logika
    res.json({ message: 'Post created' });
  }
);

// Middleware tömb
const postMiddlewares = [
  authenticateJWT,
  requireRole('user'),
  validatePost
];

app.post('/api/posts', postMiddlewares, (req, res) => {
  // ...
});
    \end{verbatim}
  \end{block}
\end{frame}

\begin{frame}{Middleware Best Practices}
  \begin{enumerate}
    \item \textbf{Sorrend számít:}
      \begin{itemize}
        \item CORS és security middleware-ek ELŐRE
        \item Error handler middleware HÁTRA
      \end{itemize}
    
    \vspace{0.2cm}
    
    \item \textbf{Mindig hívd meg a next()-et:}
      \begin{itemize}
        \item Kivéve ha response-t küldesz vagy hibát dobsz
      \end{itemize}
    
    \vspace{0.2cm}
    
    \item \textbf{Error handling:}
      \begin{itemize}
        \item Async függvényekben try-catch + next(error)
        \item 4 paraméteres error handler middleware
      \end{itemize}
    
    \vspace{0.2cm}
    
    \item \textbf{Teljesítmény:}
      \begin{itemize}
        \item Ne futtass middleware-t szükségtelenül (route-specific)
        \item Async műveletek csak ha szükséges
      \end{itemize}
    
    \vspace{0.2cm}
    
    \item \textbf{Újrafelhasználhatóság:}
      \begin{itemize}
        \item Middleware factory pattern (pl. requireRole)
        \item Konfigurálható middleware-ek
      \end{itemize}
  \end{enumerate}
\end{frame}

\begin{frame}{Middleware execution order}
  \begin{block}{Tipikus middleware sorrend Express alkalmazásban}
    \small
    \begin{enumerate}
      \item \textbf{helmet()} - Security headers
      \item \textbf{cors()} - CORS beállítások
      \item \textbf{morgan/logger} - Request logging
      \item \textbf{express.json()} - Body parser
      \item \textbf{express.urlencoded()} - URL-encoded body
      \item \textbf{cookie-parser()} - Cookie parsing
      \item \textbf{Rate limiter} - API rate limiting
      \item \textbf{Custom middlewares} - Saját middleware-ek
      \item \textbf{Routes} - Route handler-ek
      \item \textbf{404 handler} - Not found middleware
      \item \textbf{Error handler} - Központi hibakezelés (4 param)
    \end{enumerate}
  \end{block}
\end{frame}

\begin{frame}{Összefoglalás - Middleware}
  \begin{itemize}
    \item \textbf{Middleware} = Függvény a kérés-válasz között
    \item \textbf{Paraméterek:} (req, res, next) vagy (err, req, res, next)
    \item \textbf{Típusok:} Application, Router, Error-handling, Built-in, Third-party
    \item \textbf{next():} Következő middleware-re adja a vezérlést
    \item \textbf{Használat:}
      \begin{itemize}
        \item Logging (morgan, winston)
        \item Authentication (JWT validáció)
        \item Authorization (szerepkör ellenőrzés)
        \item Validation (input ellenőrzés)
        \item Rate limiting (express-rate-limit)
        \item Security (helmet, cors)
        \item Error handling (központi hibakezelés)
      \end{itemize}
    \item \textbf{Sorrend fontos:} Security → Parsing → Auth → Routes → Error
  \end{itemize}
\end{frame}
