giveAccessTo method

  1. @override
Future<Patient> giveAccessTo(
  1. Patient patient,
  2. String delegatedTo
)
override

Give access to another dataOwner to the patient

Parameters:

  • Patient patient to giveAccessTo delegateTo
  • String delegatedTo: dataOwnerId to giveAccessTo

Data owner id can be either a:

  • healthcarePartyId,
  • patientId
  • deviceId

Implementation

@override
Future<Patient> giveAccessTo(Patient patient, String delegatedTo) async {
  final localCrypto = _api.crypto;
  final currentUser = (await _api.baseUserApi.getCurrentUser())
      ?? (throw StateError("There is no user currently logged in. You must call this method from an authenticated MedTechApi"));

  if (currentUser.dataOwnerId() == null) {
    throw StateError("The current user is not a data owner. You must been either a patient, a device or a healthcare professional to call this method");
  }

// Check if delegatedBy has access
  if (!patient.systemMetaData!.delegations.entries.any((element) => element.key == currentUser.dataOwnerId())) {
    throw StateError("DataOwner ${currentUser.dataOwnerId()} does not have the right to access patient ${patient.id}");
  }

  final patientDto = patient.toPatientDto();

  final myId = currentUser!.dataOwnerId()!;
  final newSecretIds = await localCrypto.findAndDecryptPotentiallyUnknownKeysForDelegate(myId, delegatedTo, patientDto.delegations);
  final newEncryptionKeys = await localCrypto.findAndDecryptPotentiallyUnknownKeysForDelegate(myId, delegatedTo, patientDto.encryptionKeys);

  if (newSecretIds.isEmpty && newSecretIds.isEmpty) {
    return patient;
  }

  DataOwnerDto? dataOwner = null;
  final Map<String, String> encryptedKeys = {};
  for (var clearKey in { ...newSecretIds, ...newEncryptionKeys }) {
    final encryptedKeyAndOwner = await localCrypto.encryptAESKeyForHcp(
        myId,
        delegatedTo,
        patientDto.id,
        clearKey.formatAsKey()
    );
    encryptedKeys[clearKey] = encryptedKeyAndOwner.item1;
    dataOwner = encryptedKeyAndOwner.item2 ?? dataOwner;
  }
  final newSecretIdsDelegations = newSecretIds.map((clearKey) =>
      Delegation(owner: myId, delegatedTo: delegatedTo, key: encryptedKeys[clearKey]!)
  );
  final newEncryptionKeysDelegations = newEncryptionKeys.map((clearKey) =>
      Delegation(owner: myId, delegatedTo: delegatedTo, key: encryptedKeys[clearKey]!)
  );

  if (patient.systemMetaData == null) {
    patient.systemMetaData = SystemMetaDataOwnerEncrypted(delegations: {}, encryptionKeys: {});
  }
  final existingDelegationsForDelegate = patient.systemMetaData!.delegations[delegatedTo] ?? [];
  patient.systemMetaData!.delegations[delegatedTo] = [...existingDelegationsForDelegate, ...newSecretIdsDelegations];
  final existingEncryptionKeysForDelegate = patient.systemMetaData!.encryptionKeys[delegatedTo] ?? [];
  patient.systemMetaData!.encryptionKeys[delegatedTo] = [...existingEncryptionKeysForDelegate, ...newEncryptionKeysDelegations];

  if (dataOwner != null && dataOwner.dataOwnerId == patient.id) {
    patient.rev = dataOwner.rev;
    patient.systemMetaData!.hcPartyKeys = dataOwner.hcPartyKeys;
    patient.systemMetaData!.aesExchangeKeys = dataOwner.aesExchangeKeys;
  }

  return (await createOrModifyPatient(patient)) ?? (throw StateError("Couldn't give access to $delegatedTo to patient ${patient.id}"));
}