feat(web-security): encrypt offline data at rest

This commit is contained in:
2026-04-06 16:07:37 +08:00
parent 1ea483016f
commit 1564d2dd30
8 changed files with 399 additions and 38 deletions
+21 -3
View File
@@ -1,5 +1,10 @@
import { localDb, type LocalAiChatSessionRecord } from "@/services/local-db";
import type { WebAiChannel } from "@/services/ai-api";
import {
decryptAiChatSessionRecord,
encryptAiChatSessionRecord,
shouldEncryptAiChatSessionRecord
} from "@/services/local-sensitive-codec";
export type LocalAiChatMessageRecord = {
id: string;
@@ -64,20 +69,33 @@ export async function listLocalAiChatSessions(
userId: string
): Promise<LocalAiChatSessionSnapshot[]> {
const records = await localDb.aiChatSessions.where("userId").equals(userId).toArray();
return records.map(toSnapshot);
const encryptedRecords = await Promise.all(
records
.filter(shouldEncryptAiChatSessionRecord)
.map((record) => encryptAiChatSessionRecord(record))
);
if (encryptedRecords.length > 0) {
await localDb.aiChatSessions.bulkPut(encryptedRecords);
}
const decryptedRecords = await Promise.all(
records.map((record) => decryptAiChatSessionRecord(record))
);
return decryptedRecords.map(toSnapshot);
}
export async function saveLocalAiChatSession(
input: SaveLocalAiChatSessionInput
): Promise<LocalAiChatSessionRecord> {
const record: LocalAiChatSessionRecord = {
const record = await encryptAiChatSessionRecord({
key: createSessionKey(input.userId, input.channel),
userId: input.userId,
channel: input.channel,
sessionId: input.sessionId,
messagesJson: JSON.stringify(input.messages),
updatedAt: Date.now()
};
});
await localDb.aiChatSessions.put(record);
return record;