Skip to content

Commit

Permalink
#276 - added encryption support to RecordsWrite
Browse files Browse the repository at this point in the history
  • Loading branch information
thehenrytsai authored Apr 12, 2023
1 parent 5e6aa96 commit e760006
Show file tree
Hide file tree
Showing 20 changed files with 726 additions and 101 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.93%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-92.64%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-91.47%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-93.93%25-brightgreen.svg?style=flat)
![Statements](https://img.shields.io/badge/statements-93.56%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-93.09%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.56%25-brightgreen.svg?style=flat)

## Introduction

Expand Down
2 changes: 1 addition & 1 deletion json-schemas/records/records-write.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"derivationScheme": {
"type": "string",
"enum": [
"protocol"
"protocol-context"
]
},
"algorithm": {
Expand Down
10 changes: 8 additions & 2 deletions src/core/dwn-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ export enum DwnErrorCode {
AuthorizationMissing = 'AuthorizationMissing',
AuthorizationUnknownAuthor = 'AuthorizationUnknownAuthor',
HdKeyDerivationPathInvalid = 'HdKeyDerivationPathInvalid',
RecordsWriteGetEntryIdUndefinedAuthor = 'RecordsWriteGetEntryIdUndefinedAuthor',
MessageStoreDataCidMismatch = 'MessageStoreDataCidMismatch',
MessageStoreDataNotFound = 'MessageStoreDataNotFound',
MessageStoreDataSizeMismatch = 'MessageStoreDataSizeMismatch'
MessageStoreDataSizeMismatch = 'MessageStoreDataSizeMismatch',
RecordsDecryptNoMatchingKeyDerivationScheme = 'RecordsDecryptNoMatchingKeyDerivationScheme',
RecordsDeriveLeafPrivateKeyUnSupportedCurve = 'RecordsDeriveLeafPrivateKeyUnSupportedCurve',
RecordsDeriveLeafPublicKeyUnSupportedCurve = 'RecordsDeriveLeafPublicKeyUnSupportedCurve',
RecordsInvalidAncestorKeyDerivationSegment = 'RecordsInvalidAncestorKeyDerivationSegment',
RecordsWriteGetEntryIdUndefinedAuthor = 'RecordsWriteGetEntryIdUndefinedAuthor',
RecordsWriteValidateIntegrityEncryptionCidMismatch = 'RecordsWriteValidateIntegrityEncryptionCidMismatch',
Secp256k1KeyNotValid = 'Secp256k1KeyNotValid'
};
16 changes: 6 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
/* eslint-disable max-len */

/**
* exports everything that we want to be consumable
*/

// yep, it's weird that we're exporting '.js' files when they're really
// '.ts' files. Long story. If you're interested as to why, check out:
// - https://stackoverflow.com/questions/44979976/typescript-compiler-is-forgetting-to-add-file-extensions-to-es6-module-imports
// - https://github.com/microsoft/TypeScript/issues/40878
//
// 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 { HooksWriteMessage } from './interfaces/hooks/types.js';
Expand All @@ -20,14 +13,17 @@ export { DataStore } from './store/data-store.js';
export { DataStoreLevel } from './store/data-store-level.js';
export { DateSort } from './interfaces/records/messages/records-query.js';
export { DataStream } from './utils/data-stream.js';
export { DerivedPrivateJwk, DerivedPublicJwk, HdKey, KeyDerivationScheme } from './utils/hd-key.js';
export { DidKeyResolver } from './did/did-key-resolver.js';
export { DidIonResolver } from './did/did-ion-resolver.js';
export { DidResolver, DidMethodResolver } from './did/did-resolver.js';
export { Dwn } from './dwn.js';
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 { Encryption } from './utils/encryption.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';
export { Jws } from './utils/jws.js';
export { KeyMaterial, PrivateJwk, PublicJwk } from './jose/types.js';
Expand All @@ -36,9 +32,9 @@ export { MessageStore } from './store/message-store.js';
export { MessageStoreLevel } from './store/message-store-level.js';
export { ProtocolsConfigure, ProtocolsConfigureOptions } from './interfaces/protocols/messages/protocols-configure.js';
export { ProtocolsQuery, ProtocolsQueryOptions } from './interfaces/protocols/messages/protocols-query.js';
export { Records } from './utils/records.js';
export { RecordsDelete, RecordsDeleteOptions } from './interfaces/records/messages/records-delete.js';
export { RecordsQuery, RecordsQueryOptions } from './interfaces/records/messages/records-query.js';
export { RecordsRead, RecordsReadOptions } from './interfaces/records/messages/records-read.js';
export { RecordsWrite, RecordsWriteOptions, CreateFromOptions } from './interfaces/records/messages/records-write.js';
export { Secp256k1 } from './utils/secp256k1.js';
export { SignatureInput } from './jose/jws/general/types.js';
6 changes: 3 additions & 3 deletions src/interfaces/protocols/handlers/protocols-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ export class ProtocolsQueryHandler implements MethodHandler {
};
removeUndefinedProperties(query);

const records = await this.messageStore.query(tenant, query);
const messages = await this.messageStore.query(tenant, query);

// strip away `authorization` property for each record before responding
const entries: QueryResultEntry[] = [];
for (const record of records) {
const { authorization: _, ...objectWithRemainingProperties } = record; // a trick to stripping away `authorization`
for (const message of messages) {
const { authorization: _, ...objectWithRemainingProperties } = message; // a trick to stripping away `authorization`
entries.push(objectWithRemainingProperties);
}

Expand Down
31 changes: 16 additions & 15 deletions src/interfaces/records/handlers/records-query.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { MethodHandler } from '../../types.js';
import type { BaseMessage, QueryResultEntry } from '../../../core/types.js';
import type { DataStore, DidResolver, MessageStore } from '../../../index.js';
import type { RecordsQueryMessage, RecordsWriteMessage } from '../types.js';
import type { RecordsQueryMessage, RecordsQueryReplyEntry, RecordsWriteMessage } from '../types.js';

import { authenticate } from '../../../core/auth.js';
import { lexicographicalCompare } from '../../../utils/string.js';
import { MessageReply } from '../../../core/message-reply.js';
import type { RecordsWriteMessageWithOptionalEncodedData } from '../../../store/storage-controller.js';
import { StorageController } from '../../../store/storage-controller.js';

import { DateSort, RecordsQuery } from '../messages/records-query.js';
Expand Down Expand Up @@ -33,7 +33,7 @@ export class RecordsQueryHandler implements MethodHandler {
return MessageReply.fromError(e, 401);
}

let records: BaseMessage[];
let records: RecordsWriteMessageWithOptionalEncodedData[];
if (recordsQuery.author === tenant) {
records = await this.fetchRecordsAsOwner(tenant, recordsQuery);
} else {
Expand All @@ -46,7 +46,7 @@ export class RecordsQueryHandler implements MethodHandler {
}

// strip away `authorization` property for each record before responding
const entries: QueryResultEntry[] = [];
const entries: RecordsQueryReplyEntry[] = [];
for (const record of records) {
const { authorization: _, ...objectWithRemainingProperties } = record; // a trick to stripping away `authorization`
entries.push(objectWithRemainingProperties);
Expand All @@ -61,7 +61,7 @@ export class RecordsQueryHandler implements MethodHandler {
/**
* Fetches the records as the owner of the DWN with no additional filtering.
*/
private async fetchRecordsAsOwner(tenant: string, recordsQuery: RecordsQuery): Promise<BaseMessage[]> {
private async fetchRecordsAsOwner(tenant: string, recordsQuery: RecordsQuery): Promise<RecordsWriteMessageWithOptionalEncodedData[]> {
// fetch all published records matching the query
const filter = {
...RecordsQuery.convertFilter(recordsQuery.message.descriptor.filter),
Expand All @@ -79,7 +79,7 @@ export class RecordsQueryHandler implements MethodHandler {
* 2. unpublished records intended for the requester (where `recipient` is the requester)
*/
private async fetchRecordsAsNonOwner(tenant: string, recordsQuery: RecordsQuery)
: Promise<BaseMessage[]> {
: Promise<RecordsWriteMessageWithOptionalEncodedData[]> {
const publishedRecords = await this.fetchPublishedRecords(tenant, recordsQuery);
const unpublishedRecordsForRequester = await this.fetchUnpublishedRecordsForRequester(tenant, recordsQuery);
const unpublishedRecordsByRequester = await this.fetchUnpublishedRecordsByRequester(tenant, recordsQuery);
Expand All @@ -90,7 +90,7 @@ export class RecordsQueryHandler implements MethodHandler {
/**
* Fetches only published records.
*/
private async fetchPublishedRecords(tenant: string, recordsQuery: RecordsQuery): Promise<BaseMessage[]> {
private async fetchPublishedRecords(tenant: string, recordsQuery: RecordsQuery): Promise<RecordsWriteMessageWithOptionalEncodedData[]> {
// fetch all published records matching the query
const filter = {
...RecordsQuery.convertFilter(recordsQuery.message.descriptor.filter),
Expand All @@ -106,7 +106,9 @@ export class RecordsQueryHandler implements MethodHandler {
/**
* Fetches only unpublished records that are intended for the requester (where `recipient` is the requester).
*/
private async fetchUnpublishedRecordsForRequester(tenant: string, recordsQuery: RecordsQuery): Promise<BaseMessage[]> {
private async fetchUnpublishedRecordsForRequester(tenant: string, recordsQuery: RecordsQuery)
: Promise<RecordsWriteMessageWithOptionalEncodedData[]> {

// include records where recipient is requester
const filter = {
...RecordsQuery.convertFilter(recordsQuery.message.descriptor.filter),
Expand All @@ -124,7 +126,9 @@ export class RecordsQueryHandler implements MethodHandler {
/**
* Fetches only unpublished records that are authored by the requester.
*/
private async fetchUnpublishedRecordsByRequester(tenant: string, recordsQuery: RecordsQuery): Promise<BaseMessage[]> {
private async fetchUnpublishedRecordsByRequester(tenant: string, recordsQuery: RecordsQuery)
: Promise<RecordsWriteMessageWithOptionalEncodedData[]> {

// include records where recipient is requester
const filter = {
...RecordsQuery.convertFilter(recordsQuery.message.descriptor.filter),
Expand All @@ -148,17 +152,14 @@ export class RecordsQueryHandler implements MethodHandler {
* 4. publishedDescending - If the message is published, sort in desc based on publish date
*
* If sorting is based on date published, records that are not published are filtered out.
* @param entries - Entries to be sorted if dateSort is present
* @param messages - Messages to be sorted if dateSort is present
* @param dateSort - Sorting scheme
* @returns Sorted Messages
*/
async function sortRecords(
entries: BaseMessage[],
messages: RecordsWriteMessage[],
dateSort: DateSort
): Promise<BaseMessage[]> {

const messages = entries as RecordsWriteMessage[];

): Promise<RecordsWriteMessage[]> {
switch (dateSort) {
case DateSort.CreatedAscending:
return messages.sort((a, b) => lexicographicalCompare(a.descriptor.dateCreated, b.descriptor.dateCreated));
Expand Down
Loading

0 comments on commit e760006

Please sign in to comment.