[mob][photos] In-app public link fixes (#4495)

## Description

Fixed these issues:
- Unrelated files coming up (these are local device files) in public
link when opened in-app.
- Max number of files in link capped to 2000.
- Sort order not working.
This commit is contained in:
Ashil
2024-12-24 21:07:41 +05:30
committed by GitHub
5 changed files with 97 additions and 54 deletions

View File

@@ -1067,6 +1067,24 @@ class CollectionsService {
_cachedPublicAlbumToken[collection.id] = authToken!;
_cachedPublicCollectionID.add(collection.id);
_cachedPublicAlbumKey[collection.id] = albumKey;
if (collectionData['pubMagicMetadata'] != null) {
final utfEncodedMmd = await CryptoUtil.decryptChaCha(
CryptoUtil.base642bin(collectionData['pubMagicMetadata']['data']),
collectionKey,
CryptoUtil.base642bin(
collectionData['pubMagicMetadata']['header'],
),
);
collection.mMdPubEncodedJson = utf8.decode(utfEncodedMmd);
collection.mMbPubVersion =
collectionData['pubMagicMetadata']['version'];
collection.pubMagicMetadata =
CollectionPubMagicMetadata.fromEncodedJson(
collection.mMdPubEncodedJson ?? '{}',
);
}
collection.setName(_getDecryptedCollectionName(collection));
return collection;
} catch (e, s) {

View File

@@ -306,8 +306,12 @@ class _HomeWidgetState extends State<HomeWidget> {
if (result) {
await dialog.show();
final List<EnteFile> sharedFiles = await _diffFetcher
.getPublicFiles(context, collection.id);
final List<EnteFile> sharedFiles =
await _diffFetcher.getPublicFiles(
context,
collection.id,
collection.pubMagicMetadata.asc ?? false,
);
await dialog.hide();
Navigator.of(context).pop();
@@ -334,8 +338,11 @@ class _HomeWidgetState extends State<HomeWidget> {
} else {
await dialog.show();
final List<EnteFile> sharedFiles =
await _diffFetcher.getPublicFiles(context, collection.id);
final List<EnteFile> sharedFiles = await _diffFetcher.getPublicFiles(
context,
collection.id,
collection.pubMagicMetadata.asc ?? false,
);
await dialog.hide();
await routeToPage(

View File

@@ -27,7 +27,9 @@ class FileWidget extends StatelessWidget {
Widget build(BuildContext context) {
// Specify key to ensure that the widget is rebuilt when the file changes
// Before changing this, ensure that file deletes are handled properly
final String fileKey = "file_${file.generatedID}";
final String fileKey =
"file_genID_${file.generatedID}___file_id_${file.uploadedFileID}";
if (file.fileType == FileType.livePhoto ||
file.fileType == FileType.image) {
return ZoomableLiveImageNew(

View File

@@ -51,6 +51,8 @@ class _ZoomableLiveImageNewState extends State<ZoomableLiveImageNew>
@override
void initState() {
super.initState();
_enteFile = widget.enteFile;
_logger.info(
'initState for ${_enteFile.generatedID} with tag ${_enteFile.tag} and name ${_enteFile.displayName}',
@@ -64,7 +66,6 @@ class _ZoomableLiveImageNewState extends State<ZoomableLiveImageNew>
isGuestView = event.isGuestView;
});
});
super.initState();
}
void _onLongPressEvent(bool isPressed) {

View File

@@ -21,69 +21,84 @@ class DiffFetcher {
Future<List<EnteFile>> getPublicFiles(
BuildContext context,
int collectionID,
bool sortAsc,
) async {
try {
final authToken = await CollectionsService.instance
.getSharedPublicAlbumToken(collectionID);
final authJWTToken = await CollectionsService.instance
.getSharedPublicAlbumTokenJWT(collectionID);
bool hasMore = false;
final sharedFiles = <EnteFile>[];
final headers = {
"X-Auth-Access-Token": authToken,
if (authJWTToken != null) "X-Auth-Access-Token-JWT": authJWTToken,
};
final response = await _enteDio.get(
"/public-collection/diff",
options: Options(headers: headers),
queryParameters: {"sinceTime": 0},
);
int sinceTime = 0;
final diff = response.data["diff"] as List;
final startTime = DateTime.now();
final sharedFiles = <EnteFile>[];
for (final item in diff) {
final file = EnteFile();
if (item["isDeleted"]) {
continue;
}
file.uploadedFileID = item["id"];
file.collectionID = item["collectionID"];
file.ownerID = item["ownerID"];
file.encryptedKey = item["encryptedKey"];
file.keyDecryptionNonce = item["keyDecryptionNonce"];
file.fileDecryptionHeader = item["file"]["decryptionHeader"];
file.thumbnailDecryptionHeader = item["thumbnail"]["decryptionHeader"];
file.metadataDecryptionHeader = item["metadata"]["decryptionHeader"];
if (item["info"] != null) {
file.fileSize = item["info"]["fileSize"];
}
final fileKey = getFileKey(file);
final encodedMetadata = await CryptoUtil.decryptChaCha(
CryptoUtil.base642bin(item["metadata"]["encryptedData"]),
fileKey,
CryptoUtil.base642bin(file.metadataDecryptionHeader!),
do {
final response = await _enteDio.get(
"/public-collection/diff",
options: Options(headers: headers),
queryParameters: {"sinceTime": sinceTime},
);
final Map<String, dynamic> metadata =
jsonDecode(utf8.decode(encodedMetadata));
file.applyMetadata(metadata);
if (item['pubMagicMetadata'] != null) {
final utfEncodedMmd = await CryptoUtil.decryptChaCha(
CryptoUtil.base642bin(item['pubMagicMetadata']['data']),
fileKey,
CryptoUtil.base642bin(item['pubMagicMetadata']['header']),
);
file.pubMmdEncodedJson = utf8.decode(utfEncodedMmd);
file.pubMmdVersion = item['pubMagicMetadata']['version'];
file.pubMagicMetadata =
PubMagicMetadata.fromEncodedJson(file.pubMmdEncodedJson!);
}
sharedFiles.add(file);
}
_logger.info('[Collection-$collectionID] parsed ${diff.length} '
'diff items ( ${sharedFiles.length} updated) in ${DateTime.now().difference(startTime).inMilliseconds}ms');
final diff = response.data["diff"] as List;
hasMore = response.data["hasMore"] as bool;
for (final item in diff) {
final file = EnteFile();
if (item["isDeleted"]) {
continue;
}
file.uploadedFileID = item["id"];
file.collectionID = item["collectionID"];
file.ownerID = item["ownerID"];
file.encryptedKey = item["encryptedKey"];
file.keyDecryptionNonce = item["keyDecryptionNonce"];
file.fileDecryptionHeader = item["file"]["decryptionHeader"];
file.thumbnailDecryptionHeader =
item["thumbnail"]["decryptionHeader"];
file.metadataDecryptionHeader = item["metadata"]["decryptionHeader"];
if (item["info"] != null) {
file.fileSize = item["info"]["fileSize"];
}
final fileKey = getFileKey(file);
final encodedMetadata = await CryptoUtil.decryptChaCha(
CryptoUtil.base642bin(item["metadata"]["encryptedData"]),
fileKey,
CryptoUtil.base642bin(file.metadataDecryptionHeader!),
);
final Map<String, dynamic> metadata =
jsonDecode(utf8.decode(encodedMetadata));
file.applyMetadata(metadata);
if (item['pubMagicMetadata'] != null) {
final utfEncodedMmd = await CryptoUtil.decryptChaCha(
CryptoUtil.base642bin(item['pubMagicMetadata']['data']),
fileKey,
CryptoUtil.base642bin(item['pubMagicMetadata']['header']),
);
file.pubMmdEncodedJson = utf8.decode(utfEncodedMmd);
file.pubMmdVersion = item['pubMagicMetadata']['version'];
file.pubMagicMetadata =
PubMagicMetadata.fromEncodedJson(file.pubMmdEncodedJson!);
}
// To avoid local file to be used as thumbnail or full file.
file.localID = null;
sharedFiles.add(file);
}
if (diff.isNotEmpty) {
sinceTime = diff.last["updationTime"];
}
} while (hasMore);
if (sortAsc) {
sharedFiles.sort((a, b) => a.creationTime!.compareTo(b.creationTime!));
}
return sharedFiles;
} catch (e, s) {
_logger.severe("Failed to decrypt collection ", e, s);