Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+340
View File
@@ -0,0 +1,340 @@
<!-- @format -->
# Decentralized Web Node (DWN) SDK <!-- omit in toc -->
[![NPM](https://img.shields.io/npm/v/@tbd54566975/dwn-sdk-js.svg?logo=npm)](https://www.npmjs.com/package/@tbd54566975/dwn-sdk-js)
[![codecov](https://codecov.io/github/TBD54566975/dwn-sdk-js/graphs/badge.svg)](https://codecov.io/github/TBD54566975/dwn-sdk-js)
[![Build Status](https://img.shields.io/github/actions/workflow/status/TBD54566975/dwn-sdk-js/npm-publish-unstable.yml?branch=main&logo=github)](https://github.com/tbd54566975/dwn-sdk-js/actions/workflows/npm-publish-unstable.yml)
[![License](https://img.shields.io/npm/l/@tbd54566975/dwn-sdk-js.svg?logo=apache)](https://github.com/tbd54566975/dwn-sdk-js/blob/main/LICENSE)
[![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg?logo=discord)](https://discord.com/channels/937858703112155166/1068273971432280196)
- [Introduction](#introduction)
- [Installation](#installation)
- [Additional Steps](#additional-steps)
- [Node.js \<= 18](#nodejs--18)
- [React Native](#react-native)
- [Usage in Browser:](#usage-in-browser)
- [Vanilla HTML / JS](#vanilla-html--js)
- [Webpack \>= 5](#webpack--5)
- [Vite](#vite)
- [esbuild](#esbuild)
- [Usage](#usage)
- [Release/Build Process](#releasebuild-process)
- [Stable Build](#stable-build)
- [Unstable Build](#unstable-build)
- [Some projects that use this library:](#some-projects-that-use-this-library)
- [Architecture](#architecture)
- [Project Resources](#project-resources)
## Introduction
This repository contains a reference implementation of Decentralized Web Node (DWN) as per the [specification](https://identity.foundation/decentralized-web-node/spec/). This specification is in a draft state and very much so a WIP. For the foreseeable future, a lot of the work on DWN will be split across this repo and the [repo that houses the specification](https://github.com/decentralized-identity/decentralized-web-node). The current implementation does not include all interfaces described in the DWN spec, but is enough to begin building test applications.
This project is used as a dependency by several other projects.
Proposals and issues for the specification itself should be submitted as pull requests to the [spec repo](https://github.com/decentralized-identity/decentralized-web-node).
## Running online environment
Interested in contributing instantly? You can make your updates directly without cloning in the running CodeSandbox environment.
[![Button to click to edit code in CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/github/TBD54566975/dwn-sdk-js/main)
## Installation
If you are interested in using DWNs and web5 in your web app, you probably want to look at web5-js, instead of this repository. Head on over here: https://github.com/TBD54566975/web5-js.
For advanced users wishing to use this repo directly:
```bash
npm install @tbd54566975/dwn-sdk-js
```
## Additional Steps
This package has dependency on [`@noble/ed25519`](https://github.com/paulmillr/noble-ed25519#usage) and [`@noble/secp256k1`](https://github.com/paulmillr/noble-secp256k1#usage) v2, additional steps are needed for some environments:
### Node.js <= 18
```js
// node.js 18 and earlier, needs globalThis.crypto polyfill
import { webcrypto } from "node:crypto";
// @ts-ignore
if (!globalThis.crypto) globalThis.crypto = webcrypto;
```
### React Native
Usage of DWN SDK in react native requires a bit of set up at the moment. To simplify, we've [published an npm package](https://www.npmjs.com/package/@tbd54566975/web5-react-native-polyfills) that can be used to set everything up. Follow the instructions to get started.
### Usage in Browser:
`dwn-sdk-js` requires 2 polyfills: `crypto` and `stream`. we recommend using `crypto-browserify` and `stream-browserify`. Both of these polyfills can be installed using npm. e.g. `npm install --save crypto-browserify stream-browserify`
#### Vanilla HTML / JS
DWN SDK includes a polyfilled distribution that can imported in a `module` script tag. e.g.
```html
<!DOCTYPE html>
<html lang="en">
<body>
<script type="module">
// Import necessary modules from external sources using ES6 modules.
import { Dwn, DataStream, DidKeyResolver, Jws, RecordsWrite } from 'https://cdn.jsdelivr.net/npm/@tbd54566975/dwn-sdk-js@0.1.1/dist/bundles/dwn.js'
import { MessageStoreLevel, DataStoreLevel, EventLogLevel } from 'https://cdn.jsdelivr.net/npm/@tbd54566975/dwn-sdk-js@0.1.1/dist/bundles/level-stores.js'
// Create instances of various components from the imported modules.
const messageStore = new MessageStoreLevel();
const dataStore = new DataStoreLevel();
const eventLog = new EventLogLevel();
const dwn = await Dwn.create({ messageStore, dataStore, eventLog });
// Generate a did:key DID (Decentralized Identifier).
const didKey = await TestDataGenerator.generateDidKeyPersona();
// Create some data to be stored.
const encoder = new TextEncoder();
const data = encoder.encode('Hello, World!');
// Create a RecordsWrite message to be stored in DWN.
const recordsWrite = await RecordsWrite.create({
data,
dataFormat: 'application/json',
published: true,
schema: 'yeeter/post', // Specify a schema for the data.
signer: Jws.createSigner(didKey) // Sign the data using the generated DID key.
});
// Create a readable stream from the data to be stored.
const dataStream = DataStream.fromBytes(data);
// Process the RecordsWrite message using the DWN instance.
const result = await dwn.processMessage(didKey.did, recordsWrite.message, { dataStream });
// Log the processing result status and perform an assertion.
console.log(result.status);
console.assert(result.status.code === 202)
// Close the DWN instance, freeing up resources.
await dwn.close()
</script>
</body>
</html>
```
#### Webpack >= 5
Add the following to the top level of your webpack config (`webpack.config.js`)
```js
resolve: {
fallback: {
stream: require.resolve("stream-browserify"),
crypto: require.resolve("crypto-browserify")
}
}
```
#### Vite
Add the following to the top level of your vite config (`vite.config.js`)
```js
define: {
global: 'globalThis'
},
resolve: {
alias: {
'crypto': 'crypto-browserify',
'stream': 'stream-browserify'
}
}
```
#### esbuild
We recommend using `node-stdlib-browser` instead of `crypto-browserify` and `stream-browserify` individually. Example usage:
```js
import esbuild from 'esbuild'
import stdLibBrowser from 'node-stdlib-browser'
import polyfillProviderPlugin from 'node-stdlib-browser/helpers/esbuild/plugin'
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
// Build the project using esbuild.
esbuild.build({
entryPoints: ['dwn-sdk-test.js'],
platform: 'browser',
bundle: true,
format: 'esm',
outfile: 'dist/dwn-sdk-test.js',
// Inject the specified shim for Node.js standard library browser compatibility.
inject : [require.resolve('node-stdlib-browser/helpers/esbuild/shim')],
// Use the polyfillProviderPlugin to provide polyfills for Node.js standard library.
plugins : [polyfillProviderPlugin(stdLibBrowser)],
// Define 'global' as 'globalThis' to ensure compatibility with global objects.
define : {
'global': 'globalThis'
}
})
```
## Usage
[API docs](https://tbd54566975.github.io/dwn-sdk-js/)
```ts
import { Dwn, DataStream, DidKeyResolver, Jws, RecordsWrite } from '@tbd54566975/dwn-sdk-js';
import { DataStoreLevel, EventLogLevel, MessageStoreLevel } from '@tbd54566975/dwn-sdk-js/stores';
// Initialize the required stores and components for the DWN SDK.
const messageStore = new MessageStoreLevel();
const dataStore = new DataStoreLevel();
const eventLog = new EventLogLevel();
const dwn = await Dwn.create({ messageStore, dataStore, eventLog });
// Generate a did:key DID (Decentralized Identifier).
const didKey = await TestDataGenerator.generateDidKeyPersona();
// Create some data to be stored.
const encoder = new TextEncoder();
const data = encoder.encode('Hello, World!');
// Create a RecordsWrite message to be stored in the DWN.
const recordsWrite = await RecordsWrite.create({
data,
dataFormat: 'application/json',
published: true, // Mark the data as published.
schema: 'yeeter/post', // Specify a schema for the data.
signer: Jws.createSigner(didKey) // Sign the data using the generated DID key.
});
// Create a readable stream from the data to be stored.
const dataStream = DataStream.fromBytes(data);
// Process the RecordsWrite message using the DWN instance.
const result = await dwn.processMessage(didKey.did, recordsWrite.message, { dataStream });
// Log the processing result status.
console.log(result.status);
```
With a web wallet installed:
```javascript
const result = await window.web5.dwn.processMessage({
method: "RecordsQuery",
message: {
filter: {
schema: "http://some-schema-registry.org/todo",
},
dateSort: "createdAscending",
},
});
```
### Custom Tenant Gating
By default, all DIDs are allowed as tenants. A custom tenant gate implementation can be provided when initializing the DWN.
```ts
import { ActiveTenantCheckResult, Dwn, TenantGate, DataStoreLevel, EventLogLevel, MessageStoreLevel } from '@tbd54566975/dwn-sdk-js';
// Define a custom implementation of the TenantGate interface.
class CustomTenantGate implements TenantGate {
public async isActiveTenant(did): Promise<ActiveTenantCheckResult> {
// Custom implementation
}
}
// Initialize the required stores and components for the DWN SDK.
const messageStore = new MessageStoreLevel();
const dataStore = new DataStoreLevel();
const eventLog = new EventLogLevel();
// Create an instance of the custom TenantGate.
const tenantGate = new CustomTenantGate();
// Create a DWN instance with configured stores, logs, and the custom TenantGate.
const dwn = await Dwn.create({ messageStore, dataStore, eventLog, tenantGate });
```
### Custom Signature Signer
If you have the private key readily available, it is recommended to use the built-in `PrivateKeySigner`. Otherwise, you can implement a customer signer to interface with external signing service, API, HSM, TPM etc and use it for signing your DWN messages:
```ts
// Create a custom signer implementing the Signer interface.
class CustomSigner implements Signer {
public keyId = 'did:example:alice#key1'; // Specify the key ID.
public algorithm = 'EdDSA'; // Specify the signing algorithm (valid `alg` value published).
https://www.iana.org/assignments/jose/jose.xhtml
public async sign (content: Uint8Array): Promise<Uint8Array> {
... // custom signing logic
}
}
// Create an instance of the custom signer for authorization.
const signer = new CustomSigner();
// Define options for creating a RecordsWrite message.
const options: RecordsWriteOptions = {
...
signer // Use the custom signer for authorization.
};
// Create a RecordsWrite message with the specified options.
const recordsWrite = await RecordsWrite.create(options);
```
## Release/Build Process
The DWN JS SDK releases builds to [npmjs.com](https://www.npmjs.com/package/@tbd54566975/dwn-sdk-js). There are two build types: stable build and unstable build.
### Stable Build
This is triggered manually by:
1. Increment `version` in `package.json` in [Semantic Versioning (semver)](https://semver.org/) format.
2. Merge the change into `main` branch
3. Create a release from GitHub.
An official build with version matching the `package.json` will be published to [npmjs.com](https://www.npmjs.com/package/@tbd54566975/dwn-sdk-js).
### Unstable Build
Every push to the `main` branch will automatically trigger an unstable build to [npmjs.com](https://www.npmjs.com/package/@tbd54566975/dwn-sdk-js) for developers to experiment and test.
The version string contains the date as well as the commit hash of the last change.
An example version string:
`0.0.26-unstable-2023-03-16-36ec2ce`
- `0.0.26` came from `version` in `package.json`
- `2023-03-16` indicates the date of March 16th 2023
- `36ec2ce` is the commit hash of the last change
## Some projects that use this library:
- [Web5 JS SDK](https://github.com/TBD54566975/web5-js)
- [Example CLI](https://github.com/TBD54566975/dwn-cli)
- [Example with a web wallet](https://github.com/TBD54566975/incubating-web5-labs/)
- [Server side aggregator](https://github.com/TBD54566975/dwn-server)
## Architecture
<img src="./images/dwn-architecture.png" alt="Architecture diagram of DWN SDN" width="700">
> NOTE: The diagram is a conceptual view of the architecture, the actual component abstraction and names in source file may differ.
## Project Resources
| Resource | Description |
| -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [CODEOWNERS](https://github.com/TBD54566975/dwn-sdk-js/blob/main/CODEOWNERS) | Outlines the project lead(s) |
| [CODE_OF_CONDUCT.md](https://github.com/TBD54566975/dwn-sdk-js/blob/main/CODE_OF_CONDUCT.md) | Expected behavior for project contributors, promoting a welcoming environment |
| [CONTRIBUTING.md](https://github.com/TBD54566975/dwn-sdk-js/blob/main/CONTRIBUTING.md) | Developer guide to build, test, run, access CI, chat, discuss, file issues |
| [GOVERNANCE.md](https://github.com/TBD54566975/dwn-sdk-js/blob/main/GOVERNANCE.md) | Project governance |
| [LICENSE](https://github.com/TBD54566975/dwn-sdk-js/blob/main/LICENSE) | Apache License, Version 2.0 |
| [Q_AND_A.md](https://github.com/TBD54566975/dwn-sdk-js/blob/main/Q_AND_A.md) | Questions and answers on DWN |
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1 @@
{"type": "commonjs"}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,23 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://identity.foundation/dwn/json-schemas/defs.json",
"type": "object",
"$defs": {
"base64url": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"uuid": {
"type": "string",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
},
"did": {
"type": "string",
"pattern": "^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_.:%-]*)*)(\/[^#?]*)?([?][^#]*)?(#.*)?$"
},
"date-time": {
"type": "string",
"pattern": "^\\d{4}-[0-1]\\d-[0-3]\\dT(?:[0-2]\\d:[0-5]\\d:[0-5]\\d|23:59:60)\\.\\d{6}Z$"
}
}
}
@@ -0,0 +1,41 @@
import { Jws } from '../utils/jws.js';
import { Message } from './message.js';
/**
* An abstract implementation of the `MessageInterface` interface.
*/
export class AbstractMessage {
get message() {
return this._message;
}
get signer() {
return this._signer;
}
get author() {
return this._author;
}
get signaturePayload() {
return this._signaturePayload;
}
constructor(message) {
this._message = message;
if (message.authorization !== undefined) {
this._signer = Message.getSigner(message);
// if the message authorization contains author delegated grant, the author would be the grantor of the grant
// else the author would be the signer of the message
if (message.authorization.authorDelegatedGrant !== undefined) {
this._author = Message.getSigner(message.authorization.authorDelegatedGrant);
}
else {
this._author = this._signer;
}
this._signaturePayload = Jws.decodePlainObjectPayload(message.authorization.signature);
}
}
/**
* Called by `JSON.stringify(...)` automatically.
*/
toJSON() {
return this.message;
}
}
//# sourceMappingURL=abstract-message.js.map
@@ -0,0 +1 @@
{"version":3,"file":"abstract-message.js","sourceRoot":"","sources":["../../../../src/core/abstract-message.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;GAEG;AACH,MAAM,OAAgB,eAAe;IAEnC,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,QAAa,CAAC;IAC5B,CAAC;IAGD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAGD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAGD,IAAW,gBAAgB;QACzB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED,YAAsB,OAAU;QAC9B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QAExB,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE;YACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAE1C,6GAA6G;YAC7G,qDAAqD;YACrD,IAAI,OAAO,CAAC,aAAa,CAAC,oBAAoB,KAAK,SAAS,EAAE;gBAC5D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;aAC9E;iBAAM;gBACL,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;aAC7B;YAED,IAAI,CAAC,iBAAiB,GAAG,GAAG,CAAC,wBAAwB,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;SACxF;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
@@ -0,0 +1,54 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { GeneralJwsVerifier } from '../jose/jws/general/verifier.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
/**
* Verifies all the signature(s) within the authorization property.
*
* @throws {Error} if fails authentication
*/
export function authenticate(authorizationModel, didResolver) {
return __awaiter(this, void 0, void 0, function* () {
if (authorizationModel === undefined) {
throw new DwnError(DwnErrorCode.AuthenticateJwsMissing, 'Missing JWS.');
}
yield GeneralJwsVerifier.verifySignatures(authorizationModel.signature, didResolver);
if (authorizationModel.ownerSignature !== undefined) {
yield GeneralJwsVerifier.verifySignatures(authorizationModel.ownerSignature, didResolver);
}
if (authorizationModel.authorDelegatedGrant !== undefined) {
// verify the signature of the grantor of the author-delegated grant
const authorDelegatedGrant = yield RecordsWrite.parse(authorizationModel.authorDelegatedGrant);
yield GeneralJwsVerifier.verifySignatures(authorDelegatedGrant.message.authorization.signature, didResolver);
}
if (authorizationModel.ownerDelegatedGrant !== undefined) {
// verify the signature of the grantor of the owner-delegated grant
const ownerDelegatedGrant = yield RecordsWrite.parse(authorizationModel.ownerDelegatedGrant);
yield GeneralJwsVerifier.verifySignatures(ownerDelegatedGrant.message.authorization.signature, didResolver);
}
});
}
/**
* Authorizes owner authored message.
* @throws {DwnError} if fails authorization.
*/
export function authorizeOwner(tenant, incomingMessage) {
return __awaiter(this, void 0, void 0, function* () {
// if author is the same as the target tenant, we can directly grant access
if (incomingMessage.author === tenant) {
return;
}
else {
throw new DwnError(DwnErrorCode.AuthorizationAuthorNotOwner, `Message authored by ${incomingMessage.author}, not authored by expected owner ${tenant}.`);
}
});
}
//# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/core/auth.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;GAIG;AACH,MAAM,UAAgB,YAAY,CAAC,kBAAkD,EAAE,WAAwB;;QAE7G,IAAI,kBAAkB,KAAK,SAAS,EAAE;YACpC,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,sBAAsB,EAAE,cAAc,CAAC,CAAC;SACzE;QAED,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAErF,IAAI,kBAAkB,CAAC,cAAc,KAAK,SAAS,EAAE;YACnD,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;SAC3F;QAED,IAAI,kBAAkB,CAAC,oBAAoB,KAAK,SAAS,EAAE;YACzD,oEAAoE;YACpE,MAAM,oBAAoB,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,CAAC;YAC/F,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;SAC9G;QAED,IAAI,kBAAkB,CAAC,mBAAmB,KAAK,SAAS,EAAE;YACxD,mEAAmE;YACnE,MAAM,mBAAmB,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,kBAAkB,CAAC,mBAAmB,CAAC,CAAC;YAC7F,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;SAC7G;IACH,CAAC;CAAA;AAED;;;GAGG;AACH,MAAM,UAAgB,cAAc,CAAC,MAAc,EAAE,eAAiD;;QACpG,2EAA2E;QAC3E,IAAI,eAAe,CAAC,MAAM,KAAK,MAAM,EAAE;YACrC,OAAO;SACR;aAAM;YACL,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,2BAA2B,EACxC,uBAAuB,eAAe,CAAC,MAAM,oCAAoC,MAAM,GAAG,CAC3F,CAAC;SACH;IACH,CAAC;CAAA"}
@@ -0,0 +1,10 @@
export class DwnConstant {
}
/**
* The maximum size of raw data that will be returned as `encodedData`.
*
* We chose 30k, as after encoding it would give plenty of headroom up to the 65k limit in most SQL variants.
* We currently encode using base64url which is a 33% increase in size.
*/
DwnConstant.maxDataSizeAllowedToBeEncoded = 30000;
//# sourceMappingURL=dwn-constant.js.map
@@ -0,0 +1 @@
{"version":3,"file":"dwn-constant.js","sourceRoot":"","sources":["../../../../src/core/dwn-constant.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,WAAW;;AACtB;;;;;GAKG;AACoB,yCAA6B,GAAG,KAAM,CAAC"}
@@ -0,0 +1,164 @@
/**
* A class that represents a DWN error.
*/
export class DwnError extends Error {
constructor(code, message) {
super(`${code}: ${message}`);
this.code = code;
this.name = 'DwnError';
}
}
/**
* DWN SDK error codes.
*/
export var DwnErrorCode;
(function (DwnErrorCode) {
DwnErrorCode["AuthenticateJwsMissing"] = "AuthenticateJwsMissing";
DwnErrorCode["AuthenticateDescriptorCidMismatch"] = "AuthenticateDescriptorCidMismatch";
DwnErrorCode["AuthenticationMoreThanOneSignatureNotSupported"] = "AuthenticationMoreThanOneSignatureNotSupported";
DwnErrorCode["AuthorizationAuthorNotOwner"] = "AuthorizationAuthorNotOwner";
DwnErrorCode["AuthorizationNotGrantedToAuthor"] = "AuthorizationNotGrantedToAuthor";
DwnErrorCode["ComputeCidCodecNotSupported"] = "ComputeCidCodecNotSupported";
DwnErrorCode["ComputeCidMultihashNotSupported"] = "ComputeCidMultihashNotSupported";
DwnErrorCode["DidMethodNotSupported"] = "DidMethodNotSupported";
DwnErrorCode["DidNotString"] = "DidNotString";
DwnErrorCode["DidNotValid"] = "DidNotValid";
DwnErrorCode["DidResolutionFailed"] = "DidResolutionFailed";
DwnErrorCode["Ed25519InvalidJwk"] = "Ed25519InvalidJwk";
DwnErrorCode["EventEmitterStreamNotOpenError"] = "EventEmitterStreamNotOpenError";
DwnErrorCode["EventsSubscribeEventStreamUnimplemented"] = "EventsSubscribeEventStreamUnimplemented";
DwnErrorCode["GeneralJwsVerifierGetPublicKeyNotFound"] = "GeneralJwsVerifierGetPublicKeyNotFound";
DwnErrorCode["GeneralJwsVerifierInvalidSignature"] = "GeneralJwsVerifierInvalidSignature";
DwnErrorCode["GrantAuthorizationGrantExpired"] = "GrantAuthorizationGrantExpired";
DwnErrorCode["GrantAuthorizationGrantMissing"] = "GrantAuthorizationGrantMissing";
DwnErrorCode["GrantAuthorizationGrantRevoked"] = "GrantAuthorizationGrantRevoked";
DwnErrorCode["GrantAuthorizationInterfaceMismatch"] = "GrantAuthorizationInterfaceMismatch";
DwnErrorCode["GrantAuthorizationMethodMismatch"] = "GrantAuthorizationMethodMismatch";
DwnErrorCode["GrantAuthorizationNotGrantedForTenant"] = "GrantAuthorizationNotGrantedForTenant";
DwnErrorCode["GrantAuthorizationNotGrantedToAuthor"] = "GrantAuthorizationNotGrantedToAuthor";
DwnErrorCode["GrantAuthorizationGrantNotYetActive"] = "GrantAuthorizationGrantNotYetActive";
DwnErrorCode["HdKeyDerivationPathInvalid"] = "HdKeyDerivationPathInvalid";
DwnErrorCode["JwsVerifySignatureUnsupportedCrv"] = "JwsVerifySignatureUnsupportedCrv";
DwnErrorCode["IndexInvalidCursorValueType"] = "IndexInvalidCursorValueType";
DwnErrorCode["IndexInvalidCursorSortProperty"] = "IndexInvalidCursorSortProperty";
DwnErrorCode["IndexInvalidSortPropertyInMemory"] = "IndexInvalidSortPropertyInMemory";
DwnErrorCode["IndexMissingIndexableProperty"] = "IndexMissingIndexableProperty";
DwnErrorCode["JwsDecodePlainObjectPayloadInvalid"] = "JwsDecodePlainObjectPayloadInvalid";
DwnErrorCode["MessageGetInvalidCid"] = "MessageGetInvalidCid";
DwnErrorCode["ParseCidCodecNotSupported"] = "ParseCidCodecNotSupported";
DwnErrorCode["ParseCidMultihashNotSupported"] = "ParseCidMultihashNotSupported";
DwnErrorCode["PermissionsProtocolValidateSchemaUnexpectedRecord"] = "PermissionsProtocolValidateSchemaUnexpectedRecord";
DwnErrorCode["PermissionsProtocolValidateScopeContextIdProhibitedProperties"] = "PermissionsProtocolValidateScopeContextIdProhibitedProperties";
DwnErrorCode["PermissionsProtocolValidateScopeSchemaProhibitedProperties"] = "PermissionsProtocolValidateScopeSchemaProhibitedProperties";
DwnErrorCode["PrivateKeySignerUnableToDeduceAlgorithm"] = "PrivateKeySignerUnableToDeduceAlgorithm";
DwnErrorCode["PrivateKeySignerUnableToDeduceKeyId"] = "PrivateKeySignerUnableToDeduceKeyId";
DwnErrorCode["PrivateKeySignerUnsupportedCurve"] = "PrivateKeySignerUnsupportedCurve";
DwnErrorCode["ProtocolAuthorizationActionNotAllowed"] = "ProtocolAuthorizationActionNotAllowed";
DwnErrorCode["ProtocolAuthorizationActionRulesNotFound"] = "ProtocolAuthorizationActionRulesNotFound";
DwnErrorCode["ProtocolAuthorizationIncorrectDataFormat"] = "ProtocolAuthorizationIncorrectDataFormat";
DwnErrorCode["ProtocolAuthorizationIncorrectContextId"] = "ProtocolAuthorizationIncorrectContextId";
DwnErrorCode["ProtocolAuthorizationIncorrectProtocolPath"] = "ProtocolAuthorizationIncorrectProtocolPath";
DwnErrorCode["ProtocolAuthorizationDuplicateRoleRecipient"] = "ProtocolAuthorizationDuplicateRoleRecipient";
DwnErrorCode["ProtocolAuthorizationInvalidSchema"] = "ProtocolAuthorizationInvalidSchema";
DwnErrorCode["ProtocolAuthorizationInvalidType"] = "ProtocolAuthorizationInvalidType";
DwnErrorCode["ProtocolAuthorizationMatchingRoleRecordNotFound"] = "ProtocolAuthorizationMatchingRoleRecordNotFound";
DwnErrorCode["ProtocolAuthorizationMaxSizeInvalid"] = "ProtocolAuthorizationMaxSizeInvalid";
DwnErrorCode["ProtocolAuthorizationMinSizeInvalid"] = "ProtocolAuthorizationMinSizeInvalid";
DwnErrorCode["ProtocolAuthorizationMissingContextId"] = "ProtocolAuthorizationMissingContextId";
DwnErrorCode["ProtocolAuthorizationMissingRuleSet"] = "ProtocolAuthorizationMissingRuleSet";
DwnErrorCode["ProtocolAuthorizationParentlessIncorrectProtocolPath"] = "ProtocolAuthorizationParentlessIncorrectProtocolPath";
DwnErrorCode["ProtocolAuthorizationNotARole"] = "ProtocolAuthorizationNotARole";
DwnErrorCode["ProtocolAuthorizationParentNotFoundConstructingRecordChain"] = "ProtocolAuthorizationParentNotFoundConstructingRecordChain";
DwnErrorCode["ProtocolAuthorizationProtocolNotFound"] = "ProtocolAuthorizationProtocolNotFound";
DwnErrorCode["ProtocolAuthorizationQueryWithoutRole"] = "ProtocolAuthorizationQueryWithoutRole";
DwnErrorCode["ProtocolAuthorizationRoleMissingRecipient"] = "ProtocolAuthorizationRoleMissingRecipient";
DwnErrorCode["ProtocolAuthorizationTagsInvalidSchema"] = "ProtocolAuthorizationTagsInvalidSchema";
DwnErrorCode["ProtocolsConfigureDuplicateActorInRuleSet"] = "ProtocolsConfigureDuplicateActorInRuleSet";
DwnErrorCode["ProtocolsConfigureDuplicateRoleInRuleSet"] = "ProtocolsConfigureDuplicateRoleInRuleSet";
DwnErrorCode["ProtocolsConfigureInvalidSize"] = "ProtocolsConfigureInvalidSize";
DwnErrorCode["ProtocolsConfigureInvalidActionMissingOf"] = "ProtocolsConfigureInvalidActionMissingOf";
DwnErrorCode["ProtocolsConfigureInvalidActionOfNotAllowed"] = "ProtocolsConfigureInvalidActionOfNotAllowed";
DwnErrorCode["ProtocolsConfigureInvalidActionDeleteWithoutCreate"] = "ProtocolsConfigureInvalidActionDeleteWithoutCreate";
DwnErrorCode["ProtocolsConfigureInvalidActionUpdateWithoutCreate"] = "ProtocolsConfigureInvalidActionUpdateWithoutCreate";
DwnErrorCode["ProtocolsConfigureInvalidRecipientOfAction"] = "ProtocolsConfigureInvalidRecipientOfAction";
DwnErrorCode["ProtocolsConfigureInvalidRuleSetRecordType"] = "ProtocolsConfigureInvalidRuleSetRecordType";
DwnErrorCode["ProtocolsConfigureInvalidTagSchema"] = "ProtocolsConfigureInvalidTagSchema";
DwnErrorCode["ProtocolsConfigureQueryNotAllowed"] = "ProtocolsConfigureQueryNotAllowed";
DwnErrorCode["ProtocolsConfigureRecordNestingDepthExceeded"] = "ProtocolsConfigureRecordNestingDepthExceeded";
DwnErrorCode["ProtocolsConfigureRoleDoesNotExistAtGivenPath"] = "ProtocolsConfigureRoleDoesNotExistAtGivenPath";
DwnErrorCode["ProtocolsConfigureUnauthorized"] = "ProtocolsConfigureUnauthorized";
DwnErrorCode["ProtocolsQueryUnauthorized"] = "ProtocolsQueryUnauthorized";
DwnErrorCode["RecordsAuthorDelegatedGrantAndIdExistenceMismatch"] = "RecordsAuthorDelegatedGrantAndIdExistenceMismatch";
DwnErrorCode["RecordsAuthorDelegatedGrantCidMismatch"] = "RecordsAuthorDelegatedGrantCidMismatch";
DwnErrorCode["RecordsAuthorDelegatedGrantGrantedToAndOwnerSignatureMismatch"] = "RecordsAuthorDelegatedGrantGrantedToAndOwnerSignatureMismatch";
DwnErrorCode["RecordsAuthorDelegatedGrantNotADelegatedGrant"] = "RecordsAuthorDelegatedGrantNotADelegatedGrant";
DwnErrorCode["RecordsDecryptNoMatchingKeyEncryptedFound"] = "RecordsDecryptNoMatchingKeyEncryptedFound";
DwnErrorCode["RecordsDeleteAuthorizationFailed"] = "RecordsDeleteAuthorizationFailed";
DwnErrorCode["RecordsQueryCreateFilterPublishedSortInvalid"] = "RecordsQueryCreateFilterPublishedSortInvalid";
DwnErrorCode["RecordsQueryParseFilterPublishedSortInvalid"] = "RecordsQueryParseFilterPublishedSortInvalid";
DwnErrorCode["RecordsGrantAuthorizationConditionPublicationProhibited"] = "RecordsGrantAuthorizationConditionPublicationProhibited";
DwnErrorCode["RecordsGrantAuthorizationConditionPublicationRequired"] = "RecordsGrantAuthorizationConditionPublicationRequired";
DwnErrorCode["RecordsGrantAuthorizationDeleteProtocolScopeMismatch"] = "RecordsGrantAuthorizationDeleteProtocolScopeMismatch";
DwnErrorCode["RecordsGrantAuthorizationQueryOrSubscribeProtocolScopeMismatch"] = "RecordsGrantAuthorizationQueryOrSubscribeProtocolScopeMismatch";
DwnErrorCode["RecordsGrantAuthorizationScopeContextIdMismatch"] = "RecordsGrantAuthorizationScopeContextIdMismatch";
DwnErrorCode["RecordsGrantAuthorizationScopeMissingProtocol"] = "RecordsGrantAuthorizationScopeMissingProtocol";
DwnErrorCode["RecordsGrantAuthorizationScopeNotRecords"] = "RecordsGrantAuthorizationScopeNotRecords";
DwnErrorCode["RecordsGrantAuthorizationScopeProtocolMismatch"] = "RecordsGrantAuthorizationScopeProtocolMismatch";
DwnErrorCode["RecordsGrantAuthorizationScopeProtocolPathMismatch"] = "RecordsGrantAuthorizationScopeProtocolPathMismatch";
DwnErrorCode["RecordsGrantAuthorizationScopeSchema"] = "RecordsGrantAuthorizationScopeSchema";
DwnErrorCode["RecordsDerivePrivateKeyUnSupportedCurve"] = "RecordsDerivePrivateKeyUnSupportedCurve";
DwnErrorCode["RecordsInvalidAncestorKeyDerivationSegment"] = "RecordsInvalidAncestorKeyDerivationSegment";
DwnErrorCode["RecordsOwnerDelegatedGrantAndIdExistenceMismatch"] = "RecordsOwnerDelegatedGrantAndIdExistenceMismatch";
DwnErrorCode["RecordsOwnerDelegatedGrantCidMismatch"] = "RecordsOwnerDelegatedGrantCidMismatch";
DwnErrorCode["RecordsOwnerDelegatedGrantGrantedToAndOwnerSignatureMismatch"] = "RecordsOwnerDelegatedGrantGrantedToAndOwnerSignatureMismatch";
DwnErrorCode["RecordsOwnerDelegatedGrantNotADelegatedGrant"] = "RecordsOwnerDelegatedGrantNotADelegatedGrant";
DwnErrorCode["RecordsProtocolContextDerivationSchemeMissingContextId"] = "RecordsProtocolContextDerivationSchemeMissingContextId";
DwnErrorCode["RecordsProtocolPathDerivationSchemeMissingProtocol"] = "RecordsProtocolPathDerivationSchemeMissingProtocol";
DwnErrorCode["RecordsQueryFilterMissingRequiredProperties"] = "RecordsQueryFilterMissingRequiredProperties";
DwnErrorCode["RecordsReadReturnedMultiple"] = "RecordsReadReturnedMultiple";
DwnErrorCode["RecordsReadAuthorizationFailed"] = "RecordsReadAuthorizationFailed";
DwnErrorCode["RecordsSubscribeEventStreamUnimplemented"] = "RecordsSubscribeEventStreamUnimplemented";
DwnErrorCode["RecordsSubscribeFilterMissingRequiredProperties"] = "RecordsSubscribeFilterMissingRequiredProperties";
DwnErrorCode["RecordsSchemasDerivationSchemeMissingSchema"] = "RecordsSchemasDerivationSchemeMissingSchema";
DwnErrorCode["RecordsWriteAttestationIntegrityMoreThanOneSignature"] = "RecordsWriteAttestationIntegrityMoreThanOneSignature";
DwnErrorCode["RecordsWriteAttestationIntegrityDescriptorCidMismatch"] = "RecordsWriteAttestationIntegrityDescriptorCidMismatch";
DwnErrorCode["RecordsWriteAttestationIntegrityInvalidPayloadProperty"] = "RecordsWriteAttestationIntegrityInvalidPayloadProperty";
DwnErrorCode["RecordsWriteAuthorizationFailed"] = "RecordsWriteAuthorizationFailed";
DwnErrorCode["RecordsWriteCreateMissingSigner"] = "RecordsWriteCreateMissingSigner";
DwnErrorCode["RecordsWriteCreateDataAndDataCidMutuallyExclusive"] = "RecordsWriteCreateDataAndDataCidMutuallyExclusive";
DwnErrorCode["RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive"] = "RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive";
DwnErrorCode["RecordsWriteCreateProtocolAndProtocolPathMutuallyInclusive"] = "RecordsWriteCreateProtocolAndProtocolPathMutuallyInclusive";
DwnErrorCode["RecordsWriteDataCidMismatch"] = "RecordsWriteDataCidMismatch";
DwnErrorCode["RecordsWriteDataSizeMismatch"] = "RecordsWriteDataSizeMismatch";
DwnErrorCode["RecordsWriteGetEntryIdUndefinedAuthor"] = "RecordsWriteGetEntryIdUndefinedAuthor";
DwnErrorCode["RecordsWriteGetInitialWriteNotFound"] = "RecordsWriteGetInitialWriteNotFound";
DwnErrorCode["RecordsWriteImmutablePropertyChanged"] = "RecordsWriteImmutablePropertyChanged";
DwnErrorCode["RecordsWriteMissingSigner"] = "RecordsWriteMissingSigner";
DwnErrorCode["RecordsWriteMissingDataInPrevious"] = "RecordsWriteMissingDataInPrevious";
DwnErrorCode["RecordsWriteMissingEncodedDataInPrevious"] = "RecordsWriteMissingEncodedDataInPrevious";
DwnErrorCode["RecordsWriteMissingDataStream"] = "RecordsWriteMissingDataStream";
DwnErrorCode["RecordsWriteMissingProtocol"] = "RecordsWriteMissingProtocol";
DwnErrorCode["RecordsWriteMissingSchema"] = "RecordsWriteMissingSchema";
DwnErrorCode["RecordsWriteOwnerAndTenantMismatch"] = "RecordsWriteOwnerAndTenantMismatch";
DwnErrorCode["RecordsWriteSignAsOwnerDelegateUnknownAuthor"] = "RecordsWriteSignAsOwnerDelegateUnknownAuthor";
DwnErrorCode["RecordsWriteSignAsOwnerUnknownAuthor"] = "RecordsWriteSignAsOwnerUnknownAuthor";
DwnErrorCode["RecordsWriteValidateIntegrityAttestationMismatch"] = "RecordsWriteValidateIntegrityAttestationMismatch";
DwnErrorCode["RecordsWriteValidateIntegrityContextIdMismatch"] = "RecordsWriteValidateIntegrityContextIdMismatch";
DwnErrorCode["RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload"] = "RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload";
DwnErrorCode["RecordsWriteValidateIntegrityDateCreatedMismatch"] = "RecordsWriteValidateIntegrityDateCreatedMismatch";
DwnErrorCode["RecordsWriteValidateIntegrityEncryptionCidMismatch"] = "RecordsWriteValidateIntegrityEncryptionCidMismatch";
DwnErrorCode["RecordsWriteValidateIntegrityRecordIdUnauthorized"] = "RecordsWriteValidateIntegrityRecordIdUnauthorized";
DwnErrorCode["SchemaValidatorAdditionalPropertyNotAllowed"] = "SchemaValidatorAdditionalPropertyNotAllowed";
DwnErrorCode["SchemaValidatorFailure"] = "SchemaValidatorFailure";
DwnErrorCode["SchemaValidatorSchemaNotFound"] = "SchemaValidatorSchemaNotFound";
DwnErrorCode["SchemaValidatorUnevaluatedPropertyNotAllowed"] = "SchemaValidatorUnevaluatedPropertyNotAllowed";
DwnErrorCode["Secp256k1KeyNotValid"] = "Secp256k1KeyNotValid";
DwnErrorCode["Secp256r1KeyNotValid"] = "Secp256r1KeyNotValid";
DwnErrorCode["TimestampInvalid"] = "TimestampInvalid";
DwnErrorCode["UrlProtocolNotNormalized"] = "UrlProtocolNotNormalized";
DwnErrorCode["UrlProtocolNotNormalizable"] = "UrlProtocolNotNormalizable";
DwnErrorCode["UrlSchemaNotNormalized"] = "UrlSchemaNotNormalized";
DwnErrorCode["UrlSchemaNotNormalizable"] = "UrlSchemaNotNormalizable";
})(DwnErrorCode || (DwnErrorCode = {}));
;
//# sourceMappingURL=dwn-error.js.map
@@ -0,0 +1 @@
{"version":3,"file":"dwn-error.js","sourceRoot":"","sources":["../../../../src/core/dwn-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAoB,IAAY,EAAE,OAAe;QAC/C,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QADX,SAAI,GAAJ,IAAI,CAAQ;QAG9B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,YAmJX;AAnJD,WAAY,YAAY;IACtB,iEAAiD,CAAA;IACjD,uFAAuE,CAAA;IACvE,iHAAiG,CAAA;IACjG,2EAA2D,CAAA;IAC3D,mFAAmE,CAAA;IACnE,2EAA2D,CAAA;IAC3D,mFAAmE,CAAA;IACnE,+DAA+C,CAAA;IAC/C,6CAA6B,CAAA;IAC7B,2CAA2B,CAAA;IAC3B,2DAA2C,CAAA;IAC3C,uDAAuC,CAAA;IACvC,iFAAiE,CAAA;IACjE,mGAAmF,CAAA;IACnF,iGAAiF,CAAA;IACjF,yFAAyE,CAAA;IACzE,iFAAiE,CAAA;IACjE,iFAAiE,CAAA;IACjE,iFAAiE,CAAA;IACjE,2FAA2E,CAAA;IAC3E,qFAAqE,CAAA;IACrE,+FAA+E,CAAA;IAC/E,6FAA6E,CAAA;IAC7E,2FAA2E,CAAA;IAC3E,yEAAyD,CAAA;IACzD,qFAAqE,CAAA;IACrE,2EAA2D,CAAA;IAC3D,iFAAiE,CAAA;IACjE,qFAAqE,CAAA;IACrE,+EAA+D,CAAA;IAC/D,yFAAyE,CAAA;IACzE,6DAA6C,CAAA;IAC7C,uEAAuD,CAAA;IACvD,+EAA+D,CAAA;IAC/D,uHAAuG,CAAA;IACvG,+IAA+H,CAAA;IAC/H,yIAAyH,CAAA;IACzH,mGAAmF,CAAA;IACnF,2FAA2E,CAAA;IAC3E,qFAAqE,CAAA;IACrE,+FAA+E,CAAA;IAC/E,qGAAqF,CAAA;IACrF,qGAAqF,CAAA;IACrF,mGAAmF,CAAA;IACnF,yGAAyF,CAAA;IACzF,2GAA2F,CAAA;IAC3F,yFAAyE,CAAA;IACzE,qFAAqE,CAAA;IACrE,mHAAmG,CAAA;IACnG,2FAA2E,CAAA;IAC3E,2FAA2E,CAAA;IAC3E,+FAA+E,CAAA;IAC/E,2FAA2E,CAAA;IAC3E,6HAA6G,CAAA;IAC7G,+EAA+D,CAAA;IAC/D,yIAAyH,CAAA;IACzH,+FAA+E,CAAA;IAC/E,+FAA+E,CAAA;IAC/E,uGAAuF,CAAA;IACvF,iGAAiF,CAAA;IACjF,uGAAuF,CAAA;IACvF,qGAAqF,CAAA;IACrF,+EAA+D,CAAA;IAC/D,qGAAqF,CAAA;IACrF,2GAA2F,CAAA;IAC3F,yHAAyG,CAAA;IACzG,yHAAyG,CAAA;IACzG,yGAAyF,CAAA;IACzF,yGAAyF,CAAA;IACzF,yFAAyE,CAAA;IACzE,uFAAuE,CAAA;IACvE,6GAA6F,CAAA;IAC7F,+GAA+F,CAAA;IAC/F,iFAAiE,CAAA;IACjE,yEAAyD,CAAA;IACzD,uHAAuG,CAAA;IACvG,iGAAiF,CAAA;IACjF,+IAA+H,CAAA;IAC/H,+GAA+F,CAAA;IAC/F,uGAAuF,CAAA;IACvF,qFAAqE,CAAA;IACrE,6GAA6F,CAAA;IAC7F,2GAA2F,CAAA;IAC3F,mIAAmH,CAAA;IACnH,+HAA+G,CAAA;IAC/G,6HAA6G,CAAA;IAC7G,iJAAiI,CAAA;IACjI,mHAAmG,CAAA;IACnG,+GAA+F,CAAA;IAC/F,qGAAqF,CAAA;IACrF,iHAAiG,CAAA;IACjG,yHAAyG,CAAA;IACzG,6FAA6E,CAAA;IAC7E,mGAAmF,CAAA;IACnF,yGAAyF,CAAA;IACzF,qHAAqG,CAAA;IACrG,+FAA+E,CAAA;IAC/E,6IAA6H,CAAA;IAC7H,6GAA6F,CAAA;IAC7F,iIAAiH,CAAA;IACjH,yHAAyG,CAAA;IACzG,2GAA2F,CAAA;IAC3F,2EAA2D,CAAA;IAC3D,iFAAiE,CAAA;IACjE,qGAAqF,CAAA;IACrF,mHAAmG,CAAA;IACnG,2GAA2F,CAAA;IAC3F,6HAA6G,CAAA;IAC7G,+HAA+G,CAAA;IAC/G,iIAAiH,CAAA;IACjH,mFAAmE,CAAA;IACnE,mFAAmE,CAAA;IACnE,uHAAuG,CAAA;IACvG,+HAA+G,CAAA;IAC/G,yIAAyH,CAAA;IACzH,2EAA2D,CAAA;IAC3D,6EAA6D,CAAA;IAC7D,+FAA+E,CAAA;IAC/E,2FAA2E,CAAA;IAC3E,6FAA6E,CAAA;IAC7E,uEAAuD,CAAA;IACvD,uFAAuE,CAAA;IACvE,qGAAqF,CAAA;IACrF,+EAA+D,CAAA;IAC/D,2EAA2D,CAAA;IAC3D,uEAAuD,CAAA;IACvD,yFAAyE,CAAA;IACzE,6GAA6F,CAAA;IAC7F,6FAA6E,CAAA;IAC7E,qHAAqG,CAAA;IACrG,iHAAiG,CAAA;IACjG,uJAAuI,CAAA;IACvI,qHAAqG,CAAA;IACrG,yHAAyG,CAAA;IACzG,uHAAuG,CAAA;IACvG,2GAA2F,CAAA;IAC3F,iEAAiD,CAAA;IACjD,+EAA+D,CAAA;IAC/D,6GAA6F,CAAA;IAC7F,6DAA6C,CAAA;IAC7C,6DAA6C,CAAA;IAC7C,qDAAqC,CAAA;IACrC,qEAAqD,CAAA;IACrD,yEAAyD,CAAA;IACzD,iEAAiD,CAAA;IACjD,qEAAqD,CAAA;AACvD,CAAC,EAnJW,YAAY,KAAZ,YAAY,QAmJvB;AAAA,CAAC"}
@@ -0,0 +1,97 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Message } from './message.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
export class GrantAuthorization {
/**
* Performs base permissions-grant-based authorization against the given message:
* 1. Validates the `expectedGrantor` and `expectedGrantee` values against the actual values in given permission grant.
* 2. Verifies that the incoming message is within the allowed time frame of the grant, and the grant has not been revoked.
* 3. Verifies that the `interface` and `method` grant scopes match the incoming message.
*
* NOTE: Does not validate grant `conditions` or `scope` beyond `interface` and `method`
*
* @param messageStore Used to check if the grant has been revoked.
* @throws {DwnError} if validation fails
*/
static performBaseValidation(input) {
return __awaiter(this, void 0, void 0, function* () {
const { incomingMessage, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
const incomingMessageDescriptor = incomingMessage.descriptor;
GrantAuthorization.verifyExpectedGrantorAndGrantee(expectedGrantor, expectedGrantee, permissionGrant);
// verify that grant is active during incomingMessage's timestamp
const grantedFor = expectedGrantor; // renaming for better readability now that we have verified the grantor above
yield GrantAuthorization.verifyGrantActive(grantedFor, incomingMessageDescriptor.messageTimestamp, permissionGrant, messageStore);
// Check grant scope for interface and method
yield GrantAuthorization.verifyGrantScopeInterfaceAndMethod(incomingMessageDescriptor.interface, incomingMessageDescriptor.method, permissionGrant);
});
}
/**
* Verifies the given `expectedGrantor` and `expectedGrantee` values against
* the actual signer and recipient in given permission grant.
* @throws {DwnError} if `expectedGrantor` or `expectedGrantee` do not match the actual values in the grant.
*/
static verifyExpectedGrantorAndGrantee(expectedGrantor, expectedGrantee, permissionGrant) {
const actualGrantee = permissionGrant.grantee;
if (expectedGrantee !== actualGrantee) {
throw new DwnError(DwnErrorCode.GrantAuthorizationNotGrantedToAuthor, `Permission grant is granted to ${actualGrantee}, but need to be granted to ${expectedGrantee}`);
}
const actualGrantor = permissionGrant.grantor;
if (expectedGrantor !== actualGrantor) {
throw new DwnError(DwnErrorCode.GrantAuthorizationNotGrantedForTenant, `Permission grant is granted by ${actualGrantor}, but need to be granted by ${expectedGrantor}`);
}
}
/**
* Verify that the incoming message is within the allowed time frame of the grant,
* and the grant has not been revoked.
* @param messageStore Used to check if the grant has been revoked.
* @throws {DwnError} if incomingMessage has timestamp for a time in which the grant is not active.
*/
static verifyGrantActive(grantedFor, incomingMessageTimestamp, permissionGrant, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// Check that incomingMessage is within the grant's time frame
if (incomingMessageTimestamp < permissionGrant.dateGranted) {
// grant is not yet active
throw new DwnError(DwnErrorCode.GrantAuthorizationGrantNotYetActive, `The message has a timestamp before the associated permission grant becomes active`);
}
if (incomingMessageTimestamp >= permissionGrant.dateExpires) {
// grant has expired
throw new DwnError(DwnErrorCode.GrantAuthorizationGrantExpired, `The message has timestamp after the expiry of the associated permission grant`);
}
// Check if grant has been revoked
const query = {
parentId: permissionGrant.id,
protocolPath: `grant/revocation`,
isLatestBaseState: true
};
const { messages: revokes } = yield messageStore.query(grantedFor, [query]);
const oldestExistingRevoke = yield Message.getOldestMessage(revokes);
if (oldestExistingRevoke !== undefined && oldestExistingRevoke.descriptor.messageTimestamp <= incomingMessageTimestamp) {
throw new DwnError(DwnErrorCode.GrantAuthorizationGrantRevoked, `Permission grant with CID ${permissionGrant.id} has been revoked`);
}
});
}
/**
* Verify that the `interface` and `method` grant scopes match the incoming message
* @param permissionGrantId Purely being passed for logging purposes.
* @throws {DwnError} if the `interface` and `method` of the incoming message do not match the scope of the permission grant.
*/
static verifyGrantScopeInterfaceAndMethod(dwnInterface, dwnMethod, permissionGrant) {
return __awaiter(this, void 0, void 0, function* () {
if (dwnInterface !== permissionGrant.scope.interface) {
throw new DwnError(DwnErrorCode.GrantAuthorizationInterfaceMismatch, `DWN Interface of incoming message is outside the scope of permission grant with ID ${permissionGrant.id}`);
}
else if (dwnMethod !== permissionGrant.scope.method) {
throw new DwnError(DwnErrorCode.GrantAuthorizationMethodMismatch, `DWN Method of incoming message is outside the scope of permission grant with ID ${permissionGrant.id}`);
}
});
}
}
//# sourceMappingURL=grant-authorization.js.map
@@ -0,0 +1 @@
{"version":3,"file":"grant-authorization.js","sourceRoot":"","sources":["../../../../src/core/grant-authorization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
export function messageReplyFromError(e, code) {
const detail = e instanceof Error ? e.message : 'Error';
return { status: { code, detail } };
}
//# sourceMappingURL=message-reply.js.map
@@ -0,0 +1 @@
{"version":3,"file":"message-reply.js","sourceRoot":"","sources":["../../../../src/core/message-reply.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,qBAAqB,CAAC,CAAU,EAAE,IAAY;IAE5D,MAAM,MAAM,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAExD,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;AACtC,CAAC"}
@@ -0,0 +1,217 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Cid } from '../utils/cid.js';
import { Encoder } from '../utils/encoder.js';
import { GeneralJwsBuilder } from '../jose/jws/general/builder.js';
import { Jws } from '../utils/jws.js';
import { lexicographicalCompare } from '../utils/string.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { validateJsonSchema } from '../schema-validator.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
/**
* A class containing utility methods for working with DWN messages.
*/
export class Message {
/**
* Validates the given message against the corresponding JSON schema.
* @throws {Error} if fails validation.
*/
static validateJsonSchema(rawMessage) {
const dwnInterface = rawMessage.descriptor.interface;
const dwnMethod = rawMessage.descriptor.method;
const schemaLookupKey = dwnInterface + dwnMethod;
// throws an error if message is invalid
validateJsonSchema(schemaLookupKey, rawMessage);
}
;
/**
* Gets the DID of the signer of the given message, returns `undefined` if message is not signed.
*/
static getSigner(message) {
if (message.authorization === undefined) {
return undefined;
}
const signer = Jws.getSignerDid(message.authorization.signature.signatures[0]);
return signer;
}
/**
* Gets the CID of the given message.
*/
static getCid(message) {
return __awaiter(this, void 0, void 0, function* () {
// NOTE: we wrap the `computeCid()` here in case that
// the message will contain properties that should not be part of the CID computation
// and we need to strip them out (like `encodedData` that we historically had for a long time),
// but we can remove this method entirely if the code becomes stable and it is apparent that the wrapper is not needed
// ^--- seems like we might need to keep this around for now.
const rawMessage = Object.assign({}, message);
if (rawMessage.encodedData) {
delete rawMessage.encodedData;
}
const cid = yield Cid.computeCid(rawMessage);
return cid;
});
}
/**
* Compares message CID in lexicographical order according to the spec.
* @returns 1 if `a` is larger than `b`; -1 if `a` is smaller/older than `b`; 0 otherwise (same message)
*/
static compareCid(a, b) {
return __awaiter(this, void 0, void 0, function* () {
// the < and > operators compare strings in lexicographical order
const cidA = yield Message.getCid(a);
const cidB = yield Message.getCid(b);
return lexicographicalCompare(cidA, cidB);
});
}
/**
* Creates the `authorization` property to be included in a DWN message.
* @param signer Message signer.
* @returns {AuthorizationModel} used as an `authorization` property.
*/
static createAuthorization(input) {
return __awaiter(this, void 0, void 0, function* () {
const { descriptor, signer, delegatedGrant, permissionGrantId, protocolRole } = input;
let delegatedGrantId;
if (delegatedGrant !== undefined) {
delegatedGrantId = yield Message.getCid(delegatedGrant);
}
const signature = yield Message.createSignature(descriptor, signer, { delegatedGrantId, permissionGrantId, protocolRole });
const authorization = {
signature
};
if (delegatedGrant !== undefined) {
authorization.authorDelegatedGrant = delegatedGrant;
}
return authorization;
});
}
/**
* Creates a generic signature from the given DWN message descriptor by including `descriptorCid` as the required property in the signature payload.
* NOTE: there is an opportunity to consolidate RecordsWrite.createSignerSignature() wth this method
*/
static createSignature(descriptor, signer, additionalPayloadProperties) {
return __awaiter(this, void 0, void 0, function* () {
const descriptorCid = yield Cid.computeCid(descriptor);
const signaturePayload = Object.assign({ descriptorCid }, additionalPayloadProperties);
removeUndefinedProperties(signaturePayload);
const signaturePayloadBytes = Encoder.objectToBytes(signaturePayload);
const builder = yield GeneralJwsBuilder.create(signaturePayloadBytes, [signer]);
const signature = builder.getJws();
return signature;
});
}
/**
* @returns newest message in the array. `undefined` if given array is empty.
*/
static getNewestMessage(messages) {
return __awaiter(this, void 0, void 0, function* () {
let currentNewestMessage = undefined;
for (const message of messages) {
if (currentNewestMessage === undefined || (yield Message.isNewer(message, currentNewestMessage))) {
currentNewestMessage = message;
}
}
return currentNewestMessage;
});
}
/**
* @returns oldest message in the array. `undefined` if given array is empty.
*/
static getOldestMessage(messages) {
return __awaiter(this, void 0, void 0, function* () {
let currentOldestMessage = undefined;
for (const message of messages) {
if (currentOldestMessage === undefined || (yield Message.isOlder(message, currentOldestMessage))) {
currentOldestMessage = message;
}
}
return currentOldestMessage;
});
}
/**
* Checks if first message is newer than second message.
* @returns `true` if `a` is newer than `b`; `false` otherwise
*/
static isNewer(a, b) {
return __awaiter(this, void 0, void 0, function* () {
const aIsNewer = ((yield Message.compareMessageTimestamp(a, b)) > 0);
return aIsNewer;
});
}
/**
* Checks if first message is older than second message.
* @returns `true` if `a` is older than `b`; `false` otherwise
*/
static isOlder(a, b) {
return __awaiter(this, void 0, void 0, function* () {
const aIsOlder = ((yield Message.compareMessageTimestamp(a, b)) < 0);
return aIsOlder;
});
}
/**
* See if the given message is signed by an author-delegate.
*/
static isSignedByAuthorDelegate(message) {
var _a;
return ((_a = message.authorization) === null || _a === void 0 ? void 0 : _a.authorDelegatedGrant) !== undefined;
}
/**
* See if the given message is signed by an owner-delegate.
*/
static isSignedByOwnerDelegate(message) {
var _a;
return ((_a = message.authorization) === null || _a === void 0 ? void 0 : _a.ownerDelegatedGrant) !== undefined;
}
/**
* Compares the `messageTimestamp` of the given messages with a fallback to message CID according to the spec.
* @returns 1 if `a` is larger/newer than `b`; -1 if `a` is smaller/older than `b`; 0 otherwise (same age)
*/
static compareMessageTimestamp(a, b) {
return __awaiter(this, void 0, void 0, function* () {
if (a.descriptor.messageTimestamp > b.descriptor.messageTimestamp) {
return 1;
}
else if (a.descriptor.messageTimestamp < b.descriptor.messageTimestamp) {
return -1;
}
// else `messageTimestamp` is the same between a and b
// compare the `dataCid` instead, the < and > operators compare strings in lexicographical order
return Message.compareCid(a, b);
});
}
/**
* Validates the structural integrity of the message signature given:
* 1. The message signature must contain exactly 1 signature
* 2. Passes JSON schema validation
* 3. The `descriptorCid` property matches the CID of the message descriptor
* NOTE: signature is NOT verified.
* @param payloadJsonSchemaKey The key to look up the JSON schema referenced in `compile-validators.js` and perform payload schema validation on.
* @returns the parsed JSON payload object if validation succeeds.
*/
static validateSignatureStructure(messageSignature, messageDescriptor, payloadJsonSchemaKey = 'GenericSignaturePayload') {
return __awaiter(this, void 0, void 0, function* () {
if (messageSignature.signatures.length !== 1) {
throw new DwnError(DwnErrorCode.AuthenticationMoreThanOneSignatureNotSupported, 'expected no more than 1 signature for authorization purpose');
}
// validate payload integrity
const payloadJson = Jws.decodePlainObjectPayload(messageSignature);
validateJsonSchema(payloadJsonSchemaKey, payloadJson);
// `descriptorCid` validation - ensure that the provided descriptorCid matches the CID of the actual message
const { descriptorCid } = payloadJson;
const expectedDescriptorCid = yield Cid.computeCid(messageDescriptor);
if (descriptorCid !== expectedDescriptorCid) {
throw new DwnError(DwnErrorCode.AuthenticateDescriptorCidMismatch, `provided descriptorCid ${descriptorCid} does not match expected CID ${expectedDescriptorCid}`);
}
return payloadJson;
});
}
}
//# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../../src/core/message.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,608 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import Ajv from 'ajv/dist/2020.js';
import { FilterUtility } from '../utils/filter.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { Records } from '../utils/records.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { ProtocolAction, ProtocolActor } from '../types/protocols-types.js';
export class ProtocolAuthorization {
/**
* Performs validation on the structure of RecordsWrite messages that use a protocol.
* @throws {Error} if validation fails.
*/
static validateReferentialIntegrity(tenant, incomingMessage, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, incomingMessage.message.descriptor.protocol, messageStore);
// verify declared protocol type exists in protocol and that it conforms to type specification
ProtocolAuthorization.verifyType(incomingMessage.message, protocolDefinition.types);
// validate `protocolPath`
yield ProtocolAuthorization.verifyProtocolPathAndContextId(tenant, incomingMessage, messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(incomingMessage.message.descriptor.protocolPath, protocolDefinition);
// Validate as a role record if the incoming message is writing a role record
yield ProtocolAuthorization.verifyAsRoleRecordIfNeeded(tenant, incomingMessage, ruleSet, messageStore);
// Verify size limit
ProtocolAuthorization.verifySizeLimit(incomingMessage, ruleSet);
// Verify protocol tags
ProtocolAuthorization.verifyTagsIfNeeded(incomingMessage, ruleSet);
});
}
/**
* Performs protocol-based authorization against the incoming RecordsWrite message.
* @throws {Error} if authorization fails.
*/
static authorizeWrite(tenant, incomingMessage, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const existingInitialWrite = yield ProtocolAuthorization.fetchInitialWrite(tenant, incomingMessage.message.recordId, messageStore);
let recordChain;
if (existingInitialWrite === undefined) {
// NOTE: we can assume this message is an initial write because an existing initial write does not exist.
// Additionally, we check further down in the `RecordsWriteHandler` if the incoming message is an initialWrite,
// so we don't check explicitly here to avoid an unnecessary duplicate check.
recordChain = yield ProtocolAuthorization.constructRecordChain(tenant, incomingMessage.message.descriptor.parentId, messageStore);
}
else {
recordChain = yield ProtocolAuthorization.constructRecordChain(tenant, incomingMessage.message.recordId, messageStore);
}
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, incomingMessage.message.descriptor.protocol, messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(incomingMessage.message.descriptor.protocolPath, protocolDefinition);
// If the incoming message has `protocolRole` in the descriptor, validate the invoked role
yield ProtocolAuthorization.verifyInvokedRole(tenant, incomingMessage, incomingMessage.message.descriptor.protocol, incomingMessage.message.contextId, protocolDefinition, messageStore);
// verify method invoked against the allowed actions in the rule set
yield ProtocolAuthorization.authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, recordChain, messageStore);
});
}
/**
* Performs protocol-based authorization against the incoming `RecordsRead` message.
* @param newestRecordsWrite The latest RecordsWrite associated with the recordId being read.
* @throws {Error} if authorization fails.
*/
static authorizeRead(tenant, incomingMessage, newestRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// fetch record chain
const recordChain = yield ProtocolAuthorization.constructRecordChain(tenant, newestRecordsWrite.message.recordId, messageStore);
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, newestRecordsWrite.message.descriptor.protocol, messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(newestRecordsWrite.message.descriptor.protocolPath, protocolDefinition);
// If the incoming message has `protocolRole` in the descriptor, validate the invoked role
yield ProtocolAuthorization.verifyInvokedRole(tenant, incomingMessage, newestRecordsWrite.message.descriptor.protocol, newestRecordsWrite.message.contextId, protocolDefinition, messageStore);
// verify method invoked against the allowed actions in the rule set
yield ProtocolAuthorization.authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, recordChain, messageStore);
});
}
static authorizeQueryOrSubscribe(tenant, incomingMessage, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const { protocol, protocolPath, contextId } = incomingMessage.message.descriptor.filter;
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, protocol, // `authorizeQueryOrSubscribe` is only called if `protocol` is present
messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(protocolPath, // presence of `protocolPath` is verified in `parse()`
protocolDefinition);
// If the incoming message has `protocolRole` in the descriptor, validate the invoked role
yield ProtocolAuthorization.verifyInvokedRole(tenant, incomingMessage, protocol, contextId, protocolDefinition, messageStore);
// verify method invoked against the allowed actions in the rule set
yield ProtocolAuthorization.authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, [], // record chain is not relevant to queries or subscriptions
messageStore);
});
}
/**
* Performs protocol-based authorization against the incoming `RecordsDelete` message.
* @param newestRecordsWrite The latest `RecordsWrite` associated with the recordId being deleted.
*/
static authorizeDelete(tenant, incomingMessage, newestRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// fetch record chain
const recordChain = yield ProtocolAuthorization.constructRecordChain(tenant, incomingMessage.message.descriptor.recordId, messageStore);
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, newestRecordsWrite.message.descriptor.protocol, messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(newestRecordsWrite.message.descriptor.protocolPath, protocolDefinition);
// If the incoming message has `protocolRole` in the descriptor, validate the invoked role
yield ProtocolAuthorization.verifyInvokedRole(tenant, incomingMessage, newestRecordsWrite.message.descriptor.protocol, newestRecordsWrite.message.contextId, protocolDefinition, messageStore);
// verify method invoked against the allowed actions in the rule set
yield ProtocolAuthorization.authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, recordChain, messageStore);
});
}
/**
* Fetches the protocol definition based on the protocol specified in the given message.
*/
static fetchProtocolDefinition(tenant, protocolUri, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// if first-class protocol, return the definition from const object directly without going to data store
if (protocolUri === PermissionsProtocol.uri) {
return PermissionsProtocol.definition;
}
// fetch the corresponding protocol definition
const query = {
interface: DwnInterfaceName.Protocols,
method: DwnMethodName.Configure,
protocol: protocolUri
};
const { messages: protocols } = yield messageStore.query(tenant, [query]);
if (protocols.length === 0) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationProtocolNotFound, `unable to find protocol definition for ${protocolUri}`);
}
const protocolMessage = protocols[0];
return protocolMessage.descriptor.definition;
});
}
/**
* Constructs the chain of EXISTING records in the datastore where the first record is the root initial `RecordsWrite` of the record chain
* and last record is the initial `RecordsWrite` of the descendant record specified.
* @param descendantRecordId The ID of the descendent record to start constructing the record chain from by repeatedly looking up the parent.
* @returns the record chain where each record is represented by its initial `RecordsWrite`;
* returns empty array if `descendantRecordId` is `undefined`.
* @throws {DwnError} if `descendantRecordId` is defined but any initial `RecordsWrite` is not found in the chain of records.
*/
static constructRecordChain(tenant, descendantRecordId, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (descendantRecordId === undefined) {
return [];
}
const recordChain = [];
// keep walking up the chain from the inbound message's parent, until there is no more parent
let currentRecordId = descendantRecordId;
while (currentRecordId !== undefined) {
const initialWrite = yield ProtocolAuthorization.fetchInitialWrite(tenant, currentRecordId, messageStore);
// RecordsWrite needed should be available since we perform necessary checks at the time of writes,
// eg. check the immediate parent in `verifyProtocolPathAndContextId` at the time of writing,
// so if this condition is triggered, it means there is an unexpected bug that caused an incomplete chain.
// We add additional defensive check here because returning an unexpected/incorrect record chain could lead to security vulnerabilities.
if (initialWrite === undefined) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationParentNotFoundConstructingRecordChain, `Unexpected error that should never trigger: no parent found with ID ${currentRecordId} when constructing record chain.`);
}
recordChain.push(initialWrite);
currentRecordId = initialWrite.descriptor.parentId;
}
return recordChain.reverse(); // root record first
});
}
/**
* Fetches the initial RecordsWrite message associated with the given (tenant + recordId).
*/
static fetchInitialWrite(tenant, recordId, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const query = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
recordId: recordId
};
const { messages } = yield messageStore.query(tenant, [query]);
if (messages.length === 0) {
return undefined;
}
const initialWrite = yield RecordsWrite.getInitialWrite(messages);
return initialWrite;
});
}
/**
* Gets the rule set corresponding to the given protocolPath.
*/
static getRuleSet(protocolPath, protocolDefinition) {
const ruleSet = ProtocolAuthorization.getRuleSetAtProtocolPath(protocolPath, protocolDefinition);
if (ruleSet === undefined) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMissingRuleSet, `No rule set defined for protocolPath ${protocolPath}`);
}
return ruleSet;
}
/**
* Verifies the `protocolPath` declared in the given message (if it is a RecordsWrite) matches the path of actual record chain.
* @throws {DwnError} if fails verification.
*/
static verifyProtocolPathAndContextId(tenant, inboundMessage, messageStore) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const declaredProtocolPath = inboundMessage.message.descriptor.protocolPath;
const declaredTypeName = ProtocolAuthorization.getTypeName(declaredProtocolPath);
const parentId = inboundMessage.message.descriptor.parentId;
if (parentId === undefined) {
if (declaredProtocolPath !== declaredTypeName) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationParentlessIncorrectProtocolPath, `Declared protocol path '${declaredProtocolPath}' is not valid for records with no parent'.`);
}
return;
}
// Else `parentId` is defined, so we need to verify both protocolPath and contextId
// fetch the parent message
const protocol = inboundMessage.message.descriptor.protocol;
const query = {
isLatestBaseState: true,
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
protocol,
recordId: parentId
};
const { messages: parentMessages } = yield messageStore.query(tenant, [query]);
const parentMessage = parentMessages[0];
// verifying protocolPath of incoming message is a child of the parent message's protocolPath
const parentProtocolPath = (_a = parentMessage === null || parentMessage === void 0 ? void 0 : parentMessage.descriptor) === null || _a === void 0 ? void 0 : _a.protocolPath;
const expectedProtocolPath = `${parentProtocolPath}/${declaredTypeName}`;
if (expectedProtocolPath !== declaredProtocolPath) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationIncorrectProtocolPath, `Could not find matching parent record to verify declared protocol path '${declaredProtocolPath}'.`);
}
// verifying contextId of incoming message is a child of the parent message's contextId
const expectedContextId = `${parentMessage.contextId}/${inboundMessage.message.recordId}`;
const actualContextId = inboundMessage.message.contextId;
if (actualContextId !== expectedContextId) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationIncorrectContextId, `Declared contextId '${actualContextId}' is not the same as expected: '${expectedContextId}'.`);
}
});
}
/**
* Verifies the `dataFormat` and `schema` declared in the given message (if it is a RecordsWrite) matches dataFormat
* and schema of the type in the given protocol.
* @throws {DwnError} if fails verification.
*/
static verifyType(inboundMessage, protocolTypes) {
const typeNames = Object.keys(protocolTypes);
const declaredProtocolPath = inboundMessage.descriptor.protocolPath;
const declaredTypeName = ProtocolAuthorization.getTypeName(declaredProtocolPath);
if (!typeNames.includes(declaredTypeName)) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationInvalidType, `record with type ${declaredTypeName} not allowed in protocol`);
}
const protocolPath = inboundMessage.descriptor.protocolPath;
// existence of `protocolType` has already been verified
const typeName = ProtocolAuthorization.getTypeName(protocolPath);
const protocolType = protocolTypes[typeName];
// no `schema` specified in protocol definition means that any schema is allowed
const { schema } = inboundMessage.descriptor;
if (protocolType.schema !== undefined && protocolType.schema !== schema) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationInvalidSchema, `type '${typeName}' must have schema '${protocolType.schema}', \
instead has '${schema}'`);
}
// no `dataFormats` specified in protocol definition means that all dataFormats are allowed
const { dataFormat } = inboundMessage.descriptor;
if (protocolType.dataFormats !== undefined && !protocolType.dataFormats.includes(dataFormat)) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationIncorrectDataFormat, `type '${typeName}' must have data format in (${protocolType.dataFormats}), \
instead has '${dataFormat}'`);
}
}
/**
* Check if the incoming message is invoking a role. If so, validate the invoked role.
*/
static verifyInvokedRole(tenant, incomingMessage, protocolUri, contextId, protocolDefinition, messageStore) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const protocolRole = (_a = incomingMessage.signaturePayload) === null || _a === void 0 ? void 0 : _a.protocolRole;
// Only verify role if there is a role being invoked
if (protocolRole === undefined) {
return;
}
const roleRuleSet = ProtocolAuthorization.getRuleSetAtProtocolPath(protocolRole, protocolDefinition);
if (roleRuleSet === undefined || !roleRuleSet.$role) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationNotARole, `Protocol path ${protocolRole} does not match role record type.`);
}
// Construct a filter to fetch the invoked role record
const roleRecordFilter = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
protocol: protocolUri,
protocolPath: protocolRole,
recipient: incomingMessage.author,
isLatestBaseState: true,
};
const ancestorSegmentCountOfRolePath = protocolRole.split('/').length - 1;
if (contextId === undefined && ancestorSegmentCountOfRolePath > 0) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMissingContextId, 'Could not verify role because contextId is missing.');
}
// Compute `contextId` prefix filter for fetching the invoked role record if the role path is not at the root level.
// e.g. if invoked role path is `Thread/Participant`, and the `contextId` of the message is `threadX/messageY/attachmentZ`,
// then we need to add a prefix filter as `threadX` for the `contextId`
// because the `contextId` of the Participant record would be in the form of be `threadX/participantA`
if (ancestorSegmentCountOfRolePath > 0) {
const contextIdSegments = contextId.split('/'); // NOTE: currently contextId segment count is never shorter than the role path count.
const contextIdPrefix = contextIdSegments.slice(0, ancestorSegmentCountOfRolePath).join('/');
const contextIdPrefixFilter = FilterUtility.constructPrefixFilterAsRangeFilter(contextIdPrefix);
roleRecordFilter.contextId = contextIdPrefixFilter;
}
const { messages: matchingMessages } = yield messageStore.query(tenant, [roleRecordFilter]);
if (matchingMessages.length === 0) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound, `No matching role record found for protocol path ${protocolRole}`);
}
});
}
/**
* Returns all the ProtocolActions that would authorized the incoming message
* (but we still need to later verify if there is a rule defined that matches one of the actions).
* NOTE: the reason why there could be multiple actions is because:
* - In case of an initial RecordsWrite, the RecordsWrite can be authorized by an allow `create` or `write` rule.
* - In case of a non-initial RecordsWrite by the original record author, the RecordsWrite can be authorized by a `write` or `co-update` rule.
*
* It is important to recognize that the `write` access that allowed the original record author to create the record maybe revoked
* (e.g. by role revocation) by the time a "non-initial" write by the same author is attempted.
*/
static getActionsSeekingARuleMatch(tenant, incomingMessage, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
switch (incomingMessage.message.descriptor.method) {
case DwnMethodName.Delete:
const recordsDelete = incomingMessage;
const recordId = recordsDelete.message.descriptor.recordId;
const initialWrite = yield RecordsWrite.fetchInitialRecordsWrite(messageStore, tenant, recordId);
// if there is no initial write, then no action rule can authorize the incoming message, because we won't know who the original author is
// NOTE: purely defensive programming: currently not reachable
// because RecordsDelete handler already have an existence check prior to this method being called.
if (initialWrite === undefined) {
return [];
}
const actionsThatWouldAuthorizeDelete = [];
const prune = recordsDelete.message.descriptor.prune;
if (prune) {
actionsThatWouldAuthorizeDelete.push(ProtocolAction.CoPrune);
// A prune by the original record author can also be authorized by a 'prune' rule.
if (incomingMessage.author === initialWrite.author) {
actionsThatWouldAuthorizeDelete.push(ProtocolAction.Prune);
}
}
else {
actionsThatWouldAuthorizeDelete.push(ProtocolAction.CoDelete);
// A delete by the original record author can also be authorized by a 'delete' rule.
if (incomingMessage.author === initialWrite.author) {
actionsThatWouldAuthorizeDelete.push(ProtocolAction.Delete);
}
}
return actionsThatWouldAuthorizeDelete;
case DwnMethodName.Query:
return [ProtocolAction.Query];
case DwnMethodName.Read:
return [ProtocolAction.Read];
case DwnMethodName.Subscribe:
return [ProtocolAction.Subscribe];
case DwnMethodName.Write:
const incomingRecordsWrite = incomingMessage;
if (yield incomingRecordsWrite.isInitialWrite()) {
return [ProtocolAction.Create];
}
else {
// else incoming RecordsWrite not an initial write
const recordId = incomingMessage.message.recordId;
const initialWrite = yield RecordsWrite.fetchInitialRecordsWrite(messageStore, tenant, recordId);
// if there is no initial write to update from, then no action rule can authorize the incoming message
if (initialWrite === undefined) {
return [];
}
if (incomingMessage.author === initialWrite.author) {
// 'update' or 'co-update' action authorizes the incoming message
return [ProtocolAction.CoUpdate, ProtocolAction.Update];
}
else {
// An update by someone who is not the record author can only be authorized by a 'co-update' rule.
return [ProtocolAction.CoUpdate];
}
}
}
// purely defensive programming: should not be reachable
// setting to empty array will prevent any message from being authorized
return [];
});
}
/**
* Verifies the given message is authorized by one of the action rules in the given protocol rule set.
* @throws {Error} if action not allowed.
*/
static authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, recordChain, messageStore) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const incomingMessageMethod = incomingMessage.message.descriptor.method;
const actionsSeekingARuleMatch = yield ProtocolAuthorization.getActionsSeekingARuleMatch(tenant, incomingMessage, messageStore);
const author = incomingMessage.author;
const actionRules = ruleSet.$actions;
// NOTE: We have already checked that the message is not from tenant, owner, or permission grant authorized prior to this method being called.
if (actionRules === undefined) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationActionRulesNotFound, `no action rule defined for Records${incomingMessageMethod}, ${author} is unauthorized`);
}
const invokedRole = (_a = incomingMessage.signaturePayload) === null || _a === void 0 ? void 0 : _a.protocolRole;
// Iterate through the action rules to find a rule that authorizes the incoming message.
for (const actionRule of actionRules) {
// If the action rule does not have an allowed action that matches an action that can authorize the message, skip to evaluate next action rule.
const ruleHasAMatchingAllowedAction = actionRule.can.some(allowedAction => actionsSeekingARuleMatch.includes(allowedAction));
if (!ruleHasAMatchingAllowedAction) {
continue;
}
// Code reaches here means this action rule has an allowed action that matches the action of the message.
// The remaining code checks the actor/author of the incoming message.
// If the action rule allows `anyone`, then no further checks are needed.
if (actionRule.who === ProtocolActor.Anyone) {
return;
}
// Since not `anyone` is allowed in this action rule, we will need to check the author of the incoming message,
// if the author of incoming message is not defined, this action rule cannot authorize the incoming message.
if (author === undefined) {
continue;
}
// go through role validation path if a role is invoked by the incoming message
if (invokedRole !== undefined) {
// When a protocol role is being invoked, we require that there is a matching `role` rule.
if (actionRule.role === invokedRole) {
// role is successfully invoked
return;
}
else {
continue;
}
}
// else we go through the actor (`who`) validation
// If `of` is not set, handle it as a special case
// NOTE: `of` is always set if `who` is set to `author` (we do this check in `validateRuleSetRecursively()`)
if (actionRule.who === ProtocolActor.Recipient && actionRule.of === undefined) {
// If the action rule specifies a recipient without `of` and the incoming message is authenticated:
// Author must be recipient of the record being accessed
let recordsWriteMessage;
if (incomingMessage.message.descriptor.method === DwnMethodName.Write) {
recordsWriteMessage = incomingMessage.message;
}
else {
// else the incoming message must be a `RecordsDelete` because only `co-update`, `co-delete`, `co-prune` are allowed recipient actions,
// (we do this check in `validateRuleSetRecursively()`)
// and we have already checked that the incoming message is not a `RecordsWrite` above which covers `co-update` path.
recordsWriteMessage = recordChain[recordChain.length - 1];
}
if (recordsWriteMessage.descriptor.recipient === author) {
return;
}
else {
continue;
}
}
// validate the actor is allowed by the current action rule
const ancestorRuleSuccess = yield ProtocolAuthorization.checkActor(author, actionRule, recordChain);
if (ancestorRuleSuccess) {
return;
}
}
// No action rules were satisfied, message is not authorized
throw new DwnError(DwnErrorCode.ProtocolAuthorizationActionNotAllowed, `Inbound message action Records${incomingMessageMethod} by author ${incomingMessage.author} not allowed.`);
});
}
/**
* Verifies that writes adhere to the $size constraints if provided
* @throws {Error} if size is exceeded.
*/
static verifySizeLimit(incomingMessage, ruleSet) {
const { min = 0, max } = ruleSet.$size || {};
const dataSize = incomingMessage.message.descriptor.dataSize;
if (dataSize < min) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMinSizeInvalid, `data size ${dataSize} is less than allowed ${min}`);
}
if (max === undefined) {
return;
}
if (dataSize > max) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMaxSizeInvalid, `data size ${dataSize} is more than allowed ${max}`);
}
}
static verifyTagsIfNeeded(incomingMessage, ruleSet) {
if (ruleSet.$tags !== undefined) {
const { tags = {}, protocol, protocolPath } = incomingMessage.message.descriptor;
const _a = ruleSet.$tags, { $allowUndefinedTags, $requiredTags } = _a, properties = __rest(_a, ["$allowUndefinedTags", "$requiredTags"]);
// if $allowUndefinedTags is set to false and there are properties not defined in the schema, an error is thrown
const additionalProperties = $allowUndefinedTags || false;
// if $requiredTags is set, all required tags must be present
const required = $requiredTags || [];
const ajv = new Ajv.default();
const compiledTags = ajv.compile({
type: 'object',
properties,
required,
additionalProperties,
});
const validSchema = compiledTags(tags);
if (!validSchema) {
// the `dataVar` is used to add a qualifier to the error message.
// For example. If the error is related to a tag `status` in a protocol `https://example.protocol` with the protocolPath `example/path`
// the error would be described as `https://example.protocol/example/path/$tags/status'
// without this decorator it would show up as `data/status` which may be confusing.
const schemaError = ajv.errorsText(compiledTags.errors, { dataVar: `${protocol}/${protocolPath}/$tags` });
throw new DwnError(DwnErrorCode.ProtocolAuthorizationTagsInvalidSchema, `tags schema validation error: ${schemaError}`);
}
}
}
/**
* If the given RecordsWrite is not a role record, this method does nothing and succeeds immediately.
*
* Else it verifies the validity of the given `RecordsWrite` as a role record, including:
* 1. The same role has not been assigned to the same entity/recipient.
*/
static verifyAsRoleRecordIfNeeded(tenant, incomingMessage, ruleSet, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (!ruleSet.$role) {
return;
}
// else this is a role record
const incomingRecordsWrite = incomingMessage;
const recipient = incomingRecordsWrite.message.descriptor.recipient;
if (recipient === undefined) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationRoleMissingRecipient, 'Role records must have a recipient');
}
const protocolPath = incomingRecordsWrite.message.descriptor.protocolPath;
const filter = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
isLatestBaseState: true,
protocol: incomingRecordsWrite.message.descriptor.protocol,
protocolPath,
recipient,
};
const parentContextId = Records.getParentContextFromOfContextId(incomingRecordsWrite.message.contextId);
// if this is not the root record, add a prefix filter to the query
if (parentContextId !== '') {
const prefixFilter = FilterUtility.constructPrefixFilterAsRangeFilter(parentContextId);
filter.contextId = prefixFilter;
}
const { messages: matchingMessages } = yield messageStore.query(tenant, [filter]);
const matchingRecords = matchingMessages;
const matchingRecordsExceptIncomingRecordId = matchingRecords.filter((recordsWriteMessage) => recordsWriteMessage.recordId !== incomingRecordsWrite.message.recordId);
if (matchingRecordsExceptIncomingRecordId.length > 0) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationDuplicateRoleRecipient, `DID '${recipient}' is already recipient of a role record at protocol path '${protocolPath} under the parent context ${parentContextId}.`);
}
});
}
static getRuleSetAtProtocolPath(protocolPath, protocolDefinition) {
const protocolPathArray = protocolPath.split('/');
let currentRuleSet = protocolDefinition.structure;
let i = 0;
while (i < protocolPathArray.length) {
const currentTypeName = protocolPathArray[i];
const nextRuleSet = currentRuleSet[currentTypeName];
if (nextRuleSet === undefined) {
return undefined;
}
currentRuleSet = nextRuleSet;
i++;
}
return currentRuleSet;
}
/**
* Checks if the `who: 'author' | 'recipient'` action rule has a matching record in the record chain.
* @returns `true` if the action rule is satisfied; `false` otherwise.
*/
static checkActor(author, actionRule, recordChain) {
return __awaiter(this, void 0, void 0, function* () {
// find a message with matching protocolPath
const ancestorRecordsWrite = recordChain.find((recordsWriteMessage) => recordsWriteMessage.descriptor.protocolPath === actionRule.of);
if (ancestorRecordsWrite === undefined) {
// If this is reached, there is likely an issue with the protocol definition.
// The protocolPath to the actionRule should start with actionRule.of
// consider moving this check to ProtocolsConfigure message ingestion
return false;
}
if (actionRule.who === ProtocolActor.Recipient) {
// author of the incoming message must be the recipient of the ancestor message
return author === ancestorRecordsWrite.descriptor.recipient;
}
else { // actionRule.who === ProtocolActor.Author
// author of the incoming message must be the author of the ancestor message
const ancestorAuthor = (yield RecordsWrite.parse(ancestorRecordsWrite)).author;
return author === ancestorAuthor;
}
});
}
static getTypeName(protocolPath) {
return protocolPath.split('/').slice(-1)[0];
}
}
//# sourceMappingURL=protocol-authorization.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,170 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { GrantAuthorization } from './grant-authorization.js';
import { PermissionConditionPublication } from '../types/permission-types.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
export class RecordsGrantAuthorization {
/**
* Authorizes the given RecordsWrite in the scope of the DID given.
*/
static authorizeWrite(input) {
return __awaiter(this, void 0, void 0, function* () {
const { recordsWriteMessage, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
yield GrantAuthorization.performBaseValidation({
incomingMessage: recordsWriteMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});
// NOTE: validated the invoked permission is for Records in GrantAuthorization.performBaseValidation()
RecordsGrantAuthorization.verifyScope(recordsWriteMessage, permissionGrant.scope);
RecordsGrantAuthorization.verifyConditions(recordsWriteMessage, permissionGrant.conditions);
});
}
/**
* Authorizes a RecordsReadMessage using the given permission grant.
* @param messageStore Used to check if the given grant has been revoked.
*/
static authorizeRead(input) {
return __awaiter(this, void 0, void 0, function* () {
const { recordsReadMessage, recordsWriteMessageToBeRead, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
yield GrantAuthorization.performBaseValidation({
incomingMessage: recordsReadMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});
// NOTE: validated the invoked permission is for Records in GrantAuthorization.performBaseValidation()
RecordsGrantAuthorization.verifyScope(recordsWriteMessageToBeRead, permissionGrant.scope);
});
}
/**
* Authorizes the scope of a permission grant for RecordsQuery or RecordsSubscribe.
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeQueryOrSubscribe(input) {
return __awaiter(this, void 0, void 0, function* () {
const { incomingMessage, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
yield GrantAuthorization.performBaseValidation({
incomingMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});
// If the grant specifies a protocol, the subscribe or query must specify the same protocol.
// NOTE: validated the invoked permission is for Records in GrantAuthorization.performBaseValidation()
const permissionScope = permissionGrant.scope;
const protocolInGrant = permissionScope.protocol;
const protocolInMessage = incomingMessage.descriptor.filter.protocol;
if (protocolInGrant !== undefined && protocolInMessage !== protocolInGrant) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationQueryOrSubscribeProtocolScopeMismatch, `Grant protocol scope ${protocolInGrant} does not match protocol in message ${protocolInMessage}`);
}
});
}
/**
* Authorizes the scope of a permission grant for RecordsDelete.
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeDelete(input) {
return __awaiter(this, void 0, void 0, function* () {
const { recordsDeleteMessage, recordsWriteToDelete, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
yield GrantAuthorization.performBaseValidation({
incomingMessage: recordsDeleteMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});
// If the grant specifies a protocol, the delete must be deleting a record with the same protocol.
// NOTE: validated the invoked permission is for Records in GrantAuthorization.performBaseValidation()
const permissionScope = permissionGrant.scope;
const protocolInGrant = permissionScope.protocol;
const protocolOfRecordToDelete = recordsWriteToDelete.descriptor.protocol;
if (protocolInGrant !== undefined && protocolOfRecordToDelete !== protocolInGrant) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationDeleteProtocolScopeMismatch, `Grant protocol scope ${protocolInGrant} does not match protocol in record to delete ${protocolOfRecordToDelete}`);
}
});
}
/**
* Verifies the given record against the scope of the given grant.
*/
static verifyScope(recordsWriteMessage, grantScope) {
if (RecordsGrantAuthorization.isUnrestrictedScope(grantScope)) {
// scope has no restrictions beyond interface and method. Message is authorized to access any record.
return;
}
else if (recordsWriteMessage.descriptor.protocol !== undefined) {
// authorization of protocol records must have grants that explicitly include the protocol
RecordsGrantAuthorization.verifyProtocolRecordScope(recordsWriteMessage, grantScope);
}
else {
RecordsGrantAuthorization.verifyFlatRecordScope(recordsWriteMessage, grantScope);
}
}
/**
* Verifies a protocol record against the scope of the given grant.
*/
static verifyProtocolRecordScope(recordsWriteMessage, grantScope) {
// Protocol records must have grants specifying the protocol
if (grantScope.protocol === undefined) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeMissingProtocol, 'Grant for protocol record must specify protocol in its scope');
}
// The record's protocol must match the protocol specified in the record
if (grantScope.protocol !== recordsWriteMessage.descriptor.protocol) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolMismatch, `Grant scope specifies different protocol than what appears in the record`);
}
// If grant specifies a contextId, check that record falls under that contextId
if (grantScope.contextId !== undefined) {
if (recordsWriteMessage.contextId === undefined || !recordsWriteMessage.contextId.startsWith(grantScope.contextId)) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeContextIdMismatch, `Grant scope specifies different contextId than what appears in the record`);
}
}
// If grant specifies protocolPath, check that record is at that protocolPath
if (grantScope.protocolPath !== undefined && grantScope.protocolPath !== recordsWriteMessage.descriptor.protocolPath) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolPathMismatch, `Grant scope specifies different protocolPath than what appears in the record`);
}
}
/**
* Verifies a non-protocol record against the scope of the given grant.
*/
static verifyFlatRecordScope(recordsWriteMessage, grantScope) {
if (grantScope.schema !== undefined) {
if (grantScope.schema !== recordsWriteMessage.descriptor.schema) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeSchema, `Record does not have schema in permission grant scope with schema '${grantScope.schema}'`);
}
}
}
/**
* Verifies grant `conditions`.
* Currently the only condition is `published` which only applies to RecordsWrites
*/
static verifyConditions(recordsWriteMessage, conditions) {
// If conditions require publication, RecordsWrite must have `published` === true
if ((conditions === null || conditions === void 0 ? void 0 : conditions.publication) === PermissionConditionPublication.Required && !recordsWriteMessage.descriptor.published) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationConditionPublicationRequired, 'Permission grant requires message to be published');
}
// if conditions prohibit publication, RecordsWrite must have published === false or undefined
if ((conditions === null || conditions === void 0 ? void 0 : conditions.publication) === PermissionConditionPublication.Prohibited && recordsWriteMessage.descriptor.published) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationConditionPublicationProhibited, 'Permission grant prohibits message from being published');
}
}
/**
* Checks if scope has no restrictions beyond interface and method.
* Grant-holder is authorized to access any record.
*/
static isUnrestrictedScope(grantScope) {
return grantScope.protocol === undefined &&
grantScope.schema === undefined;
}
}
//# sourceMappingURL=records-grant-authorization.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-grant-authorization.js","sourceRoot":"","sources":["../../../../src/core/records-grant-authorization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* A tenant gate that treats every DID as an active tenant.
*/
export class AllowAllTenantGate {
isActiveTenant(_did) {
return __awaiter(this, void 0, void 0, function* () {
return { isActiveTenant: true };
});
}
}
//# sourceMappingURL=tenant-gate.js.map
@@ -0,0 +1 @@
{"version":3,"file":"tenant-gate.js","sourceRoot":"","sources":["../../../../src/core/tenant-gate.ts"],"names":[],"mappings":";;;;;;;;;AAyBA;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAChB,cAAc,CAAC,IAAY;;YACtC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;QAClC,CAAC;KAAA;CACF"}
@@ -0,0 +1,150 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AllowAllTenantGate } from './core/tenant-gate.js';
import { EventsGetHandler } from './handlers/events-get.js';
import { EventsQueryHandler } from './handlers/events-query.js';
import { EventsSubscribeHandler } from './handlers/events-subscribe.js';
import { Message } from './core/message.js';
import { messageReplyFromError } from './core/message-reply.js';
import { MessagesGetHandler } from './handlers/messages-get.js';
import { ProtocolsConfigureHandler } from './handlers/protocols-configure.js';
import { ProtocolsQueryHandler } from './handlers/protocols-query.js';
import { RecordsDeleteHandler } from './handlers/records-delete.js';
import { RecordsQueryHandler } from './handlers/records-query.js';
import { RecordsReadHandler } from './handlers/records-read.js';
import { RecordsSubscribeHandler } from './handlers/records-subscribe.js';
import { RecordsWriteHandler } from './handlers/records-write.js';
import { DidDht, DidIon, DidKey, DidResolverCacheLevel, UniversalResolver } from '@web5/dids';
import { DwnInterfaceName, DwnMethodName } from './enums/dwn-interface-method.js';
export class Dwn {
constructor(config) {
this.didResolver = config.didResolver;
this.tenantGate = config.tenantGate;
this.eventStream = config.eventStream;
this.messageStore = config.messageStore;
this.dataStore = config.dataStore;
this.eventLog = config.eventLog;
this.eventStream = config.eventStream;
this.methodHandlers = {
[DwnInterfaceName.Events + DwnMethodName.Get]: new EventsGetHandler(this.didResolver, this.eventLog),
[DwnInterfaceName.Events + DwnMethodName.Query]: new EventsQueryHandler(this.didResolver, this.eventLog),
[DwnInterfaceName.Events + DwnMethodName.Subscribe]: new EventsSubscribeHandler(this.didResolver, this.eventStream),
[DwnInterfaceName.Messages + DwnMethodName.Get]: new MessagesGetHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Protocols + DwnMethodName.Configure]: new ProtocolsConfigureHandler(this.didResolver, this.messageStore, this.eventLog, this.eventStream),
[DwnInterfaceName.Protocols + DwnMethodName.Query]: new ProtocolsQueryHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Records + DwnMethodName.Delete]: new RecordsDeleteHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog, this.eventStream),
[DwnInterfaceName.Records + DwnMethodName.Query]: new RecordsQueryHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Records + DwnMethodName.Read]: new RecordsReadHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Records + DwnMethodName.Subscribe]: new RecordsSubscribeHandler(this.didResolver, this.messageStore, this.eventStream),
[DwnInterfaceName.Records + DwnMethodName.Write]: new RecordsWriteHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog, this.eventStream)
};
}
/**
* Creates an instance of the DWN.
*/
static create(config) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
(_a = config.didResolver) !== null && _a !== void 0 ? _a : (config.didResolver = new UniversalResolver({
didResolvers: [DidDht, DidIon, DidKey],
cache: new DidResolverCacheLevel({ location: 'RESOLVERCACHE' }),
}));
(_b = config.tenantGate) !== null && _b !== void 0 ? _b : (config.tenantGate = new AllowAllTenantGate());
const dwn = new Dwn(config);
yield dwn.open();
return dwn;
});
}
open() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
yield this.messageStore.open();
yield this.dataStore.open();
yield this.eventLog.open();
yield ((_a = this.eventStream) === null || _a === void 0 ? void 0 : _a.open());
});
}
close() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
yield ((_a = this.eventStream) === null || _a === void 0 ? void 0 : _a.close());
yield this.messageStore.close();
yield this.dataStore.close();
yield this.eventLog.close();
});
}
processMessage(tenant, rawMessage, options = {}) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const errorMessageReply = (_a = yield this.validateTenant(tenant)) !== null && _a !== void 0 ? _a : yield this.validateMessageIntegrity(rawMessage);
if (errorMessageReply !== undefined) {
return errorMessageReply;
}
const { dataStream, subscriptionHandler } = options;
const handlerKey = rawMessage.descriptor.interface + rawMessage.descriptor.method;
const methodHandlerReply = yield this.methodHandlers[handlerKey].handle({
tenant,
message: rawMessage,
dataStream,
subscriptionHandler
});
return methodHandlerReply;
});
}
/**
* Checks tenant gate to see if tenant is allowed.
* @param tenant The tenant DID to route the given message to.
* @returns GenericMessageReply if the message has an integrity error, otherwise undefined.
*/
validateTenant(tenant) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const result = yield this.tenantGate.isActiveTenant(tenant);
if (!result.isActiveTenant) {
const detail = (_a = result.detail) !== null && _a !== void 0 ? _a : `DID ${tenant} is not an active tenant.`;
return {
status: { code: 401, detail }
};
}
});
}
/**
* Validates structure of DWN message
* @param tenant The tenant DID to route the given message to.
* @param dwnMessageInterface The interface of DWN message.
* @param dwnMessageMethod The interface of DWN message.
* @returns GenericMessageReply if the message has an integrity error, otherwise undefined.
*/
validateMessageIntegrity(rawMessage) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
// Verify interface and method
const dwnInterface = (_a = rawMessage === null || rawMessage === void 0 ? void 0 : rawMessage.descriptor) === null || _a === void 0 ? void 0 : _a.interface;
const dwnMethod = (_b = rawMessage === null || rawMessage === void 0 ? void 0 : rawMessage.descriptor) === null || _b === void 0 ? void 0 : _b.method;
if (dwnInterface === undefined || dwnMethod === undefined) {
return {
status: { code: 400, detail: `Both interface and method must be present, interface: ${dwnInterface}, method: ${dwnMethod}` }
};
}
// validate message structure
try {
// consider to push this down to individual handlers
Message.validateJsonSchema(rawMessage);
}
catch (error) {
return messageReplyFromError(error, 400);
}
});
}
}
;
;
//# sourceMappingURL=dwn.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
export var DwnInterfaceName;
(function (DwnInterfaceName) {
DwnInterfaceName["Events"] = "Events";
DwnInterfaceName["Messages"] = "Messages";
DwnInterfaceName["Protocols"] = "Protocols";
DwnInterfaceName["Records"] = "Records";
})(DwnInterfaceName || (DwnInterfaceName = {}));
export var DwnMethodName;
(function (DwnMethodName) {
DwnMethodName["Configure"] = "Configure";
DwnMethodName["Create"] = "Create";
DwnMethodName["Get"] = "Get";
DwnMethodName["Grant"] = "Grant";
DwnMethodName["Query"] = "Query";
DwnMethodName["Read"] = "Read";
DwnMethodName["Request"] = "Request";
DwnMethodName["Revoke"] = "Revoke";
DwnMethodName["Write"] = "Write";
DwnMethodName["Delete"] = "Delete";
DwnMethodName["Subscribe"] = "Subscribe";
})(DwnMethodName || (DwnMethodName = {}));
//# sourceMappingURL=dwn-interface-method.js.map
@@ -0,0 +1 @@
{"version":3,"file":"dwn-interface-method.js","sourceRoot":"","sources":["../../../../src/enums/dwn-interface-method.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,gBAKX;AALD,WAAY,gBAAgB;IAC1B,qCAAiB,CAAA;IACjB,yCAAqB,CAAA;IACrB,2CAAuB,CAAA;IACvB,uCAAmB,CAAA;AACrB,CAAC,EALW,gBAAgB,KAAhB,gBAAgB,QAK3B;AAED,MAAM,CAAN,IAAY,aAYX;AAZD,WAAY,aAAa;IACvB,wCAAuB,CAAA;IACvB,kCAAiB,CAAA;IACjB,4BAAW,CAAA;IACX,gCAAe,CAAA;IACf,gCAAe,CAAA;IACf,8BAAa,CAAA;IACb,oCAAmB,CAAA;IACnB,kCAAiB,CAAA;IACjB,gCAAe,CAAA;IACf,kCAAiB,CAAA;IACjB,wCAAuB,CAAA;AACzB,CAAC,EAZW,aAAa,KAAb,aAAa,QAYxB"}
@@ -0,0 +1,60 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { EventEmitter } from 'events';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
const EVENTS_LISTENER_CHANNEL = 'events';
;
export class EventEmitterStream {
constructor(config = {}) {
this.isOpen = false;
/**
* we subscribe to the `EventEmitter` error handler with a provided handler or set one which logs the errors.
*/
this.errorHandler = (error) => { console.error('event emitter error', error); };
// we capture the rejections and currently just log the errors that are produced
this.eventEmitter = new EventEmitter({ captureRejections: true });
// number of listeners per particular eventName before a warning is emitted
// we set to 0 which represents infinity.
// https://nodejs.org/api/events.html#emittersetmaxlistenersn
this.eventEmitter.setMaxListeners(0);
if (config.errorHandler) {
this.errorHandler = config.errorHandler;
}
this.eventEmitter.on('error', this.errorHandler);
}
subscribe(tenant, id, listener) {
return __awaiter(this, void 0, void 0, function* () {
this.eventEmitter.on(`${tenant}_${EVENTS_LISTENER_CHANNEL}`, listener);
return {
id,
close: () => __awaiter(this, void 0, void 0, function* () { this.eventEmitter.off(`${tenant}_${EVENTS_LISTENER_CHANNEL}`, listener); })
};
});
}
open() {
return __awaiter(this, void 0, void 0, function* () {
this.isOpen = true;
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
this.isOpen = false;
this.eventEmitter.removeAllListeners();
});
}
emit(tenant, event, indexes) {
if (!this.isOpen) {
this.errorHandler(new DwnError(DwnErrorCode.EventEmitterStreamNotOpenError, 'a message emitted when EventEmitterStream is closed'));
return;
}
this.eventEmitter.emit(`${tenant}_${EVENTS_LISTENER_CHANNEL}`, tenant, event, indexes);
}
}
//# sourceMappingURL=event-emitter-stream.js.map
@@ -0,0 +1 @@
{"version":3,"file":"event-emitter-stream.js","sourceRoot":"","sources":["../../../../src/event-log/event-emitter-stream.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAQxC,CAAC;AAEF,MAAM,OAAO,kBAAkB;IAI7B,YAAY,SAAmC,EAAE;QAFzC,WAAM,GAAY,KAAK,CAAC;QAkBhC;;WAEG;QACK,iBAAY,GAAwB,CAAC,KAAK,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAlBtG,gFAAgF;QAChF,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;QAElE,2EAA2E;QAC3E,yCAAyC;QACzC,6DAA6D;QAC7D,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAErC,IAAI,MAAM,CAAC,YAAY,EAAE;YACvB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;SACzC;QAED,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,CAAC;IAOK,SAAS,CAAC,MAAc,EAAE,EAAU,EAAE,QAAuB;;YACjE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,uBAAuB,EAAE,EAAE,QAAQ,CAAC,CAAC;YACvE,OAAO;gBACL,EAAE;gBACF,KAAK,EAAE,GAAwB,EAAE,gDAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,uBAAuB,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;aAC/G,CAAC;QACJ,CAAC;KAAA;IAEK,IAAI;;YACR,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;KAAA;IAEK,KAAK;;YACT,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;YACpB,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;QACzC,CAAC;KAAA;IAED,IAAI,CAAC,MAAc,EAAE,KAAmB,EAAE,OAAkB;QAC1D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAChB,IAAI,CAAC,YAAY,CAAC,IAAI,QAAQ,CAC5B,YAAY,CAAC,8BAA8B,EAC3C,qDAAqD,CACtD,CAAC,CAAC;YACH,OAAO;SACR;QACD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,uBAAuB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACzF,CAAC;CACF"}
@@ -0,0 +1,63 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { createLevelDatabase } from '../store/level-wrapper.js';
import { IndexLevel } from '../store/index-level.js';
import { monotonicFactory } from 'ulidx';
export class EventLogLevel {
constructor(config) {
this.index = new IndexLevel(Object.assign({ location: 'EVENTLOG', createLevelDatabase }, config));
this.ulidFactory = monotonicFactory();
}
open() {
return __awaiter(this, void 0, void 0, function* () {
return this.index.open();
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
return this.index.close();
});
}
clear() {
return __awaiter(this, void 0, void 0, function* () {
return this.index.clear();
});
}
append(tenant, messageCid, indexes) {
return __awaiter(this, void 0, void 0, function* () {
const watermark = this.ulidFactory();
yield this.index.put(tenant, messageCid, Object.assign(Object.assign({}, indexes), { watermark }));
});
}
queryEvents(tenant, filters, cursor) {
return __awaiter(this, void 0, void 0, function* () {
const results = yield this.index.query(tenant, filters, { sortProperty: 'watermark', cursor });
return {
events: results.map(({ messageCid }) => messageCid),
cursor: IndexLevel.createCursorFromLastArrayItem(results, 'watermark'),
};
});
}
getEvents(tenant, cursor) {
return __awaiter(this, void 0, void 0, function* () {
return this.queryEvents(tenant, [], cursor);
});
}
deleteEventsByCid(tenant, messageCids) {
return __awaiter(this, void 0, void 0, function* () {
const indexDeletePromises = [];
for (const messageCid of messageCids) {
indexDeletePromises.push(this.index.delete(tenant, messageCid));
}
yield Promise.all(indexDeletePromises);
});
}
}
//# sourceMappingURL=event-log-level.js.map
@@ -0,0 +1 @@
{"version":3,"file":"event-log-level.js","sourceRoot":"","sources":["../../../../src/event-log/event-log-level.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAazC,MAAM,OAAO,aAAa;IAIxB,YAAY,MAA4B;QACtC,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,iBACzB,QAAQ,EAAE,UAAU,EACpB,mBAAmB,IAChB,MAAM,EACT,CAAC;QAEH,IAAI,CAAC,WAAW,GAAG,gBAAgB,EAAE,CAAC;IACxC,CAAC;IAEK,IAAI;;YACR,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC3B,CAAC;KAAA;IAEK,KAAK;;YACT,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;KAAA;IAEK,KAAK;;YACT,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;KAAA;IAEK,MAAM,CAAC,MAAc,EAAE,UAAkB,EAAE,OAAkB;;YACjE,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,kCAAO,OAAO,KAAE,SAAS,IAAG,CAAC;QACtE,CAAC;KAAA;IAEK,WAAW,CAAC,MAAc,EAAE,OAAiB,EAAE,MAAyB;;YAC5E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/F,OAAO;gBACL,MAAM,EAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC;gBACpD,MAAM,EAAG,UAAU,CAAC,6BAA6B,CAAC,OAAO,EAAE,WAAW,CAAC;aACxE,CAAC;QACJ,CAAC;KAAA;IAEK,SAAS,CAAC,MAAc,EAAE,MAAyB;;YACvD,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;KAAA;IAEK,iBAAiB,CAAC,MAAc,EAAE,WAA0B;;YAChE,MAAM,mBAAmB,GAAoB,EAAE,CAAC;YAChD,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;gBACpC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;aACjE;YAED,MAAM,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACzC,CAAC;KAAA;CACF"}
@@ -0,0 +1,46 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { EventsGet } from '../interfaces/events-get.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
export class EventsGetHandler {
constructor(didResolver, eventLog) {
this.didResolver = didResolver;
this.eventLog = eventLog;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let eventsGet;
try {
eventsGet = yield EventsGet.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, eventsGet);
}
catch (e) {
return messageReplyFromError(e, 401);
}
// if a cursor was provided in message, get all events _after_ the cursor.
// Otherwise, get all events.
const { cursor: queryCursor } = message.descriptor;
const { events, cursor } = yield this.eventLog.getEvents(tenant, queryCursor);
return {
status: { code: 200, detail: 'OK' },
entries: events,
cursor
};
});
}
}
//# sourceMappingURL=events-get.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-get.js","sourceRoot":"","sources":["../../../../src/handlers/events-get.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAI/D,MAAM,OAAO,gBAAgB;IAC3B,YAAoB,WAAwB,EAAU,QAAkB;QAApD,gBAAW,GAAX,WAAW,CAAa;QAAU,aAAQ,GAAR,QAAQ,CAAU;IAAG,CAAC;IAE/D,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAc;;YACjD,IAAI,SAAoB,CAAC;YAEzB,IAAI;gBACF,SAAS,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAC5C;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;aACzC;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,0EAA0E;YAC1E,6BAA6B;YAC7B,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;YACnD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAE9E,OAAO;gBACL,MAAM,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAG,MAAM;gBAChB,MAAM;aACP,CAAC;QACJ,CAAC;KAAA;CACF"}
@@ -0,0 +1,45 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Events } from '../utils/events.js';
import { EventsQuery } from '../interfaces/events-query.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
export class EventsQueryHandler {
constructor(didResolver, eventLog) {
this.didResolver = didResolver;
this.eventLog = eventLog;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let eventsQuery;
try {
eventsQuery = yield EventsQuery.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, eventsQuery);
}
catch (e) {
return messageReplyFromError(e, 401);
}
const eventFilters = Events.convertFilters(message.descriptor.filters);
const { events, cursor } = yield this.eventLog.queryEvents(tenant, eventFilters, message.descriptor.cursor);
return {
status: { code: 200, detail: 'OK' },
entries: events,
cursor
};
});
}
}
//# sourceMappingURL=events-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-query.js","sourceRoot":"","sources":["../../../../src/handlers/events-query.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG/D,MAAM,OAAO,kBAAkB;IAE7B,YAAoB,WAAwB,EAAU,QAAkB;QAApD,gBAAW,GAAX,WAAW,CAAa;QAAU,aAAQ,GAAR,QAAQ,CAAU;IAAI,CAAC;IAEhE,MAAM,CAAC,EAClB,MAAM,EACN,OAAO,EACuC;;YAC9C,IAAI,WAAwB,CAAC;YAE7B,IAAI;gBACF,WAAW,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAChD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;aAC3C;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACvE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAE5G,OAAO;gBACL,MAAM,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAG,MAAM;gBAChB,MAAM;aACP,CAAC;QACJ,CAAC;KAAA;CACF"}
@@ -0,0 +1,57 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Events } from '../utils/events.js';
import { EventsSubscribe } from '../interfaces/events-subscribe.js';
import { FilterUtility } from '../utils/filter.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
export class EventsSubscribeHandler {
constructor(didResolver, eventStream) {
this.didResolver = didResolver;
this.eventStream = eventStream;
}
handle({ tenant, message, subscriptionHandler }) {
return __awaiter(this, void 0, void 0, function* () {
if (this.eventStream === undefined) {
return messageReplyFromError(new DwnError(DwnErrorCode.EventsSubscribeEventStreamUnimplemented, 'Subscriptions are not supported'), 501);
}
let eventsSubscribe;
try {
eventsSubscribe = yield EventsSubscribe.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, eventsSubscribe);
}
catch (error) {
return messageReplyFromError(error, 401);
}
const { filters } = message.descriptor;
const eventsFilters = Events.convertFilters(filters);
const messageCid = yield Message.getCid(message);
const listener = (eventTenant, event, eventIndexes) => {
if (tenant === eventTenant && FilterUtility.matchAnyFilter(eventIndexes, eventsFilters)) {
subscriptionHandler(event);
}
};
const subscription = yield this.eventStream.subscribe(tenant, messageCid, listener);
return {
status: { code: 200, detail: 'OK' },
subscription,
};
});
}
}
//# sourceMappingURL=events-subscribe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-subscribe.js","sourceRoot":"","sources":["../../../../src/handlers/events-subscribe.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,OAAO,sBAAsB;IACjC,YACU,WAAwB,EACxB,WAAyB;QADzB,gBAAW,GAAX,WAAW,CAAa;QACxB,gBAAW,GAAX,WAAW,CAAc;IAChC,CAAC;IAES,MAAM,CAAC,EAClB,MAAM,EACN,OAAO,EACP,mBAAmB,EAKpB;;YACC,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE;gBAClC,OAAO,qBAAqB,CAAC,IAAI,QAAQ,CACvC,YAAY,CAAC,uCAAuC,EACpD,iCAAiC,CAClC,EAAE,GAAG,CAAC,CAAC;aACT;YAED,IAAI,eAAgC,CAAC;YACrC,IAAI;gBACF,eAAe,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aACxD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;aAC/C;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;aAC1C;YAED,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;YACvC,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAEjD,MAAM,QAAQ,GAAkB,CAAC,WAAW,EAAE,KAAK,EAAE,YAAY,EAAO,EAAE;gBACxE,IAAI,MAAM,KAAK,WAAW,IAAI,aAAa,CAAC,cAAc,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE;oBACvF,mBAAmB,CAAC,KAAK,CAAC,CAAC;iBAC5B;YACH,CAAC,CAAC;YAEF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YAEpF,OAAO;gBACL,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACnC,YAAY;aACb,CAAC;QACJ,CAAC;KAAA;CACF"}
@@ -0,0 +1,76 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { messageReplyFromError } from '../core/message-reply.js';
import { MessagesGet } from '../interfaces/messages-get.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class MessagesGetHandler {
constructor(didResolver, messageStore, dataStore) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let messagesGet;
try {
messagesGet = yield MessagesGet.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, messagesGet);
}
catch (e) {
return messageReplyFromError(e, 401);
}
const promises = [];
const messageCids = new Set(message.descriptor.messageCids);
for (const messageCid of messageCids) {
const promise = this.messageStore.get(tenant, messageCid)
.then(message => {
return { messageCid, message };
})
.catch(_ => {
return { messageCid, message: undefined, error: `Failed to get message ${messageCid}` };
});
promises.push(promise);
}
const messages = yield Promise.all(promises);
// for every message, include associated data as `encodedData` IF:
// * its a RecordsWrite
// * the data size is equal or smaller than the size threshold
for (const entry of messages) {
const { message } = entry;
if (!message) {
continue;
}
const { interface: messageInterface, method } = message.descriptor;
if (messageInterface !== DwnInterfaceName.Records || method !== DwnMethodName.Write) {
continue;
}
// RecordsWrite specific handling, if MessageStore has embedded `encodedData` return it with the entry.
// we store `encodedData` along with the message if the data is below a certain threshold.
const recordsWrite = message;
if (recordsWrite.encodedData !== undefined) {
entry.encodedData = recordsWrite.encodedData;
delete recordsWrite.encodedData;
}
}
return {
status: { code: 200, detail: 'OK' },
entries: messages
};
});
}
}
//# sourceMappingURL=messages-get.js.map
@@ -0,0 +1 @@
{"version":3,"file":"messages-get.js","sourceRoot":"","sources":["../../../../src/handlers/messages-get.ts"],"names":[],"mappings":";;;;;;;;;AAOA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAInF,MAAM,OAAO,kBAAkB;IAC7B,YAAoB,WAAwB,EAAU,YAA0B,EAAU,SAAoB;QAA1F,gBAAW,GAAX,WAAW,CAAa;QAAU,iBAAY,GAAZ,YAAY,CAAc;QAAU,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAErG,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAc;;YACjD,IAAI,WAAwB,CAAC;YAE7B,IAAI;gBACF,WAAW,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAChD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;aAC3C;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,MAAM,QAAQ,GAAqC,EAAE,CAAC;YACtD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAE5D,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;gBACpC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;qBACtD,IAAI,CAAC,OAAO,CAAC,EAAE;oBACd,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;gBACjC,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,CAAC,EAAE;oBACT,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,yBAAyB,UAAU,EAAE,EAAE,CAAC;gBAC1F,CAAC,CAAC,CAAC;gBAEL,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aACxB;YAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAE7C,kEAAkE;YAClE,wBAAwB;YACxB,+DAA+D;YAC/D,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE;gBAC5B,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;gBAE1B,IAAI,CAAC,OAAO,EAAE;oBACZ,SAAS;iBACV;gBAED,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;gBACnE,IAAI,gBAAgB,KAAK,gBAAgB,CAAC,OAAO,IAAI,MAAM,KAAK,aAAa,CAAC,KAAK,EAAE;oBACnF,SAAS;iBACV;gBAED,uGAAuG;gBACvG,0FAA0F;gBAC1F,MAAM,YAAY,GAAG,OAAiC,CAAC;gBACvD,IAAI,YAAY,CAAC,WAAW,KAAK,SAAS,EAAE;oBAC1C,KAAK,CAAC,WAAW,GAAG,YAAY,CAAC,WAAW,CAAC;oBAC7C,OAAO,YAAY,CAAC,WAAW,CAAC;iBACjC;aACF;YAED,OAAO;gBACL,MAAM,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAG,QAAQ;aACnB,CAAC;QACJ,CAAC;KAAA;CACF"}
@@ -0,0 +1,107 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolsConfigure } from '../interfaces/protocols-configure.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class ProtocolsConfigureHandler {
constructor(didResolver, messageStore, eventLog, eventStream) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.eventLog = eventLog;
this.eventStream = eventStream;
}
handle({ tenant, message, }) {
return __awaiter(this, void 0, void 0, function* () {
let protocolsConfigure;
try {
protocolsConfigure = yield ProtocolsConfigure.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication & authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, protocolsConfigure);
}
catch (e) {
return messageReplyFromError(e, 401);
}
// attempt to get existing protocol
const query = {
interface: DwnInterfaceName.Protocols,
method: DwnMethodName.Configure,
protocol: message.descriptor.definition.protocol
};
const { messages: existingMessages } = yield this.messageStore.query(tenant, [query]);
// find newest message, and if the incoming message is the newest
let newestMessage = yield Message.getNewestMessage(existingMessages);
let incomingMessageIsNewest = false;
if (newestMessage === undefined || (yield Message.isNewer(message, newestMessage))) {
incomingMessageIsNewest = true;
newestMessage = message;
}
// write the incoming message to DB if incoming message is newest
let messageReply;
if (incomingMessageIsNewest) {
const indexes = ProtocolsConfigureHandler.constructIndexes(protocolsConfigure);
yield this.messageStore.put(tenant, message, indexes);
const messageCid = yield Message.getCid(message);
yield this.eventLog.append(tenant, messageCid, indexes);
// only emit if the event stream is set
if (this.eventStream !== undefined) {
this.eventStream.emit(tenant, { message }, indexes);
}
messageReply = {
status: { code: 202, detail: 'Accepted' }
};
}
else {
messageReply = {
status: { code: 409, detail: 'Conflict' }
};
}
// delete all existing records that are smaller
const deletedMessageCids = [];
for (const message of existingMessages) {
if (yield Message.isNewer(newestMessage, message)) {
const messageCid = yield Message.getCid(message);
deletedMessageCids.push(messageCid);
yield this.messageStore.delete(tenant, messageCid);
}
}
yield this.eventLog.deleteEventsByCid(tenant, deletedMessageCids);
return messageReply;
});
}
;
static constructIndexes(protocolsConfigure) {
// strip out `definition` as it is not indexable
const _a = protocolsConfigure.message.descriptor, { definition } = _a, propertiesToIndex = __rest(_a, ["definition"]);
const { author } = protocolsConfigure;
const indexes = Object.assign(Object.assign({}, propertiesToIndex), { author: author, protocol: definition.protocol, published: definition.published // retain published state from definition
});
return indexes;
}
}
//# sourceMappingURL=protocols-configure.js.map
@@ -0,0 +1 @@
{"version":3,"file":"protocols-configure.js","sourceRoot":"","sources":["../../../../src/handlers/protocols-configure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { DwnErrorCode } from '../core/dwn-error.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolsQuery } from '../interfaces/protocols-query.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class ProtocolsQueryHandler {
constructor(didResolver, messageStore, dataStore) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let protocolsQuery;
try {
protocolsQuery = yield ProtocolsQuery.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication & authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield protocolsQuery.authorize(tenant, this.messageStore);
}
catch (error) {
// return public ProtocolsConfigures if query fails with a certain authentication or authorization code
if (error.code === DwnErrorCode.AuthenticateJwsMissing || // unauthenticated
error.code === DwnErrorCode.ProtocolsQueryUnauthorized) {
const entries = yield this.fetchPublishedProtocolsConfigure(tenant, protocolsQuery);
return {
status: { code: 200, detail: 'OK' },
entries
};
}
else {
return messageReplyFromError(error, 401);
}
}
const query = Object.assign(Object.assign({}, message.descriptor.filter), { interface: DwnInterfaceName.Protocols, method: DwnMethodName.Configure });
removeUndefinedProperties(query);
const { messages } = yield this.messageStore.query(tenant, [query]);
return {
status: { code: 200, detail: 'OK' },
entries: messages
};
});
}
;
/**
* Fetches only published `ProtocolsConfigure`.
*/
fetchPublishedProtocolsConfigure(tenant, protocolsQuery) {
return __awaiter(this, void 0, void 0, function* () {
// fetch all published `ProtocolConfigure` matching the query
const filter = Object.assign(Object.assign({}, protocolsQuery.message.descriptor.filter), { interface: DwnInterfaceName.Protocols, method: DwnMethodName.Configure, published: true });
const { messages: publishedProtocolsConfigure } = yield this.messageStore.query(tenant, [filter]);
return publishedProtocolsConfigure;
});
}
}
//# sourceMappingURL=protocols-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"protocols-query.js","sourceRoot":"","sources":["../../../../src/handlers/protocols-query.ts"],"names":[],"mappings":";;;;;;;;;AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEnF,MAAM,OAAO,qBAAqB;IAEhC,YAAoB,WAAwB,EAAU,YAA0B,EAAS,SAAoB;QAAzF,gBAAW,GAAX,WAAW,CAAa;QAAU,iBAAY,GAAZ,YAAY,CAAc;QAAS,cAAS,GAAT,SAAS,CAAW;IAAI,CAAC;IAErG,MAAM,CAAC,EAClB,MAAM,EACN,OAAO,EAC2C;;YAElD,IAAI,cAA8B,CAAC;YACnC,IAAI;gBACF,cAAc,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aACtD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,iCAAiC;YACjC,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;aAC3D;YAAC,OAAO,KAAU,EAAE;gBAEnB,uGAAuG;gBACvG,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,sBAAsB,IAAI,kBAAkB;oBACxE,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,0BAA0B,EAAE;oBAE1D,MAAM,OAAO,GAAgC,MAAM,IAAI,CAAC,gCAAgC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;oBACjH,OAAO;wBACL,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;wBACnC,OAAO;qBACR,CAAC;iBACH;qBAAM;oBACL,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;iBAC1C;aACF;YAED,MAAM,KAAK,mCACN,OAAO,CAAC,UAAU,CAAC,MAAM,KAC5B,SAAS,EAAG,gBAAgB,CAAC,SAAS,EACtC,MAAM,EAAM,aAAa,CAAC,SAAS,GACpC,CAAC;YACF,yBAAyB,CAAC,KAAK,CAAC,CAAC;YAEjC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,CAAE,KAAK,CAAE,CAAC,CAAC;YAEtE,OAAO;gBACL,MAAM,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAG,QAAuC;aAClD,CAAC;QACJ,CAAC;KAAA;IAAA,CAAC;IAEF;;OAEG;IACW,gCAAgC,CAAC,MAAc,EAAE,cAA8B;;YAC3F,6DAA6D;YAC7D,MAAM,MAAM,mCACP,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,KAC3C,SAAS,EAAG,gBAAgB,CAAC,SAAS,EACtC,MAAM,EAAM,aAAa,CAAC,SAAS,EACnC,SAAS,EAAG,IAAI,GACjB,CAAC;YACF,MAAM,EAAE,QAAQ,EAAE,2BAA2B,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,CAAE,MAAM,CAAE,CAAC,CAAC;YACpG,OAAO,2BAA0D,CAAC;QACpE,CAAC;KAAA;CACF"}
@@ -0,0 +1,124 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { RecordsDelete } from '../interfaces/records-delete.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { StorageController } from '../store/storage-controller.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsDeleteHandler {
constructor(didResolver, messageStore, dataStore, eventLog, eventStream) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
this.eventLog = eventLog;
this.eventStream = eventStream;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let recordsDelete;
try {
recordsDelete = yield RecordsDelete.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication
try {
yield authenticate(message.authorization, this.didResolver);
}
catch (e) {
return messageReplyFromError(e, 401);
}
// get existing records matching the `recordId`
const query = {
interface: DwnInterfaceName.Records,
recordId: message.descriptor.recordId
};
const { messages: existingMessages } = yield this.messageStore.query(tenant, [query]);
// find which message is the newest, and if the incoming message is the newest
const newestExistingMessage = yield Message.getNewestMessage(existingMessages);
let incomingMessageIsNewest = false;
let newestMessage;
// if incoming message is newest
if (newestExistingMessage === undefined || (yield Message.isNewer(message, newestExistingMessage))) {
incomingMessageIsNewest = true;
newestMessage = message;
}
else { // existing message is the same age or newer than the incoming message
newestMessage = newestExistingMessage;
}
if (!incomingMessageIsNewest) {
return {
status: { code: 409, detail: 'Conflict' }
};
}
// return Not Found if record does not exist or is already deleted
if (newestExistingMessage === undefined || newestExistingMessage.descriptor.method === DwnMethodName.Delete) {
return {
status: { code: 404, detail: 'Not Found' }
};
}
// authorization
try {
yield RecordsDeleteHandler.authorizeRecordsDelete(tenant, recordsDelete, yield RecordsWrite.parse(newestExistingMessage), this.messageStore);
}
catch (e) {
return messageReplyFromError(e, 401);
}
const initialWrite = yield RecordsWrite.getInitialWrite(existingMessages);
const indexes = recordsDelete.constructIndexes(initialWrite);
const messageCid = yield Message.getCid(message);
yield this.messageStore.put(tenant, message, indexes);
yield this.eventLog.append(tenant, messageCid, indexes);
// only emit if the event stream is set
if (this.eventStream !== undefined) {
this.eventStream.emit(tenant, { message, initialWrite }, indexes);
}
if (message.descriptor.prune) {
// purge/hard-delete all descendent records
yield StorageController.purgeRecordDescendants(tenant, message.descriptor.recordId, this.messageStore, this.dataStore, this.eventLog);
}
// delete all existing messages that are not newest, except for the initial write
yield StorageController.deleteAllOlderMessagesButKeepInitialWrite(tenant, existingMessages, newestMessage, this.messageStore, this.dataStore, this.eventLog);
const messageReply = {
status: { code: 202, detail: 'Accepted' }
};
return messageReply;
});
}
;
/**
* Authorizes a RecordsDelete message.
*
* @param newestRecordsWrite Newest RecordsWrite of the record to be deleted.
*/
static authorizeRecordsDelete(tenant, recordsDelete, newestRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (Message.isSignedByAuthorDelegate(recordsDelete.message)) {
yield recordsDelete.authorizeDelegate(newestRecordsWrite.message, messageStore);
}
if (recordsDelete.author === tenant) {
return;
}
else if (newestRecordsWrite.message.descriptor.protocol !== undefined) {
yield ProtocolAuthorization.authorizeDelete(tenant, recordsDelete, newestRecordsWrite, messageStore);
}
else {
throw new DwnError(DwnErrorCode.RecordsDeleteAuthorizationFailed, 'RecordsDelete message failed authorization');
}
});
}
}
;
//# sourceMappingURL=records-delete.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-delete.js","sourceRoot":"","sources":["../../../../src/handlers/records-delete.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,209 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { DateSort } from '../types/records-types.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { Records } from '../utils/records.js';
import { RecordsQuery } from '../interfaces/records-query.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { SortDirection } from '../types/query-types.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsQueryHandler {
constructor(didResolver, messageStore, dataStore) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let recordsQuery;
try {
recordsQuery = yield RecordsQuery.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
let recordsWrites;
let cursor;
// if this is an anonymous query and the filter supports published records, query only published records
if (Records.filterIncludesPublishedRecords(recordsQuery.message.descriptor.filter) && recordsQuery.author === undefined) {
const results = yield this.fetchPublishedRecords(tenant, recordsQuery);
recordsWrites = results.messages;
cursor = results.cursor;
}
else {
// authentication and authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield RecordsQueryHandler.authorizeRecordsQuery(tenant, recordsQuery, this.messageStore);
}
catch (e) {
return messageReplyFromError(e, 401);
}
if (recordsQuery.author === tenant) {
const results = yield this.fetchRecordsAsOwner(tenant, recordsQuery);
recordsWrites = results.messages;
cursor = results.cursor;
}
else {
const results = yield this.fetchRecordsAsNonOwner(tenant, recordsQuery);
recordsWrites = results.messages;
cursor = results.cursor;
}
}
// attach initial write if returned RecordsWrite is not initial write
for (const recordsWrite of recordsWrites) {
if (!(yield RecordsWrite.isInitialWrite(recordsWrite))) {
const initialWriteQueryResult = yield this.messageStore.query(tenant, [{ recordId: recordsWrite.recordId, isLatestBaseState: false, method: DwnMethodName.Write }]);
const initialWrite = initialWriteQueryResult.messages[0];
delete initialWrite.encodedData; // defensive measure but technically optional because we do this when an update RecordsWrite takes place
recordsWrite.initialWrite = initialWrite;
}
}
return {
status: { code: 200, detail: 'OK' },
entries: recordsWrites,
cursor
};
});
}
/**
* Convert an incoming DateSort to a sort type accepted by MessageStore
* Defaults to 'dateCreated' in Descending order if no sort is supplied.
*
* @param dateSort the optional DateSort from the RecordsQuery message descriptor.
* @returns {MessageSort} for MessageStore sorting.
*/
convertDateSort(dateSort) {
switch (dateSort) {
case DateSort.CreatedAscending:
return { dateCreated: SortDirection.Ascending };
case DateSort.CreatedDescending:
return { dateCreated: SortDirection.Descending };
case DateSort.PublishedAscending:
return { datePublished: SortDirection.Ascending };
case DateSort.PublishedDescending:
return { datePublished: SortDirection.Descending };
default:
return { dateCreated: SortDirection.Ascending };
}
}
/**
* Fetches the records as the owner of the DWN with no additional filtering.
*/
fetchRecordsAsOwner(tenant, recordsQuery) {
return __awaiter(this, void 0, void 0, function* () {
const { dateSort, filter, pagination } = recordsQuery.message.descriptor;
// fetch all published records matching the query
const queryFilter = Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { interface: DwnInterfaceName.Records, method: DwnMethodName.Write, isLatestBaseState: true });
const messageSort = this.convertDateSort(dateSort);
return this.messageStore.query(tenant, [queryFilter], messageSort, pagination);
});
}
/**
* Fetches the records as a non-owner.
*
* Filters can support returning both published and unpublished records,
* as well as explicitly only published or only unpublished records.
*
* A) BOTH published and unpublished:
* 1. published records; and
* 2. unpublished records intended for the query author (where `recipient` is the query author); and
* 3. unpublished records authorized by a protocol rule.
*
* B) PUBLISHED:
* 1. only published records;
*
* C) UNPUBLISHED:
* 1. unpublished records intended for the query author (where `recipient` is the query author); and
* 2. unpublished records authorized by a protocol rule.
*
*/
fetchRecordsAsNonOwner(tenant, recordsQuery) {
return __awaiter(this, void 0, void 0, function* () {
const { dateSort, pagination, filter } = recordsQuery.message.descriptor;
const filters = [];
if (Records.filterIncludesPublishedRecords(filter)) {
filters.push(RecordsQueryHandler.buildPublishedRecordsFilter(recordsQuery));
}
if (Records.filterIncludesUnpublishedRecords(filter)) {
filters.push(RecordsQueryHandler.buildUnpublishedRecordsByQueryAuthorFilter(recordsQuery));
const recipientFilter = recordsQuery.message.descriptor.filter.recipient;
if (recipientFilter === undefined || recipientFilter === recordsQuery.author) {
filters.push(RecordsQueryHandler.buildUnpublishedRecordsForQueryAuthorFilter(recordsQuery));
}
if (Records.shouldProtocolAuthorize(recordsQuery.signaturePayload)) {
filters.push(RecordsQueryHandler.buildUnpublishedProtocolAuthorizedRecordsFilter(recordsQuery));
}
}
const messageSort = this.convertDateSort(dateSort);
return this.messageStore.query(tenant, filters, messageSort, pagination);
});
}
/**
* Fetches only published records.
*/
fetchPublishedRecords(tenant, recordsQuery) {
return __awaiter(this, void 0, void 0, function* () {
const { dateSort, pagination } = recordsQuery.message.descriptor;
const filter = RecordsQueryHandler.buildPublishedRecordsFilter(recordsQuery);
const messageSort = this.convertDateSort(dateSort);
return this.messageStore.query(tenant, [filter], messageSort, pagination);
});
}
static buildPublishedRecordsFilter(recordsQuery) {
const { dateSort, filter } = recordsQuery.message.descriptor;
// fetch all published records matching the query
return Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { interface: DwnInterfaceName.Records, method: DwnMethodName.Write, published: true, isLatestBaseState: true });
}
/**
* Creates a filter for unpublished records that are intended for the query author (where `recipient` is the author).
*/
static buildUnpublishedRecordsForQueryAuthorFilter(recordsQuery) {
const { dateSort, filter } = recordsQuery.message.descriptor;
// include records where recipient is query author
return Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { interface: DwnInterfaceName.Records, method: DwnMethodName.Write, recipient: recordsQuery.author, isLatestBaseState: true, published: false });
}
/**
* Creates a filter for unpublished records that are within the specified protocol.
* Validation that `protocol` and other required protocol-related fields occurs before this method.
*/
static buildUnpublishedProtocolAuthorizedRecordsFilter(recordsQuery) {
const { dateSort, filter } = recordsQuery.message.descriptor;
return Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { interface: DwnInterfaceName.Records, method: DwnMethodName.Write, isLatestBaseState: true, published: false });
}
/**
* Creates a filter for only unpublished records where the author is the same as the query author.
*/
static buildUnpublishedRecordsByQueryAuthorFilter(recordsQuery) {
const { dateSort, filter } = recordsQuery.message.descriptor;
// include records where author is the same as the query author
return Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { author: recordsQuery.author, interface: DwnInterfaceName.Records, method: DwnMethodName.Write, isLatestBaseState: true, published: false });
}
/**
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeRecordsQuery(tenant, recordsQuery, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (Message.isSignedByAuthorDelegate(recordsQuery.message)) {
yield recordsQuery.authorizeDelegate(messageStore);
}
// NOTE: not all RecordsQuery messages require protocol authorization even if the filter includes protocol-related fields,
// this is because we dynamically filter out records that the caller is not authorized to see.
// Currently only run protocol authorization if message deliberately invokes a protocol role.
if (Records.shouldProtocolAuthorize(recordsQuery.signaturePayload)) {
yield ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsQuery, messageStore);
}
});
}
}
//# sourceMappingURL=records-query.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,138 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { DataStream } from '../utils/data-stream.js';
import { Encoder } from '../utils/encoder.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { RecordsRead } from '../interfaces/records-read.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsReadHandler {
constructor(didResolver, messageStore, dataStore) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let recordsRead;
try {
recordsRead = yield RecordsRead.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication
try {
if (recordsRead.author !== undefined) {
yield authenticate(message.authorization, this.didResolver);
}
}
catch (e) {
return messageReplyFromError(e, 401);
}
// get the latest active messages matching the supplied filter
// only RecordsWrite messages will be returned due to 'isLatestBaseState' being set to true.
const query = Object.assign({ interface: DwnInterfaceName.Records, isLatestBaseState: true }, Records.convertFilter(message.descriptor.filter));
const { messages: existingMessages } = yield this.messageStore.query(tenant, [query]);
if (existingMessages.length === 0) {
return {
status: { code: 404, detail: 'Not Found' }
};
}
else if (existingMessages.length > 1) {
return messageReplyFromError(new DwnError(DwnErrorCode.RecordsReadReturnedMultiple, 'Multiple records exist for the RecordsRead filter'), 400);
}
const matchedRecordsWrite = existingMessages[0];
try {
yield RecordsReadHandler.authorizeRecordsRead(tenant, recordsRead, yield RecordsWrite.parse(matchedRecordsWrite), this.messageStore);
}
catch (error) {
return messageReplyFromError(error, 401);
}
let data;
if (matchedRecordsWrite.encodedData !== undefined) {
const dataBytes = Encoder.base64UrlToBytes(matchedRecordsWrite.encodedData);
data = DataStream.fromBytes(dataBytes);
delete matchedRecordsWrite.encodedData;
}
else {
const result = yield this.dataStore.get(tenant, matchedRecordsWrite.recordId, matchedRecordsWrite.descriptor.dataCid);
if ((result === null || result === void 0 ? void 0 : result.dataStream) === undefined) {
return {
status: { code: 404, detail: 'Not Found' }
};
}
data = result.dataStream;
}
const record = Object.assign(Object.assign({}, matchedRecordsWrite), { data });
// attach initial write if returned RecordsWrite is not initial write
if (!(yield RecordsWrite.isInitialWrite(record))) {
const initialWriteQueryResult = yield this.messageStore.query(tenant, [{ recordId: record.recordId, isLatestBaseState: false, method: DwnMethodName.Write }]);
const initialWrite = initialWriteQueryResult.messages[0];
delete initialWrite.encodedData; // defensive measure but technically optional because we do this when an update RecordsWrite takes place
record.initialWrite = initialWrite;
}
const messageReply = {
status: { code: 200, detail: 'OK' },
record
};
return messageReply;
});
}
;
/**
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeRecordsRead(tenant, recordsRead, matchedRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (Message.isSignedByAuthorDelegate(recordsRead.message)) {
yield recordsRead.authorizeDelegate(matchedRecordsWrite.message, messageStore);
}
const { descriptor } = matchedRecordsWrite.message;
// if author is the same as the target tenant, we can directly grant access
if (recordsRead.author === tenant) {
return;
}
else if (descriptor.published === true) {
// authentication is not required for published data
return;
}
else if (recordsRead.author !== undefined && recordsRead.author === descriptor.recipient) {
// The recipient of a message may always read it
return;
}
else if (recordsRead.author !== undefined && recordsRead.signaturePayload.permissionGrantId !== undefined) {
const permissionGrant = yield PermissionsProtocol.fetchGrant(tenant, messageStore, recordsRead.signaturePayload.permissionGrantId);
yield RecordsGrantAuthorization.authorizeRead({
recordsReadMessage: recordsRead.message,
recordsWriteMessageToBeRead: matchedRecordsWrite.message,
expectedGrantor: tenant,
expectedGrantee: recordsRead.author,
permissionGrant,
messageStore
});
}
else if (descriptor.protocol !== undefined) {
yield ProtocolAuthorization.authorizeRead(tenant, recordsRead, matchedRecordsWrite, messageStore);
}
else {
throw new DwnError(DwnErrorCode.RecordsReadAuthorizationFailed, 'message failed authorization');
}
});
}
}
//# sourceMappingURL=records-read.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-read.js","sourceRoot":"","sources":["../../../../src/handlers/records-read.ts"],"names":[],"mappings":";;;;;;;;;AAOA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEnF,MAAM,OAAO,kBAAkB;IAE7B,YAAoB,WAAwB,EAAU,YAA0B,EAAU,SAAoB;QAA1F,gBAAW,GAAX,WAAW,CAAa;QAAU,iBAAY,GAAZ,YAAY,CAAc;QAAU,cAAS,GAAT,SAAS,CAAW;IAAI,CAAC;IAEtG,MAAM,CAAC,EAClB,MAAM,EACN,OAAO,EACyC;;YAEhD,IAAI,WAAwB,CAAC;YAC7B,IAAI;gBACF,WAAW,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAChD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,iBAAiB;YACjB,IAAI;gBACF,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS,EAAE;oBACpC,MAAM,YAAY,CAAC,OAAO,CAAC,aAAc,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;iBAC9D;aACF;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,8DAA8D;YAC9D,4FAA4F;YAC5F,MAAM,KAAK,mBACT,SAAS,EAAW,gBAAgB,CAAC,OAAO,EAC5C,iBAAiB,EAAG,IAAI,IACrB,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CACpD,CAAC;YACF,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,CAAE,KAAK,CAAE,CAAC,CAAC;YACxF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE;gBACjC,OAAO;oBACL,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE;iBAC3C,CAAC;aACH;iBAAM,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;gBACtC,OAAO,qBAAqB,CAAC,IAAI,QAAQ,CACvC,YAAY,CAAC,2BAA2B,EACxC,mDAAmD,CACpD,EAAE,GAAG,CAAC,CAAC;aACT;YAED,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,CAAC,CAA2B,CAAC;YAC1E,IAAI;gBACF,MAAM,kBAAkB,CAAC,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;aACtI;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;aAC1C;YAED,IAAI,IAAI,CAAC;YACT,IAAI,mBAAmB,CAAC,WAAW,KAAK,SAAS,EAAE;gBACjD,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;gBAC5E,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;gBACvC,OAAO,mBAAmB,CAAC,WAAW,CAAC;aACxC;iBAAM;gBACL,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBACtH,IAAI,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,UAAU,MAAK,SAAS,EAAE;oBACpC,OAAO;wBACL,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE;qBAC3C,CAAC;iBACH;gBACD,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC;aAC1B;YAED,MAAM,MAAM,mCACP,mBAAmB,KACtB,IAAI,GACL,CAAC;YAEF,qEAAqE;YACrE,IAAI,CAAC,CAAA,MAAM,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA,EAAE;gBAC9C,MAAM,uBAAuB,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAC3D,MAAM,EACN,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,CAAC,CACvF,CAAC;gBACF,MAAM,YAAY,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAA2B,CAAC;gBACnF,OAAO,YAAY,CAAC,WAAW,CAAC,CAAC,wGAAwG;gBACzI,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC;aACpC;YAED,MAAM,YAAY,GAAqB;gBACrC,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACnC,MAAM;aACP,CAAC;YACF,OAAO,YAAY,CAAC;QACtB,CAAC;KAAA;IAAA,CAAC;IAEF;;OAEG;IACK,MAAM,CAAO,oBAAoB,CACvC,MAAc,EACd,WAAwB,EACxB,mBAAiC,EACjC,YAA0B;;YAE1B,IAAI,OAAO,CAAC,wBAAwB,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE;gBACzD,MAAM,WAAW,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;aAChF;YAED,MAAM,EAAE,UAAU,EAAE,GAAG,mBAAmB,CAAC,OAAO,CAAC;YAEnD,2EAA2E;YAC3E,IAAI,WAAW,CAAC,MAAM,KAAK,MAAM,EAAE;gBACjC,OAAO;aACR;iBAAM,IAAI,UAAU,CAAC,SAAS,KAAK,IAAI,EAAE;gBACxC,oDAAoD;gBACpD,OAAO;aACR;iBAAM,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS,IAAI,WAAW,CAAC,MAAM,KAAK,UAAU,CAAC,SAAS,EAAE;gBAC1F,gDAAgD;gBAChD,OAAO;aACR;iBAAM,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS,IAAI,WAAW,CAAC,gBAAiB,CAAC,iBAAiB,KAAK,SAAS,EAAE;gBAC5G,MAAM,eAAe,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,CAAC,gBAAiB,CAAC,iBAAiB,CAAC,CAAC;gBACpI,MAAM,yBAAyB,CAAC,aAAa,CAAC;oBAC5C,kBAAkB,EAAY,WAAW,CAAC,OAAO;oBACjD,2BAA2B,EAAG,mBAAmB,CAAC,OAAO;oBACzD,eAAe,EAAe,MAAM;oBACpC,eAAe,EAAe,WAAW,CAAC,MAAM;oBAChD,eAAe;oBACf,YAAY;iBACb,CAAC,CAAC;aACJ;iBAAM,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,EAAE;gBAC5C,MAAM,qBAAqB,CAAC,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,YAAY,CAAC,CAAC;aACnG;iBAAM;gBACL,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,8BAA8B,EAAE,8BAA8B,CAAC,CAAC;aACjG;QACH,CAAC;KAAA;CACF"}
@@ -0,0 +1,171 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { FilterUtility } from '../utils/filter.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { Records } from '../utils/records.js';
import { RecordsSubscribe } from '../interfaces/records-subscribe.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsSubscribeHandler {
constructor(didResolver, messageStore, eventStream) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.eventStream = eventStream;
}
handle({ tenant, message, subscriptionHandler }) {
return __awaiter(this, void 0, void 0, function* () {
if (this.eventStream === undefined) {
return messageReplyFromError(new DwnError(DwnErrorCode.RecordsSubscribeEventStreamUnimplemented, 'Subscriptions are not supported'), 501);
}
let recordsSubscribe;
try {
recordsSubscribe = yield RecordsSubscribe.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
let filters = [];
// if this is an anonymous subscribe and the filter supports published records, subscribe to only published records
if (Records.filterIncludesPublishedRecords(recordsSubscribe.message.descriptor.filter) && recordsSubscribe.author === undefined) {
// build filters for a stream of published records
filters = [RecordsSubscribeHandler.buildPublishedRecordsFilter(recordsSubscribe)];
// delete the undefined authorization property else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
delete message.authorization;
}
else {
// authentication and authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield RecordsSubscribeHandler.authorizeRecordsSubscribe(tenant, recordsSubscribe, this.messageStore);
}
catch (error) {
return messageReplyFromError(error, 401);
}
if (recordsSubscribe.author === tenant) {
// if the subscribe author is the tenant, filter as owner.
filters = yield RecordsSubscribeHandler.filterAsOwner(recordsSubscribe);
}
else {
// otherwise build filters based on published records, permissions, or protocol rules
filters = yield RecordsSubscribeHandler.filterAsNonOwner(recordsSubscribe);
}
}
const listener = (eventTenant, event, eventIndexes) => {
if (tenant === eventTenant && FilterUtility.matchAnyFilter(eventIndexes, filters)) {
// the filters check for interface and method
// if matched the message is either a `RecordsWriteMessage` or `RecordsDeleteMessage` so we cast the event to a `RecordEvent`
subscriptionHandler(event);
}
};
const messageCid = yield Message.getCid(message);
const subscription = yield this.eventStream.subscribe(tenant, messageCid, listener);
return {
status: { code: 200, detail: 'OK' },
subscription
};
});
}
/**
* Subscribe to records as the owner of the DWN with no additional filtering.
*/
static filterAsOwner(RecordsSubscribe) {
return __awaiter(this, void 0, void 0, function* () {
const { filter } = RecordsSubscribe.message.descriptor;
const subscribeFilter = Object.assign(Object.assign({}, Records.convertFilter(filter)), { interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete] });
return [subscribeFilter];
});
}
/**
* Creates filters in order to subscribe to records as a non-owner.
*
* Filters can support emitting messages for both published and unpublished records,
* as well as explicitly only published or only unpublished records.
*
* A) BOTH published and unpublished:
* 1. published records; and
* 2. unpublished records intended for the subscription author (where `recipient` is the subscription author); and
* 3. unpublished records authorized by a protocol rule.
*
* B) PUBLISHED:
* 1. only published records;
*
* C) UNPUBLISHED:
* 1. unpublished records intended for the subscription author (where `recipient` is the subscription author); and
* 2. unpublished records authorized by a protocol rule.
*/
static filterAsNonOwner(recordsSubscribe) {
return __awaiter(this, void 0, void 0, function* () {
const filters = [];
const { filter } = recordsSubscribe.message.descriptor;
if (Records.filterIncludesPublishedRecords(filter)) {
filters.push(RecordsSubscribeHandler.buildPublishedRecordsFilter(recordsSubscribe));
}
if (Records.filterIncludesUnpublishedRecords(filter)) {
filters.push(RecordsSubscribeHandler.buildUnpublishedRecordsBySubscribeAuthorFilter(recordsSubscribe));
const recipientFilter = recordsSubscribe.message.descriptor.filter.recipient;
if (recipientFilter === undefined || recipientFilter === recordsSubscribe.author) {
filters.push(RecordsSubscribeHandler.buildUnpublishedRecordsForSubscribeAuthorFilter(recordsSubscribe));
}
if (Records.shouldProtocolAuthorize(recordsSubscribe.signaturePayload)) {
filters.push(RecordsSubscribeHandler.buildUnpublishedProtocolAuthorizedRecordsFilter(recordsSubscribe));
}
}
return filters;
});
}
/**
* Creates a filter for all published records matching the subscribe
*/
static buildPublishedRecordsFilter(recordsSubscribe) {
return Object.assign(Object.assign({}, Records.convertFilter(recordsSubscribe.message.descriptor.filter)), { interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete], published: true });
}
/**
* Creates a filter for unpublished records that are intended for the subscribe author (where `recipient` is the author).
*/
static buildUnpublishedRecordsForSubscribeAuthorFilter(recordsSubscribe) {
// include records where recipient is subscribe author
return Object.assign(Object.assign({}, Records.convertFilter(recordsSubscribe.message.descriptor.filter)), { interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete], recipient: recordsSubscribe.author, published: false });
}
/**
* Creates a filter for unpublished records that are within the specified protocol.
* Validation that `protocol` and other required protocol-related fields occurs before this method.
*/
static buildUnpublishedProtocolAuthorizedRecordsFilter(recordsSubscribe) {
return Object.assign(Object.assign({}, Records.convertFilter(recordsSubscribe.message.descriptor.filter)), { interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete], published: false });
}
/**
* Creates a filter for only unpublished records where the author is the same as the subscribe author.
*/
static buildUnpublishedRecordsBySubscribeAuthorFilter(recordsSubscribe) {
// include records where author is the same as the subscribe author
return Object.assign(Object.assign({}, Records.convertFilter(recordsSubscribe.message.descriptor.filter)), { author: recordsSubscribe.author, interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete], published: false });
}
/**
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeRecordsSubscribe(tenant, recordsSubscribe, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (Message.isSignedByAuthorDelegate(recordsSubscribe.message)) {
yield recordsSubscribe.authorizeDelegate(messageStore);
}
// NOTE: not all RecordsSubscribe messages require protocol authorization even if the filter includes protocol-related fields,
// this is because we dynamically filter out records that the caller is not authorized to see.
// Currently only run protocol authorization if message deliberately invokes a protocol role.
if (Records.shouldProtocolAuthorize(recordsSubscribe.signaturePayload)) {
yield ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsSubscribe, messageStore);
}
});
}
}
//# sourceMappingURL=records-subscribe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-subscribe.js","sourceRoot":"","sources":["../../../../src/handlers/records-subscribe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,310 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { Cid } from '../utils/cid.js';
import { DataStream } from '../utils/data-stream.js';
import { DwnConstant } from '../core/dwn-constant.js';
import { Encoder } from '../utils/encoder.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { StorageController } from '../store/storage-controller.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsWriteHandler {
constructor(didResolver, messageStore, dataStore, eventLog, eventStream) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
this.eventLog = eventLog;
this.eventStream = eventStream;
}
handle({ tenant, message, dataStream }) {
return __awaiter(this, void 0, void 0, function* () {
let recordsWrite;
try {
recordsWrite = yield RecordsWrite.parse(message);
// Protocol-authorized record specific validation
if (message.descriptor.protocol !== undefined) {
yield ProtocolAuthorization.validateReferentialIntegrity(tenant, recordsWrite, this.messageStore);
}
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication & authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield RecordsWriteHandler.authorizeRecordsWrite(tenant, recordsWrite, this.messageStore);
}
catch (e) {
return messageReplyFromError(e, 401);
}
// get existing messages matching the `recordId`
const query = {
interface: DwnInterfaceName.Records,
recordId: message.recordId
};
const { messages: existingMessages } = yield this.messageStore.query(tenant, [query]);
// if the incoming write is not the initial write, then it must not modify any immutable properties defined by the initial write
const newMessageIsInitialWrite = yield recordsWrite.isInitialWrite();
let initialWrite;
if (!newMessageIsInitialWrite) {
try {
initialWrite = yield RecordsWrite.getInitialWrite(existingMessages);
RecordsWrite.verifyEqualityOfImmutableProperties(initialWrite, message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
}
const newestExistingMessage = yield Message.getNewestMessage(existingMessages);
let incomingMessageIsNewest = false;
let newestMessage; // keep reference of newest message for pruning later
if (newestExistingMessage === undefined || (yield Message.isNewer(message, newestExistingMessage))) {
incomingMessageIsNewest = true;
newestMessage = message;
}
else { // existing message is the same age or newer than the incoming message
newestMessage = newestExistingMessage;
}
if (!incomingMessageIsNewest) {
return {
status: { code: 409, detail: 'Conflict' }
};
}
try {
// NOTE: We allow isLatestBaseState to be true ONLY if the incoming message comes with data, or if the incoming message is NOT an initial write
// This would allow an initial write to be written to the DB without data, but having it not queryable,
// because query implementation filters on `isLatestBaseState` being `true`
// thus preventing a user's attempt to gain authorized access to data by referencing the dataCid of a private data in their initial writes,
// See: https://github.com/TBD54566975/dwn-sdk-js/issues/359 for more info
let isLatestBaseState = false;
let messageWithOptionalEncodedData = message;
if (dataStream !== undefined) {
messageWithOptionalEncodedData = yield this.processMessageWithDataStream(tenant, message, dataStream);
isLatestBaseState = true;
}
else {
// else data stream is NOT provided
if ((newestExistingMessage === null || newestExistingMessage === void 0 ? void 0 : newestExistingMessage.descriptor.method) === DwnMethodName.Delete) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingDataStream, 'No data stream was provided with the previous message being a delete');
}
// at this point we know that newestExistingMessage exists is not a Delete
// if the incoming message is not an initial write, and no dataStream is provided, we would allow it provided it passes validation
// processMessageWithoutDataStream() abstracts that logic
if (!newMessageIsInitialWrite) {
const newestExistingWrite = newestExistingMessage;
messageWithOptionalEncodedData = yield this.processMessageWithoutDataStream(tenant, message, newestExistingWrite);
isLatestBaseState = true;
}
}
const indexes = yield recordsWrite.constructIndexes(isLatestBaseState);
yield this.messageStore.put(tenant, messageWithOptionalEncodedData, indexes);
yield this.eventLog.append(tenant, yield Message.getCid(message), indexes);
// NOTE: We only emit a `RecordsWrite` when the message is the latest base state.
// Because we allow a `RecordsWrite` which is not the latest state to be written, but not queried, we shouldn't emit it either.
// It will be emitted as a part of a subsequent next write, if it is the latest base state.
if (this.eventStream !== undefined && isLatestBaseState) {
this.eventStream.emit(tenant, { message, initialWrite }, indexes);
}
}
catch (error) {
const e = error;
if (e.code !== undefined) {
if (e.code === DwnErrorCode.RecordsWriteMissingEncodedDataInPrevious ||
e.code === DwnErrorCode.RecordsWriteMissingDataInPrevious ||
e.code === DwnErrorCode.RecordsWriteMissingDataStream ||
e.code === DwnErrorCode.RecordsWriteDataCidMismatch ||
e.code === DwnErrorCode.RecordsWriteDataSizeMismatch ||
e.code.startsWith('PermissionsProtocolValidate') ||
e.code.startsWith('SchemaValidator')) {
return messageReplyFromError(error, 400);
}
}
// else throw
throw error;
}
const messageReply = {
status: { code: 202, detail: 'Accepted' }
};
// delete all existing messages of the same record that are not newest, except for the initial write
yield StorageController.deleteAllOlderMessagesButKeepInitialWrite(tenant, existingMessages, newestMessage, this.messageStore, this.dataStore, this.eventLog);
yield this.postProcessingForCoreRecordsWrite(tenant, recordsWrite);
return messageReply;
});
}
;
static validateSchemaForCoreRecordsWrite(recordsWriteMessage, dataBytes) {
if (recordsWriteMessage.descriptor.protocol === PermissionsProtocol.uri) {
PermissionsProtocol.validateSchema(recordsWriteMessage, dataBytes);
}
}
/**
* Performs additional necessary tasks if the RecordsWrite handled is a core DWN RecordsWrite that need additional processing.
* For instance: a Permission revocation RecordsWrite.
*/
postProcessingForCoreRecordsWrite(tenant, recordsWrite) {
return __awaiter(this, void 0, void 0, function* () {
// If this message is a Permission revocation, we need to delete all grant-authorized messages with timestamp after revocation
// TODO: https://github.com/TBD54566975/dwn-sdk-js/issues/716
// This code is a direct copy and paste from the original PermissionsRevokeHandler (no longer exists),
// but it appears that there was no test for it and it does not look like the code worked:
// - not seeing `permissionGrantId` being an index
// - not seeing `this.dataStore` being called to delete actual data
// - test coverage is missing for the main delete logic
if (recordsWrite.message.descriptor.protocol === PermissionsProtocol.uri &&
recordsWrite.message.descriptor.protocolPath === PermissionsProtocol.revocationPath) {
const permissionGrantId = recordsWrite.message.descriptor.parentId;
const grantAuthorizedMessagesQuery = {
permissionGrantId,
dateCreated: { gte: recordsWrite.message.descriptor.messageTimestamp },
};
const { messages: grantAuthorizedMessagesAfterRevoke } = yield this.messageStore.query(tenant, [grantAuthorizedMessagesQuery]);
const grantAuthorizedMessageCidsAfterRevoke = [];
for (const grantAuthorizedMessage of grantAuthorizedMessagesAfterRevoke) {
const messageCid = yield Message.getCid(grantAuthorizedMessage);
yield this.messageStore.delete(tenant, messageCid);
}
this.eventLog.deleteEventsByCid(tenant, grantAuthorizedMessageCidsAfterRevoke);
}
});
}
/**
* Returns a `RecordsQueryReplyEntry` with a copy of the incoming message and the incoming data encoded to `Base64URL`.
*/
cloneAndAddEncodedData(message, dataBytes) {
return __awaiter(this, void 0, void 0, function* () {
const recordsWrite = Object.assign({}, message);
recordsWrite.encodedData = Encoder.bytesToBase64Url(dataBytes);
return recordsWrite;
});
}
processMessageWithDataStream(tenant, message, dataStream) {
return __awaiter(this, void 0, void 0, function* () {
let messageWithOptionalEncodedData = message;
// if data is below the threshold, we store it within MessageStore
if (message.descriptor.dataSize <= DwnConstant.maxDataSizeAllowedToBeEncoded) {
// validate data integrity before setting.
const dataBytes = yield DataStream.toBytes(dataStream);
const dataCid = yield Cid.computeDagPbCidFromBytes(dataBytes);
RecordsWriteHandler.validateDataIntegrity(message.descriptor.dataCid, message.descriptor.dataSize, dataCid, dataBytes.length);
RecordsWriteHandler.validateSchemaForCoreRecordsWrite(message, dataBytes);
messageWithOptionalEncodedData = yield this.cloneAndAddEncodedData(message, dataBytes);
}
else {
// split the dataStream into two: one for CID computation and one for storage
const [dataStreamCopy1, dataStreamCopy2] = DataStream.duplicateDataStream(dataStream, 2);
try {
// perform storage and CID computation in parallel
const [dataCid, DataStorePutResult] = yield Promise.all([
Cid.computeDagPbCidFromStream(dataStreamCopy1),
this.dataStore.put(tenant, message.recordId, message.descriptor.dataCid, dataStreamCopy2)
]);
RecordsWriteHandler.validateDataIntegrity(message.descriptor.dataCid, message.descriptor.dataSize, dataCid, DataStorePutResult.dataSize);
}
catch (error) {
// unwind/delete data if we have issue with storage or the data failed integrity validation
yield this.dataStore.delete(tenant, message.recordId, message.descriptor.dataCid);
throw error;
}
}
return messageWithOptionalEncodedData;
});
}
processMessageWithoutDataStream(tenant, message, newestExistingWrite) {
return __awaiter(this, void 0, void 0, function* () {
const messageWithOptionalEncodedData = Object.assign({}, message); // clone
const { dataCid, dataSize } = message.descriptor;
// Since incoming message is not an initial write, and no dataStream is provided, we first check integrity against newest existing write.
// we preform the dataCid check in case a user attempts to gain access to data by referencing a different known dataCid,
// so we insure that the data is already associated with the existing newest message
// See: https://github.com/TBD54566975/dwn-sdk-js/issues/359 for more info
RecordsWriteHandler.validateDataIntegrity(dataCid, dataSize, newestExistingWrite.descriptor.dataCid, newestExistingWrite.descriptor.dataSize);
if (dataSize <= DwnConstant.maxDataSizeAllowedToBeEncoded) {
// we encode the data from the original write if it is smaller than the data-store threshold
if (newestExistingWrite.encodedData !== undefined) {
messageWithOptionalEncodedData.encodedData = newestExistingWrite.encodedData;
}
else {
throw new DwnError(DwnErrorCode.RecordsWriteMissingEncodedDataInPrevious, `No dataStream was provided and unable to get data from previous message`);
}
}
else {
// else just make sure the data is in the data store
// attempt to retrieve the data from the previous message
const DataStoreGetResult = yield this.dataStore.get(tenant, newestExistingWrite.recordId, message.descriptor.dataCid);
if (DataStoreGetResult === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingDataInPrevious, `No dataStream was provided and unable to get data from previous message`);
}
}
return messageWithOptionalEncodedData;
});
}
/**
* Validates the expected `dataCid` and `dataSize` in the descriptor vs the received data.
*
* @throws {DwnError} with `DwnErrorCode.RecordsWriteDataCidMismatch`
* if the data stream resulted in a data CID that mismatches with `dataCid` in the given message
* @throws {DwnError} with `DwnErrorCode.RecordsWriteDataSizeMismatch`
* if `dataSize` in `descriptor` given mismatches the actual data size
*/
static validateDataIntegrity(expectedDataCid, expectedDataSize, actualDataCid, actualDataSize) {
if (expectedDataCid !== actualDataCid) {
throw new DwnError(DwnErrorCode.RecordsWriteDataCidMismatch, `actual data CID ${actualDataCid} does not match dataCid in descriptor: ${expectedDataCid}`);
}
if (expectedDataSize !== actualDataSize) {
throw new DwnError(DwnErrorCode.RecordsWriteDataSizeMismatch, `actual data size ${actualDataSize} bytes does not match dataSize in descriptor: ${expectedDataSize}`);
}
}
static authorizeRecordsWrite(tenant, recordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// if owner signature is given (`owner` is not `undefined`), it must be the same as the tenant DID
if (recordsWrite.owner !== undefined && recordsWrite.owner !== tenant) {
throw new DwnError(DwnErrorCode.RecordsWriteOwnerAndTenantMismatch, `Owner ${recordsWrite.owner} must be the same as tenant ${tenant} when specified.`);
}
if (recordsWrite.isSignedByAuthorDelegate) {
yield recordsWrite.authorizeAuthorDelegate(messageStore);
}
if (recordsWrite.isSignedByOwnerDelegate) {
yield recordsWrite.authorizeOwnerDelegate(messageStore);
}
if (recordsWrite.owner !== undefined) {
// if incoming message is a write retained by this tenant, we by-design always allow
// NOTE: the "owner === tenant" check is already done earlier in this method
return;
}
else if (recordsWrite.author === tenant) {
// if author is the same as the target tenant, we can directly grant access
return;
}
else if (recordsWrite.author !== undefined && recordsWrite.signaturePayload.permissionGrantId !== undefined) {
const permissionGrant = yield PermissionsProtocol.fetchGrant(tenant, messageStore, recordsWrite.signaturePayload.permissionGrantId);
yield RecordsGrantAuthorization.authorizeWrite({
recordsWriteMessage: recordsWrite.message,
expectedGrantor: tenant,
expectedGrantee: recordsWrite.author,
permissionGrant,
messageStore
});
}
else if (recordsWrite.message.descriptor.protocol !== undefined) {
yield ProtocolAuthorization.authorizeWrite(tenant, recordsWrite, messageStore);
}
else {
throw new DwnError(DwnErrorCode.RecordsWriteAuthorizationFailed, 'message failed authorization');
}
});
}
}
//# sourceMappingURL=records-write.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,42 @@
export { authenticate } from './core/auth.js';
export { AllowAllTenantGate } from './core/tenant-gate.js';
export { Cid } from './utils/cid.js';
export { RecordsQuery } from './interfaces/records-query.js';
export { DataStream } from './utils/data-stream.js';
export { DateSort } from './types/records-types.js';
export { HdKey, KeyDerivationScheme } from './utils/hd-key.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 './enums/dwn-interface-method.js';
export { Encoder } from './utils/encoder.js';
export { EventsGet } from './interfaces/events-get.js';
export { EventsQuery } from './interfaces/events-query.js';
export { EventsSubscribe } from './interfaces/events-subscribe.js';
export { Encryption, EncryptionAlgorithm } from './utils/encryption.js';
export { RecordsWrite } from './interfaces/records-write.js';
export { executeUnlessAborted } from './utils/abort.js';
export { Jws } from './utils/jws.js';
export { Message } from './core/message.js';
export { MessagesGet } from './interfaces/messages-get.js';
export { PermissionsProtocol } from './protocols/permissions.js';
export { PrivateKeySigner } from './utils/private-key-signer.js';
export { Protocols } from './utils/protocols.js';
export { ProtocolsConfigure } from './interfaces/protocols-configure.js';
export { ProtocolsQuery } from './interfaces/protocols-query.js';
export { Records } from './utils/records.js';
export { RecordsDelete } from './interfaces/records-delete.js';
export { RecordsRead } from './interfaces/records-read.js';
export { RecordsSubscribe } from './interfaces/records-subscribe.js';
export { Secp256k1 } from './utils/secp256k1.js';
export { Secp256r1 } from './utils/secp256r1.js';
export { SortDirection } from './types/query-types.js';
export { Time } from './utils/time.js';
// concrete implementations of stores and event stream
export { DataStoreLevel } from './store/data-store-level.js';
export { EventLogLevel } from './event-log/event-log-level.js';
export { MessageStoreLevel } from './store/message-store-level.js';
export { EventEmitterStream } from './event-log/event-emitter-stream.js';
// test library exports
export { TestDataGenerator } from '../tests/utils/test-data-generator.js';
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAA2B,kBAAkB,EAAc,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAuB,MAAM,+BAA+B,CAAC;AAElF,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAqB,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAoB,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,WAAW,EAAsB,MAAM,8BAA8B,CAAC;AAC/E,OAAO,EAAE,eAAe,EAA0B,MAAM,kCAAkC,CAAC;AAC3F,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAuC,YAAY,EAA0C,MAAM,+BAA+B,CAAC;AAC1I,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAsB,MAAM,8BAA8B,CAAC;AAG/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAA6B,MAAM,qCAAqC,CAAC;AACpG,OAAO,EAAE,cAAc,EAAyB,MAAM,iCAAiC,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAwB,MAAM,gCAAgC,CAAC;AACrF,OAAO,EAAE,WAAW,EAAsB,MAAM,8BAA8B,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAA2B,MAAM,mCAAmC,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,sDAAsD;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE,uBAAuB;AACvB,OAAO,EAAW,iBAAiB,EAAE,MAAM,uCAAuC,CAAC"}
@@ -0,0 +1,41 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class EventsGet extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new EventsGet(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Events,
method: DwnMethodName.Get,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
};
if (options.cursor) {
descriptor.cursor = options.cursor;
}
const authorization = yield Message.createAuthorization({ descriptor, signer: options.signer });
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new EventsGet(message);
});
}
}
//# sourceMappingURL=events-get.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-get.js","sourceRoot":"","sources":["../../../../src/interfaces/events-get.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAQnF,MAAM,OAAO,SAAU,SAAQ,eAAiC;IAEvD,MAAM,CAAO,KAAK,CAAC,OAAyB;;YACjD,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC9F,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAE5D,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;KAAA;IAEM,MAAM,CAAO,MAAM,CAAC,OAAyB;;;YAClD,MAAM,UAAU,GAAwB;gBACtC,SAAS,EAAU,gBAAgB,CAAC,MAAM;gBAC1C,MAAM,EAAa,aAAa,CAAC,GAAG;gBACpC,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,IAAI,CAAC,mBAAmB,EAAE;aAC1E,CAAC;YAEF,IAAI,OAAO,CAAC,MAAM,EAAE;gBAClB,UAAU,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;aACpC;YAED,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAChG,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAE9C,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEpC,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;;KAC/B;CACF"}
@@ -0,0 +1,51 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Events } from '../utils/events.js';
import { Message } from '../core/message.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
export class EventsQuery extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
for (const filter of message.descriptor.filters) {
if ('protocol' in filter && filter.protocol !== undefined) {
validateProtocolUrlNormalized(filter.protocol);
}
if ('schema' in filter && filter.schema !== undefined) {
validateSchemaUrlNormalized(filter.schema);
}
}
return new EventsQuery(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Events,
method: DwnMethodName.Query,
filters: Events.normalizeFilters(options.filters),
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
cursor: options.cursor,
};
removeUndefinedProperties(descriptor);
const authorization = yield Message.createAuthorization({ descriptor, signer: options.signer });
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new EventsQuery(message);
});
}
}
//# sourceMappingURL=events-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-query.js","sourceRoot":"","sources":["../../../../src/interfaces/events-query.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAS7F,MAAM,OAAO,WAAY,SAAQ,eAAmC;IAE3D,MAAM,CAAO,KAAK,CAAC,OAA2B;;YACnD,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAE9F,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE;gBAC/C,IAAI,UAAU,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE;oBACzD,6BAA6B,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;iBAChD;gBACD,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE;oBACrD,2BAA2B,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;iBAC5C;aACF;YAED,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;KAAA;IAEM,MAAM,CAAO,MAAM,CAAC,OAA2B;;;YACpD,MAAM,UAAU,GAA0B;gBACxC,SAAS,EAAU,gBAAgB,CAAC,MAAM;gBAC1C,MAAM,EAAa,aAAa,CAAC,KAAK;gBACtC,OAAO,EAAY,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC3D,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,IAAI,CAAC,mBAAmB,EAAE;gBACzE,MAAM,EAAa,OAAO,CAAC,MAAM;aAClC,CAAC;YAEF,yBAAyB,CAAC,UAAU,CAAC,CAAC;YAEtC,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAChG,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAE9C,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEpC,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;;KACjC;CACF"}
@@ -0,0 +1,59 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
export class EventsSubscribe extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
for (const filter of message.descriptor.filters) {
if ('protocol' in filter && filter.protocol !== undefined) {
validateProtocolUrlNormalized(filter.protocol);
}
if ('schema' in filter && filter.schema !== undefined) {
validateSchemaUrlNormalized(filter.schema);
}
}
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new EventsSubscribe(message);
});
}
/**
* Creates a EventsSubscribe message.
*
* @throws {DwnError} if json schema validation fails.
*/
static create(options) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
const currentTime = Time.getCurrentTimestamp();
const descriptor = {
interface: DwnInterfaceName.Events,
method: DwnMethodName.Subscribe,
filters: (_a = options.filters) !== null && _a !== void 0 ? _a : [],
messageTimestamp: (_b = options.messageTimestamp) !== null && _b !== void 0 ? _b : currentTime,
};
removeUndefinedProperties(descriptor);
const authorization = yield Message.createAuthorization({
descriptor,
signer: options.signer
});
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new EventsSubscribe(message);
});
}
}
//# sourceMappingURL=events-subscribe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-subscribe.js","sourceRoot":"","sources":["../../../../src/interfaces/events-subscribe.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAS7F,MAAM,OAAO,eAAgB,SAAQ,eAAuC;IACnE,MAAM,CAAO,KAAK,CAAC,OAA+B;;YACvD,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAE9F,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE;gBAC/C,IAAI,UAAU,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE;oBACzD,6BAA6B,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;iBAChD;gBACD,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE;oBACrD,2BAA2B,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;iBAC5C;aACF;YAED,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAC5D,OAAO,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;KAAA;IAED;;;;OAIG;IACI,MAAM,CAAO,MAAM,CACxB,OAA+B;;;YAE/B,MAAM,WAAW,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAE/C,MAAM,UAAU,GAA8B;gBAC5C,SAAS,EAAU,gBAAgB,CAAC,MAAM;gBAC1C,MAAM,EAAa,aAAa,CAAC,SAAS;gBAC1C,OAAO,EAAY,MAAA,OAAO,CAAC,OAAO,mCAAI,EAAE;gBACxC,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,WAAW;aAC3D,CAAC;YAEF,yBAAyB,CAAC,UAAU,CAAC,CAAC;YAEtC,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC;gBACtD,UAAU;gBACV,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC,CAAC;YAEH,MAAM,OAAO,GAA2B,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YACtE,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,OAAO,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;;KACrC;CACF"}
@@ -0,0 +1,58 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Cid } from '../utils/cid.js';
import { Message } from '../core/message.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class MessagesGet extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
this.validateMessageCids(message.descriptor.messageCids);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new MessagesGet(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Messages,
method: DwnMethodName.Get,
messageCids: options.messageCids,
messageTimestamp: (_a = options === null || options === void 0 ? void 0 : options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
};
const authorization = yield Message.createAuthorization({ descriptor, signer: options.signer });
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
MessagesGet.validateMessageCids(options.messageCids);
return new MessagesGet(message);
});
}
/**
* validates the provided cids
* @param messageCids - the cids in question
* @throws {DwnError} if an invalid cid is found.
*/
static validateMessageCids(messageCids) {
for (const cid of messageCids) {
try {
Cid.parseCid(cid);
}
catch (_) {
throw new DwnError(DwnErrorCode.MessageGetInvalidCid, `${cid} is not a valid CID`);
}
}
}
}
//# sourceMappingURL=messages-get.js.map
@@ -0,0 +1 @@
{"version":3,"file":"messages-get.js","sourceRoot":"","sources":["../../../../src/interfaces/messages-get.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAQnF,MAAM,OAAO,WAAY,SAAQ,eAAmC;IAC3D,MAAM,CAAO,KAAK,CAAC,OAA2B;;YACnD,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAEzD,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC9F,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAE5D,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;KAAA;IAEM,MAAM,CAAO,MAAM,CAAC,OAA2B;;;YACpD,MAAM,UAAU,GAA0B;gBACxC,SAAS,EAAU,gBAAgB,CAAC,QAAQ;gBAC5C,MAAM,EAAa,aAAa,CAAC,GAAG;gBACpC,WAAW,EAAQ,OAAO,CAAC,WAAW;gBACtC,gBAAgB,EAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,mCAAI,IAAI,CAAC,mBAAmB,EAAE;aAC3E,CAAC;YAEF,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAChG,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAE9C,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,WAAW,CAAC,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAErD,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;;KACjC;IAED;;;;OAIG;IACK,MAAM,CAAC,mBAAmB,CAAC,WAAqB;QACtD,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE;YAC7B,IAAI;gBACF,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;aACnB;YAAC,OAAO,CAAC,EAAE;gBACV,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,oBAAoB,EAAE,GAAG,GAAG,qBAAqB,CAAC,CAAC;aACpF;SACF;IACH,CAAC;CACF"}
@@ -0,0 +1,244 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { AbstractMessage } from '../core/abstract-message.js';
import Ajv from 'ajv/dist/2020.js';
import { Message } from '../core/message.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, normalizeSchemaUrl, validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
import { ProtocolAction, ProtocolActor } from '../types/protocols-types.js';
export class ProtocolsConfigure extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
ProtocolsConfigure.validateProtocolDefinition(message.descriptor.definition);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new ProtocolsConfigure(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Protocols,
method: DwnMethodName.Configure,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
definition: ProtocolsConfigure.normalizeDefinition(options.definition)
};
const authorization = yield Message.createAuthorization({
descriptor,
signer: options.signer,
permissionGrantId: options.permissionGrantId
});
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
ProtocolsConfigure.validateProtocolDefinition(message.descriptor.definition);
const protocolsConfigure = new ProtocolsConfigure(message);
return protocolsConfigure;
});
}
/**
* Performs validation on the given protocol definition that are not easy to do using a JSON schema.
*/
static validateProtocolDefinition(definition) {
const { protocol, types } = definition;
// validate protocol url
validateProtocolUrlNormalized(protocol);
// validate schema url normalized
for (const typeName in types) {
const schema = types[typeName].schema;
if (schema !== undefined) {
validateSchemaUrlNormalized(schema);
}
}
// validate `structure
ProtocolsConfigure.validateStructure(definition);
}
static validateStructure(definition) {
// gather all declared record types
const recordTypes = Object.keys(definition.types);
// gather all roles
const roles = ProtocolsConfigure.fetchAllRolePathsRecursively('', definition.structure, []);
// validate the entire rule set structure recursively
ProtocolsConfigure.validateRuleSetRecursively({
ruleSet: definition.structure,
ruleSetProtocolPath: '',
recordTypes,
roles
});
}
/**
* Parses the given rule set hierarchy to get all the role protocol paths.
* @throws DwnError if the hierarchy depth goes beyond 10 levels.
*/
static fetchAllRolePathsRecursively(ruleSetProtocolPath, ruleSet, roles) {
// Limit the depth of the record hierarchy to 10 levels
// There is opportunity to optimize here to avoid repeated string splitting
if (ruleSetProtocolPath.split('/').length > 10) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureRecordNestingDepthExceeded, 'Record nesting depth exceeded 10 levels.');
}
for (const recordType in ruleSet) {
// ignore non-nested-record properties
if (recordType.startsWith('$')) {
continue;
}
const childRuleSet = ruleSet[recordType];
let childRuleSetProtocolPath;
if (ruleSetProtocolPath === '') {
childRuleSetProtocolPath = recordType;
}
else {
childRuleSetProtocolPath = `${ruleSetProtocolPath}/${recordType}`;
}
// if this is a role record, add it to the list, else continue to traverse
if (childRuleSet.$role) {
roles.push(childRuleSetProtocolPath);
}
else {
ProtocolsConfigure.fetchAllRolePathsRecursively(childRuleSetProtocolPath, childRuleSet, roles);
}
}
return roles;
}
/**
* Validates the given rule set structure then recursively validates its nested child rule sets.
*/
static validateRuleSetRecursively(input) {
var _a;
const { ruleSet, ruleSetProtocolPath, recordTypes, roles } = input;
// Validate $actions in the rule set
if (ruleSet.$size !== undefined) {
const { min = 0, max } = ruleSet.$size;
if (max !== undefined && max < min) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidSize, `Invalid size range found: max limit ${max} less than min limit ${min} at protocol path '${ruleSetProtocolPath}'`);
}
}
if (ruleSet.$tags) {
const ajv = new Ajv.default();
const _b = ruleSet.$tags, { $allowUndefinedTags, $requiredTags } = _b, tagProperties = __rest(_b, ["$allowUndefinedTags", "$requiredTags"]);
// we validate each tag's expected schema to ensure it is a valid JSON schema
for (const tag in tagProperties) {
const tagSchemaDefinition = tagProperties[tag];
if (!ajv.validateSchema(tagSchemaDefinition)) {
const schemaError = ajv.errorsText(ajv.errors, { dataVar: `${ruleSetProtocolPath}/$tags/${tag}` });
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidTagSchema, `tags schema validation error: ${schemaError}`);
}
}
}
// validate each action rule
const actionRules = (_a = ruleSet.$actions) !== null && _a !== void 0 ? _a : [];
for (let i = 0; i < actionRules.length; i++) {
const actionRule = actionRules[i];
// Validate the `role` property of an `action` if exists.
if (actionRule.role !== undefined) {
// make sure the role contains a valid protocol paths to a role record
if (!roles.includes(actionRule.role)) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureRoleDoesNotExistAtGivenPath, `Role in action ${JSON.stringify(actionRule)} for rule set ${ruleSetProtocolPath} does not exist.`);
}
}
// Validate that if `who` is set to `anyone` then `of` is not set
if (actionRule.who === 'anyone' && actionRule.of) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidActionOfNotAllowed, `'of' is not allowed at rule set protocol path (${ruleSetProtocolPath})`);
}
// Validate that if `who === recipient` and `of === undefined`, then `can` can only contain `co-update`, `co-delete`, and `co-prune`.
// We do not allow `read`, `write`, or `query` in the `can` array because:
// - `read` - Recipients are always allowed to `read`.
// - `write` - Entails ability to create and update.
// Since `of` is undefined, it implies the recipient of THIS record,
// there is no 'recipient' until this record has been created, so it makes no sense to allow recipient to write this record.
// - `query` - Only authorized using roles, so allowing direct recipients to query is outside the scope.
if (actionRule.who === ProtocolActor.Recipient && actionRule.of === undefined) {
// throw if `can` contains a value that is not `co-update`, `co-delete`, or `co-prune`
const hasDisallowedAction = actionRule.can.some(action => ![ProtocolAction.CoUpdate, ProtocolAction.CoDelete, ProtocolAction.CoPrune].includes(action));
if (hasDisallowedAction) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidRecipientOfAction, 'Rules for `recipient` without `of` property must have `can` containing only `co-update`, `co-delete`, and `co-prune`.');
}
}
// Validate that if `who` is set to `author` then `of` is set
if (actionRule.who === ProtocolActor.Author && !actionRule.of) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidActionMissingOf, `'of' is required when 'author' is specified as 'who'`);
}
// validate that if `can` contains `update` or `delete`, it must also contain `create`
if (actionRule.can !== undefined) {
if (actionRule.can.includes(ProtocolAction.Update) && !actionRule.can.includes(ProtocolAction.Create)) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidActionUpdateWithoutCreate, `Action rule ${JSON.stringify(actionRule)} contains 'update' action but missing the required 'create' action.`);
}
if (actionRule.can.includes(ProtocolAction.Delete) && !actionRule.can.includes(ProtocolAction.Create)) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidActionDeleteWithoutCreate, `Action rule ${JSON.stringify(actionRule)} contains 'delete' action but missing the required 'create' action.`);
}
}
// Validate that there are no duplicate actors or roles in the remaining action rules:
// ie. no two action rules can have the same combination of `who` + `of` or `role`.
// NOTE: we only need to check the remaining action rules that have yet to go through action rule validation loop, as a perf shortcut.
for (let j = i + 1; j < actionRules.length; j++) {
const otherActionRule = actionRules[j];
if (actionRule.who !== undefined) {
if (actionRule.who === otherActionRule.who && actionRule.of === otherActionRule.of) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureDuplicateActorInRuleSet, `More than one action rule per actor ${actionRule.who} of ${actionRule.of} not allowed within a rule set: ${JSON.stringify(actionRule)}`);
}
}
else {
// else implicitly a role-based action rule
if (actionRule.role === otherActionRule.role) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureDuplicateRoleInRuleSet, `More than one action rule per role ${actionRule.role} not allowed within a rule set: ${JSON.stringify(actionRule)}`);
}
}
}
}
// Validate nested rule sets
for (const recordType in ruleSet) {
if (recordType.startsWith('$')) {
continue;
}
if (!recordTypes.includes(recordType)) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidRuleSetRecordType, `Rule set ${recordType} is not declared as an allowed type in the protocol definition.`);
}
const childRuleSet = ruleSet[recordType];
let childRuleSetProtocolPath;
if (ruleSetProtocolPath === '') {
childRuleSetProtocolPath = recordType; // case of initial definition structure
}
else {
childRuleSetProtocolPath = `${ruleSetProtocolPath}/${recordType}`;
}
ProtocolsConfigure.validateRuleSetRecursively({
ruleSet: childRuleSet,
ruleSetProtocolPath: childRuleSetProtocolPath,
recordTypes,
roles
});
}
}
static normalizeDefinition(definition) {
const typesCopy = Object.assign({}, definition.types);
// Normalize schema url
for (const typeName in typesCopy) {
const schema = typesCopy[typeName].schema;
if (schema !== undefined) {
typesCopy[typeName].schema = normalizeSchemaUrl(schema);
}
}
return Object.assign(Object.assign({}, definition), { protocol: normalizeProtocolUrl(definition.protocol), types: typesCopy });
}
}
//# sourceMappingURL=protocols-configure.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,84 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { GrantAuthorization } from '../core/grant-authorization.js';
import { Message } from '../core/message.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, validateProtocolUrlNormalized } from '../utils/url.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
export class ProtocolsQuery extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
if (message.authorization !== undefined) {
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
if (message.descriptor.filter !== undefined) {
validateProtocolUrlNormalized(message.descriptor.filter.protocol);
}
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new ProtocolsQuery(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Protocols,
method: DwnMethodName.Query,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
filter: options.filter ? ProtocolsQuery.normalizeFilter(options.filter) : undefined,
};
// delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);
// only generate the `authorization` property if signature input is given
let authorization;
if (options.signer !== undefined) {
authorization = yield Message.createAuthorization({
descriptor,
signer: options.signer,
permissionGrantId: options.permissionGrantId
});
}
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
const protocolsQuery = new ProtocolsQuery(message);
return protocolsQuery;
});
}
static normalizeFilter(filter) {
return Object.assign(Object.assign({}, filter), { protocol: normalizeProtocolUrl(filter.protocol) });
}
authorize(tenant, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// if author is the same as the target tenant, we can directly grant access
if (this.author === tenant) {
return;
}
else if (this.author !== undefined && this.signaturePayload.permissionGrantId) {
const permissionGrant = yield PermissionsProtocol.fetchGrant(tenant, messageStore, this.signaturePayload.permissionGrantId);
yield GrantAuthorization.performBaseValidation({
incomingMessage: this.message,
expectedGrantor: tenant,
expectedGrantee: this.author,
permissionGrant,
messageStore
});
}
else {
throw new DwnError(DwnErrorCode.ProtocolsQueryUnauthorized, 'The ProtocolsQuery failed authorization');
}
});
}
}
//# sourceMappingURL=protocols-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"protocols-query.js","sourceRoot":"","sources":["../../../../src/interfaces/protocols-query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsDelete extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
let signaturePayload;
if (message.authorization !== undefined) {
signaturePayload = yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
yield Records.validateDelegatedGrantReferentialIntegrity(message, signaturePayload);
Time.validateTimestamp(message.descriptor.messageTimestamp);
const recordsDelete = new RecordsDelete(message);
return recordsDelete;
});
}
/**
* Creates a RecordsDelete message.
* @param options.recordId If `undefined`, will be auto-filled as a originating message as convenience for developer.
* @param options.messageTimestamp If `undefined`, it will be auto-filled with current time.
*/
static create(options) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
const recordId = options.recordId;
const currentTime = Time.getCurrentTimestamp();
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Delete,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : currentTime,
recordId,
prune: (_b = options.prune) !== null && _b !== void 0 ? _b : false
};
const authorization = yield Message.createAuthorization({
descriptor,
signer: options.signer,
protocolRole: options.protocolRole,
delegatedGrant: options.delegatedGrant
});
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new RecordsDelete(message);
});
}
/**
* Indexed properties needed for MessageStore indexing.
*/
constructIndexes(initialWrite) {
const message = this.message;
const descriptor = Object.assign({}, message.descriptor);
// we add the immutable properties from the initial RecordsWrite message in order to use them when querying relevant deletes.
const { protocol, protocolPath, recipient, schema, parentId, dateCreated } = initialWrite.descriptor;
// NOTE: the "trick" not may not be apparent on how a query is able to omit deleted records:
// we intentionally not add index for `isLatestBaseState` at all, this means that upon a successful delete,
// no messages with the record ID will match any query because queries by design filter by `isLatestBaseState = true`,
// `isLatestBaseState` for the initial delete would have been toggled to `false`
const indexes = Object.assign({
// isLatestBaseState : "true", // intentionally showing that this index is omitted
protocol, protocolPath, recipient, schema, parentId, dateCreated, contextId: initialWrite.contextId, author: this.author }, descriptor);
removeUndefinedProperties(indexes);
return indexes;
}
/*
* Authorizes the delegate who signed the message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeDelegate(recordsWriteToDelete, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeDelete({
recordsDeleteMessage: this.message,
recordsWriteToDelete,
expectedGrantor: this.author,
expectedGrantee: this.signer,
permissionGrant: delegatedGrant,
messageStore
});
});
}
}
//# sourceMappingURL=records-delete.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-delete.js","sourceRoot":"","sources":["../../../../src/interfaces/records-delete.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { DateSort } from '../types/records-types.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
/**
* A class representing a RecordsQuery DWN message.
*/
export class RecordsQuery extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
if (message.descriptor.filter.published === false) {
if (message.descriptor.dateSort === DateSort.PublishedAscending || message.descriptor.dateSort === DateSort.PublishedDescending) {
throw new DwnError(DwnErrorCode.RecordsQueryParseFilterPublishedSortInvalid, `queries must not filter for \`published:false\` and sort by ${message.descriptor.dateSort}`);
}
}
let signaturePayload;
if (message.authorization !== undefined) {
signaturePayload = yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
yield Records.validateDelegatedGrantReferentialIntegrity(message, signaturePayload);
if ((signaturePayload === null || signaturePayload === void 0 ? void 0 : signaturePayload.protocolRole) !== undefined) {
if (message.descriptor.filter.protocolPath === undefined) {
throw new DwnError(DwnErrorCode.RecordsQueryFilterMissingRequiredProperties, 'Role-authorized queries must include `protocolPath` in the filter');
}
}
if (message.descriptor.filter.protocol !== undefined) {
validateProtocolUrlNormalized(message.descriptor.filter.protocol);
}
if (message.descriptor.filter.schema !== undefined) {
validateSchemaUrlNormalized(message.descriptor.filter.schema);
}
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new RecordsQuery(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Query,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
filter: Records.normalizeFilter(options.filter),
dateSort: options.dateSort,
pagination: options.pagination,
};
if (options.filter.published === false) {
if (options.dateSort === DateSort.PublishedAscending || options.dateSort === DateSort.PublishedDescending) {
throw new DwnError(DwnErrorCode.RecordsQueryCreateFilterPublishedSortInvalid, `queries must not filter for \`published:false\` and sort by ${options.dateSort}`);
}
}
// delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);
// only generate the `authorization` property if signature input is given
const signer = options.signer;
let authorization;
if (signer) {
authorization = yield Message.createAuthorization({
descriptor,
signer,
protocolRole: options.protocolRole,
delegatedGrant: options.delegatedGrant
});
}
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new RecordsQuery(message);
});
}
/**
* Authorizes the delegate who signed this message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeDelegate(messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeQueryOrSubscribe({
incomingMessage: this.message,
expectedGrantee: this.signer,
expectedGrantor: this.author,
permissionGrant: delegatedGrant,
messageStore
});
});
}
}
//# sourceMappingURL=records-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-query.js","sourceRoot":"","sources":["../../../../src/interfaces/records-query.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAgB7F;;GAEG;AACH,MAAM,OAAO,YAAa,SAAQ,eAAoC;IAE7D,MAAM,CAAO,KAAK,CAAC,OAA4B;;YAEpD,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,KAAK,KAAK,EAAE;gBACjD,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,KAAK,QAAQ,CAAC,kBAAkB,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,KAAK,QAAQ,CAAC,mBAAmB,EAAE;oBAC/H,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,2CAA2C,EACxD,+DAA+D,OAAO,CAAC,UAAU,CAAC,QAAQ,EAAE,CAC7F,CAAC;iBACH;aACF;YAED,IAAI,gBAAgB,CAAC;YACrB,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE;gBACvC,gBAAgB,GAAG,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;aAClH;YAED,MAAM,OAAO,CAAC,0CAA0C,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;YAEpF,IAAI,CAAA,gBAAgB,aAAhB,gBAAgB,uBAAhB,gBAAgB,CAAE,YAAY,MAAK,SAAS,EAAE;gBAChD,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS,EAAE;oBACxD,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,2CAA2C,EACxD,mEAAmE,CACpE,CAAC;iBACH;aACF;YAED,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE;gBACpD,6BAA6B,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;aACnE;YACD,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE;gBAClD,2BAA2B,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;aAC/D;YAED,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAE5D,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC;KAAA;IAEM,MAAM,CAAO,MAAM,CAAC,OAA4B;;;YACrD,MAAM,UAAU,GAA2B;gBACzC,SAAS,EAAU,gBAAgB,CAAC,OAAO;gBAC3C,MAAM,EAAa,aAAa,CAAC,KAAK;gBACtC,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,IAAI,CAAC,mBAAmB,EAAE;gBACzE,MAAM,EAAa,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC;gBAC1D,QAAQ,EAAW,OAAO,CAAC,QAAQ;gBACnC,UAAU,EAAS,OAAO,CAAC,UAAU;aACtC,CAAC;YAEF,IAAI,OAAO,CAAC,MAAM,CAAC,SAAS,KAAK,KAAK,EAAE;gBACtC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,kBAAkB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,mBAAmB,EAAE;oBACzG,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,4CAA4C,EACzD,+DAA+D,OAAO,CAAC,QAAQ,EAAE,CAClF,CAAC;iBACH;aACF;YAED,+IAA+I;YAC/I,mFAAmF;YACnF,yBAAyB,CAAC,UAAU,CAAC,CAAC;YAEtC,yEAAyE;YACzE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC9B,IAAI,aAAa,CAAC;YAClB,IAAI,MAAM,EAAE;gBACV,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC;oBAChD,UAAU;oBACV,MAAM;oBACN,YAAY,EAAK,OAAO,CAAC,YAAY;oBACrC,cAAc,EAAG,OAAO,CAAC,cAAc;iBACxC,CAAC,CAAC;aACJ;YACD,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAE9C,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEpC,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;;KAClC;IAED;;;OAGG;IACU,iBAAiB,CAAC,YAA0B;;YACvD,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,aAAc,CAAC,oBAAqB,CAAC,CAAC;YACtG,MAAM,yBAAyB,CAAC,yBAAyB,CAAC;gBACxD,eAAe,EAAG,IAAI,CAAC,OAAO;gBAC9B,eAAe,EAAG,IAAI,CAAC,MAAO;gBAC9B,eAAe,EAAG,IAAI,CAAC,MAAO;gBAC9B,eAAe,EAAG,cAAc;gBAChC,YAAY;aACb,CAAC,CAAC;QACL,CAAC;KAAA;CACF"}
@@ -0,0 +1,84 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsRead extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
let signaturePayload;
if (message.authorization !== undefined) {
signaturePayload = yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
yield Records.validateDelegatedGrantReferentialIntegrity(message, signaturePayload);
Time.validateTimestamp(message.descriptor.messageTimestamp);
const recordsRead = new RecordsRead(message);
return recordsRead;
});
}
/**
* Creates a RecordsRead message.
* @param options.recordId If `undefined`, will be auto-filled as a originating message as convenience for developer.
* @param options.date If `undefined`, it will be auto-filled with current time.
*
* @throws {DwnError} when a combination of required RecordsReadOptions are missing
*/
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const { filter, signer, permissionGrantId, protocolRole } = options;
const currentTime = Time.getCurrentTimestamp();
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Read,
filter: Records.normalizeFilter(filter),
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : currentTime,
};
removeUndefinedProperties(descriptor);
// only generate the `authorization` property if signature input is given
let authorization = undefined;
if (signer !== undefined) {
authorization = yield Message.createAuthorization({
descriptor,
signer,
permissionGrantId,
protocolRole,
delegatedGrant: options.delegatedGrant
});
}
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new RecordsRead(message);
});
}
/**
* Authorizes the delegate who signed this message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeDelegate(matchedRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeRead({
recordsReadMessage: this.message,
recordsWriteMessageToBeRead: matchedRecordsWrite,
expectedGrantor: this.author,
expectedGrantee: this.signer,
permissionGrant: delegatedGrant,
messageStore
});
});
}
}
//# sourceMappingURL=records-read.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-read.js","sourceRoot":"","sources":["../../../../src/interfaces/records-read.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAmBnF,MAAM,OAAO,WAAY,SAAQ,eAAmC;IAE3D,MAAM,CAAO,KAAK,CAAC,OAA2B;;YACnD,IAAI,gBAAgB,CAAC;YACrB,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE;gBACvC,gBAAgB,GAAG,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;aAClH;YAED,MAAM,OAAO,CAAC,0CAA0C,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;YAEpF,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAE5D,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;YAC7C,OAAO,WAAW,CAAC;QACrB,CAAC;KAAA;IAED;;;;;;OAMG;IACI,MAAM,CAAO,MAAM,CAAC,OAA2B;;;YACpD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;YACpE,MAAM,WAAW,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAE/C,MAAM,UAAU,GAA0B;gBACxC,SAAS,EAAU,gBAAgB,CAAC,OAAO;gBAC3C,MAAM,EAAa,aAAa,CAAC,IAAI;gBACrC,MAAM,EAAa,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC;gBAClD,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,WAAW;aAC3D,CAAC;YAEF,yBAAyB,CAAC,UAAU,CAAC,CAAC;YAEtC,yEAAyE;YACzE,IAAI,aAAa,GAAG,SAAS,CAAC;YAC9B,IAAI,MAAM,KAAK,SAAS,EAAE;gBACxB,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC;oBAChD,UAAU;oBACV,MAAM;oBACN,iBAAiB;oBACjB,YAAY;oBACZ,cAAc,EAAE,OAAO,CAAC,cAAc;iBACvC,CAAC,CAAC;aACJ;YACD,MAAM,OAAO,GAAuB,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAElE,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEpC,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;;KACjC;IAED;;;OAGG;IACU,iBAAiB,CAAC,mBAAwC,EAAE,YAA0B;;YACjG,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,aAAc,CAAC,oBAAqB,CAAC,CAAC;YACtG,MAAM,yBAAyB,CAAC,aAAa,CAAC;gBAC5C,kBAAkB,EAAY,IAAI,CAAC,OAAO;gBAC1C,2BAA2B,EAAG,mBAAmB;gBACjD,eAAe,EAAe,IAAI,CAAC,MAAO;gBAC1C,eAAe,EAAe,IAAI,CAAC,MAAO;gBAC1C,eAAe,EAAe,cAAc;gBAC5C,YAAY;aACb,CAAC,CAAC;QACL,CAAC;KAAA;CACF"}
@@ -0,0 +1,91 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
/**
* A class representing a RecordsSubscribe DWN message.
*/
export class RecordsSubscribe extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
let signaturePayload;
if (message.authorization !== undefined) {
signaturePayload = yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
yield Records.validateDelegatedGrantReferentialIntegrity(message, signaturePayload);
if ((signaturePayload === null || signaturePayload === void 0 ? void 0 : signaturePayload.protocolRole) !== undefined) {
if (message.descriptor.filter.protocolPath === undefined) {
throw new DwnError(DwnErrorCode.RecordsSubscribeFilterMissingRequiredProperties, 'Role-authorized subscriptions must include `protocolPath` in the filter');
}
}
if (message.descriptor.filter.protocol !== undefined) {
validateProtocolUrlNormalized(message.descriptor.filter.protocol);
}
if (message.descriptor.filter.schema !== undefined) {
validateSchemaUrlNormalized(message.descriptor.filter.schema);
}
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new RecordsSubscribe(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Subscribe,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
filter: Records.normalizeFilter(options.filter),
};
// delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);
// only generate the `authorization` property if signature input is given
const signer = options.signer;
let authorization;
if (signer) {
authorization = yield Message.createAuthorization({
descriptor,
signer,
protocolRole: options.protocolRole,
delegatedGrant: options.delegatedGrant
});
}
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new RecordsSubscribe(message);
});
}
/**
* Authorizes the delegate who signed the message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeDelegate(messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeQueryOrSubscribe({
incomingMessage: this.message,
expectedGrantor: this.author,
expectedGrantee: this.signer,
permissionGrant: delegatedGrant,
messageStore
});
});
}
}
//# sourceMappingURL=records-subscribe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-subscribe.js","sourceRoot":"","sources":["../../../../src/interfaces/records-subscribe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,766 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { Cid } from '../utils/cid.js';
import { Encoder } from '../utils/encoder.js';
import { Encryption } from '../utils/encryption.js';
import { EncryptionAlgorithm } from '../utils/encryption.js';
import { GeneralJwsBuilder } from '../jose/jws/general/builder.js';
import { Jws } from '../utils/jws.js';
import { KeyDerivationScheme } from '../utils/hd-key.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Secp256k1 } from '../utils/secp256k1.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, normalizeSchemaUrl, validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
/**
* A class representing a RecordsWrite DWN message.
* NOTE: Unable to extend `AbstractMessage` directly because the incompatible `_message` type, which is not just a generic `<M>` type.
*/
export class RecordsWrite {
/**
* Valid JSON message representing this RecordsWrite.
* @throws `DwnErrorCode.RecordsWriteMissingSigner` if the message is not signed yet.
*/
get message() {
if (this._message.authorization === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingSigner, 'This RecordsWrite is not yet signed, JSON message cannot be generated from an incomplete state.');
}
return this._message;
}
get author() {
return this._author;
}
get signaturePayload() {
return this._signaturePayload;
}
/**
* The owner DID of the message if owner signature is present in the message; `undefined` otherwise.
* This is the logical owner of the message, not to be confused with the actual signer of the owner signature,
* this is because the signer of the owner signature may not be the actual DWN owner, but a delegate authorized by the owner.
*/
get owner() {
return this._owner;
}
/**
* Decoded owner signature payload.
*/
get ownerSignaturePayload() {
return this._ownerSignaturePayload;
}
/**
* If this message is signed by an author-delegate.
*/
get isSignedByAuthorDelegate() {
return Message.isSignedByAuthorDelegate(this._message);
}
/**
* If this message is signed by an owner-delegate.
*/
get isSignedByOwnerDelegate() {
return Message.isSignedByOwnerDelegate(this._message);
}
/**
* Gets the signer of this message.
* This is not to be confused with the logical author of the message.
*/
get signer() {
return Message.getSigner(this._message);
}
/**
* Gets the signer of owner signature; `undefined` if owner signature is not present in the message.
* This is not to be confused with the logical owner {@link #owner} of the message,
* this is because the signer of the owner signature may not be the actual DWN owner, but a delegate authorized by the owner.
* In the case that the owner signature is signed by the actual DWN owner, this value will be the same as {@link #owner}.
*/
get ownerSignatureSigner() {
var _a;
if (((_a = this._message.authorization) === null || _a === void 0 ? void 0 : _a.ownerSignature) === undefined) {
return undefined;
}
const signer = Jws.getSignerDid(this._message.authorization.ownerSignature.signatures[0]);
return signer;
}
constructor(message, parentContextId) {
this.parentContextId = parentContextId;
this._message = message;
if (message.authorization !== undefined) {
this._author = Records.getAuthor(message);
this._signaturePayload = Jws.decodePlainObjectPayload(message.authorization.signature);
if (message.authorization.ownerSignature !== undefined) {
// if the message authorization contains owner delegated grant, the owner would be the grantor of the grant
// else the owner would be the signer of the owner signature
if (message.authorization.ownerDelegatedGrant !== undefined) {
this._owner = Message.getSigner(message.authorization.ownerDelegatedGrant);
}
else {
this._owner = Jws.getSignerDid(message.authorization.ownerSignature.signatures[0]);
}
this._ownerSignaturePayload = Jws.decodePlainObjectPayload(message.authorization.ownerSignature);
}
}
this.attesters = RecordsWrite.getAttesters(message);
// consider converting isInitialWrite() & getEntryId() into properties for performance and convenience
}
/**
* Parses a RecordsWrite message and returns a {RecordsWrite} instance.
*/
static parse(recordsWriteMessage) {
return __awaiter(this, void 0, void 0, function* () {
// Make a copy so that the stored copy is not subject to external, unexpected modification.
const message = JSON.parse(JSON.stringify(recordsWriteMessage));
// asynchronous checks that are required by the constructor to initialize members properly
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor, 'RecordsWriteSignaturePayload');
if (message.authorization.ownerSignature !== undefined) {
yield Message.validateSignatureStructure(message.authorization.ownerSignature, message.descriptor);
}
yield RecordsWrite.validateAttestationIntegrity(message);
const recordsWrite = new RecordsWrite(message);
yield recordsWrite.validateIntegrity(); // RecordsWrite specific data integrity check
return recordsWrite;
});
}
/**
* Creates a RecordsWrite message.
* @param options.recordId If `undefined`, will be auto-filled as the initial message as convenience for developer.
* @param options.data Data used to compute the `dataCid`, must be the encrypted data bytes if `options.encryptionInput` is given.
* Must specify `options.dataCid` if `undefined`.
* @param options.dataCid CID of the data that is already stored in the DWN. Must specify `options.data` if `undefined`.
* @param options.dataSize Size of data in number of bytes. Must be defined if `options.dataCid` is defined; must be `undefined` otherwise.
* @param options.dateCreated If `undefined`, it will be auto-filled with current time.
* @param options.messageTimestamp If `undefined`, it will be auto-filled with current time.
* @param options.parentContextId Must be given if this message is for a non-root protocol record.
* If not given, it either means this write is for a root protocol record or a flat-space record.
*/
static create(options) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
if ((options.protocol === undefined && options.protocolPath !== undefined) ||
(options.protocol !== undefined && options.protocolPath === undefined)) {
throw new DwnError(DwnErrorCode.RecordsWriteCreateProtocolAndProtocolPathMutuallyInclusive, '`protocol` and `protocolPath` must both be defined or undefined at the same time');
}
if ((options.data === undefined && options.dataCid === undefined) ||
(options.data !== undefined && options.dataCid !== undefined)) {
throw new DwnError(DwnErrorCode.RecordsWriteCreateDataAndDataCidMutuallyExclusive, 'one and only one parameter between `data` and `dataCid` is required');
}
if ((options.dataCid === undefined && options.dataSize !== undefined) ||
(options.dataCid !== undefined && options.dataSize === undefined)) {
throw new DwnError(DwnErrorCode.RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive, '`dataCid` and `dataSize` must both be defined or undefined at the same time');
}
if (options.signer === undefined && options.delegatedGrant !== undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteCreateMissingSigner, '`signer` must be given when `delegatedGrant` is given');
}
const dataCid = (_a = options.dataCid) !== null && _a !== void 0 ? _a : yield Cid.computeDagPbCidFromBytes(options.data);
const dataSize = (_b = options.dataSize) !== null && _b !== void 0 ? _b : options.data.length;
const currentTime = Time.getCurrentTimestamp();
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
protocol: options.protocol !== undefined ? normalizeProtocolUrl(options.protocol) : undefined,
protocolPath: options.protocolPath,
recipient: options.recipient,
schema: options.schema !== undefined ? normalizeSchemaUrl(options.schema) : undefined,
tags: options.tags,
parentId: RecordsWrite.getRecordIdFromContextId(options.parentContextId),
dataCid,
dataSize,
dateCreated: (_c = options.dateCreated) !== null && _c !== void 0 ? _c : currentTime,
messageTimestamp: (_d = options.messageTimestamp) !== null && _d !== void 0 ? _d : currentTime,
published: options.published,
datePublished: options.datePublished,
dataFormat: options.dataFormat
};
// generate `datePublished` if the message is to be published but `datePublished` is not given
if (options.published === true &&
options.datePublished === undefined) {
descriptor.datePublished = currentTime;
}
// delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);
// `recordId` computation
const recordId = options.recordId;
// `attestation` generation
const descriptorCid = yield Cid.computeCid(descriptor);
const attestation = yield RecordsWrite.createAttestation(descriptorCid, options.attestationSigners);
// `encryption` generation
const encryption = yield RecordsWrite.createEncryptionProperty(descriptor, options.encryptionInput);
const message = {
recordId,
descriptor
};
// assign optional properties only if they exist
if (attestation !== undefined) {
message.attestation = attestation;
}
if (encryption !== undefined) {
message.encryption = encryption;
}
const recordsWrite = new RecordsWrite(message, options.parentContextId);
if (options.signer !== undefined) {
yield recordsWrite.sign({
signer: options.signer,
delegatedGrant: options.delegatedGrant,
permissionGrantId: options.permissionGrantId,
protocolRole: options.protocolRole
});
}
return recordsWrite;
});
}
static getRecordIdFromContextId(contextId) {
return contextId === null || contextId === void 0 ? void 0 : contextId.split('/').filter(segment => segment !== '').pop();
}
/**
* Convenience method that creates a message by:
* 1. Copying over immutable properties from the given source message
* 2. Copying over mutable properties that are not overwritten from the given source message
* 3. Replace the mutable properties that are given new value
* @param options.recordsWriteMessage Message that the new RecordsWrite will be based from.
* @param options.messageTimestamp The new date the record is modified. If not given, current time will be used .
* @param options.data The new data or the record. If not given, data from given message will be used.
* @param options.published The new published state. If not given, then will be set to `true` if {options.messageTimestamp} is given;
* else the state from given message will be used.
* @param options.publishedDate The new date the record is modified. If not given, then:
* - will not be set if the record will be unpublished as the result of this RecordsWrite; else
* - will be set to the same published date as the given message if it wss already published; else
* - will be set to current time (because this is a toggle from unpublished to published)
*/
static createFrom(options) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
const sourceMessage = options.recordsWriteMessage;
const sourceRecordsWrite = yield RecordsWrite.parse(sourceMessage);
const currentTime = Time.getCurrentTimestamp();
// inherit published value from parent if neither published nor datePublished is specified
const published = (_a = options.published) !== null && _a !== void 0 ? _a : (options.datePublished ? true : sourceMessage.descriptor.published);
// use current time if published but no explicit time given
let datePublished = undefined;
// if given explicitly published dated
if (options.datePublished) {
datePublished = options.datePublished;
}
else {
// if this RecordsWrite will publish the record
if (published) {
// the parent was already published, inherit the same published date
if (sourceMessage.descriptor.published) {
datePublished = sourceMessage.descriptor.datePublished;
}
else {
// this is a toggle from unpublished to published, use current time
datePublished = currentTime;
}
}
}
const createOptions = {
// immutable properties below, just copy from the source message
recipient: sourceMessage.descriptor.recipient,
recordId: sourceMessage.recordId,
dateCreated: sourceMessage.descriptor.dateCreated,
protocol: sourceMessage.descriptor.protocol,
protocolPath: sourceMessage.descriptor.protocolPath,
schema: sourceMessage.descriptor.schema,
parentContextId: Records.getParentContextFromOfContextId(sourceMessage.contextId),
// mutable properties below
messageTimestamp: (_b = options.messageTimestamp) !== null && _b !== void 0 ? _b : currentTime,
published,
datePublished,
tags: options.tags,
data: options.data,
dataCid: options.data ? undefined : sourceMessage.descriptor.dataCid,
dataSize: options.data ? undefined : sourceMessage.descriptor.dataSize,
dataFormat: (_c = options.dataFormat) !== null && _c !== void 0 ? _c : sourceMessage.descriptor.dataFormat,
protocolRole: (_d = options.protocolRole) !== null && _d !== void 0 ? _d : sourceRecordsWrite.signaturePayload.protocolRole,
delegatedGrant: options.delegatedGrant,
// finally still need signers
signer: options.signer,
attestationSigners: options.attestationSigners
};
const recordsWrite = yield RecordsWrite.create(createOptions);
return recordsWrite;
});
}
/**
* Called by `JSON.stringify(...)` automatically.
*/
toJSON() {
return this.message;
}
/**
* Encrypts the symmetric encryption key using the public keys given and attach the resulting `encryption` property to the RecordsWrite.
*/
encryptSymmetricEncryptionKey(encryptionInput) {
return __awaiter(this, void 0, void 0, function* () {
this._message.encryption = yield RecordsWrite.createEncryptionProperty(this._message.descriptor, encryptionInput);
// opportunity here to re-sign instead of remove
delete this._message.authorization;
this._signaturePayload = undefined;
this._author = undefined;
});
}
/**
* Signs the RecordsWrite, the signer is commonly the author, but can also be a delegate.
*/
sign(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const { signer, delegatedGrant, permissionGrantId, protocolRole } = options;
// compute delegated grant ID and author if delegated grant is given
let delegatedGrantId;
let authorDid;
if (delegatedGrant !== undefined) {
delegatedGrantId = yield Message.getCid(delegatedGrant);
authorDid = Jws.getSignerDid(delegatedGrant.authorization.signature.signatures[0]);
}
else {
authorDid = Jws.extractDid(signer.keyId);
}
const descriptor = this._message.descriptor;
const descriptorCid = yield Cid.computeCid(descriptor);
// compute `recordId` if not given at construction time
this._message.recordId = (_a = this._message.recordId) !== null && _a !== void 0 ? _a : yield RecordsWrite.getEntryId(authorDid, descriptor);
// compute `contextId` if this is a protocol-space record
if (this._message.descriptor.protocol !== undefined) {
// if `parentContextId` is not given, this is a root protocol record
if (this.parentContextId === undefined || this.parentContextId === '') {
this._message.contextId = this._message.recordId;
}
else {
// else this is a non-root protocol record
this._message.contextId = this.parentContextId + '/' + this._message.recordId;
}
}
// `signature` generation
const signature = yield RecordsWrite.createSignerSignature({
recordId: this._message.recordId,
contextId: this._message.contextId,
descriptorCid,
attestation: this._message.attestation,
encryption: this._message.encryption,
signer,
delegatedGrantId,
permissionGrantId,
protocolRole
});
this._message.authorization = { signature };
if (delegatedGrant !== undefined) {
this._message.authorization.authorDelegatedGrant = delegatedGrant;
}
// there is opportunity to optimize here as the payload is constructed within `createAuthorization(...)`
this._signaturePayload = Jws.decodePlainObjectPayload(signature);
this._author = authorDid;
});
}
/**
* Signs the `RecordsWrite` as the DWN owner.
* This is used when the DWN owner wants to retain a copy of a message that the owner did not author.
* NOTE: requires the `RecordsWrite` to already have the author's signature.
*/
signAsOwner(signer) {
return __awaiter(this, void 0, void 0, function* () {
if (this._author === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteSignAsOwnerUnknownAuthor, 'Unable to sign as owner without message signature because owner needs to sign over `recordId` which depends on author DID.');
}
const descriptor = this._message.descriptor;
const ownerSignature = yield Message.createSignature(descriptor, signer);
this._message.authorization.ownerSignature = ownerSignature;
this._ownerSignaturePayload = Jws.decodePlainObjectPayload(ownerSignature);
this._owner = Jws.extractDid(signer.keyId);
;
});
}
/**
* Signs the `RecordsWrite` as the DWN owner-delegate.
* This is used when a DWN owner-delegate wants to retain a copy of a message that the owner did not author.
* NOTE: requires the `RecordsWrite` to already have the author's signature.
*/
signAsOwnerDelegate(signer, delegatedGrant) {
return __awaiter(this, void 0, void 0, function* () {
if (this._author === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteSignAsOwnerDelegateUnknownAuthor, 'Unable to sign as owner delegate without message signature because owner delegate needs to sign over `recordId` which depends on author DID.');
}
const delegatedGrantId = yield Message.getCid(delegatedGrant);
const descriptor = this._message.descriptor;
const ownerSignature = yield Message.createSignature(descriptor, signer, { delegatedGrantId });
this._message.authorization.ownerSignature = ownerSignature;
this._message.authorization.ownerDelegatedGrant = delegatedGrant;
this._ownerSignaturePayload = Jws.decodePlainObjectPayload(ownerSignature);
this._owner = Jws.getSignerDid(delegatedGrant.authorization.signature.signatures[0]);
});
}
/**
* Validates the integrity of the RecordsWrite message assuming the message passed basic schema validation.
* There is opportunity to integrate better with `validateSchema(...)`
*/
validateIntegrity() {
return __awaiter(this, void 0, void 0, function* () {
// if the new message is the initial write
const isInitialWrite = yield this.isInitialWrite();
if (isInitialWrite) {
// `messageTimestamp` and `dateCreated` equality check
const dateRecordCreated = this.message.descriptor.dateCreated;
const messageTimestamp = this.message.descriptor.messageTimestamp;
if (messageTimestamp !== dateRecordCreated) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityDateCreatedMismatch, `messageTimestamp ${messageTimestamp} must match dateCreated ${dateRecordCreated} for the initial write`);
}
// if the message is also a protocol context root, the `contextId` must match the expected deterministic value
if (this.message.descriptor.protocol !== undefined &&
this.message.descriptor.parentId === undefined) {
const expectedContextId = yield this.getEntryId();
if (this.message.contextId !== expectedContextId) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityContextIdMismatch, `contextId in message: ${this.message.contextId} does not match deterministic contextId: ${expectedContextId}`);
}
}
}
// NOTE: validateSignatureStructure() call earlier enforces the presence of `authorization` and thus `signature` in RecordsWrite
const signaturePayload = this.signaturePayload;
// make sure the `recordId` in message is the same as the `recordId` in the payload of the message signature
if (this.message.recordId !== signaturePayload.recordId) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityRecordIdUnauthorized, `recordId in message ${this.message.recordId} does not match recordId in authorization: ${signaturePayload.recordId}`);
}
// if `contextId` is given in message, make sure the same `contextId` is in the payload of the message signature
if (this.message.contextId !== signaturePayload.contextId) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload, `contextId in message ${this.message.contextId} does not match contextId in authorization: ${signaturePayload.contextId}`);
}
yield Records.validateDelegatedGrantReferentialIntegrity(this.message, signaturePayload, this.ownerSignaturePayload);
// if `attestation` is given in message, make sure the correct `attestationCid` is in the payload of the message signature
if (signaturePayload.attestationCid !== undefined) {
const expectedAttestationCid = yield Cid.computeCid(this.message.attestation);
const actualAttestationCid = signaturePayload.attestationCid;
if (actualAttestationCid !== expectedAttestationCid) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityAttestationMismatch, `CID ${expectedAttestationCid} of attestation property in message does not match attestationCid in authorization: ${actualAttestationCid}`);
}
}
// if `encryption` is given in message, make sure the correct `encryptionCid` is in the payload of the message signature
if (signaturePayload.encryptionCid !== undefined) {
const expectedEncryptionCid = yield Cid.computeCid(this.message.encryption);
const actualEncryptionCid = signaturePayload.encryptionCid;
if (actualEncryptionCid !== expectedEncryptionCid) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityEncryptionCidMismatch, `CID ${expectedEncryptionCid} of encryption property in message does not match encryptionCid in authorization: ${actualEncryptionCid}`);
}
}
if (this.message.descriptor.protocol !== undefined) {
validateProtocolUrlNormalized(this.message.descriptor.protocol);
}
if (this.message.descriptor.schema !== undefined) {
validateSchemaUrlNormalized(this.message.descriptor.schema);
}
Time.validateTimestamp(this.message.descriptor.messageTimestamp);
Time.validateTimestamp(this.message.descriptor.dateCreated);
if (this.message.descriptor.datePublished) {
Time.validateTimestamp(this.message.descriptor.datePublished);
}
});
}
/**
* Validates the structural integrity of the `attestation` property.
* NOTE: signature is not verified.
*/
static validateAttestationIntegrity(message) {
return __awaiter(this, void 0, void 0, function* () {
if (message.attestation === undefined) {
return;
}
// TODO: multi-attesters to be unblocked by #205 - Revisit database interfaces (https://github.com/TBD54566975/dwn-sdk-js/issues/205)
if (message.attestation.signatures.length !== 1) {
throw new DwnError(DwnErrorCode.RecordsWriteAttestationIntegrityMoreThanOneSignature, `Currently implementation only supports 1 attester, but got ${message.attestation.signatures.length}`);
}
const payloadJson = Jws.decodePlainObjectPayload(message.attestation);
const { descriptorCid } = payloadJson;
// `descriptorCid` validation - ensure that the provided descriptorCid matches the CID of the actual message
const expectedDescriptorCid = yield Cid.computeCid(message.descriptor);
if (descriptorCid !== expectedDescriptorCid) {
throw new DwnError(DwnErrorCode.RecordsWriteAttestationIntegrityDescriptorCidMismatch, `descriptorCid ${descriptorCid} does not match expected descriptorCid ${expectedDescriptorCid}`);
}
// check to ensure that no other unexpected properties exist in payload.
const propertyCount = Object.keys(payloadJson).length;
if (propertyCount > 1) {
throw new DwnError(DwnErrorCode.RecordsWriteAttestationIntegrityInvalidPayloadProperty, `Only 'descriptorCid' is allowed in attestation payload, but got ${propertyCount} properties.`);
}
});
}
;
/**
* Computes the deterministic Entry ID of this message.
*/
getEntryId() {
return __awaiter(this, void 0, void 0, function* () {
const entryId = yield RecordsWrite.getEntryId(this.author, this.message.descriptor);
return entryId;
});
}
;
/**
* Computes the deterministic Entry ID of this message.
*/
static getEntryId(author, descriptor) {
return __awaiter(this, void 0, void 0, function* () {
if (author === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteGetEntryIdUndefinedAuthor, 'Property `author` is needed to compute entry ID.');
}
const entryIdInput = Object.assign({}, descriptor);
entryIdInput.author = author;
const cid = yield Cid.computeCid(entryIdInput);
return cid;
});
}
;
/**
* Checks if the given message is the initial entry of a record.
*/
isInitialWrite() {
return __awaiter(this, void 0, void 0, function* () {
const entryId = yield this.getEntryId();
return (entryId === this.message.recordId);
});
}
constructIndexes(isLatestBaseState) {
return __awaiter(this, void 0, void 0, function* () {
const message = this.message;
// we want to process tags separately from the rest of descriptors as it is an object and not a primitive KeyValue type.
const _a = message.descriptor, { tags } = _a, descriptor = __rest(_a, ["tags"]);
delete descriptor.published; // handle `published` specifically further down
let indexes = Object.assign(Object.assign({}, descriptor), { isLatestBaseState, published: !!message.descriptor.published, author: this.author, recordId: message.recordId, entryId: yield RecordsWrite.getEntryId(this.author, this.message.descriptor) });
// in order to avoid name clashes with first-class index keys
// we build the indexes with `tag.property_name` for each tag property.
// we only index tags if the message is the latest base state, as that's the only time filtering for tags is relevant.
if (tags !== undefined && isLatestBaseState === true) {
const flattenedTags = Records.buildTagIndexes(Object.assign({}, tags));
indexes = Object.assign(Object.assign({}, indexes), flattenedTags);
}
// add additional indexes to optional values if given
// TODO: index multi-attesters to be unblocked by #205 - Revisit database interfaces (https://github.com/TBD54566975/dwn-sdk-js/issues/205)
if (this.attesters.length > 0) {
indexes.attester = this.attesters[0];
}
if (message.contextId !== undefined) {
indexes.contextId = message.contextId;
}
return indexes;
});
}
/**
* Authorizes the author-delegate who signed this message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeAuthorDelegate(messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeWrite({
recordsWriteMessage: this.message,
expectedGrantor: this.author,
expectedGrantee: this.signer,
permissionGrant: delegatedGrant,
messageStore
});
});
}
/**
* Authorizes the owner-delegate who signed this message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeOwnerDelegate(messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.ownerDelegatedGrant);
yield RecordsGrantAuthorization.authorizeWrite({
recordsWriteMessage: this.message,
expectedGrantor: this.owner,
expectedGrantee: this.ownerSignatureSigner,
permissionGrant: delegatedGrant,
messageStore
});
});
}
/**
* Checks if the given message is the initial entry of a record.
*/
static isInitialWrite(message) {
return __awaiter(this, void 0, void 0, function* () {
// can't be the initial write if the message is not a Records Write
if (message.descriptor.interface !== DwnInterfaceName.Records ||
message.descriptor.method !== DwnMethodName.Write) {
return false;
}
const recordsWriteMessage = message;
const author = Records.getAuthor(recordsWriteMessage);
const entryId = yield RecordsWrite.getEntryId(author, recordsWriteMessage.descriptor);
return (entryId === recordsWriteMessage.recordId);
});
}
/**
* Creates the `encryption` property if encryption input is given. Else `undefined` is returned.
* @param descriptor Descriptor of the `RecordsWrite` message which contains the information need by key path derivation schemes.
*/
static createEncryptionProperty(descriptor, encryptionInput) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
if (encryptionInput === undefined) {
return undefined;
}
// encrypt the data encryption key once per encryption input
const keyEncryption = [];
for (const keyEncryptionInput of encryptionInput.keyEncryptionInputs) {
if (keyEncryptionInput.derivationScheme === KeyDerivationScheme.ProtocolPath && descriptor.protocol === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingProtocol, '`protocols` encryption scheme cannot be applied to record without the `protocol` property.');
}
if (keyEncryptionInput.derivationScheme === KeyDerivationScheme.Schemas && descriptor.schema === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingSchema, '`schemas` encryption scheme cannot be applied to record without the `schema` property.');
}
// NOTE: right now only `ECIES-ES256K` algorithm is supported for asymmetric encryption,
// so we will assume that's the algorithm without additional switch/if statements
const publicKeyBytes = Secp256k1.publicJwkToBytes(keyEncryptionInput.publicKey);
const keyEncryptionOutput = yield Encryption.eciesSecp256k1Encrypt(publicKeyBytes, encryptionInput.key);
const encryptedKey = Encoder.bytesToBase64Url(keyEncryptionOutput.ciphertext);
const ephemeralPublicKey = yield Secp256k1.publicKeyToJwk(keyEncryptionOutput.ephemeralPublicKey);
const keyEncryptionInitializationVector = Encoder.bytesToBase64Url(keyEncryptionOutput.initializationVector);
const messageAuthenticationCode = Encoder.bytesToBase64Url(keyEncryptionOutput.messageAuthenticationCode);
const encryptedKeyData = {
rootKeyId: keyEncryptionInput.publicKeyId,
algorithm: (_a = keyEncryptionInput.algorithm) !== null && _a !== void 0 ? _a : EncryptionAlgorithm.EciesSecp256k1,
derivationScheme: keyEncryptionInput.derivationScheme,
ephemeralPublicKey,
initializationVector: keyEncryptionInitializationVector,
messageAuthenticationCode,
encryptedKey
};
// we need to attach the actual public key if derivation scheme is protocol-context,
// so that the responder to this message is able to encrypt the message/symmetric key using the same protocol-context derived public key,
// without needing the knowledge of the corresponding private key
if (keyEncryptionInput.derivationScheme === KeyDerivationScheme.ProtocolContext) {
encryptedKeyData.derivedPublicKey = keyEncryptionInput.publicKey;
}
keyEncryption.push(encryptedKeyData);
}
const encryption = {
algorithm: (_b = encryptionInput.algorithm) !== null && _b !== void 0 ? _b : EncryptionAlgorithm.Aes256Ctr,
initializationVector: Encoder.bytesToBase64Url(encryptionInput.initializationVector),
keyEncryption
};
return encryption;
});
}
/**
* Creates the `attestation` property of a RecordsWrite message if given signature inputs; returns `undefined` otherwise.
*/
static createAttestation(descriptorCid, signers) {
return __awaiter(this, void 0, void 0, function* () {
if (signers === undefined || signers.length === 0) {
return undefined;
}
const attestationPayload = { descriptorCid };
const attestationPayloadBytes = Encoder.objectToBytes(attestationPayload);
const builder = yield GeneralJwsBuilder.create(attestationPayloadBytes, signers);
return builder.getJws();
});
}
/**
* Creates the `signature` property in the `authorization` of a `RecordsWrite` message.
*/
static createSignerSignature(input) {
return __awaiter(this, void 0, void 0, function* () {
const { recordId, contextId, descriptorCid, attestation, encryption, signer, delegatedGrantId, permissionGrantId, protocolRole } = input;
const attestationCid = attestation ? yield Cid.computeCid(attestation) : undefined;
const encryptionCid = encryption ? yield Cid.computeCid(encryption) : undefined;
const signaturePayload = {
recordId,
descriptorCid,
contextId,
attestationCid,
encryptionCid,
delegatedGrantId,
permissionGrantId,
protocolRole
};
removeUndefinedProperties(signaturePayload);
const signaturePayloadBytes = Encoder.objectToBytes(signaturePayload);
const builder = yield GeneralJwsBuilder.create(signaturePayloadBytes, [signer]);
const signature = builder.getJws();
return signature;
});
}
/**
* Gets the initial write from the given list of `RecordsWrite`.
*/
static getInitialWrite(messages) {
return __awaiter(this, void 0, void 0, function* () {
for (const message of messages) {
if (yield RecordsWrite.isInitialWrite(message)) {
return message;
}
}
throw new DwnError(DwnErrorCode.RecordsWriteGetInitialWriteNotFound, `Initial write is not found.`);
});
}
/**
* Verifies that immutable properties of the two given messages are identical.
* @throws {Error} if immutable properties between two RecordsWrite message
*/
static verifyEqualityOfImmutableProperties(existingWriteMessage, newMessage) {
const mutableDescriptorProperties = ['dataCid', 'dataSize', 'dataFormat', 'datePublished', 'published', 'messageTimestamp', 'tags'];
// get distinct property names that exist in either the existing message given or new message
let descriptorPropertyNames = [];
descriptorPropertyNames.push(...Object.keys(existingWriteMessage.descriptor));
descriptorPropertyNames.push(...Object.keys(newMessage.descriptor));
descriptorPropertyNames = [...new Set(descriptorPropertyNames)]; // step to remove duplicates
// ensure all immutable properties are not modified
for (const descriptorPropertyName of descriptorPropertyNames) {
// if property is supposed to be immutable
if (mutableDescriptorProperties.indexOf(descriptorPropertyName) === -1) {
const valueInExistingWrite = existingWriteMessage.descriptor[descriptorPropertyName];
const valueInNewMessage = newMessage.descriptor[descriptorPropertyName];
if (valueInNewMessage !== valueInExistingWrite) {
throw new DwnError(DwnErrorCode.RecordsWriteImmutablePropertyChanged, `${descriptorPropertyName} is an immutable property: cannot change '${valueInExistingWrite}' to '${valueInNewMessage}'`);
}
}
}
return true;
}
/**
* Gets the DID of the attesters of the given message.
*/
static getAttesters(message) {
var _a, _b;
const attestationSignatures = (_b = (_a = message.attestation) === null || _a === void 0 ? void 0 : _a.signatures) !== null && _b !== void 0 ? _b : [];
const attesters = attestationSignatures.map((signature) => Jws.getSignerDid(signature));
return attesters;
}
/**
* Fetches the initial RecordsWrite of a record.
* @returns The initial RecordsWrite if found; `undefined` if the record is not found.
*/
static fetchInitialRecordsWrite(messageStore, tenant, recordId) {
return __awaiter(this, void 0, void 0, function* () {
const query = { entryId: recordId };
const { messages } = yield messageStore.query(tenant, [query]);
if (messages.length === 0) {
return undefined;
}
const initialRecordsWrite = yield RecordsWrite.parse(messages[0]);
return initialRecordsWrite;
});
}
}
//# sourceMappingURL=records-write.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,51 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as Ed25519 from '@noble/ed25519';
import { Encoder } from '../../../utils/encoder.js';
import { DwnError, DwnErrorCode } from '../../../core/dwn-error.js';
function validateKey(jwk) {
if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {
throw new DwnError(DwnErrorCode.Ed25519InvalidJwk, 'invalid jwk. kty MUST be OKP. crv MUST be Ed25519');
}
}
function publicKeyToJwk(publicKeyBytes) {
const x = Encoder.bytesToBase64Url(publicKeyBytes);
const publicJwk = {
alg: 'EdDSA',
kty: 'OKP',
crv: 'Ed25519',
x
};
return publicJwk;
}
export const ed25519 = {
sign: (content, privateJwk) => __awaiter(void 0, void 0, void 0, function* () {
validateKey(privateJwk);
const privateKeyBytes = Encoder.base64UrlToBytes(privateJwk.d);
return Ed25519.signAsync(content, privateKeyBytes);
}),
verify: (content, signature, publicJwk) => __awaiter(void 0, void 0, void 0, function* () {
validateKey(publicJwk);
const publicKeyBytes = Encoder.base64UrlToBytes(publicJwk.x);
return Ed25519.verifyAsync(signature, content, publicKeyBytes);
}),
generateKeyPair: () => __awaiter(void 0, void 0, void 0, function* () {
const privateKeyBytes = Ed25519.utils.randomPrivateKey();
const publicKeyBytes = yield Ed25519.getPublicKeyAsync(privateKeyBytes);
const d = Encoder.bytesToBase64Url(privateKeyBytes);
const publicJwk = publicKeyToJwk(publicKeyBytes);
const privateJwk = Object.assign(Object.assign({}, publicJwk), { d });
return { publicJwk, privateJwk };
}),
publicKeyToJwk: (publicKeyBytes) => __awaiter(void 0, void 0, void 0, function* () {
return publicKeyToJwk(publicKeyBytes);
})
};
//# sourceMappingURL=ed25519.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ed25519.js","sourceRoot":"","sources":["../../../../../../src/jose/algorithms/signing/ed25519.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAG1C,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAEpE,SAAS,WAAW,CAAC,GAA2B;IAC9C,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,EAAE;QAC9C,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,iBAAiB,EAAE,mDAAmD,CAAC,CAAC;KACzG;AACH,CAAC;AAED,SAAS,cAAc,CAAC,cAA0B;IAChD,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAEnD,MAAM,SAAS,GAAc;QAC3B,GAAG,EAAG,OAAO;QACb,GAAG,EAAG,KAAK;QACX,GAAG,EAAG,SAAS;QACf,CAAC;KACF,CAAC;IAEF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAuB;IACzC,IAAI,EAAE,CAAO,OAAmB,EAAE,UAAsB,EAAuB,EAAE;QAC/E,WAAW,CAAC,UAAU,CAAC,CAAC;QAExB,MAAM,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAE/D,OAAO,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACrD,CAAC,CAAA;IAED,MAAM,EAAE,CAAO,OAAmB,EAAE,SAAqB,EAAE,SAAoB,EAAoB,EAAE;QACnG,WAAW,CAAC,SAAS,CAAC,CAAC;QAEvB,MAAM,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAE7D,OAAO,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IACjE,CAAC,CAAA;IAED,eAAe,EAAE,GAAkE,EAAE;QACnF,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;QACzD,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC;QAExE,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;QAEpD,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,UAAU,mCAAoB,SAAS,KAAE,CAAC,GAAE,CAAC;QAEnD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;IACnC,CAAC,CAAA;IAED,cAAc,EAAE,CAAO,cAA0B,EAAsB,EAAE;QACvE,OAAO,cAAc,CAAC,cAAc,CAAC,CAAC;IACxC,CAAC,CAAA;CACF,CAAC"}
@@ -0,0 +1,20 @@
import { ed25519 } from './ed25519.js';
import { Secp256k1 } from '../../../utils/secp256k1.js';
import { Secp256r1 } from '../../../utils/secp256r1.js';
// the key should be the appropriate `crv` value
export const signatureAlgorithms = {
'Ed25519': ed25519,
'secp256k1': {
sign: Secp256k1.sign,
verify: Secp256k1.verify,
generateKeyPair: Secp256k1.generateKeyPair,
publicKeyToJwk: Secp256k1.publicKeyToJwk
},
'P-256': {
sign: Secp256r1.sign,
verify: Secp256r1.verify,
generateKeyPair: Secp256r1.generateKeyPair,
publicKeyToJwk: Secp256r1.publicKeyToJwk,
},
};
//# sourceMappingURL=signature-algorithms.js.map
@@ -0,0 +1 @@
{"version":3,"file":"signature-algorithms.js","sourceRoot":"","sources":["../../../../../../src/jose/algorithms/signing/signature-algorithms.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,gDAAgD;AAChD,MAAM,CAAC,MAAM,mBAAmB,GAAuC;IACrE,SAAS,EAAK,OAAO;IACrB,WAAW,EAAG;QACZ,IAAI,EAAc,SAAS,CAAC,IAAI;QAChC,MAAM,EAAY,SAAS,CAAC,MAAM;QAClC,eAAe,EAAG,SAAS,CAAC,eAAe;QAC3C,cAAc,EAAI,SAAS,CAAC,cAAc;KAC3C;IACD,OAAO,EAAE;QACP,IAAI,EAAc,SAAS,CAAC,IAAI;QAChC,MAAM,EAAY,SAAS,CAAC,MAAM;QAClC,eAAe,EAAG,SAAS,CAAC,eAAe;QAC3C,cAAc,EAAI,SAAS,CAAC,cAAc;KAC3C;CACF,CAAC"}
@@ -0,0 +1,47 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Encoder } from '../../../utils/encoder.js';
export class GeneralJwsBuilder {
constructor(jws) {
this.jws = jws;
}
static create(payload, signers = []) {
return __awaiter(this, void 0, void 0, function* () {
const jws = {
payload: Encoder.bytesToBase64Url(payload),
signatures: []
};
const builder = new GeneralJwsBuilder(jws);
for (const signer of signers) {
yield builder.addSignature(signer);
}
return builder;
});
}
addSignature(signer) {
return __awaiter(this, void 0, void 0, function* () {
const protectedHeader = {
kid: signer.keyId,
alg: signer.algorithm
};
const protectedHeaderString = JSON.stringify(protectedHeader);
const protectedHeaderBase64UrlString = Encoder.stringToBase64Url(protectedHeaderString);
const signingInputString = `${protectedHeaderBase64UrlString}.${this.jws.payload}`;
const signingInputBytes = Encoder.stringToBytes(signingInputString);
const signatureBytes = yield signer.sign(signingInputBytes);
const signature = Encoder.bytesToBase64Url(signatureBytes);
this.jws.signatures.push({ protected: protectedHeaderBase64UrlString, signature });
});
}
getJws() {
return this.jws;
}
}
//# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../../../../../src/jose/jws/general/builder.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEpD,MAAM,OAAO,iBAAiB;IAG5B,YAAoB,GAAe;QACjC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,MAAM,CAAO,MAAM,CAAC,OAAmB,EAAE,UAAoB,EAAE;;YAC7D,MAAM,GAAG,GAAe;gBACtB,OAAO,EAAM,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC;gBAC9C,UAAU,EAAG,EAAE;aAChB,CAAC;YAEF,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAE3C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;gBAC5B,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;aACpC;YAED,OAAO,OAAO,CAAC;QACjB,CAAC;KAAA;IAEK,YAAY,CAAC,MAAc;;YAC/B,MAAM,eAAe,GAAG;gBACtB,GAAG,EAAG,MAAM,CAAC,KAAK;gBAClB,GAAG,EAAG,MAAM,CAAC,SAAS;aACvB,CAAC;YACF,MAAM,qBAAqB,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;YAC9D,MAAM,8BAA8B,GAAG,OAAO,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,CAAC;YAExF,MAAM,kBAAkB,GAAG,GAAG,8BAA8B,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACnF,MAAM,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC;YAEpE,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;YAE3D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,8BAA8B,EAAE,SAAS,EAAE,CAAC,CAAC;QACrF,CAAC;KAAA;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,97 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Jws } from '../../../utils/jws.js';
import { MemoryCache } from '../../../utils/memory-cache.js';
import { validateJsonSchema } from '../../../schema-validator.js';
import { DwnError, DwnErrorCode } from '../../../core/dwn-error.js';
/**
* Verifies the signature(s) of a General JWS.
*/
export class GeneralJwsVerifier {
constructor(cache) {
this.cache = cache || new MemoryCache(600);
}
static get singleton() {
if (GeneralJwsVerifier._singleton === undefined) {
GeneralJwsVerifier._singleton = new GeneralJwsVerifier();
}
return GeneralJwsVerifier._singleton;
}
/**
* Verifies the signatures of the given General JWS.
* @returns the list of signers that have valid signatures.
*/
static verifySignatures(jws, didResolver) {
return __awaiter(this, void 0, void 0, function* () {
return yield GeneralJwsVerifier.singleton.verifySignatures(jws, didResolver);
});
}
/**
* Verifies the signatures of the given General JWS.
* @returns the list of signers that have valid signatures.
*/
verifySignatures(jws, didResolver) {
return __awaiter(this, void 0, void 0, function* () {
const signers = [];
for (const signatureEntry of jws.signatures) {
let isVerified;
const kid = Jws.getKid(signatureEntry);
const cacheKey = `${signatureEntry.protected}.${jws.payload}.${signatureEntry.signature}`;
const cachedValue = yield this.cache.get(cacheKey);
// explicit `undefined` check to differentiate `false`
if (cachedValue === undefined) {
const publicJwk = yield GeneralJwsVerifier.getPublicKey(kid, didResolver);
isVerified = yield Jws.verifySignature(jws.payload, signatureEntry, publicJwk);
yield this.cache.set(cacheKey, isVerified);
}
else {
isVerified = cachedValue;
}
const did = Jws.extractDid(kid);
if (isVerified) {
signers.push(did);
}
else {
throw new DwnError(DwnErrorCode.GeneralJwsVerifierInvalidSignature, `Signature verification failed for ${did}`);
}
}
return { signers };
});
}
/**
* Gets the public key given a fully qualified key ID (`kid`) by resolving the DID to its DID Document.
*/
static getPublicKey(kid, didResolver) {
return __awaiter(this, void 0, void 0, function* () {
// `resolve` throws exception if DID is invalid, DID method is not supported,
// or resolving DID fails
const did = Jws.extractDid(kid);
const { didDocument } = yield didResolver.resolve(did);
const { verificationMethod: verificationMethods = [] } = didDocument || {};
let verificationMethod;
for (const method of verificationMethods) {
// consider optimizing using a set for O(1) lookups if needed
// key ID in DID Document may or may not be fully qualified. e.g.
// `did:ion:alice#key1` or `#key1`
if (kid.endsWith(method.id)) {
verificationMethod = method;
break;
}
}
if (!verificationMethod) {
throw new DwnError(DwnErrorCode.GeneralJwsVerifierGetPublicKeyNotFound, 'public key needed to verify signature not found in DID Document');
}
validateJsonSchema('JwkVerificationMethod', verificationMethod);
const { publicKeyJwk: publicJwk } = verificationMethod;
return publicJwk;
});
}
}
//# sourceMappingURL=verifier.js.map
@@ -0,0 +1 @@
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../../../../../src/jose/jws/general/verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Encoder } from '../utils/encoder.js';
import { Message } from '../core/message.js';
/**
* A class representing a Permission Grant for a more convenient abstraction.
*/
export class PermissionGrant {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
const permissionGrant = new PermissionGrant(message);
return permissionGrant;
});
}
/**
* Creates a Permission Grant abstraction for
*/
constructor(message) {
// properties derived from the generic DWN message properties
this.id = message.recordId;
this.grantor = Message.getSigner(message);
this.grantee = message.descriptor.recipient;
this.dateGranted = message.descriptor.dateCreated;
// properties from the data payload itself.
const permissionGrantEncoded = message.encodedData;
const permissionGrant = Encoder.base64UrlToObject(permissionGrantEncoded);
this.dateExpires = permissionGrant.dateExpires;
this.delegated = permissionGrant.delegated;
this.description = permissionGrant.description;
this.requestId = permissionGrant.requestId;
this.scope = permissionGrant.scope;
this.conditions = permissionGrant.conditions;
}
}
//# sourceMappingURL=permission-grant.js.map
@@ -0,0 +1 @@
{"version":3,"file":"permission-grant.js","sourceRoot":"","sources":["../../../../src/protocols/permission-grant.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG7C;;GAEG;AACH,MAAM,OAAO,eAAe;IAoDnB,MAAM,CAAO,KAAK,CAAC,OAA4B;;YACpD,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;YACrD,OAAO,eAAe,CAAC;QACzB,CAAC;KAAA;IAED;;OAEG;IACH,YAAoB,OAA4B;QAC9C,6DAA6D;QAC7D,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAE,CAAC;QAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,SAAU,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC;QAElD,2CAA2C;QAC3C,MAAM,sBAAsB,GAAI,OAAkC,CAAC,WAAY,CAAC;QAChF,MAAM,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,sBAAsB,CAAwB,CAAC;QACjG,IAAI,CAAC,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC;QAC/C,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC;QAC/C,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC;IAC/C,CAAC;CACF"}
@@ -0,0 +1,276 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Encoder } from '../utils/encoder.js';
import { PermissionGrant } from './permission-grant.js';
import { RecordsWrite } from '../../src/interfaces/records-write.js';
import { Time } from '../utils/time.js';
import { validateJsonSchema } from '../schema-validator.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, normalizeSchemaUrl } from '../utils/url.js';
/**
* This is a first-class DWN protocol for managing permission grants of a given DWN.
*/
export class PermissionsProtocol {
static parseRequest(base64UrlEncodedRequest) {
return Encoder.base64UrlToObject(base64UrlEncodedRequest);
}
/**
* Convenience method to create a permission request.
*/
static createRequest(options) {
return __awaiter(this, void 0, void 0, function* () {
const scope = PermissionsProtocol.normalizePermissionScope(options.scope);
const permissionRequestData = {
description: options.description,
delegated: options.delegated,
scope,
conditions: options.conditions,
};
const permissionRequestBytes = Encoder.objectToBytes(permissionRequestData);
const recordsWrite = yield RecordsWrite.create({
signer: options.signer,
messageTimestamp: options.dateRequested,
protocol: PermissionsProtocol.uri,
protocolPath: PermissionsProtocol.requestPath,
dataFormat: 'application/json',
data: permissionRequestBytes,
});
return {
recordsWrite,
permissionRequestData,
permissionRequestBytes
};
});
}
/**
* Convenience method to create a permission grant.
*/
static createGrant(options) {
return __awaiter(this, void 0, void 0, function* () {
const scope = PermissionsProtocol.normalizePermissionScope(options.scope);
const permissionGrantData = {
dateExpires: options.dateExpires,
requestId: options.requestId,
description: options.description,
delegated: options.delegated,
scope,
conditions: options.conditions,
};
const permissionGrantBytes = Encoder.objectToBytes(permissionGrantData);
const recordsWrite = yield RecordsWrite.create({
signer: options.signer,
messageTimestamp: options.dateGranted,
dateCreated: options.dateGranted,
recipient: options.grantedTo,
protocol: PermissionsProtocol.uri,
protocolPath: PermissionsProtocol.grantPath,
dataFormat: 'application/json',
data: permissionGrantBytes,
});
const dataEncodedMessage = Object.assign(Object.assign({}, recordsWrite.message), { encodedData: Encoder.bytesToBase64Url(permissionGrantBytes) });
return {
recordsWrite,
permissionGrantData,
permissionGrantBytes,
dataEncodedMessage
};
});
}
/**
* Convenience method to create a permission revocation.
*/
static createRevocation(options) {
return __awaiter(this, void 0, void 0, function* () {
const permissionRevocationData = {
description: options.description,
};
const permissionRevocationBytes = Encoder.objectToBytes(permissionRevocationData);
const recordsWrite = yield RecordsWrite.create({
signer: options.signer,
parentContextId: options.grantId,
protocol: PermissionsProtocol.uri,
protocolPath: PermissionsProtocol.revocationPath,
dataFormat: 'application/json',
data: permissionRevocationBytes,
});
return {
recordsWrite,
permissionRevocationData,
permissionRevocationBytes
};
});
}
/**
* Validates the given Permissions protocol RecordsWrite. It can be a request, grant, or revocation.
*/
static validateSchema(recordsWriteMessage, dataBytes) {
const dataString = Encoder.bytesToString(dataBytes);
const dataObject = JSON.parse(dataString);
if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.requestPath) {
validateJsonSchema('PermissionRequestData', dataObject);
}
else if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.grantPath) {
validateJsonSchema('PermissionGrantData', dataObject);
// more nuanced validation that are annoying/difficult to do using JSON schema
const permissionGrantData = dataObject;
PermissionsProtocol.validateScope(permissionGrantData.scope);
Time.validateTimestamp(permissionGrantData.dateExpires);
}
else if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.revocationPath) {
validateJsonSchema('PermissionRevocationData', dataObject);
}
else {
// defensive programming, should be unreachable externally
throw new DwnError(DwnErrorCode.PermissionsProtocolValidateSchemaUnexpectedRecord, `Unexpected permission record: ${recordsWriteMessage.descriptor.protocolPath}`);
}
}
/**
* Fetches PermissionGrant with the specified `recordID`.
* @returns the PermissionGrant matching the `recordId` specified.
* @throws {Error} if PermissionGrant does not exist
*/
static fetchGrant(tenant, messageStore, permissionGrantId) {
return __awaiter(this, void 0, void 0, function* () {
const grantQuery = {
recordId: permissionGrantId,
isLatestBaseState: true
};
const { messages } = yield messageStore.query(tenant, [grantQuery]);
const possibleGrantMessage = messages[0];
const dwnInterface = possibleGrantMessage === null || possibleGrantMessage === void 0 ? void 0 : possibleGrantMessage.descriptor.interface;
const dwnMethod = possibleGrantMessage === null || possibleGrantMessage === void 0 ? void 0 : possibleGrantMessage.descriptor.method;
if (dwnInterface !== DwnInterfaceName.Records ||
dwnMethod !== DwnMethodName.Write ||
possibleGrantMessage.descriptor.protocolPath !== PermissionsProtocol.grantPath) {
throw new DwnError(DwnErrorCode.GrantAuthorizationGrantMissing, `Could not find permission grant with record ID ${permissionGrantId}.`);
}
const permissionGrantMessage = possibleGrantMessage;
const permissionGrant = yield PermissionGrant.parse(permissionGrantMessage);
return permissionGrant;
});
}
/**
* Normalizes the given permission scope if needed.
* @returns The normalized permission scope.
*/
static normalizePermissionScope(permissionScope) {
const scope = Object.assign({}, permissionScope);
if (PermissionsProtocol.isRecordPermissionScope(scope)) {
// normalize protocol and schema URLs if they are present
if (scope.protocol !== undefined) {
scope.protocol = normalizeProtocolUrl(scope.protocol);
}
if (scope.schema !== undefined) {
scope.schema = normalizeSchemaUrl(scope.schema);
}
}
return scope;
}
/**
* Type guard to determine if the scope is a record permission scope.
*/
static isRecordPermissionScope(scope) {
return scope.interface === 'Records';
}
/**
* Validates scope.
*/
static validateScope(scope) {
if (!this.isRecordPermissionScope(scope)) {
return;
}
// else we are dealing with a RecordsPermissionScope
// `schema` scopes may not have protocol-related fields
if (scope.schema !== undefined) {
if (scope.protocol !== undefined || scope.contextId !== undefined || scope.protocolPath) {
throw new DwnError(DwnErrorCode.PermissionsProtocolValidateScopeSchemaProhibitedProperties, 'Permission grants that have `schema` present cannot also have protocol-related properties present');
}
}
if (scope.protocol !== undefined) {
// `contextId` and `protocolPath` are mutually exclusive
if (scope.contextId !== undefined && scope.protocolPath !== undefined) {
throw new DwnError(DwnErrorCode.PermissionsProtocolValidateScopeContextIdProhibitedProperties, 'Permission grants cannot have both `contextId` and `protocolPath` present');
}
}
}
}
/**
* The URI of the DWN Permissions protocol.
*/
PermissionsProtocol.uri = 'https://tbd.website/dwn/permissions';
/**
* The protocol path of the `request` record.
*/
PermissionsProtocol.requestPath = 'request';
/**
* The protocol path of the `grant` record.
*/
PermissionsProtocol.grantPath = 'grant';
/**
* The protocol path of the `revocation` record.
*/
PermissionsProtocol.revocationPath = 'grant/revocation';
/**
* The definition of the Permissions protocol.
*/
PermissionsProtocol.definition = {
published: true,
protocol: PermissionsProtocol.uri,
types: {
request: {
dataFormats: ['application/json']
},
grant: {
dataFormats: ['application/json']
},
revocation: {
dataFormats: ['application/json']
}
},
structure: {
request: {
$size: {
max: 10000
},
$actions: [
{
who: 'anyone',
can: ['create']
}
]
},
grant: {
$size: {
max: 10000
},
$actions: [
{
who: 'recipient',
of: 'grant',
can: ['read', 'query']
}
],
revocation: {
$size: {
max: 10000
},
$actions: [
{
who: 'anyone',
can: ['read']
}
]
}
}
}
};
;
//# sourceMappingURL=permissions.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,37 @@
import * as precompiledValidators from '../generated/precompiled-validators.js';
import { DwnError, DwnErrorCode } from './core/dwn-error.js';
/**
* Validates the given payload using JSON schema keyed by the given schema name. Throws if the given payload fails validation.
* @param schemaName the schema name use to look up the JSON schema to be used for schema validation.
* The list of schema names can be found in compile-validators.js
* @param payload javascript object to be validated
*/
export function validateJsonSchema(schemaName, payload) {
// const validateFn = validator.getSchema(schemaName);
const validateFn = precompiledValidators[schemaName];
if (!validateFn) {
throw new DwnError(DwnErrorCode.SchemaValidatorSchemaNotFound, `schema for ${schemaName} not found.`);
}
validateFn(payload);
if (!validateFn.errors) {
return;
}
// AJV is configured by default to stop validating after the 1st error is encountered which means
// there will only ever be one error;
const [errorObj] = validateFn.errors;
let { instancePath, message, keyword } = errorObj;
if (!instancePath) {
instancePath = schemaName;
}
// handle a few frequently occurred errors to give more meaningful error for debugging
if (keyword === 'additionalProperties') {
const keyword = errorObj.params.additionalProperty;
throw new DwnError(DwnErrorCode.SchemaValidatorAdditionalPropertyNotAllowed, `${message}: ${instancePath}: ${keyword}`);
}
if (keyword === 'unevaluatedProperties') {
const keyword = errorObj.params.unevaluatedProperty;
throw new DwnError(DwnErrorCode.SchemaValidatorUnevaluatedPropertyNotAllowed, `${message}: ${instancePath}: ${keyword}`);
}
throw new DwnError(DwnErrorCode.SchemaValidatorFailure, `${instancePath}: ${message}`);
}
//# sourceMappingURL=schema-validator.js.map
@@ -0,0 +1 @@
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../../src/schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,qBAAqB,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAE,OAAY;IACjE,sDAAsD;IACtD,MAAM,UAAU,GAAI,qBAA6B,CAAC,UAAU,CAAC,CAAC;IAE9D,IAAI,CAAC,UAAU,EAAE;QACf,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,6BAA6B,EAAE,cAAc,UAAU,aAAa,CAAC,CAAC;KACvG;IAED,UAAU,CAAC,OAAO,CAAC,CAAC;IAEpB,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;QACtB,OAAO;KACR;IAED,iGAAiG;IACjG,qCAAqC;IACrC,MAAM,CAAE,QAAQ,CAAE,GAAG,UAAU,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC;IAElD,IAAI,CAAC,YAAY,EAAE;QACjB,YAAY,GAAG,UAAU,CAAC;KAC3B;IAED,sFAAsF;IAEtF,IAAI,OAAO,KAAK,sBAAsB,EAAE;QACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAAC;QACnD,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,2CAA2C,EAAE,GAAG,OAAO,KAAK,YAAY,KAAK,OAAO,EAAE,CAAC,CAAC;KACzH;IAED,IAAI,OAAO,KAAK,uBAAuB,EAAE;QACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC;QACpD,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,4CAA4C,EAAE,GAAG,OAAO,KAAK,YAAY,KAAK,OAAO,EAAE,CAAC,CAAC;KAC1H;IAED,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,sBAAsB,EAAE,GAAG,YAAY,KAAK,OAAO,EAAE,CAAC,CAAC;AACzF,CAAC"}
@@ -0,0 +1,186 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
import { CID } from 'multiformats';
import { createLevelDatabase, LevelWrapper } from './level-wrapper.js';
// `level` works in Node.js 12+ and Electron 5+ on Linux, Mac OS, Windows and
// FreeBSD, including any future Node.js and Electron release thanks to Node-API, including ARM
// platforms like Raspberry Pi and Android, as well as in Chrome, Firefox, Edge, Safari, iOS Safari
// and Chrome for Android.
/**
* Blockstore implementation using LevelDB for storing the actual messages (in the case of MessageStore)
* or the data associated with messages (in the case of a DataStore).
*/
export class BlockstoreLevel {
constructor(config, db) {
this.config = Object.assign({ createLevelDatabase }, config);
this.db = db !== null && db !== void 0 ? db : new LevelWrapper(Object.assign(Object.assign({}, this.config), { valueEncoding: 'binary' }));
}
open() {
return __awaiter(this, void 0, void 0, function* () {
return this.db.open();
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
return this.db.close();
});
}
partition(name) {
return __awaiter(this, void 0, void 0, function* () {
const db = yield this.db.partition(name);
return new BlockstoreLevel(Object.assign(Object.assign({}, this.config), { location: '' }), db);
});
}
put(key, val, options) {
return __awaiter(this, void 0, void 0, function* () {
yield this.db.put(String(key), val, options);
return CID.parse(key.toString());
});
}
get(key, options) {
return __awaiter(this, void 0, void 0, function* () {
const result = yield this.db.get(String(key), options);
return result;
});
}
has(key, options) {
return __awaiter(this, void 0, void 0, function* () {
return this.db.has(String(key), options);
});
}
delete(key, options) {
return __awaiter(this, void 0, void 0, function* () {
return this.db.delete(String(key), options);
});
}
isEmpty(options) {
return __awaiter(this, void 0, void 0, function* () {
return this.db.isEmpty(options);
});
}
putMany(source, options) {
return __asyncGenerator(this, arguments, function* putMany_1() {
var _a, e_1, _b, _c;
try {
for (var _d = true, source_1 = __asyncValues(source), source_1_1; source_1_1 = yield __await(source_1.next()), _a = source_1_1.done, !_a; _d = true) {
_c = source_1_1.value;
_d = false;
const entry = _c;
yield __await(this.put(entry.cid, entry.block, options));
yield yield __await(entry.cid);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_1.return)) yield __await(_b.call(source_1));
}
finally { if (e_1) throw e_1.error; }
}
});
}
getMany(source, options) {
return __asyncGenerator(this, arguments, function* getMany_1() {
var _a, e_2, _b, _c;
try {
for (var _d = true, source_2 = __asyncValues(source), source_2_1; source_2_1 = yield __await(source_2.next()), _a = source_2_1.done, !_a; _d = true) {
_c = source_2_1.value;
_d = false;
const key = _c;
yield yield __await({
cid: key,
block: yield __await(this.get(key, options))
});
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_2.return)) yield __await(_b.call(source_2));
}
finally { if (e_2) throw e_2.error; }
}
});
}
getAll(options) {
return __asyncGenerator(this, arguments, function* getAll_1() {
var _a, e_3, _b, _c;
// @ts-expect-error keyEncoding is 'buffer' but types for db.iterator always return the key type as 'string'
const li = this.db.iterator({
keys: true,
keyEncoding: 'buffer'
}, options);
try {
for (var _d = true, li_1 = __asyncValues(li), li_1_1; li_1_1 = yield __await(li_1.next()), _a = li_1_1.done, !_a; _d = true) {
_c = li_1_1.value;
_d = false;
const [key, value] = _c;
yield yield __await({ cid: CID.decode(key), block: value });
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (!_d && !_a && (_b = li_1.return)) yield __await(_b.call(li_1));
}
finally { if (e_3) throw e_3.error; }
}
});
}
deleteMany(source, options) {
return __asyncGenerator(this, arguments, function* deleteMany_1() {
var _a, e_4, _b, _c;
try {
for (var _d = true, source_3 = __asyncValues(source), source_3_1; source_3_1 = yield __await(source_3.next()), _a = source_3_1.done, !_a; _d = true) {
_c = source_3_1.value;
_d = false;
const key = _c;
yield __await(this.delete(key, options));
yield yield __await(key);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_3.return)) yield __await(_b.call(source_3));
}
finally { if (e_4) throw e_4.error; }
}
});
}
/**
* deletes all entries
*/
clear() {
return __awaiter(this, void 0, void 0, function* () {
return this.db.clear();
});
}
}
//# sourceMappingURL=blockstore-level.js.map
@@ -0,0 +1 @@
{"version":3,"file":"blockstore-level.js","sourceRoot":"","sources":["../../../../src/store/blockstore-level.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,167 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
import { CID } from 'multiformats';
/**
* Mock implementation for the Blockstore interface.
*
* WARNING!!! Purely to be used with `ipfs-unixfs-importer` to compute CID without needing consume any memory.
* This is particularly useful when dealing with large files and a necessity in a large-scale production service environment.
*/
export class BlockstoreMock {
open() {
return __awaiter(this, void 0, void 0, function* () {
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
});
}
put(key, _val, _options) {
return __awaiter(this, void 0, void 0, function* () {
return key;
});
}
get(_key, _options) {
return __awaiter(this, void 0, void 0, function* () {
return new Uint8Array();
});
}
has(_key, _options) {
return __awaiter(this, void 0, void 0, function* () {
return false;
});
}
delete(_key, _options) {
return __awaiter(this, void 0, void 0, function* () {
});
}
isEmpty(_options) {
return __awaiter(this, void 0, void 0, function* () {
return true;
});
}
putMany(source, options) {
return __asyncGenerator(this, arguments, function* putMany_1() {
var _a, e_1, _b, _c;
try {
for (var _d = true, source_1 = __asyncValues(source), source_1_1; source_1_1 = yield __await(source_1.next()), _a = source_1_1.done, !_a; _d = true) {
_c = source_1_1.value;
_d = false;
const entry = _c;
yield __await(this.put(entry.cid, entry.block, options));
yield yield __await(entry.cid);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_1.return)) yield __await(_b.call(source_1));
}
finally { if (e_1) throw e_1.error; }
}
});
}
getMany(source, options) {
return __asyncGenerator(this, arguments, function* getMany_1() {
var _a, e_2, _b, _c;
try {
for (var _d = true, source_2 = __asyncValues(source), source_2_1; source_2_1 = yield __await(source_2.next()), _a = source_2_1.done, !_a; _d = true) {
_c = source_2_1.value;
_d = false;
const key = _c;
yield yield __await({
cid: key,
block: yield __await(this.get(key, options))
});
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_2.return)) yield __await(_b.call(source_2));
}
finally { if (e_2) throw e_2.error; }
}
});
}
getAll(options) {
return __asyncGenerator(this, arguments, function* getAll_1() {
var _a, e_3, _b, _c;
// @ts-expect-error keyEncoding is 'buffer' but types for db.iterator always return the key type as 'string'
const li = this.db.iterator({
keys: true,
keyEncoding: 'buffer'
}, options);
try {
for (var _d = true, li_1 = __asyncValues(li), li_1_1; li_1_1 = yield __await(li_1.next()), _a = li_1_1.done, !_a; _d = true) {
_c = li_1_1.value;
_d = false;
const [key, value] = _c;
yield yield __await({ cid: CID.decode(key), block: value });
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (!_d && !_a && (_b = li_1.return)) yield __await(_b.call(li_1));
}
finally { if (e_3) throw e_3.error; }
}
});
}
deleteMany(source, options) {
return __asyncGenerator(this, arguments, function* deleteMany_1() {
var _a, e_4, _b, _c;
try {
for (var _d = true, source_3 = __asyncValues(source), source_3_1; source_3_1 = yield __await(source_3.next()), _a = source_3_1.done, !_a; _d = true) {
_c = source_3_1.value;
_d = false;
const key = _c;
yield __await(this.delete(key, options));
yield yield __await(key);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_3.return)) yield __await(_b.call(source_3));
}
finally { if (e_4) throw e_4.error; }
}
});
}
/**
* deletes all entries
*/
clear() {
return __awaiter(this, void 0, void 0, function* () {
});
}
}
//# sourceMappingURL=blockstore-mock.js.map
@@ -0,0 +1 @@
{"version":3,"file":"blockstore-mock.js","sourceRoot":"","sources":["../../../../src/store/blockstore-mock.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAInC;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IAEnB,IAAI;;QACV,CAAC;KAAA;IAEK,KAAK;;QACX,CAAC;KAAA;IAEK,GAAG,CAAC,GAAQ,EAAE,IAAgB,EAAE,QAAuB;;YAC3D,OAAO,GAAG,CAAC;QACb,CAAC;KAAA;IAEK,GAAG,CAAC,IAAS,EAAE,QAAuB;;YAC1C,OAAO,IAAI,UAAU,EAAE,CAAC;QAC1B,CAAC;KAAA;IAEK,GAAG,CAAC,IAAS,EAAE,QAAuB;;YAC1C,OAAO,KAAK,CAAC;QACf,CAAC;KAAA;IAEK,MAAM,CAAC,IAAS,EAAE,QAAuB;;QAC/C,CAAC;KAAA;IAEK,OAAO,CAAC,QAAuB;;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;KAAA;IAEO,OAAO,CAAC,MAA2B,EAAE,OAAsB;;;;gBACjE,KAA0B,eAAA,WAAA,cAAA,MAAM,CAAA,YAAA,qFAAE;oBAAR,sBAAM;oBAAN,WAAM;oBAArB,MAAM,KAAK,KAAA,CAAA;oBACpB,cAAM,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA,CAAC;oBAEhD,oBAAM,KAAK,CAAC,GAAG,CAAA,CAAC;iBACjB;;;;;;;;;QACH,CAAC;KAAA;IAEO,OAAO,CAAC,MAA0B,EAAE,OAAsB;;;;gBAChE,KAAwB,eAAA,WAAA,cAAA,MAAM,CAAA,YAAA,qFAAE;oBAAR,sBAAM;oBAAN,WAAM;oBAAnB,MAAM,GAAG,KAAA,CAAA;oBAClB,oBAAM;wBACJ,GAAG,EAAK,GAAG;wBACX,KAAK,EAAG,cAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;qBACrC,CAAA,CAAC;iBACH;;;;;;;;;QACH,CAAC;KAAA;IAEO,MAAM,CAAC,OAAsB;;;YACnC,4GAA4G;YAC5G,MAAM,EAAE,GAA6C,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;gBACpE,IAAI,EAAU,IAAI;gBAClB,WAAW,EAAG,QAAQ;aACvB,EAAE,OAAO,CAAC,CAAC;;gBAEZ,KAAiC,eAAA,OAAA,cAAA,EAAE,CAAA,QAAA,yEAAE;oBAAJ,kBAAE;oBAAF,WAAE;oBAAxB,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,KAAA,CAAA;oBAC3B,oBAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA,CAAC;iBAC9C;;;;;;;;;QACH,CAAC;KAAA;IAEO,UAAU,CAAC,MAA0B,EAAE,OAAsB;;;;gBACnE,KAAwB,eAAA,WAAA,cAAA,MAAM,CAAA,YAAA,qFAAE;oBAAR,sBAAM;oBAAN,WAAM;oBAAnB,MAAM,GAAG,KAAA,CAAA;oBAClB,cAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA,CAAC;oBAEhC,oBAAM,GAAG,CAAA,CAAC;iBACX;;;;;;;;;QACH,CAAC;KAAA;IAED;;OAEG;IACG,KAAK;;QACX,CAAC;KAAA;CACF"}

Some files were not shown because too many files have changed in this diff Show More