backgroundTasks method

Future<void> backgroundTasks()

Implementation

Future<void> backgroundTasks() async {
  final database = client.database;
  final userID = client.userID;
  if (_isUploadingKeys || database == null || userID == null) {
    return;
  }
  _isUploadingKeys = true;
  try {
    if (!_haveKeysToUpload || !(await isCached())) {
      return; // we can't backup anyways
    }
    final dbSessions = await database.getInboundGroupSessionsToUpload();
    if (dbSessions.isEmpty) {
      _haveKeysToUpload = false;
      return; // nothing to do
    }
    final privateKey =
        base64decodeUnpadded((await encryption.ssss.getCached(megolmKey))!);
    // decryption is needed to calculate the public key and thus see if the claimed information is in fact valid
    final decryption = olm.PkDecryption();
    final info = await getRoomKeysBackupInfo(false);
    String backupPubKey;
    try {
      backupPubKey = decryption.init_with_private_key(privateKey);

      if (info.algorithm !=
              BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2 ||
          info.authData['public_key'] != backupPubKey) {
        return;
      }
      final args = GenerateUploadKeysArgs(
        pubkey: backupPubKey,
        dbSessions: <DbInboundGroupSessionBundle>[],
        userId: userID,
      );
      // we need to calculate verified beforehand, as else we pass a closure to an isolate
      // with 500 keys they do, however, noticably block the UI, which is why we give brief async suspentions in here
      // so that the event loop can progress
      var i = 0;
      for (final dbSession in dbSessions) {
        final device =
            client.getUserDeviceKeysByCurve25519Key(dbSession.senderKey);
        args.dbSessions.add(DbInboundGroupSessionBundle(
          dbSession: dbSession,
          verified: device?.verified ?? false,
        ));
        i++;
        if (i > 10) {
          await Future.delayed(Duration(milliseconds: 1));
          i = 0;
        }
      }
      final roomKeys =
          await client.nativeImplementations.generateUploadKeys(args);
      Logs().i('[Key Manager] Uploading ${dbSessions.length} room keys...');
      // upload the payload...
      await client.putRoomKeys(info.version, roomKeys);
      // and now finally mark all the keys as uploaded
      // no need to optimze this, as we only run it so seldomly and almost never with many keys at once
      for (final dbSession in dbSessions) {
        await database.markInboundGroupSessionAsUploaded(
            dbSession.roomId, dbSession.sessionId);
      }
    } finally {
      decryption.free();
    }
  } catch (e, s) {
    Logs().e('[Key Manager] Error uploading room keys', e, s);
  } finally {
    _isUploadingKeys = false;
  }
}