refactor(P0): JWT 认证、并发安全、错误日志三项安全加固

- 新增 JWT httpOnly cookie 认证链路 (jose),登录/注册签发 token,
  所有用户和盲盒 API 改为从 cookie 提取 userId,不再信任客户端传值
- 新增 /api/auth/logout 端点清除认证 cookie
- GET /api/user 区分 owner/非 owner,非 owner 不暴露 email
- atomicUpdateRoom 新增 per-room 应用层互斥锁,防止 SQLite 下并发 lost update
- 修复 getRoomData 中 fire-and-forget delete 改为 await
- 37 个静默 catch 块跨 17 个文件添加 console.error 日志
- 新增 REFACTOR_PLAN.md 全景分析文档
This commit is contained in:
2026-03-02 17:24:26 +08:00
parent 99120a7042
commit ce76980fe5
41 changed files with 528 additions and 144 deletions
+1 -1
View File
@@ -128,7 +128,7 @@ function PoiSearchField({ poi, address, onSelect, location }: PoiSearchFieldProp
setSuggestions(data);
setOpen(data.length > 0);
}
} catch { /* ignore */ }
} catch (e) { console.error("PoiSearchField fetch failed:", e); }
finally { setLoading(false); }
}, 400);
return () => { if (timerRef.current) clearTimeout(timerRef.current); };
+1 -1
View File
@@ -38,7 +38,7 @@ export default function ContractCompletionModal({
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ planId: contract.id, userId, action }),
});
} catch { /* best-effort */ }
} catch (e) { console.error("ContractCompletionModal: submit failed:", e); }
setLoading(false);
if (current < contracts.length - 1) {
+3 -3
View File
@@ -107,7 +107,7 @@ export default function MatchResult({
matchType,
participants: userCount,
}),
}).catch(() => {});
}).catch((e) => { console.error("MatchResult: save history failed:", e); });
}, [registered, userId, roomId, restaurant, matchType, userCount]);
const handleOpenShareCard = useCallback(() => {
@@ -136,8 +136,8 @@ export default function MatchResult({
setFavorited(true);
toast.show("已收藏");
}
} catch {
/* ignore */
} catch (e) {
console.error("MatchResult: handleFavorite failed:", e);
}
setFavLoading(false);
}, [registered, userId, restaurant, favorited, favLoading, toast]);
+1 -1
View File
@@ -146,7 +146,7 @@ export default function RestaurantCard({ restaurant, likeCount = 0 }: Restaurant
body: JSON.stringify({ userId: getUserId(), restaurant }),
});
if (res.ok) setFavorited(true);
} catch {}
} catch (e) { console.error("RestaurantCard: handleFavorite failed:", e); }
}, [restaurant, favorited]);
const openLink = useCallback(
(url: string) => (e: React.MouseEvent | React.TouchEvent) => {
+4 -4
View File
@@ -227,8 +227,8 @@ export default function SwipeDeck({
if (data.match != null) {
setLocalMatchId(data.match);
}
} catch {
// Polling will catch match state
} catch (e) {
console.error("SwipeDeck: sendSwipe failed:", e);
}
};
@@ -273,8 +273,8 @@ export default function SwipeDeck({
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId, restaurantId: lastRid }),
});
} catch {
// Best-effort
} catch (e) {
console.error("SwipeDeck: handleUndo failed:", e);
}
setSwipeHistory((h) => h.slice(0, -1));