Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A non-tenant author of a Record should be able to RecordsRead their record. #812

Merged
merged 3 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/handlers/records-read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
68 changes: 67 additions & 1 deletion tests/handlers/records-read.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
LiranCohen marked this conversation as resolved.
Show resolved Hide resolved
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 });
Expand Down