Skip to content
This repository has been archived by the owner on Jan 4, 2022. It is now read-only.

Commit

Permalink
fix: do not allow to change ownerId and entropy
Browse files Browse the repository at this point in the history
* fix: validate components of the `Document.$id` when replacing

* chore: split errors
  • Loading branch information
jawid-h authored Mar 6, 2020
1 parent 3d10a01 commit bff5807
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const ValidationResult = require('../../../../validation/ValidationResult');

const DocumentAlreadyPresentError = require('../../../../errors/DocumentAlreadyPresentError');
const DocumentNotFoundError = require('../../../../errors/DocumentNotFoundError');
const DocumentOwnerIdMismatchError = require('../../../../errors/DocumentOwnerIdMismatchError');
const DocumentEntropyMismatchError = require('../../../../errors/DocumentEntropyMismatchError');
const InvalidDocumentRevisionError = require('../../../../errors/InvalidDocumentRevisionError');
const InvalidDocumentActionError = require('../../../errors/InvalidDocumentActionError');

Expand Down Expand Up @@ -75,6 +77,18 @@ function validateDocumentsSTDataFactory(
break;
}

if (fetchedDocument.getOwnerId() !== document.getOwnerId()) {
result.addError(
new DocumentOwnerIdMismatchError(document, fetchedDocument),
);
}

if (fetchedDocument.entropy !== document.entropy) {
result.addError(
new DocumentEntropyMismatchError(document, fetchedDocument),
);
}

if (document.getRevision() !== fetchedDocument.getRevision() + 1) {
result.addError(
new InvalidDocumentRevisionError(document, fetchedDocument),
Expand Down
34 changes: 34 additions & 0 deletions lib/errors/DocumentEntropyMismatchError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const ConsensusError = require('./ConsensusError');

class DocumentEntropyMismatchError extends ConsensusError {
/**
* @param {Document} document
* @param {Document} fetchedDocument
*/
constructor(document, fetchedDocument) {
super('Document entropy mismatch with previous versions');

this.document = document;
this.fetchedDocument = fetchedDocument;
}

/**
* Get Document
*
* @return {Document}
*/
getDocument() {
return this.document;
}

/**
* Get fetched Document
*
* @return {Document}
*/
getFetchedDocument() {
return this.fetchedDocument;
}
}

module.exports = DocumentEntropyMismatchError;
34 changes: 34 additions & 0 deletions lib/errors/DocumentOwnerIdMismatchError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const ConsensusError = require('./ConsensusError');

class DocumentOwnerIdMismatchError extends ConsensusError {
/**
* @param {Document} document
* @param {Document} fetchedDocument
*/
constructor(document, fetchedDocument) {
super('Document owner id mismatch with previous versions');

this.document = document;
this.fetchedDocument = fetchedDocument;
}

/**
* Get Document
*
* @return {Document}
*/
getDocument() {
return this.document;
}

/**
* Get fetched Document
*
* @return {Document}
*/
getFetchedDocument() {
return this.fetchedDocument;
}
}

module.exports = DocumentOwnerIdMismatchError;
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const DocumentNotFoundError = require('../../../../../lib/errors/DocumentNotFoun
const InvalidDocumentRevisionError = require('../../../../../lib/errors/InvalidDocumentRevisionError');
const ConsensusError = require('../../../../../lib/errors/ConsensusError');
const InvalidDocumentActionError = require('../../../../../lib/document/errors/InvalidDocumentActionError');
const DocumentOwnerIdMismatchError = require('../../../../../lib/errors/DocumentOwnerIdMismatchError');
const DocumentEntropyMismatchError = require('../../../../../lib/errors/DocumentEntropyMismatchError');

describe('validateDocumentsSTDataFactory', () => {
let validateDocumentsSTData;
Expand Down Expand Up @@ -170,6 +172,58 @@ describe('validateDocumentsSTDataFactory', () => {
expect(executeDataTriggersMock).to.have.not.been.called();
});

it('should return invalid result if Document with action "update" has mismatch of ownerId with previous revision', async () => {
documents[0].setAction(Document.ACTIONS.REPLACE);

const fetchedDocument = new Document(documents[0].toJSON());
fetchedDocument.revision -= 1;
fetchedDocument.ownerId = '5zcXZpTLWFwZjKjq3ME5KVavtZa9YUaZESVzrndehBhq';

fetchDocumentsMock.resolves([fetchedDocument]);

const result = await validateDocumentsSTData(stateTransition);

expectValidationError(result, DocumentOwnerIdMismatchError);

const [error] = result.getErrors();

expect(error.getDocument()).to.equal(documents[0]);
expect(error.getFetchedDocument()).to.equal(fetchedDocument);

expect(fetchAndValidateDataContractMock).to.have.been.calledOnceWithExactly(documents[0]);

expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(documents);

expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
expect(executeDataTriggersMock).to.have.not.been.called();
});

it('should return invalid result if Document with action "update" has mismatch of entropy with previous revision', async () => {
documents[0].setAction(Document.ACTIONS.REPLACE);

const fetchedDocument = new Document(documents[0].toJSON());
fetchedDocument.revision -= 1;
fetchedDocument.entropy = '5zcXZpTLWFwZjKjq3ME5KVavtZa9YUaZESVzrndehBhq';

fetchDocumentsMock.resolves([fetchedDocument]);

const result = await validateDocumentsSTData(stateTransition);

expectValidationError(result, DocumentEntropyMismatchError);

const [error] = result.getErrors();

expect(error.getDocument()).to.equal(documents[0]);
expect(error.getFetchedDocument()).to.equal(fetchedDocument);

expect(fetchAndValidateDataContractMock).to.have.been.calledOnceWithExactly(documents[0]);

expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly(documents);

expect(validateDocumentsUniquenessByIndicesMock).to.have.not.been.called();
expect(executeDataTriggersMock).to.have.not.been.called();
});

it('should return invalid result if Document with action "delete" has wrong revision', async () => {
documents[0].setData({});
documents[0].setAction(Document.ACTIONS.DELETE);
Expand Down

0 comments on commit bff5807

Please sign in to comment.