|
1 | 1 | import asyncio |
| 2 | +import hmac |
2 | 3 | import os |
3 | 4 | import platform |
4 | 5 | import signal |
5 | | -from fastapi import APIRouter |
| 6 | +from fastapi import APIRouter, Header, HTTPException |
6 | 7 | from pydantic import BaseModel |
| 8 | +from app.config.settings import SHUTDOWN_TOKEN |
7 | 9 | from app.utils.watcher import watcher_util_stop_folder_watcher |
8 | 10 | from app.logging.setup_logging import get_sync_logger |
9 | 11 |
|
@@ -38,18 +40,29 @@ async def _delayed_shutdown(delay: float = 0.1): |
38 | 40 |
|
39 | 41 |
|
40 | 42 | @router.post("/shutdown", response_model=ShutdownResponse) |
41 | | -async def shutdown(): |
| 43 | +async def shutdown(x_shutdown_token: str = Header(...)): |
42 | 44 | """ |
43 | 45 | Gracefully shutdown the sync microservice. |
44 | 46 |
|
| 47 | + This endpoint requires the ``X-Shutdown-Token`` header to match the token |
| 48 | + generated by the backend at startup. The token is shared between services |
| 49 | + via a temporary file, so only the PictoPy application itself can trigger |
| 50 | + shutdown — arbitrary local processes are rejected with 403 Forbidden. |
| 51 | +
|
45 | 52 | This endpoint: |
46 | | - 1. Stops the folder watcher |
47 | | - 2. Schedules server termination after response is sent |
48 | | - 3. Returns confirmation to the caller |
| 53 | + 1. Validates the shutdown token |
| 54 | + 2. Stops the folder watcher |
| 55 | + 3. Schedules server termination after response is sent |
| 56 | + 4. Returns confirmation to the caller |
49 | 57 |
|
50 | 58 | Returns: |
51 | 59 | ShutdownResponse with status and message |
52 | 60 | """ |
| 61 | + # Use constant-time comparison to prevent timing-based token guessing |
| 62 | + if not hmac.compare_digest(x_shutdown_token, SHUTDOWN_TOKEN): |
| 63 | + logger.warning("Shutdown attempt rejected: invalid token") |
| 64 | + raise HTTPException(status_code=403, detail="Forbidden") |
| 65 | + |
53 | 66 | logger.info("Shutdown request received for sync microservice") |
54 | 67 |
|
55 | 68 | try: |
|
0 commit comments