downloadAndDecryptAttachment method
Downloads (and decrypts if necessary) the attachment of this
event and returns it as a MatrixFile. If this event doesn't
contain an attachment, this throws an error. Set getThumbnail
to
true to download the thumbnail instead. Set fromLocalStoreOnly
to true
if you want to retrieve the attachment from the local store only without
making http request.
Implementation
Future<MatrixFile> downloadAndDecryptAttachment(
{bool getThumbnail = false,
Future<Uint8List> Function(Uri)? downloadCallback,
bool fromLocalStoreOnly = false}) async {
if (![EventTypes.Message, EventTypes.Sticker].contains(type)) {
throw ("This event has the type '$type' and so it can't contain an attachment.");
}
if (status.isSending) {
final localFile = room.sendingFilePlaceholders[eventId];
if (localFile != null) return localFile;
}
final database = room.client.database;
final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail);
if (mxcUrl == null) {
throw "This event hasn't any attachment or thumbnail.";
}
getThumbnail = mxcUrl != attachmentMxcUrl;
final isEncrypted =
getThumbnail ? isThumbnailEncrypted : isAttachmentEncrypted;
if (isEncrypted && !room.client.encryptionEnabled) {
throw ('Encryption is not enabled in your Client.');
}
// Is this file storeable?
final thisInfoMap = getThumbnail ? thumbnailInfoMap : infoMap;
var storeable = database != null &&
thisInfoMap['size'] is int &&
thisInfoMap['size'] <= database.maxFileSize;
Uint8List? uint8list;
if (storeable) {
uint8list = await room.client.database?.getFile(mxcUrl);
}
// Download the file
final canDownloadFileFromServer = uint8list == null && !fromLocalStoreOnly;
if (canDownloadFileFromServer) {
final httpClient = room.client.httpClient;
downloadCallback ??=
(Uri url) async => (await httpClient.get(url)).bodyBytes;
uint8list = await downloadCallback(mxcUrl.getDownloadLink(room.client));
storeable = database != null &&
storeable &&
uint8list.lengthInBytes < database.maxFileSize;
if (storeable) {
await database.storeFile(
mxcUrl, uint8list, DateTime.now().millisecondsSinceEpoch);
}
} else if (uint8list == null) {
throw ('Unable to download file from local store.');
}
// Decrypt the file
if (isEncrypted) {
final fileMap =
getThumbnail ? infoMap['thumbnail_file'] : content['file'];
if (!fileMap['key']['key_ops'].contains('decrypt')) {
throw ("Missing 'decrypt' in 'key_ops'.");
}
final encryptedFile = EncryptedFile(
data: uint8list,
iv: fileMap['iv'],
k: fileMap['key']['k'],
sha256: fileMap['hashes']['sha256'],
);
uint8list =
await room.client.nativeImplementations.decryptFile(encryptedFile);
if (uint8list == null) {
throw ('Unable to decrypt file');
}
}
return MatrixFile(bytes: uint8list, name: body);
}