Skip to content

Commit

Permalink
linted
Browse files Browse the repository at this point in the history
  • Loading branch information
andorsk committed Sep 27, 2023
1 parent b9be98e commit 12601c3
Show file tree
Hide file tree
Showing 15 changed files with 808 additions and 831 deletions.
265 changes: 132 additions & 133 deletions src/core/subscriptions-grant-authorization.ts
Original file line number Diff line number Diff line change
@@ -1,154 +1,153 @@
import type { MessageStore } from '../types/message-store.js';
import { SubscriptionRequest } from "../interfaces/subscription-request.js";
import type { EventMessage } from '../interfaces/event-create.js';

Check failure on line 1 in src/core/subscriptions-grant-authorization.ts

View workflow job for this annotation

GitHub Actions / build (18.16.0)

Cannot find module '../interfaces/event-create.js' or its corresponding type declarations.

Check failure on line 1 in src/core/subscriptions-grant-authorization.ts

View workflow job for this annotation

GitHub Actions / build (20.3.0)

Cannot find module '../interfaces/event-create.js' or its corresponding type declarations.
import { GrantAuthorization } from './grant-authorization.js';
import { EventStreamI } from '../event-log/event-stream.js';
import type { PermissionsGrantMessage, SubscriptionPermissionScope } from '../types/permissions-types.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
import { EventMessageI } from '../types/event-types.js';
import { Message } from './message.js';
import { EventMessage } from '../interfaces/event-create.js';
import type { MessageStore } from '../types/message-store.js';
import type { SubscriptionRequest } from '../interfaces/subscription-request.js';

import { DwnError, DwnErrorCode } from './dwn-error.js';
import type { PermissionsGrantMessage, SubscriptionPermissionScope } from '../types/permissions-types.js';

export class SubscriptionsGrantAuthorization {

/**
* Authorizes the scope of a PermissionsGrant for Subscription.
* For initial connection setup.
*/
public static async authorizeSubscribe(
tenant: string,
incomingMessage: SubscriptionRequest,
author: string,
messageStore: MessageStore,
): Promise<void> {
const permissionsGrantMessage = await GrantAuthorization.authorizeGenericMessage(tenant, incomingMessage, author, messageStore);
SubscriptionsGrantAuthorization.verifyScope(incomingMessage, permissionsGrantMessage);
}
/**
* Authorizes the scope of a PermissionsGrant for Subscription.
* For initial connection setup.
*/
public static async authorizeSubscribe(
tenant: string,
incomingMessage: SubscriptionRequest,
author: string,
messageStore: MessageStore,
): Promise<void> {
const permissionsGrantMessage = await GrantAuthorization.authorizeGenericMessage(tenant, incomingMessage, author, messageStore);
SubscriptionsGrantAuthorization.verifyScope(incomingMessage, permissionsGrantMessage);
}

/**
* Authorizes the scope of a PermissionsGrant for Subscription.
* For initial connection setup.
*/
public static async authorizeEvent(
tenant: string,
incomingMessage: SubscriptionRequest,
event: EventMessage,
messageStore: MessageStore,
author: string,
): Promise<void> {
// 1. Get Grant from initial Subscription Request. Check if it's still valid.
// Problem : Needs to check NEW message time.
incomingMessage.message.descriptor.messageTimestamp = event.message.descriptor.messageTimestamp; // HACK!
const permissionsGrantMessage = await GrantAuthorization.authorizeGenericMessage(tenant, incomingMessage, author, messageStore);
// 2. Check When Grant Was Valid
// 3. Check Event is Valid within Grant.
// 4. Verify Scope
SubscriptionsGrantAuthorization.verifyScope(incomingMessage, permissionsGrantMessage);
}
/**
* Authorizes the scope of a PermissionsGrant for Subscription.
* For initial connection setup.
*
* TODO: @andorsk Improve/Update this and remove hack.
*/
public static async authorizeEvent(
tenant: string,
incomingMessage: SubscriptionRequest,
event: EventMessage,
messageStore: MessageStore,
author: string,
): Promise<void> {
// 1. Get Grant from initial Subscription Request. Check if it's still valid.
// Problem : Needs to check NEW message time.
incomingMessage.message.descriptor.messageTimestamp = event.message.descriptor.messageTimestamp; // HACK!
const permissionsGrantMessage = await GrantAuthorization.authorizeGenericMessage(tenant, incomingMessage, author, messageStore);
// 2. Check When Grant Was Valid
// 3. Check Event is Valid within Grant.
// 4. Verify Scope
SubscriptionsGrantAuthorization.verifyScope(incomingMessage, permissionsGrantMessage);
}

/**
* @param subscriptionRequest The source of the record being authorized.
*/
private static verifyEventScope(
subscriptionRequest: SubscriptionRequest,
event: EventMessage,
permissionsGrantMessage: PermissionsGrantMessage,
): void {
const grantScope = permissionsGrantMessage.descriptor.scope as SubscriptionPermissionScope;
if (SubscriptionsGrantAuthorization.isUnrestrictedScope(grantScope)) {
// scope has no restrictions beyond interface and method. Message is authorized to access any record.
return;
} else if (subscriptionRequest.message.descriptor.scope.protocol !== undefined) {
// authorization of protocol records must have grants that explicitly include the protocol
SubscriptionsGrantAuthorization.authorizeProtocolRecord(subscriptionRequest, grantScope);
} else {
SubscriptionsGrantAuthorization.authorizeFlatRecord(subscriptionRequest, grantScope);
}
/**
* @param subscriptionRequest The source of the record being authorized.
*/
private static verifyEventScope(
subscriptionRequest: SubscriptionRequest,
event: EventMessage,
permissionsGrantMessage: PermissionsGrantMessage,
): void {
const grantScope = permissionsGrantMessage.descriptor.scope as SubscriptionPermissionScope;
if (SubscriptionsGrantAuthorization.isUnrestrictedScope(grantScope)) {
// scope has no restrictions beyond interface and method. Message is authorized to access any record.
return;
} else if (subscriptionRequest.message.descriptor.scope.protocol !== undefined) {
// authorization of protocol records must have grants that explicitly include the protocol
SubscriptionsGrantAuthorization.authorizeProtocolRecord(subscriptionRequest, grantScope);
} else {
SubscriptionsGrantAuthorization.authorizeFlatRecord(subscriptionRequest, grantScope);
}
}

/**
* @param subscriptionRequest The source of the record being authorized.
*/
private static verifyScope(
subscriptionRequest: SubscriptionRequest,
permissionsGrantMessage: PermissionsGrantMessage,
): void {
const grantScope = permissionsGrantMessage.descriptor.scope as SubscriptionPermissionScope;
if (SubscriptionsGrantAuthorization.isUnrestrictedScope(grantScope)) {
// scope has no restrictions beyond interface and method. Message is authorized to access any record.
return;
} else if (subscriptionRequest.message.descriptor.scope.protocol !== undefined) {
// authorization of protocol records must have grants that explicitly include the protocol
SubscriptionsGrantAuthorization.authorizeProtocolRecord(subscriptionRequest, grantScope);
} else {
SubscriptionsGrantAuthorization.authorizeFlatRecord(subscriptionRequest, grantScope);
}
/**
* @param subscriptionRequest The source of the record being authorized.
*/
private static verifyScope(
subscriptionRequest: SubscriptionRequest,
permissionsGrantMessage: PermissionsGrantMessage,
): void {
const grantScope = permissionsGrantMessage.descriptor.scope as SubscriptionPermissionScope;
if (SubscriptionsGrantAuthorization.isUnrestrictedScope(grantScope)) {
// scope has no restrictions beyond interface and method. Message is authorized to access any record.
return;
} else if (subscriptionRequest.message.descriptor.scope.protocol !== undefined) {
// authorization of protocol records must have grants that explicitly include the protocol
SubscriptionsGrantAuthorization.authorizeProtocolRecord(subscriptionRequest, grantScope);
} else {
SubscriptionsGrantAuthorization.authorizeFlatRecord(subscriptionRequest, grantScope);
}
}

/**
* Checks if scope has no restrictions beyond interface and method.
* Grant-holder is authorized to access any record.
*/
private static isUnrestrictedScope(grantScope: SubscriptionPermissionScope): boolean {
return grantScope.protocol === undefined &&
/**
* Checks if scope has no restrictions beyond interface and method.
* Grant-holder is authorized to access any record.
*/
private static isUnrestrictedScope(grantScope: SubscriptionPermissionScope): boolean {
return grantScope.protocol === undefined &&
grantScope.schema === undefined &&
grantScope.eventType == undefined;
}
}

/**
* Authorizes a grant scope for a protocol record
*/
private static authorizeProtocolRecord(
subscriptionRequest: SubscriptionRequest,
grantScope: SubscriptionPermissionScope
): void {
// Protocol records must have grants specifying the protocol
if (grantScope.protocol === undefined) {
throw new DwnError(
DwnErrorCode.SubscriptionsGrantAuthorizationScopeNotProtocol,
'Grant for protocol subscription must specify protocol in its scope'
);
}
/**
* Authorizes a grant scope for a protocol record
*/
private static authorizeProtocolRecord(
subscriptionRequest: SubscriptionRequest,
grantScope: SubscriptionPermissionScope
): void {
// Protocol records must have grants specifying the protocol
if (grantScope.protocol === undefined) {
throw new DwnError(
DwnErrorCode.SubscriptionsGrantAuthorizationScopeNotProtocol,
'Grant for protocol subscription must specify protocol in its scope'
);
}

// The record's protocol must match the protocol specified in the record
if (grantScope.protocol !== subscriptionRequest.message.descriptor.scope.protocol) {
throw new DwnError(
DwnErrorCode.SubscriptionsGrantAuthorizationScopeProtocolMismatch,
`Grant scope specifies different protocol than what appears in the subscription`
);
}
// The record's protocol must match the protocol specified in the record
if (grantScope.protocol !== subscriptionRequest.message.descriptor.scope.protocol) {
throw new DwnError(
DwnErrorCode.SubscriptionsGrantAuthorizationScopeProtocolMismatch,
`Grant scope specifies different protocol than what appears in the subscription`
);
}

// If grant specifies either contextId, check that record is that context
if (grantScope.contextId !== undefined && grantScope.contextId !== subscriptionRequest.message.descriptor.scope.contextId) {
throw new DwnError(
DwnErrorCode.SubscriptionsGrantAuthorizationScopeContextIdMismatch,
`Grant scope specifies different contextId than what appears in the subscription`
);
}
// If grant specifies either contextId, check that record is that context
if (grantScope.contextId !== undefined && grantScope.contextId !== subscriptionRequest.message.descriptor.scope.contextId) {
throw new DwnError(
DwnErrorCode.SubscriptionsGrantAuthorizationScopeContextIdMismatch,
`Grant scope specifies different contextId than what appears in the subscription`
);
}

// If grant specifies protocolPath, check that record is at that protocolPath
if (grantScope.protocolPath !== undefined && grantScope.protocolPath !== subscriptionRequest.message.descriptor.scope.protocolPath) {
throw new DwnError(
DwnErrorCode.SubscriptionsGrantAuthorizationScopeProtocolPathMismatch,
`Grant scope specifies different protocolPath than what appears in the subscription`
);
}
// If grant specifies protocolPath, check that record is at that protocolPath
if (grantScope.protocolPath !== undefined && grantScope.protocolPath !== subscriptionRequest.message.descriptor.scope.protocolPath) {
throw new DwnError(
DwnErrorCode.SubscriptionsGrantAuthorizationScopeProtocolPathMismatch,
`Grant scope specifies different protocolPath than what appears in the subscription`
);
}
}

/**
* Authorizes a grant scope for a non-protocol record
*/
private static authorizeFlatRecord(
subscriptionRequest: SubscriptionRequest,
grantScope: SubscriptionPermissionScope
): void {
if (grantScope.schema !== undefined) {
if (grantScope.schema !== subscriptionRequest.message.descriptor.scope.schema) {
throw new DwnError(
DwnErrorCode.RecordsGrantAuthorizationScopeSchema,
`Record does not have schema in PermissionsGrant scope with schema '${grantScope.schema}'`
);
}
}
/**
* Authorizes a grant scope for a non-protocol record
*/
private static authorizeFlatRecord(
subscriptionRequest: SubscriptionRequest,
grantScope: SubscriptionPermissionScope
): void {
if (grantScope.schema !== undefined) {
if (grantScope.schema !== subscriptionRequest.message.descriptor.scope.schema) {
throw new DwnError(
DwnErrorCode.RecordsGrantAuthorizationScopeSchema,
`Record does not have schema in PermissionsGrant scope with schema '${grantScope.schema}'`
);
}
}
}
}
57 changes: 26 additions & 31 deletions src/dwn.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,34 @@
import type { DataStore } from './types/data-store.js';
import type { EventLog } from './types/event-log.js';
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 { Readable } from 'readable-stream';
import type { RecordsWriteHandlerOptions } from './handlers/records-write.js';
import type { TenantGate } from './core/tenant-gate.js';
import type { GenericMessageReply, UnionMessageReply } from './core/message-reply.js';
import type { MessagesGetMessage, MessagesGetReply } from './types/messages-types.js';
import type { RecordsQueryMessage, RecordsQueryReply, RecordsReadMessage, RecordsReadReply, RecordsWriteMessage } from './types/records-types.js';
import type { EventStreamI } from './event-log/event-stream.js';

import { AllowAllTenantGate } from './core/tenant-gate.js';
import type { DataStore } from './types/data-store.js';
import { DidResolver } from './did/did-resolver.js';
import type { EventLog } from './types/event-log.js';
import { EventMessage } from './interfaces/event-create.js';

Check failure on line 5 in src/dwn.ts

View workflow job for this annotation

GitHub Actions / build (18.16.0)

Cannot find module './interfaces/event-create.js' or its corresponding type declarations.

Check failure on line 5 in src/dwn.ts

View workflow job for this annotation

GitHub Actions / build (20.3.0)

Cannot find module './interfaces/event-create.js' or its corresponding type declarations.
import { EventsGetHandler } from './handlers/events-get.js';
import type { GenericMessage } from './types/message-types.js';
import { messageReplyFromError } from './core/message-reply.js';
import { MessagesGetHandler } from './handlers/messages-get.js';
import type { MessageStore } from './types/message-store.js';
import type { MethodHandler } from './types/method-handler.js';
import { PermissionsGrantHandler } from './handlers/permissions-grant.js';
import { PermissionsRequestHandler } from './handlers/permissions-request.js';
import { PermissionsRevokeHandler } from './handlers/permissions-revoke.js';
import { ProtocolsConfigureHandler } from './handlers/protocols-configure.js';
import { ProtocolsQueryHandler } from './handlers/protocols-query.js';
import type { Readable } from 'readable-stream';
import { RecordsDeleteHandler } from './handlers/records-delete.js';
import { RecordsQueryHandler } from './handlers/records-query.js';
import { RecordsReadHandler } from './handlers/records-read.js';
import { RecordsWriteHandler } from './handlers/records-write.js';
import type { RecordsWriteHandlerOptions } from './handlers/records-write.js';
import { SubscriptionsRequestHandler } from './handlers/subscriptions-request.js';
import type { TenantGate } from './core/tenant-gate.js';

import { DwnInterfaceName, DwnMethodName, Message } from './core/message.js';
import { EventStream } from './event-log/event-stream.js';
import { EventEmitter } from 'events';
import { SubscriptionRequest } from './interfaces/subscription-request.js';
import { EventMessage } from './interfaces/event-create.js';

import { SubscriptionRequestMessage, SubscriptionRequestReply } from './types/subscriptions-request.js';
import { EventType } from './types/event-types.js';
import type { EventStream, EventStreamI } from './event-log/event-stream.js';
import type { GenericMessageReply, UnionMessageReply } from './core/message-reply.js';
import type { MessagesGetMessage, MessagesGetReply } from './types/messages-types.js';
import type { RecordsQueryMessage, RecordsQueryReply, RecordsReadMessage, RecordsReadReply, RecordsWriteMessage } from './types/records-types.js';
import type { SubscriptionRequestMessage, SubscriptionRequestReply } from './types/subscriptions-request.js';

export class Dwn {
private methodHandlers: { [key:string]: MethodHandler };
Expand Down Expand Up @@ -74,7 +68,8 @@ export class Dwn {

// only add subscriptions if event stream is enabled.
if (this.eventStream !== undefined) {
this.methodHandlers[DwnInterfaceName.Subscriptions + DwnMethodName.Request] = new SubscriptionsRequestHandler(this.didResolver, this.messageStore, this.dataStore, this.eventStream)
this.methodHandlers[DwnInterfaceName.Subscriptions + DwnMethodName.Request] = new SubscriptionsRequestHandler(
this.didResolver,this.messageStore, this.dataStore, this.eventStream);
}
}

Expand Down Expand Up @@ -130,7 +125,7 @@ export class Dwn {
descriptor: {
...rawMessage.descriptor,
},
})
});

if (this.eventStream){
this.eventStream.add(eventMessage);
Expand All @@ -139,20 +134,20 @@ export class Dwn {
return methodHandlerReply;
}

/**
/**
* Handles a `RecordsRead` message.
*/
public async handleSubscriptionRequest(tenant: string, message: SubscriptionRequestMessage): Promise<SubscriptionRequestReply> {
const errorMessageReply =
public async handleSubscriptionRequest(tenant: string, message: SubscriptionRequestMessage): Promise<SubscriptionRequestReply> {
const errorMessageReply =
await this.validateTenant(tenant) ??
await this.validateMessageIntegrity(message, DwnInterfaceName.Subscriptions, DwnMethodName.Request);
if (errorMessageReply !== undefined) {
return errorMessageReply;
}
const handler = new SubscriptionsRequestHandler(this.didResolver, this.messageStore, this.dataStore, this.eventStream as EventStream);
return handler.handle({ tenant, message });
if (errorMessageReply !== undefined) {
return errorMessageReply;
}

const handler = new SubscriptionsRequestHandler(this.didResolver, this.messageStore, this.dataStore, this.eventStream as EventStream);
return handler.handle({ tenant, message });
}

/**
* Handles a `RecordsQuery` message.
*/
Expand Down
Loading

0 comments on commit 12601c3

Please sign in to comment.