Skip to content

Commit

Permalink
RecordsGet to RecordsRead (#774)
Browse files Browse the repository at this point in the history
  • Loading branch information
LiranCohen authored Jun 27, 2024
1 parent 4e81d05 commit c6d8526
Show file tree
Hide file tree
Showing 18 changed files with 224 additions and 225 deletions.
4 changes: 2 additions & 2 deletions build/compile-validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import GeneralJws from '../json-schemas/general-jws.json' assert { type: 'json'
import GenericSignaturePayload from '../json-schemas/signature-payloads/generic-signature-payload.json' assert { type: 'json' };
import JwkVerificationMethod from '../json-schemas/jwk-verification-method.json' assert { type: 'json' };
import MessagesFilter from '../json-schemas/interface-methods/messages-filter.json' assert { type: 'json' };
import MessagesGet from '../json-schemas/interface-methods/messages-get.json' assert { type: 'json' };
import MessagesQuery from '../json-schemas/interface-methods/messages-query.json' assert { type: 'json' };
import MessagesRead from '../json-schemas/interface-methods/messages-read.json' assert { type: 'json' };
import MessagesSubscribe from '../json-schemas/interface-methods/messages-subscribe.json' assert { type: 'json' };
import NumberRangeFilter from '../json-schemas/interface-methods/number-range-filter.json' assert { type: 'json' };
import PaginationCursor from '../json-schemas/interface-methods/pagination-cursor.json' assert { type: 'json' };
Expand Down Expand Up @@ -67,8 +67,8 @@ const schemas = {
GeneralJws,
JwkVerificationMethod,
MessagesFilter,
MessagesGet,
MessagesQuery,
MessagesRead,
MessagesSubscribe,
NumberRangeFilter,
PaginationCursor,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://identity.foundation/dwn/json-schemas/messages-get.json",
"$id": "https://identity.foundation/dwn/json-schemas/messages-read.json",
"type": "object",
"additionalProperties": false,
"required": [
Expand Down Expand Up @@ -28,7 +28,7 @@
},
"method": {
"enum": [
"Get"
"Read"
],
"type": "string"
},
Expand Down
4 changes: 2 additions & 2 deletions json-schemas/permissions/permissions-definitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
"scope": {
"oneOf": [
{
"$ref": "https://identity.foundation/dwn/json-schemas/permissions/scopes.json#/$defs/messages-get-scope"
"$ref": "https://identity.foundation/dwn/json-schemas/permissions/scopes.json#/$defs/messages-query-scope"
},
{
"$ref": "https://identity.foundation/dwn/json-schemas/permissions/scopes.json#/$defs/messages-query-scope"
"$ref": "https://identity.foundation/dwn/json-schemas/permissions/scopes.json#/$defs/messages-read-scope"
},
{
"$ref": "https://identity.foundation/dwn/json-schemas/permissions/scopes.json#/$defs/messages-subscribe-scope"
Expand Down
12 changes: 6 additions & 6 deletions json-schemas/permissions/scopes.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
}
}
},
"messages-subscribe-scope": {
"messages-read-scope": {
"type": "object",
"additionalProperties": false,
"required" : [
"required": [
"interface",
"method"
],
Expand All @@ -34,17 +34,17 @@
"const": "Messages"
},
"method": {
"const": "Subscribe"
"const": "Read"
},
"protocol": {
"type": "string"
}
}
},
"messages-get-scope": {
"messages-subscribe-scope": {
"type": "object",
"additionalProperties": false,
"required": [
"required" : [
"interface",
"method"
],
Expand All @@ -53,7 +53,7 @@
"const": "Messages"
},
"method": {
"const": "Get"
"const": "Subscribe"
},
"protocol": {
"type": "string"
Expand Down
6 changes: 3 additions & 3 deletions src/core/dwn-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ export enum DwnErrorCode {
IndexInvalidSortPropertyInMemory = 'IndexInvalidSortPropertyInMemory',
IndexMissingIndexableProperty = 'IndexMissingIndexableProperty',
JwsDecodePlainObjectPayloadInvalid = 'JwsDecodePlainObjectPayloadInvalid',
MessagesGetInvalidCid = 'MessagesGetInvalidCid',
MessagesGetAuthorizationFailed = 'MessagesGetAuthorizationFailed',
MessagesGetVerifyScopeFailed = 'MessagesGetVerifyScopeFailed',
MessagesReadInvalidCid = 'MessagesReadInvalidCid',
MessagesReadAuthorizationFailed = 'MessagesReadAuthorizationFailed',
MessageGetInvalidCid = 'MessageGetInvalidCid',
MessagesQueryAuthorizationFailed = 'MessagesQueryAuthorizationFailed',
MessagesReadVerifyScopeFailed = 'MessagesReadVerifyScopeFailed',
ParseCidCodecNotSupported = 'ParseCidCodecNotSupported',
ParseCidMultihashNotSupported = 'ParseCidMultihashNotSupported',
PermissionsProtocolCreateGrantRecordsScopeMissingProtocol = 'PermissionsProtocolCreateGrantRecordsScopeMissingProtocol',
Expand Down
4 changes: 2 additions & 2 deletions src/core/message-reply.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { MessagesGetReplyEntry } from '../types/messages-types.js';
import type { MessagesReadReplyEntry } from '../types/messages-types.js';
import type { PaginationCursor } from '../types/query-types.js';
import type { ProtocolsConfigureMessage } from '../types/protocols-types.js';
import type { Readable } from 'readable-stream';
Expand All @@ -21,7 +21,7 @@ export type UnionMessageReply = GenericMessageReply & {
* e.g. the resulting messages from a RecordsQuery, or array of messageCid strings for MessagesQuery
* Mutually exclusive with `record`.
*/
entries?: QueryResultEntry[] | ProtocolsConfigureMessage[] | MessagesGetReplyEntry[] | string[];
entries?: QueryResultEntry[] | ProtocolsConfigureMessage[] | MessagesReadReplyEntry[] | string[];

/**
* Record corresponding to the message received if applicable (e.g. RecordsRead).
Expand Down
18 changes: 9 additions & 9 deletions src/core/messages-grant-authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { MessageStore } from '../types/message-store.js';
import type { PermissionGrant } from '../protocols/permission-grant.js';
import type { ProtocolsConfigureMessage } from '../types/protocols-types.js';
import type { DataEncodedRecordsWriteMessage, RecordsDeleteMessage, RecordsWriteMessage } from '../types/records-types.js';
import type { MessagesGetMessage, MessagesQueryMessage, MessagesSubscribeMessage } from '../types/messages-types.js';
import type { MessagesQueryMessage, MessagesReadMessage, MessagesSubscribeMessage } from '../types/messages-types.js';

import { DwnInterfaceName } from '../enums/dwn-interface-method.js';
import { GrantAuthorization } from './grant-authorization.js';
Expand All @@ -16,31 +16,31 @@ import { DwnError, DwnErrorCode } from './dwn-error.js';
export class MessagesGrantAuthorization {

/**
* Authorizes a MessagesGetMessage using the given permission grant.
* Authorizes a MessagesReadMessage using the given permission grant.
* @param messageStore Used to check if the given grant has been revoked; and to fetch related RecordsWrites if needed.
*/
public static async authorizeMessagesGet(input: {
messagesGetMessage: MessagesGetMessage,
messageToGet: GenericMessage,
public static async authorizeMessagesRead(input: {
messagesReadMessage: MessagesReadMessage,
messageToRead: GenericMessage,
expectedGrantor: string,
expectedGrantee: string,
permissionGrant: PermissionGrant,
messageStore: MessageStore,
}): Promise<void> {
const {
messagesGetMessage, messageToGet, expectedGrantor, expectedGrantee, permissionGrant, messageStore
messagesReadMessage, messageToRead, expectedGrantor, expectedGrantee, permissionGrant, messageStore
} = input;

await GrantAuthorization.performBaseValidation({
incomingMessage: messagesGetMessage,
incomingMessage: messagesReadMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});

const scope = permissionGrant.scope as MessagesPermissionScope;
await MessagesGrantAuthorization.verifyScope(expectedGrantor, messageToGet, scope, messageStore);
await MessagesGrantAuthorization.verifyScope(expectedGrantor, messageToRead, scope, messageStore);
}

/**
Expand Down Expand Up @@ -129,6 +129,6 @@ export class MessagesGrantAuthorization {
}
}

throw new DwnError(DwnErrorCode.MessagesGetVerifyScopeFailed, 'record message failed scope authorization');
throw new DwnError(DwnErrorCode.MessagesReadVerifyScopeFailed, 'record message failed scope authorization');
}
}
14 changes: 7 additions & 7 deletions src/dwn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import type { ResumableTaskStore } from './types/resumable-task-store.js';
import type { TenantGate } from './core/tenant-gate.js';
import type { UnionMessageReply } from './core/message-reply.js';
import type { GenericMessage, GenericMessageReply } from './types/message-types.js';
import type { MessagesGetMessage, MessagesGetReply, MessagesQueryMessage, MessagesQueryReply, MessagesSubscribeMessage, MessagesSubscribeMessageOptions, MessagesSubscribeReply, MessageSubscriptionHandler } from './types/messages-types.js';
import type { MessagesQueryMessage, MessagesQueryReply, MessagesReadMessage, MessagesReadReply, MessagesSubscribeMessage, MessagesSubscribeMessageOptions, MessagesSubscribeReply, MessageSubscriptionHandler } from './types/messages-types.js';
import type { ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply } from './types/protocols-types.js';
import type { RecordsDeleteMessage, RecordsQueryMessage, RecordsQueryReply, RecordsReadMessage, RecordsReadReply, RecordsSubscribeMessage, RecordsSubscribeMessageOptions, RecordsSubscribeReply, RecordSubscriptionHandler, RecordsWriteMessage, RecordsWriteMessageOptions } from './types/records-types.js';

import { AllowAllTenantGate } from './core/tenant-gate.js';
import { Message } from './core/message.js';
import { messageReplyFromError } from './core/message-reply.js';
import { MessagesGetHandler } from './handlers/messages-get.js';
import { MessagesQueryHandler } from './handlers/messages-query.js';
import { MessagesReadHandler } from './handlers/messages-read.js';
import { MessagesSubscribeHandler } from './handlers/messages-subscribe.js';
import { ProtocolsConfigureHandler } from './handlers/protocols-configure.js';
import { ProtocolsQueryHandler } from './handlers/protocols-query.js';
Expand Down Expand Up @@ -65,15 +65,15 @@ export class Dwn {
);

this.methodHandlers = {
[DwnInterfaceName.Messages + DwnMethodName.Get]: new MessagesGetHandler(
[DwnInterfaceName.Messages + DwnMethodName.Query]: new MessagesQueryHandler(
this.didResolver,
this.messageStore,
this.dataStore,
this.eventLog,
),
[DwnInterfaceName.Messages + DwnMethodName.Query]: new MessagesQueryHandler(
[DwnInterfaceName.Messages + DwnMethodName.Read]: new MessagesReadHandler(
this.didResolver,
this.messageStore,
this.eventLog,
this.dataStore,
),
[DwnInterfaceName.Messages + DwnMethodName.Subscribe]: new MessagesSubscribeHandler(
this.didResolver,
Expand Down Expand Up @@ -164,7 +164,7 @@ export class Dwn {
public async processMessage(tenant: string, rawMessage: MessagesQueryMessage): Promise<MessagesQueryReply>;
public async processMessage(
tenant: string, rawMessage: MessagesSubscribeMessage, options?: MessagesSubscribeMessageOptions): Promise<MessagesSubscribeReply>;
public async processMessage(tenant: string, rawMessage: MessagesGetMessage): Promise<MessagesGetReply>;
public async processMessage(tenant: string, rawMessage: MessagesReadMessage): Promise<MessagesReadReply>;
public async processMessage(tenant: string, rawMessage: ProtocolsConfigureMessage): Promise<GenericMessageReply>;
public async processMessage(tenant: string, rawMessage: ProtocolsQueryMessage): Promise<ProtocolsQueryReply>;
public async processMessage(tenant: string, rawMessage: RecordsDeleteMessage): Promise<GenericMessageReply>;
Expand Down
1 change: 0 additions & 1 deletion src/enums/dwn-interface-method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export enum DwnInterfaceName {

export enum DwnMethodName {
Configure = 'Configure',
Get = 'Get',
Query = 'Query',
Read = 'Read',
Write = 'Write',
Expand Down
40 changes: 20 additions & 20 deletions src/handlers/messages-get.ts → src/handlers/messages-read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ import type { GenericMessage } from '../types/message-types.js';
import type { MessageStore } from '../types/message-store.js';
import type { MethodHandler } from '../types/method-handler.js';
import type { RecordsQueryReplyEntry } from '../types/records-types.js';
import type { MessagesGetMessage, MessagesGetReply, MessagesGetReplyEntry } from '../types/messages-types.js';
import type { MessagesReadMessage, MessagesReadReply, MessagesReadReplyEntry } from '../types/messages-types.js';

import { authenticate } from '../core/auth.js';
import { DataStream } from '../utils/data-stream.js';
import { Encoder } from '../utils/encoder.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { MessagesGet } from '../interfaces/messages-get.js';
import { MessagesGrantAuthorization } from '../core/messages-grant-authorization.js';
import { MessagesRead } from '../interfaces/messages-read.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { Records } from '../utils/records.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';

type HandleArgs = { tenant: string, message: MessagesGetMessage };
type HandleArgs = { tenant: string, message: MessagesReadMessage };

export class MessagesGetHandler implements MethodHandler {
export class MessagesReadHandler implements MethodHandler {
constructor(private didResolver: DidResolver, private messageStore: MessageStore, private dataStore: DataStore) {}

public async handle({ tenant, message }: HandleArgs): Promise<MessagesGetReply> {
let messagesGet: MessagesGet;
public async handle({ tenant, message }: HandleArgs): Promise<MessagesReadReply> {
let messagesRead: MessagesRead;

try {
messagesGet = await MessagesGet.parse(message);
messagesRead = await MessagesRead.parse(message);
} catch (e) {
return messageReplyFromError(e, 400);
}
Expand All @@ -42,13 +42,13 @@ export class MessagesGetHandler implements MethodHandler {
}

try {
await MessagesGetHandler.authorizeMessagesGet(tenant, messagesGet, messageResult, this.messageStore);
await MessagesReadHandler.authorizeMessagesRead(tenant, messagesRead, messageResult, this.messageStore);
} catch (error) {
return messageReplyFromError(error, 401);
}

// 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 };
const entry: MessagesReadReplyEntry = { message: messageResult, messageCid: message.descriptor.messageCid };
if (Records.isRecordsWrite(messageResult)) {
const recordsWrite = entry.message as RecordsQueryReplyEntry;
// RecordsWrite specific handling, if MessageStore has embedded `encodedData` return it with the entry.
Expand All @@ -75,29 +75,29 @@ export class MessagesGetHandler implements MethodHandler {
/**
* @param messageStore Used to fetch related permission grant, permission revocation, and/or RecordsWrites for permission scope validation.
*/
private static async authorizeMessagesGet(
private static async authorizeMessagesRead(
tenant: string,
messagesGet: MessagesGet,
messagesRead: MessagesRead,
matchedMessage: GenericMessage,
messageStore: MessageStore
): Promise<void> {

if (messagesGet.author === tenant) {
if (messagesRead.author === tenant) {
// If the author is the tenant, no further authorization is needed
return;
} else if (messagesGet.author !== undefined && messagesGet.signaturePayload!.permissionGrantId !== undefined) {
} else if (messagesRead.author !== undefined && messagesRead.signaturePayload!.permissionGrantId !== undefined) {
// if the author is not the tenant and the message has a permissionGrantId, we need to authorize the grant
const permissionGrant = await PermissionsProtocol.fetchGrant(tenant, messageStore, messagesGet.signaturePayload!.permissionGrantId);
await MessagesGrantAuthorization.authorizeMessagesGet({
messagesGetMessage : messagesGet.message,
messageToGet : matchedMessage,
expectedGrantor : tenant,
expectedGrantee : messagesGet.author,
const permissionGrant = await PermissionsProtocol.fetchGrant(tenant, messageStore, messagesRead.signaturePayload!.permissionGrantId);
await MessagesGrantAuthorization.authorizeMessagesRead({
messagesReadMessage : messagesRead.message,
messageToRead : matchedMessage,
expectedGrantor : tenant,
expectedGrantee : messagesRead.author,
permissionGrant,
messageStore
});
} else {
throw new DwnError(DwnErrorCode.MessagesGetAuthorizationFailed, 'protocol message failed authorization');
throw new DwnError(DwnErrorCode.MessagesReadAuthorizationFailed, 'protocol message failed authorization');
}
}
}
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export type { DwnConfig } from './dwn.js';
export type { EventLog } from './types/event-log.js';
export type { EventListener, EventStream, EventSubscription, MessageEvent, SubscriptionReply } from './types/subscriptions.js';
export type { GenericMessage, GenericMessageReply, MessageSort, MessageSubscription, Pagination, QueryResultEntry } from './types/message-types.js';
export type { MessagesFilter, MessagesGetMessage, MessagesGetReply, MessagesGetReplyEntry, MessagesQueryMessage, MessagesQueryReply, MessagesSubscribeDescriptor, MessagesSubscribeMessage, MessagesSubscribeReply, MessageSubscriptionHandler } from './types/messages-types.js';
export type { MessagesFilter, MessagesReadMessage as MessagesReadMessage, MessagesReadReply as MessagesReadReply, MessagesReadReplyEntry as MessagesReadReplyEntry, MessagesQueryMessage, MessagesQueryReply, MessagesSubscribeDescriptor, MessagesSubscribeMessage, MessagesSubscribeReply, MessageSubscriptionHandler } from './types/messages-types.js';
export type { Filter, EqualFilter, OneOfFilter, RangeFilter, RangeCriterion, PaginationCursor, QueryOptions } from './types/query-types.js';
export type { ProtocolsConfigureDescriptor, ProtocolDefinition, ProtocolTypes, ProtocolRuleSet, ProtocolsQueryFilter, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply } from './types/protocols-types.js';
export type { EncryptionProperty, RecordsDeleteMessage, RecordsQueryMessage, RecordsQueryReply, RecordsQueryReplyEntry, RecordsReadMessage, RecordsReadReply, RecordsSubscribeDescriptor, RecordsSubscribeMessage, RecordsSubscribeReply, RecordSubscriptionHandler, RecordsWriteDescriptor, RecordsWriteTags, RecordsWriteTagValue, RecordsWriteMessage } from './types/records-types.js';
Expand All @@ -28,7 +28,7 @@ export { executeUnlessAborted } from './utils/abort.js';
export { Jws } from './utils/jws.js';
export { KeyMaterial, PrivateJwk, PublicJwk } from './types/jose-types.js';
export { Message } from './core/message.js';
export { MessagesGet, MessagesGetOptions } from './interfaces/messages-get.js';
export { MessagesRead as MessagesRead, MessagesReadOptions as MessagesReadOptions } from './interfaces/messages-read.js';
export { MessagesQuery, MessagesQueryOptions } from './interfaces/messages-query.js';
export { UnionMessageReply } from './core/message-reply.js';
export { MessageStore, MessageStoreOptions } from './types/message-store.js';
Expand Down
Loading

0 comments on commit c6d8526

Please sign in to comment.