Skip to content

Commit

Permalink
Fix/Check deletionInfo before creating ResponseItems (#156)
Browse files Browse the repository at this point in the history
* feat: add todo

* feat: ensure Attribute wasn't deleted by peer before answering ReadAttributeRequestItem with AttributeAlreadySharedAcceptResponseItem

* feat: ensure Attribute wasn't deleted by peer before answering ReadAttributeRequestItem with AttributeSuccessionAcceptResponseItem

* refactor: rename variables

* feat: check deletionInfo before creating AcceptResponseItem for ProposeAttributeRequestItem

* chore: version bump

* feat: adjust error message and add tests

* fix: make sourceAttribute required in CreateSharedLocalAttributeCopyParamsJSON

* feat: integrate comments

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
Milena-Czierlinski and mergify[bot] committed Jun 17, 2024
1 parent 0f5d872 commit 6d49c13
Show file tree
Hide file tree
Showing 8 changed files with 527 additions and 157 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/consumption/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nmshd/consumption",
"version": "3.12.0",
"version": "3.12.1",
"description": "The consumption library extends the transport library.",
"homepage": "https://enmeshed.eu",
"repository": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CoreAddress, CoreId, ICoreAddress, ICoreId } from "@nmshd/transport";

export interface CreateSharedLocalAttributeCopyParamsJSON {
attributeId?: string;
sourceAttributeId?: string;
sourceAttributeId: string;
peer: string;
requestReference: string;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from "@nmshd/content";
import { CoreAddress, CoreId, CoreErrors as TransportCoreErrors } from "@nmshd/transport";
import { CoreErrors } from "../../../../consumption/CoreErrors";
import { AttributeSuccessorParams, LocalAttributeShareInfo, PeerSharedAttributeSucceededEvent } from "../../../attributes";
import { AttributeSuccessorParams, DeletionStatus, LocalAttributeShareInfo, PeerSharedAttributeSucceededEvent } from "../../../attributes";
import { LocalAttribute } from "../../../attributes/local/LocalAttribute";
import { ValidationResult } from "../../../common/ValidationResult";
import { GenericRequestItemProcessor } from "../GenericRequestItemProcessor";
Expand Down Expand Up @@ -76,7 +76,7 @@ export class ProposeAttributeRequestItemProcessor extends GenericRequestItemProc
if (parsedParams.isWithExistingAttribute()) {
const foundAttribute = await this.consumptionController.attributes.getLocalAttribute(parsedParams.attributeId);

if (!foundAttribute) return ValidationResult.error(TransportCoreErrors.general.recordNotFound(LocalAttribute, requestInfo.id.toString()));
if (!foundAttribute) return ValidationResult.error(TransportCoreErrors.general.recordNotFound(LocalAttribute, parsedParams.attributeId.toString()));

const latestSharedVersion = await this.consumptionController.attributes.getSharedVersionsOfAttribute(parsedParams.attributeId, [requestInfo.peer], true);
if (latestSharedVersion.length > 0) {
Expand Down Expand Up @@ -120,7 +120,14 @@ export class ProposeAttributeRequestItemProcessor extends GenericRequestItemProc

const latestSharedVersion = await this.consumptionController.attributes.getSharedVersionsOfAttribute(parsedParams.attributeId, [requestInfo.peer], true);

if (latestSharedVersion.length === 0) {
const wasSharedBefore = latestSharedVersion.length > 0;
const wasDeletedByPeerOrOwner =
latestSharedVersion[0]?.deletionInfo?.deletionStatus === DeletionStatus.DeletedByPeer ||
latestSharedVersion[0]?.deletionInfo?.deletionStatus === DeletionStatus.DeletedByOwner;
const isLatestSharedVersion = latestSharedVersion[0]?.shareInfo?.sourceAttribute?.toString() === existingSourceAttribute.id.toString();
const predecessorWasSharedBefore = wasSharedBefore && !isLatestSharedVersion;

if (!wasSharedBefore || wasDeletedByPeerOrOwner) {
sharedLocalAttribute = await this.consumptionController.attributes.createSharedLocalAttributeCopy({
sourceAttributeId: CoreId.from(existingSourceAttribute.id),
peer: CoreAddress.from(requestInfo.peer),
Expand All @@ -133,36 +140,45 @@ export class ProposeAttributeRequestItemProcessor extends GenericRequestItemProc
});
}

const latestSharedAttribute = latestSharedVersion[0];
if (!latestSharedAttribute.shareInfo?.sourceAttribute) {
throw new Error(
`The Attribute ${latestSharedAttribute.id} doesn't have a 'shareInfo.sourceAttribute', even though it was found as shared version of an Attribute.`
);
}

if (latestSharedAttribute.shareInfo.sourceAttribute.toString() === existingSourceAttribute.id.toString()) {
if (isLatestSharedVersion) {
return AttributeAlreadySharedAcceptResponseItem.from({
result: ResponseItemResult.Accepted,
attributeId: latestSharedAttribute.id
attributeId: latestSharedVersion[0].id
});
}

const predecessorSourceAttribute = await this.consumptionController.attributes.getLocalAttribute(latestSharedAttribute.shareInfo.sourceAttribute);
if (!predecessorSourceAttribute) throw TransportCoreErrors.general.recordNotFound(LocalAttribute, latestSharedAttribute.shareInfo.sourceAttribute.toString());

if (await this.consumptionController.attributes.isSubsequentInSuccession(predecessorSourceAttribute, existingSourceAttribute)) {
if (existingSourceAttribute.isRepositoryAttribute(this.currentIdentityAddress)) {
const successorSharedAttribute = await this.performOwnSharedIdentityAttributeSuccession(latestSharedAttribute.id, existingSourceAttribute, requestInfo);
return AttributeSuccessionAcceptResponseItem.from({
result: ResponseItemResult.Accepted,
successorId: successorSharedAttribute.id,
successorContent: successorSharedAttribute.content,
predecessorId: latestSharedAttribute.id
});
if (predecessorWasSharedBefore) {
const sharedPredecessor = latestSharedVersion[0];
if (!sharedPredecessor.shareInfo?.sourceAttribute) {
throw new Error(
`The Attribute ${sharedPredecessor.id} doesn't have a 'shareInfo.sourceAttribute', even though it was found as shared version of an Attribute.`
);
}

const predecessorSourceAttribute = await this.consumptionController.attributes.getLocalAttribute(sharedPredecessor.shareInfo.sourceAttribute);
if (!predecessorSourceAttribute) throw TransportCoreErrors.general.recordNotFound(LocalAttribute, sharedPredecessor.shareInfo.sourceAttribute.toString());

if (await this.consumptionController.attributes.isSubsequentInSuccession(predecessorSourceAttribute, existingSourceAttribute)) {
if (existingSourceAttribute.isRepositoryAttribute(this.currentIdentityAddress)) {
const successorSharedAttribute = await this.performOwnSharedIdentityAttributeSuccession(sharedPredecessor.id, existingSourceAttribute, requestInfo);
return AttributeSuccessionAcceptResponseItem.from({
result: ResponseItemResult.Accepted,
successorId: successorSharedAttribute.id,
successorContent: successorSharedAttribute.content,
predecessorId: sharedPredecessor.id
});
}
}
}
}
sharedLocalAttribute = await this.createNewAttribute(parsedParams.attribute!, requestInfo);

if (!parsedParams.attribute) {
throw new Error(
"The ProposeAttributeRequestItem wasn't answered with a new Attribute, but it wasn't handled as having been answered with an existing Attribute, either."
);
}

sharedLocalAttribute = await this.createNewAttribute(parsedParams.attribute, requestInfo);

return ProposeAttributeAcceptResponseItem.from({
result: ResponseItemResult.Accepted,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from "@nmshd/content";
import { CoreAddress, CoreId, CoreErrors as TransportCoreErrors } from "@nmshd/transport";
import { CoreErrors } from "../../../../consumption/CoreErrors";
import { AttributeSuccessorParams, LocalAttributeShareInfo, PeerSharedAttributeSucceededEvent } from "../../../attributes";
import { AttributeSuccessorParams, DeletionStatus, LocalAttributeShareInfo, PeerSharedAttributeSucceededEvent } from "../../../attributes";
import { LocalAttribute } from "../../../attributes/local/LocalAttribute";
import { ValidationResult } from "../../../common/ValidationResult";
import { GenericRequestItemProcessor } from "../GenericRequestItemProcessor";
Expand All @@ -38,7 +38,7 @@ export class ReadAttributeRequestItemProcessor extends GenericRequestItemProcess

if (parsedParams.isWithExistingAttribute()) {
const foundAttribute = await this.consumptionController.attributes.getLocalAttribute(parsedParams.existingAttributeId);
if (!foundAttribute) return ValidationResult.error(TransportCoreErrors.general.recordNotFound(LocalAttribute, requestInfo.id.toString()));
if (!foundAttribute) return ValidationResult.error(TransportCoreErrors.general.recordNotFound(LocalAttribute, parsedParams.existingAttributeId.toString()));

const ownerIsCurrentIdentity = this.accountController.identity.isMe(foundAttribute.content.owner);
if (!ownerIsCurrentIdentity && foundAttribute.content instanceof IdentityAttribute) {
Expand Down Expand Up @@ -81,7 +81,14 @@ export class ReadAttributeRequestItemProcessor extends GenericRequestItemProcess

const latestSharedVersion = await this.consumptionController.attributes.getSharedVersionsOfAttribute(parsedParams.existingAttributeId, [requestInfo.peer], true);

if (latestSharedVersion.length === 0) {
const wasSharedBefore = latestSharedVersion.length > 0;
const wasDeletedByPeerOrOwner =
latestSharedVersion[0]?.deletionInfo?.deletionStatus === DeletionStatus.DeletedByPeer ||
latestSharedVersion[0]?.deletionInfo?.deletionStatus === DeletionStatus.DeletedByOwner;
const isLatestSharedVersion = latestSharedVersion[0]?.shareInfo?.sourceAttribute?.toString() === existingSourceAttribute.id.toString();
const predecessorWasSharedBefore = wasSharedBefore && !isLatestSharedVersion;

if (!wasSharedBefore || wasDeletedByPeerOrOwner) {
sharedLocalAttribute = await this.consumptionController.attributes.createSharedLocalAttributeCopy({
sourceAttributeId: CoreId.from(existingSourceAttribute.id),
peer: CoreAddress.from(requestInfo.peer),
Expand All @@ -94,42 +101,49 @@ export class ReadAttributeRequestItemProcessor extends GenericRequestItemProcess
});
}

const latestSharedAttribute = latestSharedVersion[0];
if (!latestSharedAttribute.shareInfo?.sourceAttribute) {
throw new Error(
`The Attribute ${latestSharedAttribute.id} doesn't have a 'shareInfo.sourceAttribute', even though it was found as shared version of an Attribute.`
);
}

if (latestSharedAttribute.shareInfo.sourceAttribute.toString() === existingSourceAttribute.id.toString()) {
if (isLatestSharedVersion) {
return AttributeAlreadySharedAcceptResponseItem.from({
result: ResponseItemResult.Accepted,
attributeId: latestSharedAttribute.id
attributeId: latestSharedVersion[0].id
});
}

const predecessorSourceAttribute = await this.consumptionController.attributes.getLocalAttribute(latestSharedAttribute.shareInfo.sourceAttribute);
if (!predecessorSourceAttribute) throw TransportCoreErrors.general.recordNotFound(LocalAttribute, latestSharedAttribute.shareInfo.sourceAttribute.toString());

if (await this.consumptionController.attributes.isSubsequentInSuccession(predecessorSourceAttribute, existingSourceAttribute)) {
let successorSharedAttribute: LocalAttribute;
if (existingSourceAttribute.isRepositoryAttribute(this.currentIdentityAddress)) {
successorSharedAttribute = await this.performOwnSharedIdentityAttributeSuccession(latestSharedAttribute.id, existingSourceAttribute, requestInfo);
} else if (existingSourceAttribute.isOwnedBy(this.accountController.identity.address)) {
successorSharedAttribute = await this.performOwnSharedThirdPartyRelationshipAttributeSuccession(latestSharedAttribute.id, existingSourceAttribute, requestInfo);
} else {
successorSharedAttribute = await this.performThirdPartyOwnedRelationshipAttributeSuccession(latestSharedAttribute.id, existingSourceAttribute, requestInfo);
if (predecessorWasSharedBefore) {
const sharedPredecessor = latestSharedVersion[0];
if (!sharedPredecessor.shareInfo?.sourceAttribute) {
throw new Error(
`The Attribute ${sharedPredecessor.id} doesn't have a 'shareInfo.sourceAttribute', even though it was found as shared version of an Attribute.`
);
}

return AttributeSuccessionAcceptResponseItem.from({
result: ResponseItemResult.Accepted,
successorId: successorSharedAttribute.id,
successorContent: successorSharedAttribute.content,
predecessorId: latestSharedAttribute.id
});
const predecessorSourceAttribute = await this.consumptionController.attributes.getLocalAttribute(sharedPredecessor.shareInfo.sourceAttribute);
if (!predecessorSourceAttribute) throw TransportCoreErrors.general.recordNotFound(LocalAttribute, sharedPredecessor.shareInfo.sourceAttribute.toString());

if (await this.consumptionController.attributes.isSubsequentInSuccession(predecessorSourceAttribute, existingSourceAttribute)) {
let successorSharedAttribute: LocalAttribute;
if (existingSourceAttribute.isRepositoryAttribute(this.currentIdentityAddress)) {
successorSharedAttribute = await this.performOwnSharedIdentityAttributeSuccession(sharedPredecessor.id, existingSourceAttribute, requestInfo);
} else if (existingSourceAttribute.isOwnedBy(this.accountController.identity.address)) {
successorSharedAttribute = await this.performOwnSharedThirdPartyRelationshipAttributeSuccession(sharedPredecessor.id, existingSourceAttribute, requestInfo);
} else {
successorSharedAttribute = await this.performThirdPartyOwnedRelationshipAttributeSuccession(sharedPredecessor.id, existingSourceAttribute, requestInfo);
}

return AttributeSuccessionAcceptResponseItem.from({
result: ResponseItemResult.Accepted,
successorId: successorSharedAttribute.id,
successorContent: successorSharedAttribute.content,
predecessorId: sharedPredecessor.id
});
}
}
}
sharedLocalAttribute = await this.createNewAttribute(parsedParams.newAttribute!, requestInfo);

if (!parsedParams.newAttribute) {
throw new Error("The ReadAttributeRequestItem wasn't answered with a new Attribute, but it wasn't handled as having been answered with an existing Attribute, either.");
}

sharedLocalAttribute = await this.createNewAttribute(parsedParams.newAttribute, requestInfo);
return ReadAttributeAcceptResponseItem.from({
result: ResponseItemResult.Accepted,
attributeId: sharedLocalAttribute.id,
Expand Down
Loading

0 comments on commit 6d49c13

Please sign in to comment.