From d0ad3f2fb0ccd118072260de2606d053646d5e87 Mon Sep 17 00:00:00 2001 From: Liran Cohen Date: Wed, 2 Oct 2024 10:59:16 -0400 Subject: [PATCH 1/3] allow author of a record to read that record regardless of protocol defined rules --- src/handlers/records-read.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/handlers/records-read.ts b/src/handlers/records-read.ts index 2f6b5185c..144855637 100644 --- a/src/handlers/records-read.ts +++ b/src/handlers/records-read.ts @@ -129,8 +129,10 @@ export class RecordsReadHandler implements MethodHandler { } else if (descriptor.published === true) { // authentication is not required for published data return; - } else if (recordsRead.author !== undefined && recordsRead.author === descriptor.recipient) { - // The recipient of a message may always read it + } else if (recordsRead.author !== undefined && + (recordsRead.author === descriptor.recipient || recordsRead.author === matchedRecordsWrite.author) + ) { + // The recipient or author of a message may always read it return; } else if (recordsRead.author !== undefined && recordsRead.signaturePayload!.permissionGrantId !== undefined) { const permissionGrant = await PermissionsProtocol.fetchGrant(tenant, messageStore, recordsRead.signaturePayload!.permissionGrantId); From d756be1646bb5fdacda6232bdadaefd77e2d8a53 Mon Sep 17 00:00:00 2001 From: Liran Cohen Date: Wed, 2 Oct 2024 11:09:21 -0400 Subject: [PATCH 2/3] test records read functionality for non-tenant authored records --- tests/handlers/records-read.spec.ts | 68 ++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/tests/handlers/records-read.spec.ts b/tests/handlers/records-read.spec.ts index 74cf790fe..aead319eb 100644 --- a/tests/handlers/records-read.spec.ts +++ b/tests/handlers/records-read.spec.ts @@ -106,7 +106,7 @@ export function testRecordsReadHandler(): void { expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; }); - it('should not allow non-tenant to RecordsRead their a record data', async () => { + it('should not allow non-tenant to RecordsRead a record', async () => { const alice = await TestDataGenerator.generateDidKeyPersona(); // insert data @@ -205,6 +205,72 @@ export function testRecordsReadHandler(): void { expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; }); + it('should allow a non-tenant to read RecordsRead data they have authored', async () => { + const alice = await TestDataGenerator.generateDidKeyPersona(); + const bob = await TestDataGenerator.generateDidKeyPersona(); + const carol = await TestDataGenerator.generateDidKeyPersona(); + + // Alice installs a protocol that allows anyone to write foo record + const protocolDefinition:ProtocolDefinition = { + published : true, + protocol : 'https://example.com/foo', + types : { + foo: {} + }, + structure: { + foo: { + $actions: [{ + who : 'anyone', + can : ['create'] + }] + } + } + }; + + const configureProtocol = await TestDataGenerator.generateProtocolsConfigure({ + author : alice, + protocolDefinition : protocolDefinition, + }); + const configureProtocolReply = await dwn.processMessage(alice.did, configureProtocol.message); + expect(configureProtocolReply.status.code).to.equal(202); + + // Bob writes a foo record to Alice's DWN + const { message, dataStream, dataBytes } = await TestDataGenerator.generateRecordsWrite({ + author : bob, + protocol : protocolDefinition.protocol, + protocolPath : 'foo', + }); + const writeReply = await dwn.processMessage(alice.did, message, { dataStream }); + expect(writeReply.status.code).to.equal(202); + + // Bob reads the data that Alice sent him + const recordsRead = await RecordsRead.create({ + filter: { + recordId: message.recordId, + }, + signer: Jws.createSigner(bob) + }); + + const readReply = await dwn.processMessage(alice.did, recordsRead.message); + expect(readReply.status.code).to.equal(200); + expect(readReply.record).to.exist; + expect(readReply.record?.descriptor).to.exist; + + const dataFetched = await DataStream.toBytes(readReply.record!.data!); + expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; + + // carol attempts to read Bob's record + const carolRecordsRead = await RecordsRead.create({ + filter: { + recordId: message.recordId, + }, + signer: Jws.createSigner(carol) + }); + + const carolReadReply = await dwn.processMessage(alice.did, carolRecordsRead.message); + expect(carolReadReply.status.code).to.equal(401); + }); + it('should include `initialWrite` property if RecordsWrite is not initial write', async () => { const alice = await TestDataGenerator.generateDidKeyPersona(); const write = await TestDataGenerator.generateRecordsWrite({ author: alice, published: false }); From 160f9a78f6339c1d656e9e96fabc119c5a6dece9 Mon Sep 17 00:00:00 2001 From: Liran Cohen Date: Fri, 4 Oct 2024 10:19:58 -0400 Subject: [PATCH 3/3] Update tests/handlers/records-read.spec.ts Co-authored-by: Henry Tsai --- tests/handlers/records-read.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/handlers/records-read.spec.ts b/tests/handlers/records-read.spec.ts index aead319eb..092be215a 100644 --- a/tests/handlers/records-read.spec.ts +++ b/tests/handlers/records-read.spec.ts @@ -243,7 +243,7 @@ export function testRecordsReadHandler(): void { const writeReply = await dwn.processMessage(alice.did, message, { dataStream }); expect(writeReply.status.code).to.equal(202); - // Bob reads the data that Alice sent him + // Bob reads the record he sent to Alice from Alice's DWN const recordsRead = await RecordsRead.create({ filter: { recordId: message.recordId,