| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- """登录界面自定义背景图接口。
- 用户将 background.jpg 或 background.png 放到服务端运行目录
- (打包模式为 exe 同级目录,开发模式为仓库根目录)即可让登录界面
- 自动展示自定义背景;两个文件同时存在时优先 jpg。
- 安全说明:
- - 接口公开(登录前无凭证可访问),不返回任何敏感信息;
- - 候选文件名为固定白名单,不接收路径参数,无目录穿越风险。
- """
- from __future__ import annotations
- import sys
- from pathlib import Path
- from flask import current_app, send_file
- from dms.api.v1.blueprint import api_v1
- from dms.common.errors import FileNotFoundError as DmsFileNotFoundError
- # 候选文件名(固定白名单):同时存在时按列表顺序优先
- _BACKGROUND_FILES: dict[str, str] = {
- "background.jpg": "image/jpeg",
- "background.png": "image/png",
- }
- def _runtime_root() -> Path:
- """服务端运行目录,与 launcher._app_root 同语义。
- - PyInstaller 打包模式:exe 同级目录(用户可见、可写)
- - 开发模式:本文件位于 backend/dms/api/v1/ 下,仓库根在上级第四层
- """
- if getattr(sys, "frozen", False):
- return Path(sys.executable).resolve().parent
- return Path(__file__).resolve().parents[4]
- def _candidate_paths() -> list[tuple[Path, str]]:
- # 测试与特殊部署可通过 DMS_LOGIN_BACKGROUND_DIR 覆盖运行目录
- root = Path(
- current_app.config.get("DMS_LOGIN_BACKGROUND_DIR") or _runtime_root()
- )
- return [
- (root / name, mime) for name, mime in _BACKGROUND_FILES.items()
- ]
- @api_v1.get("/config/login-background")
- def get_login_background():
- for path, mime in _candidate_paths():
- if path.is_file():
- response = send_file(path, mimetype=mime, conditional=True)
- response.headers["X-Content-Type-Options"] = "nosniff"
- # 背景图变更频率低,允许浏览器短缓存减少首屏请求
- response.headers["Cache-Control"] = "public, max-age=60"
- return response
- raise DmsFileNotFoundError("运行目录下不存在 background.jpg/png 背景图")
|