From cc66a648b00cdcb156cfba386b96a5cf2d28608d Mon Sep 17 00:00:00 2001 From: XingfenD Date: Mon, 7 Sep 2026 17:17:33 +0800 Subject: [PATCH] fix(web): logout-path parity, CSP header, epub display fallback + small review nits --- deploy/nginx.conf | 3 +++ web/src/auth/AuthContext.tsx | 20 ++++++++++++++------ web/src/pages/admin/Users.tsx | 2 +- web/src/readers/CbzReader.tsx | 4 +++- web/src/readers/EpubReader.tsx | 20 +++++++++++++------- web/vite.config.ts | 2 +- 6 files changed, 35 insertions(+), 16 deletions(-) diff --git a/deploy/nginx.conf b/deploy/nginx.conf index c0c0ee0..09aab30 100644 --- a/deploy/nginx.conf +++ b/deploy/nginx.conf @@ -5,6 +5,9 @@ server { # /etc/resolv.conf 的首个 nameserver 重写本行,兼容 podman aardvark-dns。 resolver 127.0.0.11 valid=10s; + # spec §7 风险接受所假设的 CSP:全部同源,blob:/data: 供 SW/reader 用 + add_header Content-Security-Policy "default-src 'self'; img-src 'self' blob: data:; worker-src 'self' blob:; style-src 'self' 'unsafe-inline'; connect-src 'self' blob: data:; object-src 'none'; frame-src 'self' blob:" always; + location /api/ { set $api_upstream http://api:8080; # 变量式 → 每次按 DNS 解析,scale 后轮询到新副本(spec §11) proxy_pass $api_upstream; # 无 URI 部分:保留 /api 前缀转发 diff --git a/web/src/auth/AuthContext.tsx b/web/src/auth/AuthContext.tsx index a2b56a4..1b45f6f 100644 --- a/web/src/auth/AuthContext.tsx +++ b/web/src/auth/AuthContext.tsx @@ -18,8 +18,20 @@ export function AuthProvider({ children }: { children: ReactNode }) { const qc = useQueryClient(); const [token, setTok] = useState(() => getToken()); + // 401 到期登出与显式登出同样清理:跨用户数据不得残留在 query 缓存 / SW CacheStorage + const clearSession = () => { + qc.clear(); + if (typeof caches !== "undefined") { + void caches.delete("booklib-api"); + void caches.delete("booklib-immutable"); + } + }; + useEffect(() => { - const off = () => setTok(null); // client 的 401 拦截在这里回收 React 状态 + const off = () => { + setTok(null); // client 的 401 拦截在这里回收 React 状态(token 已由 client.ts 清除) + clearSession(); + }; window.addEventListener(LOGOUT_EVENT, off); return () => window.removeEventListener(LOGOUT_EVENT, off); }, []); @@ -46,11 +58,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { logout: () => { setToken(null); setTok(null); - qc.clear(); - if (typeof caches !== "undefined") { - void caches.delete("booklib-api"); - void caches.delete("booklib-immutable"); - } + clearSession(); }, }), [meQ.data, meQ.isPending, meQ.isError, token, qc], diff --git a/web/src/pages/admin/Users.tsx b/web/src/pages/admin/Users.tsx index c29a5ac..5153cd8 100644 --- a/web/src/pages/admin/Users.tsx +++ b/web/src/pages/admin/Users.tsx @@ -45,7 +45,7 @@ export default function AdminUsers() {

用户管理

setU(e.target.value)} /> - setP(e.target.value)} /> + setP(e.target.value)} />