Skip to content

Commit

Permalink
Merge branch 'main' into diehuxx/role-query
Browse files Browse the repository at this point in the history
* main:
  Add codecov coverage job in `integrity-check.yml` (#542)
  Add support for compressed secp256k1 publicKey (#567)
  Add range filter support for dataSize (#568)
  Replace `handle<Xyz>` methods in `Dwn` class with overloaded `process… (#566)
  Add tests for error cases in did-resolver.spec.ts (#561)
  add browser tests to gh actions. (#541)
  • Loading branch information
Diane Huxley committed Oct 20, 2023
2 parents 761b882 + e5a1a31 commit cf0cf4b
Show file tree
Hide file tree
Showing 26 changed files with 608 additions and 446 deletions.
39 changes: 35 additions & 4 deletions .github/workflows/integrity-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
node-version: 18.16.0
- run: npm audit

build:
test-with-node:
runs-on: ubuntu-latest
# read more about matrix strategies here: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix
strategy:
Expand All @@ -53,8 +53,39 @@ jobs:
- run: npm run lint
# runs tests in node environment without attempting to generate code coverage badges
- run: npm run test:node:ci
# runs code coverage badge generation, throws if README output differs to README to be checked in (thus detects if tests were not run)
- run: npm run make-coverage-badges:ci

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:
fail_ci_if_error: true
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

test-with-browsers:
# Run browser tests using macOS so that WebKit tests don't fail under a Linux environment
runs-on: macos-latest
steps:
- name: Checkout source
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: https://registry.npmjs.org/

- name: Install latest npm
run: npm install -g npm@latest

- name: Install dependencies
run: npm ci

- name: Install Playwright Browsers
run: npx playwright install --with-deps

- name: Build all workspace packages
run: npm run build


- name: Run tests for all packages
run: npm run test:browser
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Here's to a thrilling Hacktoberfest voyage with us! 🎉
# Decentralized Web Node (DWN) SDK <!-- omit in toc -->

Code Coverage
![Statements](https://img.shields.io/badge/statements-98.38%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-95.32%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-95.78%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-98.38%25-brightgreen.svg?style=flat)
![Statements](https://img.shields.io/badge/statements-98.5%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-95.72%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-95.75%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-98.5%25-brightgreen.svg?style=flat)

- [Introduction](#introduction)
- [Installation](#installation)
Expand Down
2 changes: 2 additions & 0 deletions build/compile-validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ 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 MessagesGet from '../json-schemas/interface-methods/messages-get.json' assert { type: 'json' };
import NumberRangeFilter from '../json-schemas/interface-methods/number-range-filter.json' assert { type: 'json' };
import PermissionsDefinitions from '../json-schemas/permissions/permissions-definitions.json' assert { type: 'json' };
import PermissionsGrant from '../json-schemas/interface-methods/permissions-grant.json' assert { type: 'json' };
import PermissionsRequest from '../json-schemas/interface-methods/permissions-request.json' assert { type: 'json' };
Expand Down Expand Up @@ -57,6 +58,7 @@ const schemas = {
GeneralJws,
JwkVerificationMethod,
MessagesGet,
NumberRangeFilter,
PermissionsDefinitions,
PermissionsGrant,
PermissionsRequest,
Expand Down
8 changes: 8 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
coverage:
status:
project:
default:
target: auto

ignore:
- "src/types"
43 changes: 43 additions & 0 deletions json-schemas/interface-methods/number-range-filter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://identity.foundation/dwn/json-schemas/number-range-filter.json",
"type": "object",
"minProperties": 1,
"additionalProperties": false,
"properties": {
"gt": {
"type": "number"
},
"gte": {
"type": "number"
},
"lt": {
"type": "number"
},
"lte": {
"type": "number"
}
},
"dependencies": {
"gt": {
"not": {
"required": ["gte"]
}
},
"gte": {
"not": {
"required": ["gt"]
}
},
"lt": {
"not": {
"required": ["lte"]
}
},
"lte": {
"not": {
"required": ["lt"]
}
}
}
}
3 changes: 3 additions & 0 deletions json-schemas/interface-methods/records-filter.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"dataFormat": {
"type": "string"
},
"dataSize": {
"$ref": "https://identity.foundation/dwn/json-schemas/number-range-filter.json"
},
"dateCreated": {
"type": "object",
"minProperties": 1,
Expand Down
13 changes: 12 additions & 1 deletion karma.conf.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ module.exports = function configure(config) {
// available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
frameworks: ['mocha'],

client: {
// Increase Mocha's default timeout of 2 seconds to prevent timeouts during GitHub CI runs.
mocha: {
timeout: 10000 // 10 seconds
}
},

// list of files / patterns to load in the browser
files: [
{ pattern: 'tests/**/*.spec.ts', watched: false }
Expand Down Expand Up @@ -74,6 +81,10 @@ module.exports = function configure(config) {

// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true
singleRun: true,

// Increase browser timeouts to avoid DISCONNECTED messages during GitHub CI runs.
browserDisconnectTimeout : 10000, // default 2000
browserDisconnectTolerance : 1, // default 0
});
};
39 changes: 26 additions & 13 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"ajv": "8.12.0",
"blockstore-core": "4.2.0",
"cross-fetch": "4.0.0",
"eciesjs": "0.4.0",
"eciesjs": "0.4.5",
"flat": "5.0.2",
"interface-blockstore": "5.2.3",
"interface-store": "5.1.2",
Expand Down
4 changes: 4 additions & 0 deletions src/core/dwn-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export class DwnError extends Error {
export enum DwnErrorCode {
AuthenticateJwsMissing = 'AuthenticateJwsMissing',
AuthorizationUnknownAuthor = 'AuthorizationUnknownAuthor',
DidMethodNotSupported = 'DidMethodNotSupported',
DidNotString = 'DidNotString',
DidNotValid = 'DidNotValid',
DidResolutionFailed = 'DidResolutionFailed',
GeneralJwsVerifierInvalidSignature = 'GeneralJwsVerifierInvalidSignature',
GrantAuthorizationGrantExpired = 'GrantAuthorizationGrantExpired',
GrantAuthorizationGrantMissing = 'GrantAuthorizationGrantMissing',
Expand Down
5 changes: 3 additions & 2 deletions src/did/did-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Did } from './did.js';
import { DidIonResolver } from './did-ion-resolver.js';
import { DidKeyResolver } from './did-key-resolver.js';
import { MemoryCache } from '../utils/memory-cache.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';

/**
* A DID resolver that by default supports `did:key` and `did:ion` DIDs.
Expand Down Expand Up @@ -49,7 +50,7 @@ export class DidResolver {
const didResolver = this.didResolvers.get(didMethod);

if (!didResolver) {
throw new Error(`${didMethod} DID method not supported`);
throw new DwnError(DwnErrorCode.DidMethodNotSupported, `${didMethod} DID method not supported`);
}

// use cached result if exists
Expand All @@ -66,7 +67,7 @@ export class DidResolver {
let errMsg = `Failed to resolve DID ${did}.`;
errMsg += error ? ` Error: ${error}` : '';

throw new Error(errMsg);
throw new DwnError(DwnErrorCode.DidResolutionFailed, errMsg);
}

return resolutionResult;
Expand Down
6 changes: 4 additions & 2 deletions src/did/did.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';

/**
* DID related operations.
*/
Expand All @@ -16,13 +18,13 @@ export class Did {
*/
public static validate(did: unknown): void {
if (typeof did !== 'string') {
throw new Error(`DID is not string: ${did}`);
throw new DwnError(DwnErrorCode.DidNotString, `DID is not string: ${did}`);
}

// eslint-disable-next-line
const didRegex= /^did:([a-z0-9]+):((?:(?:[a-zA-Z0-9._-]|(?:%[0-9a-fA-F]{2}))*:)*((?:[a-zA-Z0-9._-]|(?:%[0-9a-fA-F]{2}))+))((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\/[^#?]*)?([?][^#]*)?(#.*)?$/;
if (!didRegex.test(did)) {
throw new TypeError(`DID is not a valid DID: ${did}`);
throw new DwnError(DwnErrorCode.DidNotValid, `DID is not a valid DID: ${did}`);
}
}

Expand Down
66 changes: 1 addition & 65 deletions src/dwn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { TenantGate } from './core/tenant-gate.js';
import type { EventsGetMessage, EventsGetReply, PermissionsGrantMessage, PermissionsRequestMessage, PermissionsRevokeMessage, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply } from './index.js';
import type { GenericMessageReply, UnionMessageReply } from './core/message-reply.js';
import type { MessagesGetMessage, MessagesGetReply } from './types/messages-types.js';
import type { RecordsDeleteMessage, RecordsQueryMessage, RecordsQueryReply, RecordsReadMessage, RecordsReadReply, RecordsWriteMessage, RecordsWriteReply } from './types/records-types.js';
import type { RecordsDeleteMessage, RecordsQueryMessage, RecordsQueryReply, RecordsReadMessage, RecordsReadReply, RecordsWriteMessage } from './types/records-types.js';

import { AllowAllTenantGate } from './core/tenant-gate.js';
import { DidResolver } from './did/did-resolver.js';
Expand Down Expand Up @@ -119,70 +119,6 @@ export class Dwn {
return methodHandlerReply;
}

/**
* Handles a `RecordsWrite` message.
*/
public async handleRecordsWrite(
tenant: string,
message: RecordsWriteMessage,
dataStream?: Readable,
options?: RecordsWriteHandlerOptions): Promise<RecordsWriteReply> {
const errorMessageReply =
await this.validateTenant(tenant) ??
await this.validateMessageIntegrity(message, DwnInterfaceName.Records, DwnMethodName.Write);
if (errorMessageReply !== undefined) {
return errorMessageReply;
}

const handler = new RecordsWriteHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog);
return handler.handle({ tenant, message, options, dataStream });
}

/**
* Handles a `RecordsQuery` message.
*/
public async handleRecordsQuery(tenant: string, message: RecordsQueryMessage): Promise<RecordsQueryReply> {
const errorMessageReply =
await this.validateTenant(tenant) ??
await this.validateMessageIntegrity(message, DwnInterfaceName.Records, DwnMethodName.Query);
if (errorMessageReply !== undefined) {
return errorMessageReply;
}

const handler = new RecordsQueryHandler(this.didResolver, this.messageStore, this.dataStore);
return handler.handle({ tenant, message });
}

/**
* Handles a `RecordsRead` message.
*/
public async handleRecordsRead(tenant: string, message: RecordsReadMessage): Promise<RecordsReadReply> {
const errorMessageReply =
await this.validateTenant(tenant) ??
await this.validateMessageIntegrity(message, DwnInterfaceName.Records, DwnMethodName.Read);
if (errorMessageReply !== undefined) {
return errorMessageReply;
}

const handler = new RecordsReadHandler(this.didResolver, this.messageStore, this.dataStore);
return handler.handle({ tenant, message });
}

/**
* Handles a `MessagesGet` message.
*/
public async handleMessagesGet(tenant: string, message: MessagesGetMessage): Promise<MessagesGetReply> {
const errorMessageReply =
await this.validateTenant(tenant) ??
await this.validateMessageIntegrity(message, DwnInterfaceName.Messages, DwnMethodName.Get);
if (errorMessageReply !== undefined) {
return errorMessageReply;
}

const handler = new MessagesGetHandler(this.didResolver, this.messageStore, this.dataStore);
return handler.handle({ tenant, message });
}

/**
* Privileged method for writing a pruned initial `RecordsWrite` to a DWN without needing to supply associated data.
*/
Expand Down
Loading

0 comments on commit cf0cf4b

Please sign in to comment.