Skip to content

Commit d85836d

Browse files
committed
fix(world): 审计修复——快照桥两处静默死链与签名时刻定时器泄漏
审计发现的三个真实缺陷(均为静默失败或资源泄漏): - dbIpcHandlers TABLE_NAME_MAP 缺 worldSnapshots 映射:快照写入抛"不在白名单"被catch吞掉,跨进程桥实际断裂。补 worldSnapshots→world_snapshots - useWorldSnapshotSync 调用 db:query 方法 'get' 不在白名单(仅getAll/getById/count),同样静默失败。改用 getById - SignatureMoment reduced-motion 路径提前 return 丢失 cleanup,卸载后定时器仍触发 setState。重构为 if/else 统一 return clearTimers
1 parent 34ed940 commit d85836d

3 files changed

Lines changed: 11 additions & 9 deletions

File tree

‎client/electron/db/dbIpcHandlers.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ const TABLE_NAME_MAP: Record<string, string> = {
7777
crdtChanges: 'crdt_changes',
7878
// v6 新增:A4 实施意图
7979
implementationIntentions: 'implementation_intentions',
80+
// v7 新增:世界状态快照(MCP 记忆接口跨进程桥)
81+
worldSnapshots: 'world_snapshots',
8082
};
8183

8284
function resolveTable(table: string): string {

‎client/src/features/retention/components/SignatureMoment.tsx‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,15 @@ export function SignatureMoment() {
7474
setAct('event');
7575
soundPlayer.play('achievement_unlocked');
7676
timers.current.push(setTimeout(dismiss, STATIC_MS));
77-
return;
77+
} else {
78+
setAct('silence');
79+
soundPlayer.play('achievement_unlocked');
80+
timers.current.push(setTimeout(() => setAct('event'), ACT1_MS));
81+
timers.current.push(setTimeout(() => setAct('afterglow'), ACT1_MS + ACT2_MS));
82+
timers.current.push(setTimeout(dismiss, ACT1_MS + ACT2_MS + ACT3_MS));
7883
}
7984

80-
setAct('silence');
81-
soundPlayer.play('achievement_unlocked');
82-
timers.current.push(setTimeout(() => setAct('event'), ACT1_MS));
83-
timers.current.push(setTimeout(() => setAct('afterglow'), ACT1_MS + ACT2_MS));
84-
timers.current.push(setTimeout(dismiss, ACT1_MS + ACT2_MS + ACT3_MS));
85-
85+
// 两条路径都必须清理:防止卸载后定时器触发 setState
8686
return clearTimers;
8787
// eslint-disable-next-line react-hooks/exhaustive-deps
8888
}, [signatureSeq]);

‎client/src/features/retention/hooks/useWorldSnapshotSync.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ export function useWorldSnapshotSync(): void {
4040
});
4141
const row = { id: SNAPSHOT_ID, payload, updated_at: new Date().toISOString() };
4242
try {
43-
// 先查后写实现 upsert(db 桥无 put 语义)
44-
const existing = await window.electronAPI.db.query('worldSnapshots', 'get', [SNAPSHOT_ID]);
43+
// 先查后写实现 upsert(db 桥查询方法白名单为 getAll/getById/count)
44+
const existing = await window.electronAPI.db.query('worldSnapshots', 'getById', [SNAPSHOT_ID]);
4545
if (existing) {
4646
await window.electronAPI.db.update('worldSnapshots', SNAPSHOT_ID, {
4747
payload, updated_at: row.updated_at,

0 commit comments

Comments
 (0)