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

Added tests to demonstrate direct child-role authorization in slack-like protocol #696

Merged
merged 2 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 0 additions & 1 deletion tests/handlers/records-read.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,6 @@ export function testRecordsReadHandler(): void {
// Alice creates a thread
const threadRecord = await TestDataGenerator.generateRecordsWrite({
author : alice,
recipient : bob.did,
protocol : protocolDefinition.protocol,
protocolPath : 'thread'
});
Expand Down
74 changes: 53 additions & 21 deletions tests/scenarios/nested-roles.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import { DidResolver } from '@web5/dids';
import { Dwn } from '../../src/dwn.js';
import { DwnErrorCode } from '../../src/core/dwn-error.js';
import { Jws } from '../../src/utils/jws.js';
import { RecordsQuery } from '../../src/index.js';
import { TestDataGenerator } from '../utils/test-data-generator.js';
import { TestEventStream } from '../test-event-stream.js';
import { TestStores } from '../test-stores.js';
import { RecordsQuery, RecordsRead } from '../../src/index.js';

chai.use(chaiAsPromised);

Expand Down Expand Up @@ -58,19 +58,22 @@ export function testNestedRoleScenarios(): void {
// scenario:
// 1. Alice installs the Slack-like protocol
// 2. Alice creates a community
// 3. Alice can assign Bob as an 'admin' in the community
// 4. Bob can create gated-channels 1 & 2 in the community
// 5. Bob as the creator/author of the channels can add participants in the gated-channels
// 3. Alice can assign Bob as an `admin` in the community
// 4. Bob can invoke his `admin` role to perform actions:
// 4a. Bob can read the community record
// 4b. Bob can create gated-channels 1 & 2 in the community
// 5. Bob as the creator/author of the channels can add participants in the gated-channels
// 5a. Bob can add himself and Carol as participants in the gated-channel 1
// 5b. Bob can add himself and Daniel as participants in the gated-channel 2
// 6. Carol CANNOT add anyone as a participant in the gated-channel 2 since she is not a participant in the channel
// 7. Carol CANNOT add Daniel as another participant in the gated-channel without invoking her role
// 8. Carol can invoke her participant role to add Daniel as another participant in the gated-channel
// 9. Bob can invoke the participant role to write a chat message in the channel
// 10. Carol can invoke the participant role to read chat messages in the channel
// 11. Carol can invoke the participant role to react to Bob's chat message in the channel
// 12. Mallory CANNOT invoke the participant role (which she is not given) to read the chat messages in the channel
// 13. Mallory CANNOT invoke the participant role (which she is not given) to write a chat message in the channel
// 6. Carol can read the gated channel 2 record by invoking her child participant role to the gated channel 2
// 7. Carol CANNOT add anyone as a participant in the gated-channel 2 since she is not a participant in the channel
// 8. Carol CANNOT add Daniel as another participant in the gated-channel without invoking her role
// 9. Carol can invoke her participant role to add Daniel as another participant in the gated-channel
// 10. Bob can invoke the participant role to write a chat message in the channel
// 11. Carol can invoke the participant role to read chat messages in the channel
// 12. Carol can invoke the participant role to react to Bob's chat message in the channel
// 13. Mallory CANNOT invoke the participant role (which she is not given) to read the chat messages in the channel
// 14. Mallory CANNOT invoke the participant role (which she is not given) to write a chat message in the channel

const alice = await TestDataGenerator.generateDidKeyPersona();
const bob = await TestDataGenerator.generateDidKeyPersona();
Expand Down Expand Up @@ -109,7 +112,22 @@ export function testNestedRoleScenarios(): void {
= await dwn.processMessage(alice.did, communityAdminBobRecord.message, { dataStream: communityAdminBobRecord.dataStream });
expect(communityAdminBobRecordReply.status.code).to.equal(202);

// 4. Bob can create gated-channels 1 & 2 in the community
// 4. Bob can invoke his `admin` role to perform actions:
// 4a. Bob can read the community record
const bobCommunityRead = await RecordsRead.create({
signer : Jws.createSigner(bob),
protocolRole : 'community/admin',
filter : {
protocol : protocolDefinition.protocol,
protocolPath : 'community',
contextId : communityRecord.message.contextId
}
});
const bobCommunityReadReply = await dwn.processMessage(alice.did, bobCommunityRead.message);
expect(bobCommunityReadReply.status.code).to.equal(200);
expect(bobCommunityReadReply.record?.recordId).to.equal(communityRecord.message.recordId);

// 4b. Bob can create gated-channels 1 & 2 in the community
const channel1Record = await TestDataGenerator.generateRecordsWrite({
author : bob,
protocol : protocolDefinition.protocol,
Expand Down Expand Up @@ -177,7 +195,21 @@ export function testNestedRoleScenarios(): void {
= await dwn.processMessage(alice.did, channel2ParticipantDanielRecord.message, { dataStream: channel2ParticipantDanielRecord.dataStream });
expect(channel2ParticipantDanielRecordReply.status.code).to.equal(202);

// 6. Carol CANNOT add anyone as a participant in the gated-channel 2 since she is not a participant in the channel
// 6. Carol can read the gated channel 1 record by invoking her child participant role to the gated channel 1
const carolRead = await RecordsRead.create({
signer : Jws.createSigner(carol),
protocolRole : 'community/gatedChannel/participant',
filter : {
protocol : protocolDefinition.protocol,
protocolPath : 'community/gatedChannel',
contextId : channel1Record.message.contextId
}
});
const carolReadReply = await dwn.processMessage(alice.did, carolRead.message);
expect(carolReadReply.status.code).to.equal(200);
expect(carolReadReply.record?.recordId).to.equal(channel1Record.message.recordId);

// 7. Carol CANNOT add anyone as a participant in the gated-channel 2 since she is not a participant in the channel
const participantCarolRecord = await TestDataGenerator.generateRecordsWrite({
author : carol,
recipient : carol.did,
Expand All @@ -191,7 +223,7 @@ export function testNestedRoleScenarios(): void {
expect(participantCarolRecordReply.status.code).to.equal(401);
expect(participantCarolRecordReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound);

// 7. Carol CANNOT add Daniel as another participant in the gated-channel without invoking her role
// 8. Carol CANNOT add Daniel as another participant in the gated-channel without invoking her role
const participantDanielRecordAttempt1 = await TestDataGenerator.generateRecordsWrite({
author : carol,
recipient : daniel.did,
Expand All @@ -204,7 +236,7 @@ export function testNestedRoleScenarios(): void {
expect(participantDanielRecordAttempt1Reply.status.code).to.equal(401);
expect(participantDanielRecordAttempt1Reply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);

// 8. Carol can invoke her participant role to add Daniel as another participant in the gated-channel
// 9. Carol can invoke her participant role to add Daniel as another participant in the gated-channel
const participantDanielRecordAttempt2 = await TestDataGenerator.generateRecordsWrite({
author : carol,
recipient : daniel.did,
Expand All @@ -217,7 +249,7 @@ export function testNestedRoleScenarios(): void {
= await dwn.processMessage(alice.did, participantDanielRecordAttempt2.message, { dataStream: participantDanielRecordAttempt2.dataStream });
expect(participantDanielRecordAttempt2Reply.status.code).to.equal(202);

// 9. Bob can invoke the participant role to write a chat message in the channel
// 10. Bob can invoke the participant role to write a chat message in the channel
const bobChatMessage = await TestDataGenerator.generateRecordsWrite({
author : bob,
protocol : protocolDefinition.protocol,
Expand All @@ -228,7 +260,7 @@ export function testNestedRoleScenarios(): void {
const bobChatMessageReply = await dwn.processMessage(alice.did, bobChatMessage.message, { dataStream: bobChatMessage.dataStream });
expect(bobChatMessageReply.status.code).to.equal(202);

// 10. Carol can invoke the participant role to read chat messages in the channel
// 11. Carol can invoke the participant role to read chat messages in the channel
const carolQuery = await RecordsQuery.create({
signer : Jws.createSigner(carol),
protocolRole : 'community/gatedChannel/participant',
Expand All @@ -242,7 +274,7 @@ export function testNestedRoleScenarios(): void {
expect(carolQueryReply.status.code).to.equal(200);
expect(carolQueryReply.entries?.[0].recordId).to.equal(bobChatMessage.message.recordId);

// 11. Carol can invoke the participant role to react to Bob's chat message in the channel
// 12. Carol can invoke the participant role to react to Bob's chat message in the channel
const carolReaction = await TestDataGenerator.generateRecordsWrite({
author : bob,
protocol : protocolDefinition.protocol,
Expand All @@ -253,7 +285,7 @@ export function testNestedRoleScenarios(): void {
const carolReactionReply = await dwn.processMessage(alice.did, carolReaction.message, { dataStream: carolReaction.dataStream });
expect(carolReactionReply.status.code).to.equal(202);

// 12. Mallory CANNOT invoke the participant role (which she is not given) to read the chat messages in the channel
// 13. Mallory CANNOT invoke the participant role (which she is not given) to read the chat messages in the channel
const malloryQuery = await RecordsQuery.create({
signer : Jws.createSigner(mallory),
protocolRole : 'community/gatedChannel/participant',
Expand All @@ -267,7 +299,7 @@ export function testNestedRoleScenarios(): void {
expect(malloryQueryReply.status.code).to.equal(401);
expect(malloryQueryReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound);

// 13. Mallory CANNOT invoke the participant role (which she is not given) to write a chat message in the channel
// 14. Mallory CANNOT invoke the participant role (which she is not given) to write a chat message in the channel
const malloryChatMessage = await TestDataGenerator.generateRecordsWrite({
author : mallory,
protocol : protocolDefinition.protocol,
Expand Down
12 changes: 11 additions & 1 deletion tests/vectors/protocol-definitions/slack.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"published": true,
"protocol": "https://slick.app",
"protocol": "https://slack.app",
"types": {
"community": {
"dataFormats": [
Expand Down Expand Up @@ -53,6 +53,12 @@
},
"structure": {
"community": {
"$actions": [
{
"role": "community/admin",
"can": "read"
}
],
"admin": {
"$role": true,
"$actions": [
Expand Down Expand Up @@ -148,6 +154,10 @@
{
"role": "community/admin",
"can": "delete"
},
{
"role": "community/gatedChannel/participant",
"can": "read"
}
],
"participant": {
Expand Down
Loading