Skip to content

Commit

Permalink
EventsGet (#305)
Browse files Browse the repository at this point in the history
Implement `EventsGet` interface
  • Loading branch information
mistermoe authored Apr 15, 2023
1 parent c6733d6 commit 149c713
Show file tree
Hide file tree
Showing 16 changed files with 417 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Decentralized Web Node (DWN) SDK

Code Coverage
![Statements](https://img.shields.io/badge/statements-93.62%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-93.2%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-91.24%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-93.62%25-brightgreen.svg?style=flat)
![Statements](https://img.shields.io/badge/statements-93.69%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-93.17%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-91.36%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-93.69%25-brightgreen.svg?style=flat)

## Introduction

Expand Down
2 changes: 2 additions & 0 deletions build/compile-validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import mkdirp from 'mkdirp';
import standaloneCode from 'ajv/dist/standalone/index.js';

import Definitions from '../json-schemas/definitions.json' assert { type: 'json' };
import EventsGet from '../json-schemas/events/events-get.json' assert { type: 'json' };
import GeneralJwk from '../json-schemas/jwk/general-jwk.json' assert { type: 'json' };
import GeneralJws from '../json-schemas/general-jws.json' assert { type: 'json' };
import HooksWrite from '../json-schemas/hooks/hooks-write.json' assert { type: 'json' };
Expand All @@ -39,6 +40,7 @@ const schemas = {
RecordsDelete,
RecordsQuery,
RecordsWrite,
EventsGet,
Definitions,
GeneralJwk,
GeneralJws,
Expand Down
40 changes: 40 additions & 0 deletions json-schemas/events/events-get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://identity.foundation/dwn/json-schemas/events-get.json",
"type": "object",
"additionalProperties": false,
"required": [
"authorization",
"descriptor"
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
},
"descriptor": {
"type": "object",
"additionalProperties": false,
"required": [
"interface",
"method"
],
"properties": {
"interface": {
"enum": [
"Events"
],
"type": "string"
},
"method": {
"enum": [
"Get"
],
"type": "string"
},
"watermark": {
"type": "string"
}
}
}
}
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tbd54566975/dwn-sdk-js",
"version": "0.0.29",
"version": "0.0.30",
"description": "A reference implementation of https://identity.foundation/decentralized-web-node/spec/",
"type": "module",
"types": "./dist/esm/src/index.d.ts",
Expand Down Expand Up @@ -142,4 +142,4 @@
"url": "https://github.com/TBD54566975/dwn-sdk-js/issues"
},
"homepage": "https://github.com/TBD54566975/dwn-sdk-js#readme"
}
}
2 changes: 1 addition & 1 deletion src/core/message-reply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class MessageReply {
status: Status;

/**
* Resulting message entries returned from the invocation of the corresponding message.
* Resulting message entries or events returned from the invocation of the corresponding message.
* e.g. the resulting messages from a RecordsQuery
* Mutually exclusive with `data`.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/core/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { lexicographicalCompare } from '../utils/string.js';
import { validateJsonSchema } from '../schema-validator.js';

export enum DwnInterfaceName {
Events = 'Events',
Hooks = 'Hooks',
Permissions = 'Permissions',
Protocols = 'Protocols',
Expand All @@ -17,6 +18,7 @@ export enum DwnInterfaceName {

export enum DwnMethodName {
Configure = 'Configure',
Get = 'Get',
Grant = 'Grant',
Query = 'Query',
Read = 'Read',
Expand Down
2 changes: 2 additions & 0 deletions src/dwn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { AllowAllTenantGate } from './core/tenant-gate.js';
import { DataStoreLevel } from './store/data-store-level.js';
import { DidResolver } from './did/did-resolver.js';
import { EventLogLevel } from './event-log/event-log-level.js';
import { EventsGetHandler } from './interfaces/events/handlers/events-get.js';
import { MessageReply } from './core/message-reply.js';
import { MessageStoreLevel } from './store/message-store-level.js';
import { PermissionsRequestHandler } from './interfaces/permissions/handlers/permissions-request.js';
Expand Down Expand Up @@ -38,6 +39,7 @@ export class Dwn {
this.tenantGate = config.tenantGate!;

this.methodHandlers = {
[DwnInterfaceName.Events + DwnMethodName.Get] : new EventsGetHandler(this.didResolver, this.eventLog),
[DwnInterfaceName.Permissions + DwnMethodName.Request] : new PermissionsRequestHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Protocols + DwnMethodName.Configure] : new ProtocolsConfigureHandler(
this.didResolver, this.messageStore, this.dataStore, this.eventLog),
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// export everything that we want to be consumable
export type { DwnConfig } from './dwn.js';
export type { DwnServiceEndpoint, ServiceEndpoint, DidDocument, DidResolutionResult, DidResolutionMetadata, DidDocumentMetadata, VerificationMethod } from './did/did-resolver.js';
export type { EventLog, Event } from './event-log/event-log.js';
export type { EventsGetMessage, EventsGetReply } from './interfaces/events/types.js';
export type { HooksWriteMessage } from './interfaces/hooks/types.js';
export type { ProtocolDefinition, ProtocolRuleSet, ProtocolsConfigureMessage, ProtocolsQueryMessage } from './interfaces/protocols/types.js';
export type { RecordsDeleteMessage, RecordsQueryMessage, RecordsWriteMessage } from './interfaces/records/types.js';
Expand All @@ -22,6 +24,8 @@ export { DwnConstant } from './core/dwn-constant.js';
export { DwnError, DwnErrorCode } from './core/dwn-error.js';
export { DwnInterfaceName, DwnMethodName } from './core/message.js';
export { Encoder } from './utils/encoder.js';
export { EventLogLevel } from './event-log/event-log-level.js';
export { EventsGet, EventsGetOptions } from './interfaces/events/messages/events-get.js';
export { Encryption, EncryptionAlgorithm } from './utils/encryption.js';
export { EncryptionInput, KeyEncryptionInput, RecordsWrite, RecordsWriteOptions, CreateFromOptions } from './interfaces/records/messages/records-write.js';
export { HooksWrite, HooksWriteOptions } from './interfaces/hooks/messages/hooks-write.js';
Expand Down
46 changes: 46 additions & 0 deletions src/interfaces/events/handlers/events-get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { DidResolver } from '../../../index.js';
import type { EventLog } from '../../../event-log/event-log.js';
import type { GetEventsOptions } from '../../../event-log/event-log.js';
import type { MethodHandler } from '../../types.js';
import type { EventsGetMessage, EventsGetReply } from '../types.js';

import { EventsGet } from '../messages/events-get.js';
import { MessageReply } from '../../../core/message-reply.js';
import { authenticate, authorize } from '../../../core/auth.js';

type HandleArgs = {tenant: string, message: EventsGetMessage};

export class EventsGetHandler implements MethodHandler {
constructor(private didResolver: DidResolver, private eventLog: EventLog) {}

public async handle({ tenant, message }: HandleArgs): Promise<EventsGetReply> {
let eventsGet: EventsGet;

try {
eventsGet = await EventsGet.parse(message);
} catch (e) {
return MessageReply.fromError(e, 400);
}

try {
await authenticate(message.authorization, this.didResolver);
await authorize(tenant, eventsGet);
} catch (e) {
return MessageReply.fromError(e, 401);
}

// if watermark was provided in message, get all events _after_ the watermark.
// Otherwise, get all events.
let options: GetEventsOptions | undefined;
if (message.descriptor.watermark) {
options = { gt: message.descriptor.watermark };
}

const events = await this.eventLog.getEvents(tenant, options);

return {
status: { code: 200, detail: 'OK' },
events
};
}
}
38 changes: 38 additions & 0 deletions src/interfaces/events/messages/events-get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { SignatureInput } from '../../../jose/jws/general/types.js';
import type { EventsGetDescriptor, EventsGetMessage } from '../types.js';

import { validateAuthorizationIntegrity } from '../../../core/auth.js';
import { DwnInterfaceName, DwnMethodName, Message } from '../../../core/message.js';

export type EventsGetOptions = {
watermark?: string;
authorizationSignatureInput: SignatureInput;
};

export class EventsGet extends Message<EventsGetMessage> {

public static async parse(message: EventsGetMessage): Promise<EventsGet> {
Message.validateJsonSchema(message);
await validateAuthorizationIntegrity(message);

return new EventsGet(message);
}

public static async create(options: EventsGetOptions): Promise<EventsGet> {
const descriptor: EventsGetDescriptor = {
interface : DwnInterfaceName.Events,
method : DwnMethodName.Get,
};

if (options.watermark) {
descriptor.watermark = options.watermark;
}

const authorization = await Message.signAsAuthorization(descriptor, options.authorizationSignatureInput);
const message = { descriptor, authorization };

Message.validateJsonSchema(message);

return new EventsGet(message);
}
}
18 changes: 18 additions & 0 deletions src/interfaces/events/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { BaseMessage } from '../../core/types.js';
import type { BaseMessageReply } from '../../core/message-reply.js';
import type { Event } from '../../event-log/event-log.js';
import type { DwnInterfaceName, DwnMethodName } from '../../core/message.js';

export type EventsGetDescriptor = {
interface : DwnInterfaceName.Events;
method: DwnMethodName.Get;
watermark?: string;
};

export type EventsGetMessage = BaseMessage & {
descriptor: EventsGetDescriptor;
};

export type EventsGetReply = BaseMessageReply & {
events?: Event[];
};
13 changes: 12 additions & 1 deletion tests/dwn.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TenantGate } from '../src/index.js';
import type { EventsGetReply, TenantGate } from '../src/index.js';

import chaiAsPromised from 'chai-as-promised';
import sinon from 'sinon';
Expand Down Expand Up @@ -86,6 +86,17 @@ describe('DWN', () => {
expect(reply.entries).to.be.empty;
});

it('should process an EventsGet message', async () => {
const alice = await DidKeyResolver.generate();
const { message } = await TestDataGenerator.generateEventsGet({ requester: alice });

const reply: EventsGetReply = await dwn.processMessage(alice.did, message);

expect(reply.status.code).to.equal(200);
expect(reply.events).to.be.empty;
expect(reply['data']).to.not.exist;
});

it('#191 - regression - should run JSON schema validation', async () => {
const invalidMessage = {
descriptor: {
Expand Down
Loading

0 comments on commit 149c713

Please sign in to comment.