feat: 发布 v0.5.0 加密存储与匿名同步
This commit is contained in:
+34
-6
@@ -1,8 +1,15 @@
|
||||
import {
|
||||
AssessmentProfile,
|
||||
AssessmentRecord,
|
||||
EncryptedAssessmentRecord,
|
||||
MindScopeBackup,
|
||||
} from '@/lib/assessment-types';
|
||||
import {
|
||||
clearDeviceRecordKey,
|
||||
decryptDeviceRecord,
|
||||
encryptRecordForDevice,
|
||||
isEncryptedRecord,
|
||||
} from '@/lib/record-crypto';
|
||||
|
||||
const DB_NAME = 'mindscope';
|
||||
const DB_VERSION = 1;
|
||||
@@ -87,7 +94,7 @@ export async function ensureActiveProfile(): Promise<AssessmentProfile> {
|
||||
export async function renameProfile(profileId: string, name: string) {
|
||||
const db = await openDatabase();
|
||||
const store = db.transaction(PROFILE_STORE, 'readwrite').objectStore(PROFILE_STORE);
|
||||
const profile = await requestResult(store.get(profileId));
|
||||
const profile = await requestResult<AssessmentProfile | undefined>(store.get(profileId));
|
||||
if (profile) {
|
||||
await requestResult(
|
||||
store.put({ ...profile, name: name.trim(), updatedAt: new Date().toISOString() }),
|
||||
@@ -114,9 +121,10 @@ export async function addAssessmentRecord(
|
||||
record: Omit<AssessmentRecord, 'id'>,
|
||||
): Promise<AssessmentRecord> {
|
||||
const completeRecord = { ...record, id: createId('record') };
|
||||
const encrypted = await encryptRecordForDevice(completeRecord);
|
||||
const db = await openDatabase();
|
||||
await requestResult(
|
||||
db.transaction(RECORD_STORE, 'readwrite').objectStore(RECORD_STORE).add(completeRecord),
|
||||
db.transaction(RECORD_STORE, 'readwrite').objectStore(RECORD_STORE).add(encrypted),
|
||||
);
|
||||
db.close();
|
||||
return completeRecord;
|
||||
@@ -125,9 +133,10 @@ export async function addAssessmentRecord(
|
||||
export async function updateRecordAnalysis(recordId: string, analysisText: string) {
|
||||
const db = await openDatabase();
|
||||
const store = db.transaction(RECORD_STORE, 'readwrite').objectStore(RECORD_STORE);
|
||||
const record = await requestResult(store.get(recordId));
|
||||
const stored = await requestResult<AssessmentRecord | EncryptedAssessmentRecord | undefined>(store.get(recordId));
|
||||
const record = stored ? await decryptDeviceRecord(stored) : undefined;
|
||||
if (record && record.analysisText !== analysisText) {
|
||||
await requestResult(store.put({ ...record, analysisText }));
|
||||
await requestResult(store.put(await encryptRecordForDevice({ ...record, analysisText })));
|
||||
}
|
||||
db.close();
|
||||
}
|
||||
@@ -135,13 +144,29 @@ export async function updateRecordAnalysis(recordId: string, analysisText: strin
|
||||
export async function getRecords(profileId?: string): Promise<AssessmentRecord[]> {
|
||||
const db = await openDatabase();
|
||||
const store = db.transaction(RECORD_STORE, 'readonly').objectStore(RECORD_STORE);
|
||||
const records = profileId
|
||||
const storedRecords = profileId
|
||||
? await requestResult(store.index('profileId').getAll(profileId))
|
||||
: await requestResult(store.getAll());
|
||||
db.close();
|
||||
|
||||
const typedRecords = storedRecords as Array<AssessmentRecord | EncryptedAssessmentRecord>;
|
||||
const records = await Promise.all(typedRecords.map(decryptDeviceRecord));
|
||||
const plaintextRecords = typedRecords.filter((record) => !isEncryptedRecord(record)) as AssessmentRecord[];
|
||||
if (plaintextRecords.length) {
|
||||
await migratePlaintextRecords(plaintextRecords);
|
||||
}
|
||||
return records.sort((a, b) => b.completedAt.localeCompare(a.completedAt));
|
||||
}
|
||||
|
||||
async function migratePlaintextRecords(records: AssessmentRecord[]) {
|
||||
const db = await openDatabase();
|
||||
const store = db.transaction(RECORD_STORE, 'readwrite').objectStore(RECORD_STORE);
|
||||
for (const record of records) {
|
||||
await requestResult(store.put(await encryptRecordForDevice(record)));
|
||||
}
|
||||
db.close();
|
||||
}
|
||||
|
||||
export async function deleteRecord(recordId: string) {
|
||||
const db = await openDatabase();
|
||||
await requestResult(
|
||||
@@ -167,7 +192,9 @@ export async function importBackup(backup: MindScopeBackup) {
|
||||
const db = await openDatabase();
|
||||
const transaction = db.transaction([PROFILE_STORE, RECORD_STORE], 'readwrite');
|
||||
backup.profiles.forEach((profile) => transaction.objectStore(PROFILE_STORE).put(profile));
|
||||
backup.records.forEach((record) => transaction.objectStore(RECORD_STORE).put(record));
|
||||
for (const record of backup.records) {
|
||||
transaction.objectStore(RECORD_STORE).put(await encryptRecordForDevice(record));
|
||||
}
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
transaction.oncomplete = () => resolve();
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
@@ -186,4 +213,5 @@ export async function clearAllAssessmentData() {
|
||||
});
|
||||
db.close();
|
||||
localStorage.removeItem(ACTIVE_PROFILE_KEY);
|
||||
clearDeviceRecordKey();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user