diff --git a/src/backup.ts b/src/backup.ts index a0d6647..b6cece3 100644 --- a/src/backup.ts +++ b/src/backup.ts @@ -116,6 +116,24 @@ export const runBackup = async ( } } + // Write per-file metadata JSON alongside the original + const metaJsonPath = join(originalsDir, `${file.id}.json`); + if (!existsSync(metaJsonPath)) { + const fileMeta: Record = { + id: file.id, + collectionID: file.collectionID, + ownerID: file.ownerID, + metadata: file.metadata, + }; + if (file.magicMetadata) { + fileMeta.magicMetadata = file.magicMetadata; + } + if (file.pubMagicMetadata) { + fileMeta.pubMagicMetadata = file.pubMagicMetadata; + } + writeFileSync(metaJsonPath, JSON.stringify(fileMeta, null, 2)); + } + if (!existsSync(linkPath) && existsSync(origPath)) { const target = relative(colDir, origPath); symlinkSync(target, linkPath); diff --git a/src/model/decrypt.ts b/src/model/decrypt.ts index dd9f7b5..5154357 100644 --- a/src/model/decrypt.ts +++ b/src/model/decrypt.ts @@ -7,6 +7,7 @@ import type { FileType, RawCollection, RawEnteFile, + RawMagicMetadata, } from "./types.js"; const KNOWN_COLLECTION_TYPES = new Set([ @@ -88,14 +89,32 @@ export const decryptFile = ( hash: metadataJSON.hash, }; + const magicMetadata = decryptMagicMetadata(raw.magicMetadata, key); + const pubMagicMetadata = decryptMagicMetadata(raw.pubMagicMetadata, key); + return { id: raw.id, collectionID: raw.collectionID, ownerID: raw.ownerID, key, metadata, + magicMetadata, + pubMagicMetadata, file: { decryptionHeader: raw.file.decryptionHeader }, thumbnail: { decryptionHeader: raw.thumbnail.decryptionHeader }, updationTime: raw.updationTime, }; }; + +const decryptMagicMetadata = ( + raw: RawMagicMetadata | undefined, + key: Uint8Array, +): Record | undefined => { + if (!raw?.data || !raw?.header) return undefined; + const bytes = decryptBlob( + fromBase64(raw.data), + fromBase64(raw.header), + key, + ); + return JSON.parse(new TextDecoder().decode(bytes)); +}; diff --git a/src/model/index.ts b/src/model/index.ts index 7d337ed..e86d6b1 100644 --- a/src/model/index.ts +++ b/src/model/index.ts @@ -9,4 +9,5 @@ export type { Microseconds, RawCollection, RawEnteFile, + RawMagicMetadata, } from "./types.js"; diff --git a/src/model/types.ts b/src/model/types.ts index 79551a0..42cb5b5 100644 --- a/src/model/types.ts +++ b/src/model/types.ts @@ -40,6 +40,8 @@ export interface EnteFile { ownerID: number; key: Uint8Array; metadata: FileMetadata; + magicMetadata?: Record; + pubMagicMetadata?: Record; file: FileBlob; thumbnail: FileBlob; updationTime: Microseconds; @@ -59,6 +61,13 @@ export interface RawCollection { isDeleted?: boolean; } +export interface RawMagicMetadata { + version: number; + count: number; + data: string; + header: string; +} + export interface RawEnteFile { id: number; collectionID: number; @@ -66,6 +75,8 @@ export interface RawEnteFile { encryptedKey: string; keyDecryptionNonce: string; metadata: { encryptedData: string; decryptionHeader: string }; + magicMetadata?: RawMagicMetadata; + pubMagicMetadata?: RawMagicMetadata; info?: { fileSize?: number; thumbSize?: number }; file: { decryptionHeader: string }; thumbnail: { decryptionHeader: string };