@enbox/dwn-sdk-js 0.4.4 → 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 +5316 -2425
- 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 +0 -5
- package/dist/esm/src/protocols/permission-grant.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/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 +0 -7
- package/dist/types/src/protocols/permission-grant.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 +0 -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 +0 -6
- package/src/types/encryption-types.ts +9 -38
- package/src/types/message-types.ts +0 -13
- package/src/types/permission-types.ts +0 -10
- 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
|
@@ -31,9 +31,8 @@ import { TestEventLog } from '../test-event-stream.js';
|
|
|
31
31
|
import { TestStores } from '../test-stores.js';
|
|
32
32
|
import { TestStubGenerator } from '../utils/test-stub-generator.js';
|
|
33
33
|
import { Time } from '../../src/utils/time.js';
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import { CoreProtocolRegistry, DataStoreLevel, DwnConstant, DwnInterfaceName, DwnMethodName, KeyDerivationScheme, MessageStoreLevel, PermissionsProtocol, RecordsDelete, RecordsQuery } from '../../src/index.js';
|
|
34
|
+
import { ContentEncryptionAlgorithm, Encryption, ROLE_AUDIENCE_DERIVATION_SCHEME } from '../../src/utils/encryption.js';
|
|
35
|
+
import { CoreProtocolRegistry, DataStoreLevel, DwnConstant, DwnInterfaceName, DwnMethodName, EncryptionProtocol, KeyDerivationScheme, MessageStoreLevel, PermissionsProtocol, Protocols, RecordsDelete, RecordsQuery } from '../../src/index.js';
|
|
37
36
|
import { defaultTestProtocolDefinition, TestDataGenerator } from '../utils/test-data-generator.js';
|
|
38
37
|
import { DidKey, UniversalResolver } from '@enbox/dids';
|
|
39
38
|
import { DwnError, DwnErrorCode } from '../../src/core/dwn-error.js';
|
|
@@ -2237,10 +2236,11 @@ export function testRecordsWriteHandler() {
|
|
|
2237
2236
|
secret: {}
|
|
2238
2237
|
}
|
|
2239
2238
|
};
|
|
2239
|
+
const encryptedProtocolDefinition = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, alice.keyId, alice.encryptionKeyPair.privateJwk);
|
|
2240
2240
|
// Alice installs the protocol
|
|
2241
2241
|
const protocolConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
2242
2242
|
author: alice,
|
|
2243
|
-
protocolDefinition:
|
|
2243
|
+
protocolDefinition: encryptedProtocolDefinition,
|
|
2244
2244
|
});
|
|
2245
2245
|
const configReply = await dwn.processMessage(alice.did, protocolConfig.message);
|
|
2246
2246
|
expect(configReply.status.code).toBe(202);
|
|
@@ -2272,25 +2272,24 @@ export function testRecordsWriteHandler() {
|
|
|
2272
2272
|
secret: {}
|
|
2273
2273
|
}
|
|
2274
2274
|
};
|
|
2275
|
+
const encryptedProtocolDefinition = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, alice.keyId, alice.encryptionKeyPair.privateJwk);
|
|
2275
2276
|
// Alice installs the protocol
|
|
2276
2277
|
const protocolConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
2277
2278
|
author: alice,
|
|
2278
|
-
protocolDefinition:
|
|
2279
|
+
protocolDefinition: encryptedProtocolDefinition,
|
|
2279
2280
|
});
|
|
2280
2281
|
const configReply = await dwn.processMessage(alice.did, protocolConfig.message);
|
|
2281
2282
|
expect(configReply.status.code).toBe(202);
|
|
2282
|
-
// Generate an X25519 key pair for encryption (did:key personas use Ed25519 for signing)
|
|
2283
|
-
const encryptionPrivateKey = await X25519.generateKey();
|
|
2284
|
-
const encryptionPublicKey = await X25519.getPublicKey({ key: encryptionPrivateKey });
|
|
2285
2283
|
const data = Encoder.stringToBytes('encrypted secret');
|
|
2286
2284
|
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
2287
|
-
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(
|
|
2285
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
2286
|
+
const encryptedData = await Encryption.encrypt(ContentEncryptionAlgorithm.A256CTR, dataEncryptionKey, dataEncryptionInitializationVector, data);
|
|
2287
|
+
const encryptionPublicKey = encryptedProtocolDefinition.structure.secret.$keyAgreement.publicKeyJwk;
|
|
2288
2288
|
const encryptionInput = {
|
|
2289
2289
|
initializationVector: dataEncryptionInitializationVector,
|
|
2290
2290
|
key: dataEncryptionKey,
|
|
2291
|
-
authenticationTag: TestDataGenerator.randomBytes(16),
|
|
2292
2291
|
keyEncryptionInputs: [{
|
|
2293
|
-
|
|
2292
|
+
keyId: await Encryption.getKeyId(encryptionPublicKey),
|
|
2294
2293
|
publicKey: encryptionPublicKey,
|
|
2295
2294
|
derivationScheme: KeyDerivationScheme.ProtocolPath
|
|
2296
2295
|
}]
|
|
@@ -2300,7 +2299,176 @@ export function testRecordsWriteHandler() {
|
|
|
2300
2299
|
protocol: protocolDefinition.protocol,
|
|
2301
2300
|
protocolPath: 'secret',
|
|
2302
2301
|
schema: 'http://secret-schema',
|
|
2303
|
-
data,
|
|
2302
|
+
data: encryptedData,
|
|
2303
|
+
encryptionInput,
|
|
2304
|
+
});
|
|
2305
|
+
const writeReply = await dwn.processMessage(alice.did, recordsWrite.message, { dataStream: recordsWrite.dataStream });
|
|
2306
|
+
expect(writeReply.status.code).toBe(202);
|
|
2307
|
+
});
|
|
2308
|
+
it('should reject an encrypted role-readable RecordsWrite without a roleAudience keyEncryption entry', async () => {
|
|
2309
|
+
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
2310
|
+
const protocolDefinition = {
|
|
2311
|
+
protocol: 'http://role-audience-entry-required.xyz',
|
|
2312
|
+
published: false,
|
|
2313
|
+
types: {
|
|
2314
|
+
thread: { schema: 'http://thread-schema', dataFormats: ['application/json'] },
|
|
2315
|
+
participant: { schema: 'http://participant-schema', dataFormats: ['application/json'] },
|
|
2316
|
+
chat: { schema: 'http://chat-schema', dataFormats: ['text/plain'], encryptionRequired: true },
|
|
2317
|
+
},
|
|
2318
|
+
structure: {
|
|
2319
|
+
thread: {
|
|
2320
|
+
participant: { $role: true },
|
|
2321
|
+
chat: {
|
|
2322
|
+
$actions: [
|
|
2323
|
+
{ role: 'thread/participant', can: ['read'] },
|
|
2324
|
+
],
|
|
2325
|
+
},
|
|
2326
|
+
},
|
|
2327
|
+
},
|
|
2328
|
+
};
|
|
2329
|
+
const encryptedProtocolDefinition = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, alice.keyId, alice.encryptionKeyPair.privateJwk);
|
|
2330
|
+
const protocolConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
2331
|
+
author: alice,
|
|
2332
|
+
protocolDefinition: encryptedProtocolDefinition,
|
|
2333
|
+
});
|
|
2334
|
+
expect((await dwn.processMessage(alice.did, protocolConfig.message)).status.code).toBe(202);
|
|
2335
|
+
const thread = await TestDataGenerator.generateRecordsWrite({
|
|
2336
|
+
author: alice,
|
|
2337
|
+
protocol: protocolDefinition.protocol,
|
|
2338
|
+
protocolPath: 'thread',
|
|
2339
|
+
schema: 'http://thread-schema',
|
|
2340
|
+
dataFormat: 'application/json',
|
|
2341
|
+
data: Encoder.stringToBytes('{"title":"secret"}'),
|
|
2342
|
+
});
|
|
2343
|
+
expect((await dwn.processMessage(alice.did, thread.message, { dataStream: thread.dataStream })).status.code).toBe(202);
|
|
2344
|
+
const data = Encoder.stringToBytes('encrypted chat');
|
|
2345
|
+
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
2346
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
2347
|
+
const encryptedData = await Encryption.encrypt(ContentEncryptionAlgorithm.A256CTR, dataEncryptionKey, dataEncryptionInitializationVector, data);
|
|
2348
|
+
const threadRuleSet = encryptedProtocolDefinition.structure.thread;
|
|
2349
|
+
const chatRuleSet = threadRuleSet.chat;
|
|
2350
|
+
const protocolPathPublicKey = chatRuleSet.$keyAgreement.publicKeyJwk;
|
|
2351
|
+
const encryptionInput = {
|
|
2352
|
+
initializationVector: dataEncryptionInitializationVector,
|
|
2353
|
+
key: dataEncryptionKey,
|
|
2354
|
+
keyEncryptionInputs: [{
|
|
2355
|
+
keyId: await Encryption.getKeyId(protocolPathPublicKey),
|
|
2356
|
+
publicKey: protocolPathPublicKey,
|
|
2357
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
2358
|
+
}],
|
|
2359
|
+
};
|
|
2360
|
+
const recordsWrite = await TestDataGenerator.generateRecordsWrite({
|
|
2361
|
+
author: alice,
|
|
2362
|
+
protocol: protocolDefinition.protocol,
|
|
2363
|
+
protocolPath: 'thread/chat',
|
|
2364
|
+
parentContextId: thread.message.contextId,
|
|
2365
|
+
schema: 'http://chat-schema',
|
|
2366
|
+
dataFormat: 'text/plain',
|
|
2367
|
+
data: encryptedData,
|
|
2368
|
+
encryptionInput,
|
|
2369
|
+
});
|
|
2370
|
+
const writeReply = await dwn.processMessage(alice.did, recordsWrite.message, { dataStream: recordsWrite.dataStream });
|
|
2371
|
+
expect(writeReply.status.code).toBe(400);
|
|
2372
|
+
expect(writeReply.status.detail).toContain(DwnErrorCode.ProtocolAuthorizationEncryptionRoleAudienceEntryMissing);
|
|
2373
|
+
});
|
|
2374
|
+
it('should accept an encrypted role-readable RecordsWrite with a matching audienceEpoch', async () => {
|
|
2375
|
+
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
2376
|
+
const protocolDefinition = {
|
|
2377
|
+
protocol: 'http://role-audience-entry-accepted.xyz',
|
|
2378
|
+
published: false,
|
|
2379
|
+
types: {
|
|
2380
|
+
thread: { schema: 'http://thread-schema', dataFormats: ['application/json'] },
|
|
2381
|
+
participant: { schema: 'http://participant-schema', dataFormats: ['application/json'] },
|
|
2382
|
+
chat: { schema: 'http://chat-schema', dataFormats: ['text/plain'], encryptionRequired: true },
|
|
2383
|
+
},
|
|
2384
|
+
structure: {
|
|
2385
|
+
thread: {
|
|
2386
|
+
participant: { $role: true },
|
|
2387
|
+
chat: {
|
|
2388
|
+
$actions: [
|
|
2389
|
+
{ role: 'thread/participant', can: ['read'] },
|
|
2390
|
+
],
|
|
2391
|
+
},
|
|
2392
|
+
},
|
|
2393
|
+
},
|
|
2394
|
+
};
|
|
2395
|
+
const encryptedProtocolDefinition = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, alice.keyId, alice.encryptionKeyPair.privateJwk);
|
|
2396
|
+
const protocolConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
2397
|
+
author: alice,
|
|
2398
|
+
protocolDefinition: encryptedProtocolDefinition,
|
|
2399
|
+
});
|
|
2400
|
+
expect((await dwn.processMessage(alice.did, protocolConfig.message)).status.code).toBe(202);
|
|
2401
|
+
const thread = await TestDataGenerator.generateRecordsWrite({
|
|
2402
|
+
author: alice,
|
|
2403
|
+
protocol: protocolDefinition.protocol,
|
|
2404
|
+
protocolPath: 'thread',
|
|
2405
|
+
schema: 'http://thread-schema',
|
|
2406
|
+
dataFormat: 'application/json',
|
|
2407
|
+
data: Encoder.stringToBytes('{"title":"secret"}'),
|
|
2408
|
+
});
|
|
2409
|
+
expect((await dwn.processMessage(alice.did, thread.message, { dataStream: thread.dataStream })).status.code).toBe(202);
|
|
2410
|
+
const role = 'thread/participant';
|
|
2411
|
+
const threadRuleSet = encryptedProtocolDefinition.structure.thread;
|
|
2412
|
+
const participantRuleSet = threadRuleSet.participant;
|
|
2413
|
+
const rolePublicKey = participantRuleSet.$keyAgreement.publicKeyJwk;
|
|
2414
|
+
const roleKeyId = await Encryption.getKeyId(rolePublicKey);
|
|
2415
|
+
const audienceEpochData = Encoder.objectToBytes({
|
|
2416
|
+
protocol: protocolDefinition.protocol,
|
|
2417
|
+
contextId: thread.message.contextId,
|
|
2418
|
+
role,
|
|
2419
|
+
epoch: 1,
|
|
2420
|
+
keyId: roleKeyId,
|
|
2421
|
+
publicKeyJwk: rolePublicKey,
|
|
2422
|
+
});
|
|
2423
|
+
const audienceEpoch = await RecordsWrite.create({
|
|
2424
|
+
data: audienceEpochData,
|
|
2425
|
+
dataFormat: 'application/json',
|
|
2426
|
+
protocol: EncryptionProtocol.uri,
|
|
2427
|
+
protocolPath: EncryptionProtocol.audienceEpochPath,
|
|
2428
|
+
schema: EncryptionProtocol.definition.types.audienceEpoch.schema,
|
|
2429
|
+
signer: Jws.createSigner(alice),
|
|
2430
|
+
tags: {
|
|
2431
|
+
protocol: protocolDefinition.protocol,
|
|
2432
|
+
contextId: thread.message.contextId,
|
|
2433
|
+
role,
|
|
2434
|
+
epoch: 1,
|
|
2435
|
+
keyId: roleKeyId,
|
|
2436
|
+
},
|
|
2437
|
+
});
|
|
2438
|
+
expect((await dwn.processMessage(alice.did, audienceEpoch.message, { dataStream: DataStream.fromBytes(audienceEpochData) })).status.code).toBe(202);
|
|
2439
|
+
const data = Encoder.stringToBytes('encrypted chat');
|
|
2440
|
+
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
2441
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
2442
|
+
const encryptedData = await Encryption.encrypt(ContentEncryptionAlgorithm.A256CTR, dataEncryptionKey, dataEncryptionInitializationVector, data);
|
|
2443
|
+
const chatRuleSet = threadRuleSet.chat;
|
|
2444
|
+
const protocolPathPublicKey = chatRuleSet.$keyAgreement.publicKeyJwk;
|
|
2445
|
+
const encryptionInput = {
|
|
2446
|
+
initializationVector: dataEncryptionInitializationVector,
|
|
2447
|
+
key: dataEncryptionKey,
|
|
2448
|
+
keyEncryptionInputs: [
|
|
2449
|
+
{
|
|
2450
|
+
keyId: await Encryption.getKeyId(protocolPathPublicKey),
|
|
2451
|
+
publicKey: protocolPathPublicKey,
|
|
2452
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
2453
|
+
},
|
|
2454
|
+
{
|
|
2455
|
+
keyId: roleKeyId,
|
|
2456
|
+
publicKey: rolePublicKey,
|
|
2457
|
+
derivationScheme: ROLE_AUDIENCE_DERIVATION_SCHEME,
|
|
2458
|
+
protocol: protocolDefinition.protocol,
|
|
2459
|
+
role,
|
|
2460
|
+
epoch: 1,
|
|
2461
|
+
},
|
|
2462
|
+
],
|
|
2463
|
+
};
|
|
2464
|
+
const recordsWrite = await TestDataGenerator.generateRecordsWrite({
|
|
2465
|
+
author: alice,
|
|
2466
|
+
protocol: protocolDefinition.protocol,
|
|
2467
|
+
protocolPath: 'thread/chat',
|
|
2468
|
+
parentContextId: thread.message.contextId,
|
|
2469
|
+
schema: 'http://chat-schema',
|
|
2470
|
+
dataFormat: 'text/plain',
|
|
2471
|
+
data: encryptedData,
|
|
2304
2472
|
encryptionInput,
|
|
2305
2473
|
});
|
|
2306
2474
|
const writeReply = await dwn.processMessage(alice.did, recordsWrite.message, { dataStream: recordsWrite.dataStream });
|
|
@@ -2320,10 +2488,11 @@ export function testRecordsWriteHandler() {
|
|
|
2320
2488
|
secret: {},
|
|
2321
2489
|
}
|
|
2322
2490
|
};
|
|
2491
|
+
const encryptedProtocolDefinition = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, alice.keyId, alice.encryptionKeyPair.privateJwk);
|
|
2323
2492
|
// Alice installs the protocol
|
|
2324
2493
|
const protocolConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
2325
2494
|
author: alice,
|
|
2326
|
-
protocolDefinition:
|
|
2495
|
+
protocolDefinition: encryptedProtocolDefinition,
|
|
2327
2496
|
});
|
|
2328
2497
|
const configReply = await dwn.processMessage(alice.did, protocolConfig.message);
|
|
2329
2498
|
expect(configReply.status.code).toBe(202);
|
|
@@ -2570,15 +2739,14 @@ export function testRecordsWriteHandler() {
|
|
|
2570
2739
|
const protocolsConfigureReply = await dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2571
2740
|
expect(protocolsConfigureReply.status.code).toBe(202);
|
|
2572
2741
|
const bobMessageBytes = Encoder.stringToBytes('message from bob');
|
|
2573
|
-
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(
|
|
2742
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
2574
2743
|
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
2575
|
-
const
|
|
2744
|
+
const bobMessageEncryptedBytes = await Encryption.encrypt(ContentEncryptionAlgorithm.A256CTR, dataEncryptionKey, dataEncryptionInitializationVector, bobMessageBytes);
|
|
2576
2745
|
const encryptionInput = {
|
|
2577
2746
|
initializationVector: dataEncryptionInitializationVector,
|
|
2578
2747
|
key: dataEncryptionKey,
|
|
2579
|
-
authenticationTag,
|
|
2580
2748
|
keyEncryptionInputs: [{
|
|
2581
|
-
|
|
2749
|
+
keyId: await Encryption.getKeyId(alice.encryptionKeyPair.publicJwk),
|
|
2582
2750
|
publicKey: alice.encryptionKeyPair.publicJwk,
|
|
2583
2751
|
derivationScheme: KeyDerivationScheme.ProtocolPath
|
|
2584
2752
|
}]
|
|
@@ -2591,8 +2759,8 @@ export function testRecordsWriteHandler() {
|
|
|
2591
2759
|
data: bobMessageEncryptedBytes,
|
|
2592
2760
|
encryptionInput
|
|
2593
2761
|
});
|
|
2594
|
-
//
|
|
2595
|
-
message.encryption.
|
|
2762
|
+
// Replace valid `encryption` property with a mismatching one while keeping the envelope schema-valid.
|
|
2763
|
+
message.encryption.initializationVector = Encoder.bytesToBase64Url(TestDataGenerator.randomBytes(16));
|
|
2596
2764
|
const recordsWriteHandler = new RecordsWriteHandler({
|
|
2597
2765
|
didResolver, messageStore, dataStore, coreProtocols: new CoreProtocolRegistry(), eventLog,
|
|
2598
2766
|
validationStateReader: createTestValidationStateReader({ messageStore, dataStore }),
|
|
@@ -2601,6 +2769,98 @@ export function testRecordsWriteHandler() {
|
|
|
2601
2769
|
expect(writeReply.status.code).toBe(400);
|
|
2602
2770
|
expect(writeReply.status.detail).toContain(DwnErrorCode.RecordsWriteValidateIntegrityEncryptionCidMismatch);
|
|
2603
2771
|
});
|
|
2772
|
+
it('should 400 if `encryption` is present without a signed encryptionCid', async () => {
|
|
2773
|
+
const alice = await TestDataGenerator.generatePersona();
|
|
2774
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
2775
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
2776
|
+
const protocol = protocolDefinition.protocol;
|
|
2777
|
+
const protocolsConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
2778
|
+
author: alice,
|
|
2779
|
+
protocolDefinition
|
|
2780
|
+
});
|
|
2781
|
+
const protocolsConfigureReply = await dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2782
|
+
expect(protocolsConfigureReply.status.code).toBe(202);
|
|
2783
|
+
const messageBytes = Encoder.stringToBytes('encrypted message');
|
|
2784
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
2785
|
+
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
2786
|
+
const encryptedBytes = await Encryption.encrypt(ContentEncryptionAlgorithm.A256CTR, dataEncryptionKey, dataEncryptionInitializationVector, messageBytes);
|
|
2787
|
+
const encryptionInput = {
|
|
2788
|
+
initializationVector: dataEncryptionInitializationVector,
|
|
2789
|
+
key: dataEncryptionKey,
|
|
2790
|
+
keyEncryptionInputs: [{
|
|
2791
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
2792
|
+
keyId: await Encryption.getKeyId(alice.encryptionKeyPair.publicJwk),
|
|
2793
|
+
publicKey: alice.encryptionKeyPair.publicJwk,
|
|
2794
|
+
}],
|
|
2795
|
+
};
|
|
2796
|
+
const { message, dataStream } = await TestDataGenerator.generateRecordsWrite({
|
|
2797
|
+
author: alice,
|
|
2798
|
+
data: encryptedBytes,
|
|
2799
|
+
encryptionInput,
|
|
2800
|
+
protocol,
|
|
2801
|
+
protocolPath: 'email',
|
|
2802
|
+
schema: 'email',
|
|
2803
|
+
});
|
|
2804
|
+
const signaturePayload = Jws.decodePlainObjectPayload(message.authorization.signature);
|
|
2805
|
+
delete signaturePayload.encryptionCid;
|
|
2806
|
+
message.authorization.signature.payload = Encoder.stringToBase64Url(JSON.stringify(signaturePayload));
|
|
2807
|
+
const recordsWriteHandler = new RecordsWriteHandler({
|
|
2808
|
+
coreProtocols: new CoreProtocolRegistry(),
|
|
2809
|
+
dataStore,
|
|
2810
|
+
didResolver,
|
|
2811
|
+
eventLog,
|
|
2812
|
+
messageStore,
|
|
2813
|
+
validationStateReader: createTestValidationStateReader({ messageStore, dataStore }),
|
|
2814
|
+
});
|
|
2815
|
+
const writeReply = await recordsWriteHandler.handle({ tenant: alice.did, message, dataStream: dataStream });
|
|
2816
|
+
expect(writeReply.status.code).toBe(400);
|
|
2817
|
+
expect(writeReply.status.detail).toContain(DwnErrorCode.RecordsWriteValidateIntegrityEncryptionCidMissing);
|
|
2818
|
+
});
|
|
2819
|
+
it('should 400 if a signed encryptionCid is present without `encryption`', async () => {
|
|
2820
|
+
const alice = await TestDataGenerator.generatePersona();
|
|
2821
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
2822
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
2823
|
+
const protocol = protocolDefinition.protocol;
|
|
2824
|
+
const protocolsConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
2825
|
+
author: alice,
|
|
2826
|
+
protocolDefinition
|
|
2827
|
+
});
|
|
2828
|
+
const protocolsConfigureReply = await dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2829
|
+
expect(protocolsConfigureReply.status.code).toBe(202);
|
|
2830
|
+
const messageBytes = Encoder.stringToBytes('encrypted message');
|
|
2831
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
2832
|
+
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
2833
|
+
const encryptedBytes = await Encryption.encrypt(ContentEncryptionAlgorithm.A256CTR, dataEncryptionKey, dataEncryptionInitializationVector, messageBytes);
|
|
2834
|
+
const encryptionInput = {
|
|
2835
|
+
initializationVector: dataEncryptionInitializationVector,
|
|
2836
|
+
key: dataEncryptionKey,
|
|
2837
|
+
keyEncryptionInputs: [{
|
|
2838
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
2839
|
+
keyId: await Encryption.getKeyId(alice.encryptionKeyPair.publicJwk),
|
|
2840
|
+
publicKey: alice.encryptionKeyPair.publicJwk,
|
|
2841
|
+
}],
|
|
2842
|
+
};
|
|
2843
|
+
const { message, dataStream } = await TestDataGenerator.generateRecordsWrite({
|
|
2844
|
+
author: alice,
|
|
2845
|
+
data: encryptedBytes,
|
|
2846
|
+
encryptionInput,
|
|
2847
|
+
protocol,
|
|
2848
|
+
protocolPath: 'email',
|
|
2849
|
+
schema: 'email',
|
|
2850
|
+
});
|
|
2851
|
+
delete message.encryption;
|
|
2852
|
+
const recordsWriteHandler = new RecordsWriteHandler({
|
|
2853
|
+
coreProtocols: new CoreProtocolRegistry(),
|
|
2854
|
+
dataStore,
|
|
2855
|
+
didResolver,
|
|
2856
|
+
eventLog,
|
|
2857
|
+
messageStore,
|
|
2858
|
+
validationStateReader: createTestValidationStateReader({ messageStore, dataStore }),
|
|
2859
|
+
});
|
|
2860
|
+
const writeReply = await recordsWriteHandler.handle({ tenant: alice.did, message, dataStream: dataStream });
|
|
2861
|
+
expect(writeReply.status.code).toBe(400);
|
|
2862
|
+
expect(writeReply.status.detail).toContain(DwnErrorCode.RecordsWriteValidateIntegrityEncryptionCidMissing);
|
|
2863
|
+
});
|
|
2604
2864
|
it('should return 400 if protocol is not normalized', async () => {
|
|
2605
2865
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
2606
2866
|
const protocolDefinition = emailProtocolDefinition;
|