feat: verify embedded backup media checksums

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 13:30:06 +02:00
parent 4384797e25
commit 8d6e5b4201
6 changed files with 71 additions and 63 deletions

View File

@ -200,6 +200,7 @@ final class EmbeddedBackupMediaFile {
required this.fileName,
required this.mimeType,
required this.sizeBytes,
required this.sha256,
required this.base64,
});
@ -208,6 +209,7 @@ final class EmbeddedBackupMediaFile {
final String fileName;
final String? mimeType;
final int sizeBytes;
final String sha256;
final String base64;
}

View File

@ -4900,6 +4900,7 @@ Map<String, Object?> _mediaFileToJson(EmbeddedBackupMediaFile file) => {
'fileName': file.fileName,
'mimeType': file.mimeType,
'sizeBytes': file.sizeBytes,
'sha256': file.sha256,
'base64': file.base64,
};
@ -4949,6 +4950,7 @@ List<EmbeddedBackupMediaFile> _mediaFilesFromBackup(Object? value) {
fileName: _stringFromBackup(payload, 'fileName'),
mimeType: payload['mimeType'] as String?,
sizeBytes: payload['sizeBytes'] as int? ?? 0,
sha256: _stringFromBackup(payload, 'sha256'),
base64: _stringFromBackup(payload, 'base64'),
);
})

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:crypto/crypto.dart' as crypto;
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
@ -101,6 +102,7 @@ final class PathProviderLocalMediaStorage
fileName: p.basename(file.path),
mimeType: resource.payload['mimeType'] as String?,
sizeBytes: bytes.length,
sha256: crypto.sha256.convert(bytes).toString(),
base64: base64Encode(bytes),
),
);
@ -123,6 +125,9 @@ final class PathProviderLocalMediaStorage
if (bytes == null) {
continue;
}
if (crypto.sha256.convert(bytes).toString() != file.sha256) {
continue;
}
final extension = p.extension(file.fileName).toLowerCase();
final target = File(
p.join(directory.path, '${file.mediaAssetId}$extension'),