@enbox/dwn-sdk-js 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.mjs +15 -15
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/generated/precompiled-validators.js +5406 -2200
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/json-schemas/definitions.json +18 -0
- package/dist/esm/src/core/constants.js +3 -3
- package/dist/esm/src/core/constants.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +29 -1
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/messages-grant-authorization.js +20 -0
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-validation.js +80 -3
- package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
- package/dist/esm/src/core/recording-validation-state-reader.js +5 -0
- package/dist/esm/src/core/recording-validation-state-reader.js.map +1 -1
- package/dist/esm/src/core/replication-apply.js +163 -7
- package/dist/esm/src/core/replication-apply.js.map +1 -1
- package/dist/esm/src/core/validation-state-reader.js +20 -0
- package/dist/esm/src/core/validation-state-reader.js.map +1 -1
- package/dist/esm/src/dwn.js +19 -2
- package/dist/esm/src/dwn.js.map +1 -1
- package/dist/esm/src/handlers/messages-query.js +3 -5
- package/dist/esm/src/handlers/messages-query.js.map +1 -1
- package/dist/esm/src/handlers/protocols-configure.js +10 -4
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +1 -1
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/index.js +2 -1
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-configure.js +23 -10
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
- package/dist/esm/src/interfaces/records-write-signing.js +2 -8
- package/dist/esm/src/interfaces/records-write-signing.js.map +1 -1
- package/dist/esm/src/interfaces/records-write.js +43 -65
- package/dist/esm/src/interfaces/records-write.js.map +1 -1
- package/dist/esm/src/protocols/encryption.js +411 -0
- package/dist/esm/src/protocols/encryption.js.map +1 -0
- package/dist/esm/src/protocols/permission-grant.js +3 -3
- package/dist/esm/src/protocols/permission-grant.js.map +1 -1
- package/dist/esm/src/protocols/permissions.js +1 -0
- package/dist/esm/src/protocols/permissions.js.map +1 -1
- package/dist/esm/src/types/message-types.js.map +1 -1
- package/dist/esm/src/types/permission-types.js.map +1 -1
- package/dist/esm/src/types/protocols-types.js.map +1 -1
- package/dist/esm/src/utils/encryption.js +135 -187
- package/dist/esm/src/utils/encryption.js.map +1 -1
- package/dist/esm/src/utils/hd-key.js +0 -1
- package/dist/esm/src/utils/hd-key.js.map +1 -1
- package/dist/esm/src/utils/permission-scope.js +9 -6
- package/dist/esm/src/utils/permission-scope.js.map +1 -1
- package/dist/esm/src/utils/protocols.js +12 -9
- package/dist/esm/src/utils/protocols.js.map +1 -1
- package/dist/esm/src/utils/records.js +54 -56
- package/dist/esm/src/utils/records.js.map +1 -1
- package/dist/esm/src/utils/replication.js +27 -4
- package/dist/esm/src/utils/replication.js.map +1 -1
- package/dist/esm/tests/core/replication-apply.spec.js +141 -1
- package/dist/esm/tests/core/replication-apply.spec.js.map +1 -1
- package/dist/esm/tests/core/replication-replay-property.spec.js +1 -0
- package/dist/esm/tests/core/replication-replay-property.spec.js.map +1 -1
- package/dist/esm/tests/core/validation-read-closure.spec.js +111 -0
- package/dist/esm/tests/core/validation-read-closure.spec.js.map +1 -1
- package/dist/esm/tests/core/validation-state-reader.spec.js +89 -0
- package/dist/esm/tests/core/validation-state-reader.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-composition.spec.js +30 -31
- package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/encryption.fuzz.spec.js +29 -121
- package/dist/esm/tests/fuzz/encryption.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-query.spec.js +71 -3
- package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-read.spec.js +2 -2
- package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-read.spec.js +9 -135
- package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-write.spec.js +279 -19
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-configure.spec.js +17 -22
- package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-write.spec.js +170 -150
- package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
- package/dist/esm/tests/protocols/encryption.spec.js +914 -0
- package/dist/esm/tests/protocols/encryption.spec.js.map +1 -0
- package/dist/esm/tests/protocols/permission-grant.spec.js +55 -0
- package/dist/esm/tests/protocols/permission-grant.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +100 -100
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store-level.spec.js +20 -2
- package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption-callbacks.spec.js +88 -125
- package/dist/esm/tests/utils/encryption-callbacks.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption.spec.js +125 -255
- package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
- package/dist/esm/tests/utils/permission-scope.spec.js +5 -1
- package/dist/esm/tests/utils/permission-scope.spec.js.map +1 -1
- package/dist/esm/tests/utils/records.spec.js +15 -5
- package/dist/esm/tests/utils/records.spec.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js +7 -44
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/encryption/grant-key.spec.js +63 -0
- package/dist/esm/tests/validation/json-schemas/encryption/grant-key.spec.js.map +1 -0
- package/dist/types/generated/precompiled-validators.d.ts +140 -92
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/constants.d.ts +2 -2
- package/dist/types/src/core/constants.d.ts.map +1 -1
- package/dist/types/src/core/core-protocol.d.ts +1 -1
- package/dist/types/src/core/core-protocol.d.ts.map +1 -1
- package/dist/types/src/core/dwn-error.d.ts +29 -1
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/messages-grant-authorization.d.ts +2 -0
- package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-validation.d.ts +2 -2
- package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
- package/dist/types/src/core/recording-validation-state-reader.d.ts +9 -0
- package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/core/replication-apply.d.ts +4 -3
- package/dist/types/src/core/replication-apply.d.ts.map +1 -1
- package/dist/types/src/core/validation-state-reader.d.ts +9 -0
- package/dist/types/src/core/validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/dwn.d.ts +1 -0
- package/dist/types/src/dwn.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-query.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +6 -5
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts +1 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write-signing.d.ts +4 -8
- package/dist/types/src/interfaces/records-write-signing.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write.d.ts +10 -26
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
- package/dist/types/src/protocols/encryption.d.ts +43 -0
- package/dist/types/src/protocols/encryption.d.ts.map +1 -0
- package/dist/types/src/protocols/permission-grant.d.ts +3 -6
- package/dist/types/src/protocols/permission-grant.d.ts.map +1 -1
- package/dist/types/src/protocols/permissions.d.ts +2 -1
- package/dist/types/src/protocols/permissions.d.ts.map +1 -1
- package/dist/types/src/types/encryption-types.d.ts +5 -38
- package/dist/types/src/types/encryption-types.d.ts.map +1 -1
- package/dist/types/src/types/message-types.d.ts +0 -13
- package/dist/types/src/types/message-types.d.ts.map +1 -1
- package/dist/types/src/types/permission-types.d.ts +44 -9
- package/dist/types/src/types/permission-types.d.ts.map +1 -1
- package/dist/types/src/types/protocols-types.d.ts +9 -14
- package/dist/types/src/types/protocols-types.d.ts.map +1 -1
- package/dist/types/src/types/records-types.d.ts +3 -3
- package/dist/types/src/types/records-types.d.ts.map +1 -1
- package/dist/types/src/types/validation-state-reader.d.ts +12 -0
- package/dist/types/src/types/validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/utils/encryption.d.ts +54 -145
- package/dist/types/src/utils/encryption.d.ts.map +1 -1
- package/dist/types/src/utils/hd-key.d.ts +1 -1
- package/dist/types/src/utils/hd-key.d.ts.map +1 -1
- package/dist/types/src/utils/permission-scope.d.ts +4 -3
- package/dist/types/src/utils/permission-scope.d.ts.map +1 -1
- package/dist/types/src/utils/protocols.d.ts +3 -5
- package/dist/types/src/utils/protocols.d.ts.map +1 -1
- package/dist/types/src/utils/records.d.ts +5 -13
- package/dist/types/src/utils/records.d.ts.map +1 -1
- package/dist/types/src/utils/replication.d.ts +3 -0
- package/dist/types/src/utils/replication.d.ts.map +1 -1
- package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
- package/dist/types/tests/protocols/encryption.spec.d.ts +2 -0
- package/dist/types/tests/protocols/encryption.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
- package/dist/types/tests/utils/test-data-generator.d.ts +0 -5
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/dist/types/tests/validation/json-schemas/encryption/grant-key.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/encryption/grant-key.spec.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/core/constants.ts +3 -3
- package/src/core/core-protocol.ts +1 -1
- package/src/core/dwn-error.ts +29 -1
- package/src/core/messages-grant-authorization.ts +27 -0
- package/src/core/protocol-authorization-validation.ts +145 -6
- package/src/core/recording-validation-state-reader.ts +13 -0
- package/src/core/replication-apply.ts +222 -8
- package/src/core/validation-state-reader.ts +30 -0
- package/src/dwn.ts +24 -2
- package/src/handlers/messages-query.ts +6 -5
- package/src/handlers/protocols-configure.ts +19 -3
- package/src/handlers/records-write.ts +1 -1
- package/src/index.ts +15 -5
- package/src/interfaces/protocols-configure.ts +39 -12
- package/src/interfaces/records-write-signing.ts +5 -12
- package/src/interfaces/records-write.ts +75 -92
- package/src/protocols/encryption.ts +649 -0
- package/src/protocols/permission-grant.ts +4 -5
- package/src/protocols/permissions.ts +8 -6
- package/src/types/encryption-types.ts +9 -38
- package/src/types/message-types.ts +0 -13
- package/src/types/permission-types.ts +57 -9
- package/src/types/protocols-types.ts +9 -16
- package/src/types/records-types.ts +3 -3
- package/src/types/validation-state-reader.ts +13 -0
- package/src/utils/encryption.ts +213 -283
- package/src/utils/hd-key.ts +1 -1
- package/src/utils/permission-scope.ts +10 -6
- package/src/utils/protocols.ts +16 -15
- package/src/utils/records.ts +86 -71
- package/src/utils/replication.ts +30 -4
- package/dist/esm/tests/vectors/protocol-definitions/chat.json +0 -70
|
@@ -7,6 +7,7 @@ import type { ValidationStateReader } from '../types/validation-state-reader.js'
|
|
|
7
7
|
import type { DataEncodedRecordsWriteMessage, RecordsWriteMessage } from '../types/records-types.js';
|
|
8
8
|
import type { ProtocolDefinition, ProtocolsConfigureMessage } from '../types/protocols-types.js';
|
|
9
9
|
|
|
10
|
+
import { ENCRYPTION_PROTOCOL_URI } from './constants.js';
|
|
10
11
|
import { FilterUtility } from '../utils/filter.js';
|
|
11
12
|
import { PermissionGrant } from '../protocols/permission-grant.js';
|
|
12
13
|
import { PermissionsProtocol } from '../protocols/permissions.js';
|
|
@@ -165,6 +166,35 @@ export class StoreValidationStateReader implements ValidationStateReader {
|
|
|
165
166
|
return matchingMessages as RecordsWriteMessage[];
|
|
166
167
|
}
|
|
167
168
|
|
|
169
|
+
/** @inheritdoc */
|
|
170
|
+
public async queryAudienceEpochs(input: {
|
|
171
|
+
tenant: string;
|
|
172
|
+
protocol: string;
|
|
173
|
+
contextId: string;
|
|
174
|
+
role: string;
|
|
175
|
+
epoch: number;
|
|
176
|
+
keyId?: string;
|
|
177
|
+
}): Promise<RecordsWriteMessage[]> {
|
|
178
|
+
const filter: Filter = {
|
|
179
|
+
interface : DwnInterfaceName.Records,
|
|
180
|
+
method : DwnMethodName.Write,
|
|
181
|
+
isLatestBaseState : true,
|
|
182
|
+
protocol : ENCRYPTION_PROTOCOL_URI,
|
|
183
|
+
protocolPath : 'audienceEpoch',
|
|
184
|
+
'tag.protocol' : input.protocol,
|
|
185
|
+
'tag.contextId' : input.contextId,
|
|
186
|
+
'tag.role' : input.role,
|
|
187
|
+
'tag.epoch' : input.epoch,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
if (input.keyId !== undefined) {
|
|
191
|
+
filter['tag.keyId'] = input.keyId;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const { messages } = await this.messageStore.query(input.tenant, [filter]);
|
|
195
|
+
return messages as RecordsWriteMessage[];
|
|
196
|
+
}
|
|
197
|
+
|
|
168
198
|
/** @inheritdoc */
|
|
169
199
|
public async fetchGrant(tenant: string, permissionGrantId: string): Promise<PermissionGrant> {
|
|
170
200
|
const grantQuery = {
|
package/src/dwn.ts
CHANGED
|
@@ -41,6 +41,7 @@ import { Cid } from './utils/cid.js';
|
|
|
41
41
|
import { CoreProtocolRegistry } from './core/core-protocol.js';
|
|
42
42
|
import { DataStream } from './utils/data-stream.js';
|
|
43
43
|
import { DwnConstant } from './core/dwn-constant.js';
|
|
44
|
+
import { EncryptionProtocol } from './protocols/encryption.js';
|
|
44
45
|
import { Message } from './core/message.js';
|
|
45
46
|
import { messageReplyFromError } from './core/message-reply.js';
|
|
46
47
|
import { MessagesQueryHandler } from './handlers/messages-query.js';
|
|
@@ -115,6 +116,7 @@ export class Dwn {
|
|
|
115
116
|
|
|
116
117
|
// Initialize the core protocol registry with built-in system protocols.
|
|
117
118
|
this._coreProtocols = new CoreProtocolRegistry();
|
|
119
|
+
this._coreProtocols.register(new EncryptionProtocol());
|
|
118
120
|
this._coreProtocols.register(new PermissionsProtocol());
|
|
119
121
|
|
|
120
122
|
// The single narrow surface through which validation logic reads state (replay-basis closure).
|
|
@@ -426,7 +428,7 @@ export class Dwn {
|
|
|
426
428
|
RecordsWrite.validateDataIntegrity(message.descriptor.dataCid, message.descriptor.dataSize, dataCid, dataBytes.length);
|
|
427
429
|
|
|
428
430
|
if (coreProtocol?.validateRecord !== undefined) {
|
|
429
|
-
coreProtocol.validateRecord(message, dataBytes);
|
|
431
|
+
await coreProtocol.validateRecord(message, dataBytes);
|
|
430
432
|
}
|
|
431
433
|
|
|
432
434
|
return;
|
|
@@ -492,7 +494,10 @@ export class Dwn {
|
|
|
492
494
|
reply: { status: { detail?: string } },
|
|
493
495
|
): Promise<ProtocolDefinition | undefined> {
|
|
494
496
|
const detail = reply.status.detail ?? '';
|
|
495
|
-
if (
|
|
497
|
+
if (
|
|
498
|
+
!detail.startsWith(`${DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound}:`) &&
|
|
499
|
+
!detail.startsWith(`${DwnErrorCode.EncryptionProtocolValidateAudienceWriterUnauthorized}:`)
|
|
500
|
+
) {
|
|
496
501
|
return undefined;
|
|
497
502
|
}
|
|
498
503
|
|
|
@@ -516,6 +521,14 @@ export class Dwn {
|
|
|
516
521
|
message: GenericMessage,
|
|
517
522
|
): ReplicationApplyProtocolDefinitionLookup | undefined {
|
|
518
523
|
if (Dwn.isRecordsWriteMessage(message)) {
|
|
524
|
+
const taggedProtocol = Dwn.getEncryptionRecordTaggedProtocol(message);
|
|
525
|
+
if (taggedProtocol !== undefined) {
|
|
526
|
+
return {
|
|
527
|
+
protocol : taggedProtocol,
|
|
528
|
+
messageTimestamp : message.descriptor.messageTimestamp,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
519
532
|
return {
|
|
520
533
|
protocol : message.descriptor.protocol,
|
|
521
534
|
messageTimestamp : message.descriptor.messageTimestamp,
|
|
@@ -526,6 +539,15 @@ export class Dwn {
|
|
|
526
539
|
return protocol === undefined ? undefined : { protocol };
|
|
527
540
|
}
|
|
528
541
|
|
|
542
|
+
private static getEncryptionRecordTaggedProtocol(message: RecordsWriteMessage): string | undefined {
|
|
543
|
+
if (message.descriptor.protocol !== EncryptionProtocol.uri) {
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const protocol = message.descriptor.tags?.protocol;
|
|
548
|
+
return typeof protocol === 'string' ? protocol : undefined;
|
|
549
|
+
}
|
|
550
|
+
|
|
529
551
|
private static getMessageProtocolForReplicationApply(message: GenericMessage): string | undefined {
|
|
530
552
|
const descriptor = message.descriptor as { protocol?: unknown; filter?: { protocol?: unknown } };
|
|
531
553
|
if (typeof descriptor.protocol === 'string') {
|
|
@@ -9,7 +9,6 @@ import { messageReplyFromError } from '../core/message-reply.js';
|
|
|
9
9
|
import { Messages } from '../utils/messages.js';
|
|
10
10
|
import { MessagesGrantAuthorization } from '../core/messages-grant-authorization.js';
|
|
11
11
|
import { MessagesQuery } from '../interfaces/messages-query.js';
|
|
12
|
-
import { PermissionsProtocol } from '../protocols/permissions.js';
|
|
13
12
|
import { Replication } from '../utils/replication.js';
|
|
14
13
|
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
15
14
|
|
|
@@ -187,10 +186,12 @@ export class MessagesQueryHandler implements MethodHandler {
|
|
|
187
186
|
protocols.add(filter.protocol);
|
|
188
187
|
}
|
|
189
188
|
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
189
|
+
const scopes: string[] = [];
|
|
190
|
+
for (const protocol of protocols) {
|
|
191
|
+
scopes.push(
|
|
192
|
+
Replication.protocolDomain(protocol),
|
|
193
|
+
...Replication.taggedCoreProtocolDomains(protocol, protocols),
|
|
194
|
+
);
|
|
194
195
|
}
|
|
195
196
|
|
|
196
197
|
return scopes;
|
|
@@ -15,7 +15,7 @@ import { RecordsWrite } from '../interfaces/records-write.js';
|
|
|
15
15
|
import { StorageController } from '../store/storage-controller.js';
|
|
16
16
|
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
17
17
|
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
|
|
18
|
-
import { getRuleSetAtPath, parseCrossProtocolRef } from '../utils/protocols.js';
|
|
18
|
+
import { getRuleSetAtPath, getTypeName, parseCrossProtocolRef } from '../utils/protocols.js';
|
|
19
19
|
|
|
20
20
|
type StoredInitialWriteConfigValidity = 'valid' | 'invalid' | 'unknown';
|
|
21
21
|
|
|
@@ -291,7 +291,12 @@ export class ProtocolsConfigureHandler implements MethodHandler {
|
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
// Walk the structure and validate all $ref paths and cross-protocol role references
|
|
294
|
-
ProtocolsConfigureHandler.validateRefsAndRolesRecursively(
|
|
294
|
+
ProtocolsConfigureHandler.validateRefsAndRolesRecursively(
|
|
295
|
+
definition,
|
|
296
|
+
definition.structure as ProtocolRuleSet,
|
|
297
|
+
'',
|
|
298
|
+
referencedDefinitions,
|
|
299
|
+
);
|
|
295
300
|
}
|
|
296
301
|
|
|
297
302
|
/**
|
|
@@ -300,6 +305,7 @@ export class ProtocolsConfigureHandler implements MethodHandler {
|
|
|
300
305
|
* - Cross-protocol `role` references point to valid `$role: true` paths in the referenced protocol
|
|
301
306
|
*/
|
|
302
307
|
private static validateRefsAndRolesRecursively(
|
|
308
|
+
definition: ProtocolDefinition,
|
|
303
309
|
ruleSet: ProtocolRuleSet,
|
|
304
310
|
protocolPath: string,
|
|
305
311
|
referencedDefinitions: Map<string, ProtocolDefinition>
|
|
@@ -362,6 +368,8 @@ export class ProtocolsConfigureHandler implements MethodHandler {
|
|
|
362
368
|
|
|
363
369
|
// Validate cross-protocol references in $actions (roles and `of` paths)
|
|
364
370
|
const actionRules = childRuleSet.$actions ?? [];
|
|
371
|
+
const typeName = getTypeName(childProtocolPath);
|
|
372
|
+
const isEncryptedPath = definition.types[typeName]?.encryptionRequired === true;
|
|
365
373
|
for (const actionRule of actionRules) {
|
|
366
374
|
// Validate cross-protocol role references
|
|
367
375
|
if (actionRule.role !== undefined) {
|
|
@@ -385,6 +393,14 @@ export class ProtocolsConfigureHandler implements MethodHandler {
|
|
|
385
393
|
`does not point to a valid role ($role: true) in protocol '${refDefinition.protocol}'.`
|
|
386
394
|
);
|
|
387
395
|
}
|
|
396
|
+
|
|
397
|
+
if (isEncryptedPath && actionRule.can.includes('read') && roleRuleSet.$keyAgreement === undefined) {
|
|
398
|
+
throw new DwnError(
|
|
399
|
+
DwnErrorCode.ProtocolsConfigureInvalidEncryptedRoleMissingKeyAgreement,
|
|
400
|
+
`encrypted protocol path '${childProtocolPath}' references cross-protocol role '${actionRule.role}' ` +
|
|
401
|
+
`with no $keyAgreement.`
|
|
402
|
+
);
|
|
403
|
+
}
|
|
388
404
|
}
|
|
389
405
|
}
|
|
390
406
|
|
|
@@ -414,7 +430,7 @@ export class ProtocolsConfigureHandler implements MethodHandler {
|
|
|
414
430
|
}
|
|
415
431
|
|
|
416
432
|
// Recurse into children
|
|
417
|
-
ProtocolsConfigureHandler.validateRefsAndRolesRecursively(childRuleSet, childProtocolPath, referencedDefinitions);
|
|
433
|
+
ProtocolsConfigureHandler.validateRefsAndRolesRecursively(definition, childRuleSet, childProtocolPath, referencedDefinitions);
|
|
418
434
|
}
|
|
419
435
|
}
|
|
420
436
|
}
|
|
@@ -244,7 +244,7 @@ export class RecordsWriteHandler implements MethodHandler {
|
|
|
244
244
|
? undefined
|
|
245
245
|
: this.deps.coreProtocols?.get(message.descriptor.protocol);
|
|
246
246
|
if (coreProtocol?.validateRecord !== undefined) {
|
|
247
|
-
coreProtocol.validateRecord(message, dataBytes);
|
|
247
|
+
await coreProtocol.validateRecord(message, dataBytes);
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
messageWithOptionalEncodedData = await this.cloneAndAddEncodedData(message, dataBytes);
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type { RecordedValidationRead } from './core/recording-validation-state-r
|
|
|
10
10
|
export { RecordingValidationStateReader } from './core/recording-validation-state-reader.js';
|
|
11
11
|
export type { MessagesFilter, MessagesQueryDescriptor, MessagesQueryMessage, MessagesQueryReply, MessagesQueryReplyEntry, MessagesReadMessage, MessagesReadReply, MessagesReadReplyEntry, MessagesReadDescriptor, MessagesSubscribeDescriptor, MessagesSubscribeMessage, MessagesSubscribeReply, MessagesSubscribeMessageOptions } from './types/messages-types.js';
|
|
12
12
|
export type { GT, LT, Filter, FilterValue, KeyValues, EqualFilter, OneOfFilter, RangeFilter, RangeCriterion, PaginationCursor, QueryOptions, RangeValue, StartsWithFilter } from './types/query-types.js';
|
|
13
|
-
export type { ProtocolsConfigureDescriptor, ProtocolDefinition, ProtocolTypes, ProtocolRuleSet, ProtocolsQueryFilter, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply, ProtocolActionRule, ProtocolDeliveryStrategy,
|
|
13
|
+
export type { ProtocolsConfigureDescriptor, ProtocolDefinition, ProtocolTypes, ProtocolRuleSet, ProtocolsQueryFilter, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply, ProtocolActionRule, ProtocolDeliveryStrategy, ProtocolKeyAgreement, ProtocolsQueryDescriptor, ProtocolRecordLimitDefinition, ProtocolSizeDefinition, ProtocolTagsDefinition, ProtocolTagSchema, ProtocolType, ProtocolUses } from './types/protocols-types.js';
|
|
14
14
|
export { ProtocolRecordLimitStrategy } from './types/protocols-types.js';
|
|
15
15
|
export type { DataEncodedRecordsWriteMessage, RecordsCountDescriptor, RecordsCountMessage, RecordsCountReply, RecordsDeleteMessage, RecordsFilter, RecordsQueryMessage, RecordsQueryReply, RecordsQueryReplyEntry, RecordsReadMessage, RecordsReadReply, RecordsSubscribeDescriptor, RecordsSubscribeMessage, RecordsSubscribeReply, RecordsWriteDescriptor, RecordsWriteTags, RecordsWriteTagValue, RecordsWriteMessage, RecordsWriteSignaturePayload, RecordsDeleteDescriptor, RecordsQueryDescriptor, RecordsReadDescriptor, RecordsSubscribeMessageOptions, RecordsWriteMessageOptions, InternalRecordsWriteMessage, RecordEvent, RecordsWriteTagsFilter } from './types/records-types.js';
|
|
16
16
|
export type { GeneralJws, SignatureEntry } from './types/jws-types.js';
|
|
@@ -38,10 +38,19 @@ export { DwnInterfaceName, DwnMethodName } from './enums/dwn-interface-method.js
|
|
|
38
38
|
export { Encoder } from './utils/encoder.js';
|
|
39
39
|
export { MessagesSubscribe } from './interfaces/messages-subscribe.js';
|
|
40
40
|
export type { MessagesSubscribeOptions } from './interfaces/messages-subscribe.js';
|
|
41
|
-
export { Encryption, ContentEncryptionAlgorithm, KeyAgreementAlgorithm } from './utils/encryption.js';
|
|
42
|
-
export type {
|
|
41
|
+
export { Encryption, ContentEncryptionAlgorithm, KeyAgreementAlgorithm, ROLE_AUDIENCE_DERIVATION_SCHEME } from './utils/encryption.js';
|
|
42
|
+
export type {
|
|
43
|
+
DwnEncryption,
|
|
44
|
+
KeyEncryption,
|
|
45
|
+
KeyEncryptionInput,
|
|
46
|
+
KeyUnwrapPayload,
|
|
47
|
+
ProtocolPathKeyEncryption,
|
|
48
|
+
ProtocolPathKeyEncryptionInput,
|
|
49
|
+
RoleAudienceKeyEncryption,
|
|
50
|
+
RoleAudienceKeyEncryptionInput,
|
|
51
|
+
} from './utils/encryption.js';
|
|
43
52
|
export { RecordsWrite } from './interfaces/records-write.js';
|
|
44
|
-
export type { EncryptionInput,
|
|
53
|
+
export type { EncryptionInput, RecordsWriteOptions, CreateFromOptions } from './interfaces/records-write.js';
|
|
45
54
|
export { executeUnlessAborted } from './utils/abort.js';
|
|
46
55
|
export { Jws } from './utils/jws.js';
|
|
47
56
|
export type { KeyMaterial, PrivateKeyJwk, PublicKeyJwk, Jwk } from './types/jose-types.js';
|
|
@@ -57,6 +66,7 @@ export type { MessageInterface } from './types/message-interface.js';
|
|
|
57
66
|
export { PermissionGrant } from './protocols/permission-grant.js';
|
|
58
67
|
export { PermissionRequest } from './protocols/permission-request.js';
|
|
59
68
|
export { PermissionsProtocol } from './protocols/permissions.js';
|
|
69
|
+
export { EncryptionProtocol } from './protocols/encryption.js';
|
|
60
70
|
export type { PermissionGrantCreateOptions, PermissionRequestCreateOptions, PermissionRevocationCreateOptions } from './protocols/permissions.js';
|
|
61
71
|
export { PermissionScopeMatcher } from './utils/permission-scope.js';
|
|
62
72
|
export type { ProtocolScope } from './utils/permission-scope.js';
|
|
@@ -80,7 +90,7 @@ export { Secp256r1 } from './utils/secp256r1.js';
|
|
|
80
90
|
export type { SupportedCurve } from './jose/algorithms/signing/signature-algorithms.js';
|
|
81
91
|
export type { MessageSigner } from './types/signer.js';
|
|
82
92
|
export { SortDirection } from './types/query-types.js';
|
|
83
|
-
export type { EncryptionKeyDeriver, KeyDecrypter } from './types/encryption-types.js';
|
|
93
|
+
export type { EncryptionKeyDeriver, KeyDecrypter, KeyDecrypterDerivationScheme } from './types/encryption-types.js';
|
|
84
94
|
export { Time } from './utils/time.js';
|
|
85
95
|
export * from './types/permission-types.js';
|
|
86
96
|
export * from './types/records-types.js';
|
|
@@ -15,7 +15,7 @@ import { Time } from '../utils/time.js';
|
|
|
15
15
|
import { validateProtocolTagSchemaDefinition } from '../utils/protocol-tags.js';
|
|
16
16
|
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
17
17
|
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
|
|
18
|
-
import { isCrossProtocolRef, parseCrossProtocolRef } from '../utils/protocols.js';
|
|
18
|
+
import { getRuleSetAtPath, isCrossProtocolRef, parseCrossProtocolRef } from '../utils/protocols.js';
|
|
19
19
|
import { normalizeProtocolUrl, normalizeSchemaUrl, validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
|
|
20
20
|
import { ProtocolAction, ProtocolActor, ProtocolRecordLimitStrategy } from '../types/protocols-types.js';
|
|
21
21
|
|
|
@@ -150,6 +150,14 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
|
|
|
150
150
|
// gather all declared record types
|
|
151
151
|
const recordTypes = Object.keys(definition.types);
|
|
152
152
|
|
|
153
|
+
const hasEncryptedTypes = Object.values(definition.types).some((type): boolean => type.encryptionRequired === true);
|
|
154
|
+
if (hasEncryptedTypes && definition.$keyAgreement === undefined) {
|
|
155
|
+
throw new DwnError(
|
|
156
|
+
DwnErrorCode.ProtocolsConfigureMissingTopLevelKeyAgreement,
|
|
157
|
+
`Protocol '${definition.protocol}' declares encrypted types but has no top-level $keyAgreement.`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
153
161
|
// gather all roles (local roles only — cross-protocol roles are validated by alias existence)
|
|
154
162
|
const roles = ProtocolsConfigure.fetchAllRolePathsRecursively('', definition.structure as ProtocolRuleSet, []);
|
|
155
163
|
|
|
@@ -161,6 +169,7 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
|
|
|
161
169
|
roles,
|
|
162
170
|
uses,
|
|
163
171
|
types : definition.types,
|
|
172
|
+
rootStructure : definition.structure,
|
|
164
173
|
});
|
|
165
174
|
}
|
|
166
175
|
|
|
@@ -207,10 +216,10 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
|
|
|
207
216
|
private static validateRuleSetRecursively(
|
|
208
217
|
input: {
|
|
209
218
|
ruleSet: ProtocolRuleSet, ruleSetProtocolPath: string, recordTypes: string[],
|
|
210
|
-
roles: string[], uses?: ProtocolUses, types: ProtocolTypes
|
|
219
|
+
roles: string[], uses?: ProtocolUses, types: ProtocolTypes, rootStructure: { [key: string]: ProtocolRuleSet }
|
|
211
220
|
}
|
|
212
221
|
): void {
|
|
213
|
-
const { ruleSet, ruleSetProtocolPath, recordTypes, roles, uses, types } = input;
|
|
222
|
+
const { ruleSet, ruleSetProtocolPath, recordTypes, roles, uses, types, rootStructure } = input;
|
|
214
223
|
|
|
215
224
|
// Validate $ref constraints: $ref is only supported at root level (no `/` in protocol path),
|
|
216
225
|
// and a $ref node is a pure attachment point with no other directives.
|
|
@@ -412,23 +421,40 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
|
|
|
412
421
|
}
|
|
413
422
|
}
|
|
414
423
|
|
|
415
|
-
// Warn when `encryptionRequired: true` is combined with `{ who: 'anyone', can: ['read'] }`.
|
|
416
|
-
// Authorization allows anyone to read the record, but encryption prevents them from
|
|
417
|
-
// decrypting the data — almost certainly unintentional. (issue #115)
|
|
418
424
|
if (ruleSetProtocolPath !== '') {
|
|
419
425
|
const typeName = ruleSetProtocolPath.split('/').pop()!;
|
|
420
426
|
const protocolType = types[typeName];
|
|
421
427
|
if (protocolType?.encryptionRequired === true) {
|
|
428
|
+
if (ruleSet.$keyAgreement === undefined) {
|
|
429
|
+
throw new DwnError(
|
|
430
|
+
DwnErrorCode.ProtocolsConfigureMissingEncryptedPathKeyAgreement,
|
|
431
|
+
`Encrypted protocol path '${ruleSetProtocolPath}' has no $keyAgreement.`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
422
435
|
const anyoneCanRead = actionRules.some(
|
|
423
436
|
(rule: ProtocolActionRule): boolean => rule.who === ProtocolActor.Anyone && rule.can.includes(ProtocolAction.Read)
|
|
424
437
|
);
|
|
425
438
|
if (anyoneCanRead) {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
`
|
|
429
|
-
`Anyone can read the record but no one outside the key holders can decrypt it.`
|
|
439
|
+
throw new DwnError(
|
|
440
|
+
DwnErrorCode.ProtocolsConfigureInvalidEncryptedAnyoneRead,
|
|
441
|
+
`Encrypted protocol path '${ruleSetProtocolPath}' allows { who: 'anyone', can: ['read'] }.`
|
|
430
442
|
);
|
|
431
443
|
}
|
|
444
|
+
|
|
445
|
+
for (const actionRule of actionRules) {
|
|
446
|
+
if (actionRule.role === undefined || !actionRule.can.includes(ProtocolAction.Read) || isCrossProtocolRef(actionRule.role)) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const roleRuleSet = getRuleSetAtPath(actionRule.role, rootStructure);
|
|
451
|
+
if (roleRuleSet?.$keyAgreement === undefined) {
|
|
452
|
+
throw new DwnError(
|
|
453
|
+
DwnErrorCode.ProtocolsConfigureInvalidEncryptedRoleMissingKeyAgreement,
|
|
454
|
+
`Encrypted protocol path '${ruleSetProtocolPath}' references role '${actionRule.role}' with no $keyAgreement.`
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
432
458
|
}
|
|
433
459
|
}
|
|
434
460
|
|
|
@@ -490,13 +516,14 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
|
|
|
490
516
|
roles,
|
|
491
517
|
uses,
|
|
492
518
|
types,
|
|
519
|
+
rootStructure,
|
|
493
520
|
});
|
|
494
521
|
}
|
|
495
522
|
}
|
|
496
523
|
|
|
497
524
|
/**
|
|
498
525
|
* Validates that a `$ref` node is a pure attachment point: it must NOT have
|
|
499
|
-
* `$actions`, `$role`, `$size`, `$tags`, or `$
|
|
526
|
+
* `$actions`, `$role`, `$size`, `$tags`, or `$keyAgreement`.
|
|
500
527
|
* Also validates that the `$ref` alias exists in the `uses` map.
|
|
501
528
|
*/
|
|
502
529
|
private static validateRefNode(ruleSet: ProtocolRuleSet, ruleSetProtocolPath: string, uses: ProtocolUses | undefined): void {
|
|
@@ -519,7 +546,7 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
|
|
|
519
546
|
}
|
|
520
547
|
|
|
521
548
|
// validate that `$ref` nodes do not have other directives
|
|
522
|
-
const forbiddenDirectives = ['$actions', '$role', '$size', '$tags', '$encryption', '$recordLimit', '$immutable', '$delivery', '$squash'] as const;
|
|
549
|
+
const forbiddenDirectives = ['$actions', '$role', '$size', '$tags', '$keyAgreement', '$encryption', '$recordLimit', '$immutable', '$delivery', '$squash'] as const;
|
|
523
550
|
for (const directive of forbiddenDirectives) {
|
|
524
551
|
if (ruleSet[directive] !== undefined) {
|
|
525
552
|
throw new DwnError(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { GeneralJws } from '../types/jws-types.js';
|
|
2
2
|
import type { MessageSigner } from '../types/signer.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { DwnEncryption, EncryptionInput } from '../utils/encryption.js';
|
|
4
4
|
import type { RecordsWriteAttestationPayload, RecordsWriteMessage, RecordsWriteSignaturePayload } from '../types/records-types.js';
|
|
5
5
|
|
|
6
6
|
import { Cid } from '../utils/cid.js';
|
|
@@ -11,22 +11,15 @@ import { Jws } from '../utils/jws.js';
|
|
|
11
11
|
import { removeUndefinedProperties } from '@enbox/common';
|
|
12
12
|
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* Creates the JWE `encryption` property if encryption input is given. Else `undefined` is returned.
|
|
16
|
-
* Uses ECDH-ES+A256KW key agreement with X25519 and AEAD content encryption (A256GCM or XC20P).
|
|
17
|
-
* @param encryptionInput The encryption input containing CEK, IV, authentication tag, and recipient key encryption inputs.
|
|
18
|
-
*/
|
|
14
|
+
/** Creates the RecordsWrite `encryption` property if encryption input is given. */
|
|
19
15
|
export async function createEncryptionProperty(
|
|
20
16
|
encryptionInput: EncryptionInput | undefined,
|
|
21
|
-
): Promise<
|
|
17
|
+
): Promise<DwnEncryption | undefined> {
|
|
22
18
|
if (encryptionInput === undefined) {
|
|
23
19
|
return undefined;
|
|
24
20
|
}
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
const jwe = await Encryption.buildJwe(encryptionInput, encryptionInput.authenticationTag);
|
|
28
|
-
|
|
29
|
-
return jwe;
|
|
22
|
+
return Encryption.buildEncryptionProperty(encryptionInput);
|
|
30
23
|
}
|
|
31
24
|
|
|
32
25
|
/**
|
|
@@ -52,7 +45,7 @@ export async function createSignerSignature(input: {
|
|
|
52
45
|
contextId: string,
|
|
53
46
|
descriptorCid: string,
|
|
54
47
|
attestation: GeneralJws | undefined,
|
|
55
|
-
encryption:
|
|
48
|
+
encryption: DwnEncryption | undefined,
|
|
56
49
|
signer: MessageSigner,
|
|
57
50
|
delegatedGrantId?: string,
|
|
58
51
|
permissionGrantId?: string,
|