Skip to content

Commit

Permalink
Added tests to demonstrate direct child-role authorization in slack-l…
Browse files Browse the repository at this point in the history
…ike protocol (#696)
  • Loading branch information
thehenrytsai authored Feb 27, 2024
1 parent 91f6ec6 commit f7c8d85
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 23 deletions.
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

0 comments on commit f7c8d85

Please sign in to comment.