Skip to content

Commit

Permalink
added extensive test case, refactored authorization, added comments f…
Browse files Browse the repository at this point in the history
…or clarity
  • Loading branch information
LiranCohen committed Jun 25, 2024
1 parent a4adbde commit a7e1e93
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 166 deletions.
1 change: 1 addition & 0 deletions src/core/dwn-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export enum DwnErrorCode {
ParseCidMultihashNotSupported = 'ParseCidMultihashNotSupported',
PermissionsProtocolCreateGrantRecordsScopeMissingProtocol = 'PermissionsProtocolCreateGrantRecordsScopeMissingProtocol',
PermissionsProtocolCreateRequestRecordsScopeMissingProtocol = 'PermissionsProtocolCreateRequestRecordsScopeMissingProtocol',
PermissionsProtocolGetScopeInvalidProtocol = 'PermissionsProtocolGetScopeInvalidProtocol',
PermissionsProtocolValidateSchemaUnexpectedRecord = 'PermissionsProtocolValidateSchemaUnexpectedRecord',
PermissionsProtocolValidateScopeContextIdProhibitedProperties = 'PermissionsProtocolValidateScopeContextIdProhibitedProperties',
PermissionsProtocolValidateScopeProtocolMismatch = 'PermissionsProtocolValidateScopeProtocolMismatch',
Expand Down
41 changes: 38 additions & 3 deletions src/core/messages-grant-authorization.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import type { GenericMessage } from '../types/message-types.js';
import type { MessagesGetMessage } from '../types/messages-types.js';
import type { MessagesPermissionScope } from '../types/permission-types.js';
import type { MessageStore } from '../types/message-store.js';
import type { PermissionGrant } from '../protocols/permission-grant.js';
import type { RecordsDeleteMessage, RecordsWriteMessage } from '../types/records-types.js';
import type { ProtocolsConfigureMessage } from '../types/protocols-types.js';
import type { DataEncodedRecordsWriteMessage, RecordsDeleteMessage, RecordsWriteMessage } from '../types/records-types.js';
import type { MessagesPermissionScope, PermissionScope } from '../types/permission-types.js';

import { GrantAuthorization } from './grant-authorization.js';
import { Message } from './message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { PermissionRequest } from '../protocols/permission-request.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { Records } from '../utils/records.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
Expand Down Expand Up @@ -64,6 +67,38 @@ export class MessagesGrantAuthorization {
// the record protocol matches the incoming scope protocol
return;
}

// otherwise we check if the protocol is the internal PermissionsProtocol for further validation
if (recordsWriteMessage.descriptor.protocol === PermissionsProtocol.uri) {
if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.revocationPath) {
// anyone can read a revocation message
return;
}

// get the permission scope from the permission message
// if the permission message is a revocation, the scope is fetched from the grant that is being revoked
let permissionScope!: PermissionScope;
if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.grantPath) {
const grant = await PermissionGrant.parse(recordsWriteMessage as DataEncodedRecordsWriteMessage);
permissionScope = grant.scope;
} else if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.requestPath) {
const request = await PermissionRequest.parse(recordsWriteMessage as DataEncodedRecordsWriteMessage);
permissionScope = request.scope;
}

if (PermissionsProtocol.hasProtocolScope(permissionScope) && permissionScope.protocol === incomingScope.protocol) {
// the permissions record scoped protocol matches the incoming scope protocol
return;
}
}
} else if (messageToGet.descriptor.interface === DwnInterfaceName.Protocols) {
// if the message is a protocol message, it must be a `ProtocolConfigure` message
const protocolsConfigureMessage = messageToGet as ProtocolsConfigureMessage;
const configureProtocol = protocolsConfigureMessage.descriptor.definition.protocol;
if (configureProtocol === incomingScope.protocol) {
// the configured protocol matches the incoming scope protocol
return;
}
}

throw new DwnError(DwnErrorCode.MessagesGetVerifyScopeFailed, 'record message failed scope authorization');
Expand Down
7 changes: 3 additions & 4 deletions src/handlers/messages-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ export class MessagesGetHandler implements MethodHandler {
return messageReplyFromError(error, 401);
}

// Include associated data as `encodedData` IF:
// * its a RecordsWrite
// * `encodedData` exists which means the data size is equal or smaller than the size threshold
// If the message is a RecordsWrite, we include the data in the response if it is available
const entry: MessagesGetReplyEntry = { message: messageResult, messageCid: message.descriptor.messageCid };
if (Records.isRecordsWrite(messageResult)) {
const recordsWrite = entry.message as RecordsQueryReplyEntry;
Expand All @@ -60,12 +58,13 @@ export class MessagesGetHandler implements MethodHandler {
entry.message.data = DataStream.fromBytes(dataBytes);
delete recordsWrite.encodedData;
} else {
// check the data store for the associated data
// otherwise check the data store for the associated data
const result = await this.dataStore.get(tenant, recordsWrite.recordId, recordsWrite.descriptor.dataCid);
if (result?.dataStream !== undefined) {
entry.message.data = result.dataStream;
} else {
// if there is no data, return with the data property undefined
// when records are deleted, their data is removed from the data store but the message remains in the message store
delete entry.message.data;
}
}
Expand Down
11 changes: 9 additions & 2 deletions src/protocols/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ export class PermissionsProtocol {
public static async createRevocation(options: PermissionRevocationCreateOptions): Promise<{
recordsWrite: RecordsWrite,
permissionRevocationData: PermissionRevocationData,
permissionRevocationBytes: Uint8Array
permissionRevocationBytes: Uint8Array,
dataEncodedMessage: DataEncodedRecordsWriteMessage,
}> {
const permissionRevocationData: PermissionRevocationData = {
description: options.description,
Expand Down Expand Up @@ -316,10 +317,16 @@ export class PermissionsProtocol {
tags : permissionTags,
});

const dataEncodedMessage: DataEncodedRecordsWriteMessage = {
...recordsWrite.message,
encodedData: Encoder.bytesToBase64Url(permissionRevocationBytes)
};

return {
recordsWrite,
permissionRevocationData,
permissionRevocationBytes
permissionRevocationBytes,
dataEncodedMessage
};
}

Expand Down
Loading

0 comments on commit a7e1e93

Please sign in to comment.