mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 21:00:41 +00:00
feat: Adds an API to update attachment metadata, supporting the repair of encrypted information of old attachments
This commit is contained in:
+69
-5
@@ -25,10 +25,11 @@ import { buildSendShareKey, getSends } from '@/lib/api/send';
|
||||
import {
|
||||
getCiphers,
|
||||
getFolders,
|
||||
repairCipherAttachmentMetadata,
|
||||
updateFolder,
|
||||
} from '@/lib/api/vault';
|
||||
import { silentlyRepairBackupSettingsIfNeeded } from '@/lib/backup-settings-repair';
|
||||
import { base64ToBytes, decryptBw, decryptStr } from '@/lib/crypto';
|
||||
import { base64ToBytes, decryptBw, decryptStr, encryptBw } from '@/lib/crypto';
|
||||
import {
|
||||
buildPublicSendUrl,
|
||||
deriveSendKeyParts,
|
||||
@@ -803,6 +804,34 @@ export default function App() {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
const sameBytes = (a: Uint8Array, b: Uint8Array) => {
|
||||
if (a.byteLength !== b.byteLength) return false;
|
||||
for (let i = 0; i < a.byteLength; i += 1) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const decryptFieldWithSource = async (
|
||||
value: string | null | undefined,
|
||||
itemEnc: Uint8Array,
|
||||
itemMac: Uint8Array
|
||||
): Promise<{ text: string; source: 'item' | 'user' | 'plain' }> => {
|
||||
const raw = String(value || '').trim();
|
||||
if (!raw) return { text: '', source: 'plain' };
|
||||
try {
|
||||
return { text: await decryptStr(raw, itemEnc, itemMac), source: 'item' };
|
||||
} catch {
|
||||
// 继续尝试旧 user key 数据。
|
||||
}
|
||||
if (!sameBytes(itemEnc, encKey) || !sameBytes(itemMac, macKey)) {
|
||||
try {
|
||||
return { text: await decryptStr(raw, encKey, macKey), source: 'user' };
|
||||
} catch {
|
||||
// 保留原文。
|
||||
}
|
||||
}
|
||||
return { text: raw, source: 'plain' };
|
||||
};
|
||||
|
||||
const folders = await Promise.all(
|
||||
foldersQuery.data.map(async (folder) => ({
|
||||
@@ -908,10 +937,45 @@ export default function App() {
|
||||
}
|
||||
if (Array.isArray(cipher.attachments)) {
|
||||
nextCipher.attachments = await Promise.all(
|
||||
cipher.attachments.map(async (attachment) => ({
|
||||
...attachment,
|
||||
decFileName: await decryptField(attachment.fileName || '', itemEnc, itemMac),
|
||||
}))
|
||||
cipher.attachments.map(async (attachment) => {
|
||||
const attachmentId = String(attachment?.id || '').trim();
|
||||
const fileNameResult = await decryptFieldWithSource(attachment.fileName || '', itemEnc, itemMac);
|
||||
const metadata: { fileName?: string; key?: string | null } = {};
|
||||
|
||||
if (attachmentId && fileNameResult.source === 'user') {
|
||||
metadata.fileName = await encryptBw(new TextEncoder().encode(fileNameResult.text), itemEnc, itemMac);
|
||||
}
|
||||
|
||||
const attachmentKey = String(attachment?.key || '').trim();
|
||||
if (
|
||||
attachmentId &&
|
||||
attachmentKey &&
|
||||
looksLikeCipherString(attachmentKey) &&
|
||||
(!sameBytes(itemEnc, encKey) || !sameBytes(itemMac, macKey))
|
||||
) {
|
||||
try {
|
||||
await decryptBw(attachmentKey, itemEnc, itemMac);
|
||||
} catch {
|
||||
try {
|
||||
const rawAttachmentKey = await decryptBw(attachmentKey, encKey, macKey);
|
||||
if (rawAttachmentKey.length >= 64) {
|
||||
metadata.key = await encryptBw(rawAttachmentKey, itemEnc, itemMac);
|
||||
}
|
||||
} catch {
|
||||
// 文件下载时会继续尝试旧格式。
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attachmentId && Object.keys(metadata).length > 0) {
|
||||
void repairCipherAttachmentMetadata(authedFetch, cipher.id, attachmentId, metadata);
|
||||
}
|
||||
|
||||
return {
|
||||
...attachment,
|
||||
decFileName: fileNameResult.text,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
return nextCipher;
|
||||
|
||||
Reference in New Issue
Block a user