downloadAndDecryptAttachment method

Future<SDNFile> downloadAndDecryptAttachment({
  1. bool getThumbnail = false,
  2. Future<Uint8List> downloadCallback(
    1. Uri
    )?,
})

Downloads (and decrypts if necessary) the attachment of this event and returns it as a SDNFile. If this event doesn't contain an attachment, this throws an error. Set getThumbnail to true to download the thumbnail instead.

Implementation

Future<SDNFile> downloadAndDecryptAttachment(
    {bool getThumbnail = false,
    Future<Uint8List> Function(Uri)? downloadCallback}) 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
  if (uint8list == null) {
    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);
    }
  }

  // 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 SDNFile(bytes: uint8list, name: body);
}