hasValidSignatureChain method

bool hasValidSignatureChain({
  1. bool verifiedOnly = true,
  2. Set<String>? visited,
  3. Set<String>? onlyValidateUserIds,
  4. bool verifiedByTheirMasterKey = false,
})

Implementation

bool hasValidSignatureChain({
  bool verifiedOnly = true,
  Set<String>? visited,
  Set<String>? onlyValidateUserIds,

  /// Only check if this key is verified by their Master key.
  bool verifiedByTheirMasterKey = false,
}) {
  if (!client.encryptionEnabled) {
    return false;
  }

  final visited_ = visited ?? <String>{};
  final onlyValidateUserIds_ = onlyValidateUserIds ?? <String>{};

  final setKey = '$userId;$identifier';
  if (visited_.contains(setKey) ||
      (onlyValidateUserIds_.isNotEmpty &&
          !onlyValidateUserIds_.contains(userId))) {
    return false; // prevent recursion & validate hasValidSignatureChain
  }
  visited_.add(setKey);

  if (signatures == null) return false;

  for (final signatureEntries in signatures!.entries) {
    final otherUserId = signatureEntries.key;
    if (!client.userDeviceKeys.containsKey(otherUserId)) {
      continue;
    }
    // we don't allow transitive trust unless it is for ourself
    if (otherUserId != userId && otherUserId != client.userID) {
      continue;
    }
    for (final signatureEntry in signatureEntries.value.entries) {
      final fullKeyId = signatureEntry.key;
      final signature = signatureEntry.value;
      final keyId = fullKeyId.substring('ed25519:'.length);
      // we ignore self-signatures here
      if (otherUserId == userId && keyId == identifier) {
        continue;
      }

      final key = client.userDeviceKeys[otherUserId]?.deviceKeys[keyId] ??
          client.userDeviceKeys[otherUserId]?.crossSigningKeys[keyId];
      if (key == null) {
        continue;
      }

      if (onlyValidateUserIds_.isNotEmpty &&
          !onlyValidateUserIds_.contains(key.userId)) {
        // we don't want to verify keys from this user
        continue;
      }

      if (key.blocked) {
        continue; // we can't be bothered about this keys signatures
      }
      var haveValidSignature = false;
      var gotSignatureFromCache = false;
      final fullKeyIdBool = validSignatures
          ?.tryGetMap<String, Object?>(otherUserId)
          ?.tryGet<bool>(fullKeyId);
      if (fullKeyIdBool == true) {
        haveValidSignature = true;
        gotSignatureFromCache = true;
      } else if (fullKeyIdBool == false) {
        haveValidSignature = false;
        gotSignatureFromCache = true;
      }

      if (!gotSignatureFromCache && key.ed25519Key != null) {
        // validate the signature manually
        haveValidSignature = _verifySignature(key.ed25519Key!, signature);
        final validSignatures = this.validSignatures ??= <String, dynamic>{};
        if (!validSignatures.containsKey(otherUserId)) {
          validSignatures[otherUserId] = <String, dynamic>{};
        }
        validSignatures[otherUserId][fullKeyId] = haveValidSignature;
      }
      if (!haveValidSignature) {
        // no valid signature, this key is useless
        continue;
      }

      if ((verifiedOnly && key.directVerified) ||
          (key is CrossSigningKey &&
              key.usage.contains('master') &&
              (verifiedByTheirMasterKey ||
                  (key.directVerified && key.userId == client.userID)))) {
        return true; // we verified this key and it is valid...all checks out!
      }
      // or else we just recurse into that key and check if it works out
      final haveChain = key.hasValidSignatureChain(
          verifiedOnly: verifiedOnly,
          visited: visited_,
          onlyValidateUserIds: onlyValidateUserIds,
          verifiedByTheirMasterKey: verifiedByTheirMasterKey);
      if (haveChain) {
        return true;
      }
    }
  }
  return false;
}