Key Encryption
This commit is contained in:
+37
-1
@@ -3,14 +3,16 @@ from __future__ import annotations
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
from loguru import logger
|
||||
|
||||
from .api.router import api_router
|
||||
from .core.bootstrap import init_db
|
||||
from .core.config import get_settings
|
||||
from .core.db import SessionLocal
|
||||
from .services.vault import VaultLocked, VaultNotInitialized, vault_service
|
||||
|
||||
|
||||
def _job_firmware_check() -> None:
|
||||
@@ -36,6 +38,14 @@ def _job_probe_devices() -> None:
|
||||
fetch_identity, fetch_interface_stats, fetch_resource, parse_uptime,
|
||||
)
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
# Если vault уже инициализирован, но заблокирован — пропускаем итерацию:
|
||||
# без DEK не получится расшифровать password_enc устройств в формате v2.
|
||||
# До инициализации (legacy-режим) опрос продолжается со старым ключом из SECRET_KEY.
|
||||
if vault_service.is_initialized_cached() is True and not vault_service.is_unlocked():
|
||||
logger.info("probe_devices: vault locked, пропускаем итерацию")
|
||||
return
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
for d in db.query(Device).all():
|
||||
@@ -160,6 +170,18 @@ async def lifespan(_: FastAPI):
|
||||
logger.info("Starting ROSzetta API ({} env)", settings.app_env)
|
||||
init_db()
|
||||
|
||||
# Прогреваем кеш «vault initialized?» — нужен encrypt_secret() для legacy-fallback
|
||||
# и probe-джобе, чтобы решать skip/run без обращения к БД.
|
||||
try:
|
||||
_db = SessionLocal()
|
||||
try:
|
||||
initialized = vault_service.refresh_initialized_cache(_db)
|
||||
logger.info("Vault initialized={}, unlocked={}", initialized, vault_service.is_unlocked())
|
||||
finally:
|
||||
_db.close()
|
||||
except Exception as exc: # pragma: no cover
|
||||
logger.warning("vault init-cache refresh failed: {}", exc)
|
||||
|
||||
# FTP-сервер для приёма push-бэкапов от MikroTik
|
||||
try:
|
||||
from .services.backup_ftp_server import start_server
|
||||
@@ -225,6 +247,20 @@ def create_app() -> FastAPI:
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
@app.exception_handler(VaultLocked)
|
||||
async def _vault_locked(_: Request, exc: VaultLocked) -> JSONResponse:
|
||||
# 423 Locked — стандартный HTTP-код для «ресурс заперт»; фронт ловит его и
|
||||
# показывает форму ввода мастер-пароля.
|
||||
return JSONResponse(status_code=423, content={"detail": str(exc), "code": "vault_locked"})
|
||||
|
||||
@app.exception_handler(VaultNotInitialized)
|
||||
async def _vault_uninit(_: Request, exc: VaultNotInitialized) -> JSONResponse:
|
||||
return JSONResponse(
|
||||
status_code=412,
|
||||
content={"detail": str(exc), "code": "vault_not_initialized"},
|
||||
)
|
||||
|
||||
app.include_router(api_router)
|
||||
return app
|
||||
|
||||
|
||||
Reference in New Issue
Block a user