Skip to content

Commit 018ff80

Browse files
authored
#212 - added attester filter to RecordsQuery
* added support for attester filter * refactored JWS related utilities * refactored CID utilities
1 parent bb246a2 commit 018ff80

File tree

27 files changed

+195
-153
lines changed

27 files changed

+195
-153
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
# Decentralized Web Node (DWN) SDK
44

55
Code Coverage
6-
![Statements](https://img.shields.io/badge/statements-94.63%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-94.12%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-91.61%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-94.63%25-brightgreen.svg?style=flat)
6+
![Statements](https://img.shields.io/badge/statements-94.74%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-94.12%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-91.61%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-94.74%25-brightgreen.svg?style=flat)
77

88
## Introduction
99

10-
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, which you can find [here](https://github.com/decentralized-identity/decentralized-web-node). The current goal is to produce a [beta implementation](https://github.com/TBD54566975/dwn-sdk-js/milestone/1) by Q4 2022. This won't include all interfaces described in the spec, but enough to begin building applications.
10+
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, which you can find [here](https://github.com/decentralized-identity/decentralized-web-node). The current goal is to produce a beta implementation by March 2023. This won't include all interfaces described in the DWN spec, but will be enough to begin building applications.
1111

1212
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).
1313

json-schemas/records/records-query.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
"protocol": {
4545
"type": "string"
4646
},
47+
"attester": {
48+
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/did"
49+
},
4750
"recipient": {
4851
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/did"
4952
},

src/core/auth.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { CID } from 'multiformats';
44
import { DidResolver } from '../did/did-resolver.js';
55
import { GeneralJws } from '../jose/jws/general/types.js';
66
import { GeneralJwsVerifier } from '../jose/jws/general/verifier.js';
7+
import { Jws } from '../utils/jws.js';
78
import { Message } from './message.js';
89
import { computeCid, parseCid } from '../utils/cid.js';
910

@@ -40,14 +41,13 @@ export async function validateAuthorizationIntegrity(
4041
throw new Error('expected no more than 1 signature for authorization');
4142
}
4243

43-
const payloadJson = GeneralJwsVerifier.decodePlainObjectPayload(message.authorization);
44+
const payloadJson = Jws.decodePlainObjectPayload(message.authorization);
4445
const { descriptorCid } = payloadJson;
4546

4647
// `descriptorCid` validation - ensure that the provided descriptorCid matches the CID of the actual message
47-
const providedDescriptorCid = parseCid(descriptorCid); // parseCid throws an exception if parsing fails
4848
const expectedDescriptorCid = await computeCid(message.descriptor);
49-
if (!providedDescriptorCid.equals(expectedDescriptorCid)) {
50-
throw new Error(`provided descriptorCid ${providedDescriptorCid} does not match expected CID ${expectedDescriptorCid}`);
49+
if (descriptorCid !== expectedDescriptorCid) {
50+
throw new Error(`provided descriptorCid ${descriptorCid} does not match expected CID ${expectedDescriptorCid}`);
5151
}
5252

5353
// check to ensure that no other unexpected properties exist in payload.

src/core/message.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import type { SignatureInput } from '../jose/jws/general/types.js';
22
import type { BaseDecodedAuthorizationPayload, BaseMessage, Descriptor, TimestampedMessage } from './types.js';
33

4-
import { CID } from 'multiformats/cid';
54
import { computeCid } from '../utils/cid.js';
65
import { GeneralJws } from '../jose/jws/general/types.js';
76
import { GeneralJwsSigner } from '../jose/jws/general/signer.js';
8-
import { GeneralJwsVerifier } from '../jose/jws/general/verifier.js';
7+
import { Jws } from '../utils/jws.js';
98
import { lexicographicalCompare } from '../utils/string.js';
109
import { RecordsWriteMessage } from '../interfaces/records/types.js';
11-
import { validateJsonSchema } from '../validator.js';
10+
import { validateJsonSchema } from '../schema-validator.js';
1211

1312
export enum DwnInterfaceName {
1413
Hooks = 'Hooks',
@@ -35,7 +34,7 @@ export abstract class Message {
3534

3635
constructor(message: BaseMessage) {
3736
this.message = message;
38-
this.authorizationPayload = GeneralJwsVerifier.decodePlainObjectPayload(message.authorization);
37+
this.authorizationPayload = Jws.decodePlainObjectPayload(message.authorization);
3938

4039
this.author = Message.getAuthor(message);
4140
}
@@ -64,15 +63,15 @@ export abstract class Message {
6463
* Gets the DID of the author of the given message.
6564
*/
6665
public static getAuthor(message: BaseMessage): string {
67-
const author = GeneralJwsVerifier.getDid(message.authorization.signatures[0]);
66+
const author = Jws.getSignerDid(message.authorization.signatures[0]);
6867
return author;
6968
}
7069

7170
/**
7271
* Gets the CID of the given message.
7372
* NOTE: `encodedData` is ignored when computing the CID of message.
7473
*/
75-
public static async getCid(message: BaseMessage): Promise<CID> {
74+
public static async getCid(message: BaseMessage): Promise<string> {
7675
const messageCopy = { ...message };
7776

7877
if (messageCopy['encodedData'] !== undefined) {
@@ -130,7 +129,7 @@ export abstract class Message {
130129
): Promise<GeneralJws> {
131130
const descriptorCid = await computeCid(descriptor);
132131

133-
const authPayload: BaseDecodedAuthorizationPayload = { descriptorCid: descriptorCid.toString() };
132+
const authPayload: BaseDecodedAuthorizationPayload = { descriptorCid };
134133
const authPayloadStr = JSON.stringify(authPayload);
135134
const authPayloadBytes = new TextEncoder().encode(authPayloadStr);
136135

src/interfaces/permissions/messages/permissions-grant.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { SignatureInput } from '../../../jose/jws/general/types';
22
import type { PermissionConditions, PermissionScope } from '../types';
33
import type { PermissionsGrantDescriptor, PermissionsGrantMessage } from '../types';
44

5-
import { CID } from 'multiformats/cid';
65
import { computeCid } from '../../../utils/cid';
76
import { getCurrentTimeInHighPrecision } from '../../../utils/time';
87
import { v4 as uuidv4 } from 'uuid';
@@ -131,8 +130,8 @@ export class PermissionsGrant extends Message {
131130
return this.message.descriptor.scope;
132131
}
133132

134-
private set delegatedFrom(cid: CID) {
135-
this.message.descriptor.delegatedFrom = cid.toString();
133+
private set delegatedFrom(cid: string) {
134+
this.message.descriptor.delegatedFrom = cid;
136135
}
137136

138137
private set delegationChain(parentGrant: PermissionsGrantMessage) {

src/interfaces/records/messages/records-query.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { SignatureInput } from '../../../jose/jws/general/types.js';
2-
import type { RecordsQueryDescriptor, RecordsQueryMessage } from '../types.js';
2+
import type { RecordsQueryDescriptor, RecordsQueryFilter, RecordsQueryMessage } from '../types.js';
33

44
import { getCurrentTimeInHighPrecision } from '../../../utils/time.js';
55
import { Message } from '../../../core/message.js';
@@ -16,15 +16,7 @@ export enum DateSort {
1616

1717
export type RecordsQueryOptions = {
1818
dateCreated?: string;
19-
filter: {
20-
recipient?: string;
21-
protocol?: string;
22-
contextId?: string;
23-
schema?: string;
24-
recordId?: string;
25-
parentId?: string;
26-
dataFormat?: string;
27-
},
19+
filter: RecordsQueryFilter;
2820
dateSort?: DateSort;
2921
authorizationSignatureInput: SignatureInput;
3022
};

src/interfaces/records/messages/records-write.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import type { RecordsWriteAttestationPayload, RecordsWriteAuthorizationPayload,
33

44
import { Encoder } from '../../../utils/encoder.js';
55
import { GeneralJwsSigner } from '../../../jose/jws/general/signer.js';
6-
import { GeneralJwsVerifier } from '../../../jose/jws/general/verifier.js';
76
import { getCurrentTimeInHighPrecision } from '../../../utils/time.js';
7+
import { Jws } from '../../../utils/jws.js';
88
import { Message } from '../../../core/message.js';
99
import { MessageStore } from '../../../store/message-store.js';
1010
import { ProtocolAuthorization } from '../../../core/protocol-authorization.js';
1111
import { removeUndefinedProperties } from '../../../utils/object.js';
1212

1313
import { authorize, validateAuthorizationIntegrity } from '../../../core/auth.js';
14-
import { computeCid, getDagPbCid, parseCid } from '../../../utils/cid.js';
14+
import { computeCid, computeDagPbCid } from '../../../utils/cid.js';
1515
import { DwnInterfaceName, DwnMethodName } from '../../../core/message.js';
1616
import { GeneralJws, SignatureInput } from '../../../jose/jws/general/types.js';
1717

@@ -78,7 +78,7 @@ export class RecordsWrite extends Message {
7878
public static async create(options: RecordsWriteOptions): Promise<RecordsWrite> {
7979
const currentTime = getCurrentTimeInHighPrecision();
8080

81-
const dataCid = await getDagPbCid(options.data);
81+
const dataCid = await computeDagPbCid(options.data);
8282
const descriptor: RecordsWriteDescriptor = {
8383
interface : DwnInterfaceName.Records,
8484
method : DwnMethodName.Write,
@@ -104,7 +104,7 @@ export class RecordsWrite extends Message {
104104
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
105105
removeUndefinedProperties(descriptor);
106106

107-
const author = GeneralJwsVerifier.extractDid(options.authorizationSignatureInput.protectedHeader.kid);
107+
const author = Jws.extractDid(options.authorizationSignatureInput.protectedHeader.kid);
108108

109109
// `recordId` computation
110110
const recordId = options.recordId ?? await RecordsWrite.getEntryId(author, descriptor);
@@ -121,7 +121,7 @@ export class RecordsWrite extends Message {
121121
}
122122

123123
// `attestation` generation
124-
const descriptorCid = (await computeCid(descriptor)).toString();
124+
const descriptorCid = await computeCid(descriptor);
125125
const attestation = await RecordsWrite.createAttestation(descriptorCid, options.attestationSignatureInputs);
126126

127127
// `authorization` generation
@@ -229,7 +229,7 @@ export class RecordsWrite extends Message {
229229
// verify dataCid matches given data
230230
if (this.message.encodedData !== undefined) {
231231
const rawData = Encoder.base64UrlToBytes(this.message.encodedData);
232-
const actualDataCid = (await getDagPbCid(rawData)).toString();
232+
const actualDataCid = (await computeDagPbCid(rawData)).toString();
233233

234234
if (actualDataCid !== this.message.descriptor.dataCid) {
235235
throw new Error('actual CID of data and `dataCid` in descriptor mismatch');
@@ -273,7 +273,7 @@ export class RecordsWrite extends Message {
273273

274274
// if `attestation` is given in message, make sure the correct `attestationCid` is in the `authorization`
275275
if (this.message.attestation !== undefined) {
276-
const expectedAttestationCid = (await computeCid(this.message.attestation)).toString();
276+
const expectedAttestationCid = await computeCid(this.message.attestation);
277277
const actualAttestationCid = this.authorizationPayload.attestationCid;
278278
if (actualAttestationCid !== expectedAttestationCid) {
279279
throw new Error(
@@ -297,14 +297,13 @@ export class RecordsWrite extends Message {
297297
throw new Error(`Currently implementation only supports 1 attester, but got ${message.attestation.signatures.length}`);
298298
}
299299

300-
const payloadJson = GeneralJwsVerifier.decodePlainObjectPayload(message.attestation);
300+
const payloadJson = Jws.decodePlainObjectPayload(message.attestation);
301301
const { descriptorCid } = payloadJson;
302302

303303
// `descriptorCid` validation - ensure that the provided descriptorCid matches the CID of the actual message
304-
const providedDescriptorCid = parseCid(descriptorCid); // parseCid throws an exception if parsing fails
305304
const expectedDescriptorCid = await computeCid(message.descriptor);
306-
if (!providedDescriptorCid.equals(expectedDescriptorCid)) {
307-
throw new Error(`descriptorCid ${providedDescriptorCid} does not match expected descriptorCid ${expectedDescriptorCid}`);
305+
if (descriptorCid !== expectedDescriptorCid) {
306+
throw new Error(`descriptorCid ${descriptorCid} does not match expected descriptorCid ${expectedDescriptorCid}`);
308307
}
309308

310309
// check to ensure that no other unexpected properties exist in payload.
@@ -330,8 +329,7 @@ export class RecordsWrite extends Message {
330329
(entryIdInput as any).author = author;
331330

332331
const cid = await computeCid(entryIdInput);
333-
const cidString = cid.toString();
334-
return cidString;
332+
return cid;
335333
};
336334

337335
/**
@@ -388,7 +386,7 @@ export class RecordsWrite extends Message {
388386
descriptorCid
389387
};
390388

391-
const attestationCid = attestation ? (await computeCid(attestation)).toString() : undefined;
389+
const attestationCid = attestation ? await computeCid(attestation) : undefined;
392390

393391
if (contextId !== undefined) { authorizationPayload.contextId = contextId; } // assign `contextId` only if it is defined
394392
if (attestationCid !== undefined) { authorizationPayload.attestationCid = attestationCid; } // assign `attestationCid` only if it is defined
@@ -445,7 +443,7 @@ export class RecordsWrite extends Message {
445443
*/
446444
public static getAttesters(message: RecordsWriteMessage): string[] {
447445
const attestationSignatures = message.attestation?.signatures ?? [];
448-
const attesters = attestationSignatures.map((signature) => GeneralJwsVerifier.getDid(signature));
446+
const attesters = attestationSignatures.map((signature) => Jws.getSignerDid(signature));
449447
return attesters;
450448
}
451449
}

src/interfaces/records/types.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,21 @@ export type RecordsQueryDescriptor = {
4040
interface: DwnInterfaceName.Records;
4141
method: DwnMethodName.Query;
4242
dateCreated: string;
43-
filter: {
44-
recipient?: string;
45-
protocol?: string;
46-
contextId?: string;
47-
schema?: string;
48-
recordId?: string;
49-
parentId?: string;
50-
dataFormat?: string;
51-
}
43+
filter: RecordsQueryFilter;
5244
dateSort?: DateSort;
5345
};
5446

47+
export type RecordsQueryFilter = {
48+
attester?: string;
49+
recipient?: string;
50+
protocol?: string;
51+
contextId?: string;
52+
schema?: string;
53+
recordId?: string;
54+
parentId?: string;
55+
dataFormat?: string;
56+
};
57+
5558
export type RecordsWriteAttestationPayload = {
5659
descriptorCid: string;
5760
};

0 commit comments

Comments
 (0)