askSetupCrossSigning method

Future<void> askSetupCrossSigning({
  1. bool setupMasterKey = false,
  2. bool setupSelfSigningKey = false,
  3. bool setupUserSigningKey = false,
})

Implementation

Future<void> askSetupCrossSigning({
  bool setupMasterKey = false,
  bool setupSelfSigningKey = false,
  bool setupUserSigningKey = false,
}) async {
  if (state != BootstrapState.askSetupCrossSigning) {
    throw BootstrapBadStateException();
  }
  if (!setupMasterKey && !setupSelfSigningKey && !setupUserSigningKey) {
    await client.dehydratedDeviceSetup(newSsssKey!);
    checkOnlineKeyBackup();
    return;
  }
  final userID = client.userID!;
  try {
    String masterSigningKey;
    final secretsToStore = <String, String>{};
    MatrixCrossSigningKey? masterKey;
    MatrixCrossSigningKey? selfSigningKey;
    MatrixCrossSigningKey? userSigningKey;
    String? masterPub;
    if (setupMasterKey) {
      final master = vod.PkSigning();
      masterSigningKey = master.secretKey;
      masterPub = master.publicKey.toBase64();
      final json = <String, dynamic>{
        'user_id': userID,
        'usage': ['master'],
        'keys': <String, dynamic>{
          'ed25519:$masterPub': masterPub,
        },
      };
      masterKey = MatrixCrossSigningKey.fromJson(json);
      secretsToStore[EventTypes.CrossSigningMasterKey] = masterSigningKey;
    } else {
      Logs().v('Get stored key...');
      masterSigningKey =
          await newSsssKey?.getStored(EventTypes.CrossSigningMasterKey) ?? '';
      if (masterSigningKey.isEmpty) {
        // no master signing key :(
        throw BootstrapBadStateException('No master key');
      }
      final master = vod.PkSigning.fromSecretKey(masterSigningKey);
      masterPub = master.publicKey.toBase64();
    }
    String? sign(Map<String, dynamic> object) {
      final keyObj = vod.PkSigning.fromSecretKey(masterSigningKey);
      return keyObj
          .sign(String.fromCharCodes(canonicalJson.encode(object)))
          .toBase64();
    }

    if (setupSelfSigningKey) {
      final selfSigning = vod.PkSigning();
      final selfSigningPriv = selfSigning.secretKey;
      final selfSigningPub = selfSigning.publicKey.toBase64();
      final json = <String, dynamic>{
        'user_id': userID,
        'usage': ['self_signing'],
        'keys': <String, dynamic>{
          'ed25519:$selfSigningPub': selfSigningPub,
        },
      };
      final signature = sign(json);
      json['signatures'] = <String, dynamic>{
        userID: <String, dynamic>{
          'ed25519:$masterPub': signature,
        },
      };
      selfSigningKey = MatrixCrossSigningKey.fromJson(json);
      secretsToStore[EventTypes.CrossSigningSelfSigning] = selfSigningPriv;
    }
    if (setupUserSigningKey) {
      final userSigning = vod.PkSigning();
      final userSigningPriv = userSigning.secretKey;
      final userSigningPub = userSigning.publicKey.toBase64();
      final json = <String, dynamic>{
        'user_id': userID,
        'usage': ['user_signing'],
        'keys': <String, dynamic>{
          'ed25519:$userSigningPub': userSigningPub,
        },
      };
      final signature = sign(json);
      json['signatures'] = <String, dynamic>{
        userID: <String, dynamic>{
          'ed25519:$masterPub': signature,
        },
      };
      userSigningKey = MatrixCrossSigningKey.fromJson(json);
      secretsToStore[EventTypes.CrossSigningUserSigning] = userSigningPriv;
    }
    // upload the keys!
    state = BootstrapState.loading;
    Logs().v('Upload device signing keys.');
    await client.uiaRequestBackground(
      (AuthenticationData? auth) => client.uploadCrossSigningKeys(
        masterKey: masterKey,
        selfSigningKey: selfSigningKey,
        userSigningKey: userSigningKey,
        auth: auth,
      ),
    );
    Logs().v('Device signing keys have been uploaded.');
    // aaaand set the SSSS secrets
    if (masterKey != null) {
      while (!(masterKey.publicKey != null &&
          client.userDeviceKeys[client.userID]?.masterKey?.ed25519Key ==
              masterKey.publicKey)) {
        Logs().v('Waiting for master to be created');
        await client.oneShotSync();
      }
    }
    if (newSsssKey != null) {
      final storeFutures = <Future<void>>[];
      for (final entry in secretsToStore.entries) {
        storeFutures.add(newSsssKey!.store(entry.key, entry.value));
      }
      Logs().v('Store new SSSS key entries...');
      await Future.wait(storeFutures);
    }

    final keysToSign = <SignableKey>[];
    if (masterKey != null) {
      if (client.userDeviceKeys[client.userID]?.masterKey?.ed25519Key !=
          masterKey.publicKey) {
        throw BootstrapBadStateException(
          'ERROR: New master key does not match up!',
        );
      }
      Logs().v('Set own master key to verified...');
      await client.userDeviceKeys[client.userID]!.masterKey!
          .setVerified(true, false);
      keysToSign.add(client.userDeviceKeys[client.userID]!.masterKey!);
    }
    if (selfSigningKey != null) {
      keysToSign.add(
        client.userDeviceKeys[client.userID]!.deviceKeys[client.deviceID]!,
      );
    }
    Logs().v('Sign ourself...');
    await encryption.crossSigning.sign(keysToSign);
  } catch (e, s) {
    Logs().e('[Bootstrapping] Error setting up cross signing', e, s);
    state = BootstrapState.error;
    return;
  }

  await client.dehydratedDeviceSetup(newSsssKey!);
  checkOnlineKeyBackup();
}