giveAccessToPotentiallyEncrypted method
Future<PotentiallyEncryptedPatient>
giveAccessToPotentiallyEncrypted(
- PotentiallyEncryptedPatient patient,
- String delegatedTo
override
Implementation
@override
Future<PotentiallyEncryptedPatient> giveAccessToPotentiallyEncrypted(PotentiallyEncryptedPatient patient, String delegatedTo) async {
if (!(patient is Patient) && !(patient is EncryptedPatient)) {
throw ArgumentError("Unexpected type for patient $patient");
}
final patientId = patient.id!;
final existingDelegations = patient.systemMetaData?.delegations ?? {};
final existingEncryptionKeys = patient.systemMetaData?.encryptionKeys ?? {};
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 (!existingDelegations.entries.any((element) => element.key == currentUser.dataOwnerId())) {
throw StateError("DataOwner ${currentUser.dataOwnerId()} does not have the right to access patient ${patientId}");
}
final myId = currentUser.dataOwnerId()!;
final newSecretIds = await localCrypto.findAndDecryptPotentiallyUnknownKeysForDelegate(
myId,
delegatedTo,
existingDelegations.map((key, value) => MapEntry(key, value.map((e) => e.toDelegationDto()).toSet()))
);
final newEncryptionKeys = await localCrypto.findAndDecryptPotentiallyUnknownKeysForDelegate(
myId,
delegatedTo,
existingEncryptionKeys.map((key, value) => MapEntry(key, value.map((e) => e.toDelegationDto()).toSet()))
);
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,
patientId,
clearKey.formatAsKey()
);
encryptedKeys[clearKey] = encryptedKeyAndOwner.item1;
dataOwner = encryptedKeyAndOwner.item2 ?? dataOwner;
}
final newSecretIdsDelegations = newSecretIds.map((clearKey) =>
Delegation(owner: myId, delegatedTo: delegatedTo, key: encryptedKeys[clearKey]!)
).toList();
final newEncryptionKeysDelegations = newEncryptionKeys.map((clearKey) =>
Delegation(owner: myId, delegatedTo: delegatedTo, key: encryptedKeys[clearKey]!)
).toList();
final Map<String, List<Delegation>> updatedDelegations = {
...existingDelegations,
delegatedTo: [...(existingDelegations[delegatedTo] ?? []), ...newSecretIdsDelegations]
};
final Map<String, List<Delegation>> updatedEncryptionKeys = {
...existingEncryptionKeys,
delegatedTo: [...(existingEncryptionKeys[delegatedTo] ?? []), ...newEncryptionKeysDelegations]
};
if (patient.systemMetaData == null) {
patient.systemMetaData = SystemMetaDataOwnerEncrypted();
}
if (dataOwner != null && dataOwner.dataOwnerId == patientId) {
patient.rev = dataOwner.rev;
patient.systemMetaData!.hcPartyKeys = dataOwner.hcPartyKeys;
patient.systemMetaData!.aesExchangeKeys = dataOwner.aesExchangeKeys;
}
patient.systemMetaData!.encryptionKeys = updatedEncryptionKeys;
patient.systemMetaData!.delegations = updatedDelegations;
return (await modifyPotentiallyEncryptedPatient(patient)) ?? (throw StateError("Couldn't give access to $delegatedTo to patient ${patient.id}"));
}