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:
@@ -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); };
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user