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

RecordsGet to RecordsRead #774

Merged
merged 2 commits into from
Jun 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
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