@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
|
@@ -7,215 +7,178 @@ import { TestDataGenerator } from '../utils/test-data-generator.js';
|
|
|
7
7
|
import { X25519 } from '@enbox/crypto';
|
|
8
8
|
import { beforeEach, describe, expect, it } from 'bun:test';
|
|
9
9
|
import { HdKey, KeyDerivationScheme } from '../../src/utils/hd-key.js';
|
|
10
|
-
describe('Encryption
|
|
10
|
+
describe('Encryption callback interfaces', () => {
|
|
11
11
|
let privateJwk;
|
|
12
12
|
let rootKeyId;
|
|
13
13
|
beforeEach(async () => {
|
|
14
|
-
|
|
15
|
-
privateJwk = key;
|
|
14
|
+
privateJwk = await X25519.generateKey();
|
|
16
15
|
rootKeyId = 'did:example:alice#enc';
|
|
17
16
|
});
|
|
18
|
-
describe('Protocols.deriveAndInjectPublicEncryptionKeys()
|
|
19
|
-
it('produces the same $
|
|
17
|
+
describe('Protocols.deriveAndInjectPublicEncryptionKeys()', () => {
|
|
18
|
+
it('produces the same $keyAgreement output as the raw-key overload', async () => {
|
|
20
19
|
const protocolDefinition = {
|
|
21
20
|
protocol: 'https://example.com/protocol/foo',
|
|
22
21
|
published: true,
|
|
23
22
|
types: {
|
|
23
|
+
message: {
|
|
24
|
+
dataFormats: ['text/plain'],
|
|
25
|
+
encryptionRequired: true,
|
|
26
|
+
schema: 'https://example.com/schema/message',
|
|
27
|
+
},
|
|
24
28
|
thread: {
|
|
29
|
+
dataFormats: ['application/json'],
|
|
25
30
|
schema: 'https://example.com/schema/thread',
|
|
26
|
-
dataFormats: ['application/json']
|
|
27
31
|
},
|
|
28
|
-
message: {
|
|
29
|
-
schema: 'https://example.com/schema/message',
|
|
30
|
-
dataFormats: ['text/plain']
|
|
31
|
-
}
|
|
32
32
|
},
|
|
33
33
|
structure: {
|
|
34
34
|
thread: {
|
|
35
|
-
message: {}
|
|
36
|
-
}
|
|
35
|
+
message: {},
|
|
36
|
+
},
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
|
-
// Call with raw (rootKeyId, privateJwk) — get result A
|
|
40
39
|
const resultA = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, rootKeyId, privateJwk);
|
|
41
|
-
|
|
42
|
-
const keyDeriver = {
|
|
43
|
-
rootKeyId,
|
|
44
|
-
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
45
|
-
derivePublicKey: async (fullDerivationPath) => {
|
|
46
|
-
const privateKeyBytes = await X25519.privateKeyToBytes({ privateKey: privateJwk });
|
|
47
|
-
const derivedPrivateKeyBytes = await HdKey.derivePrivateKeyBytes(privateKeyBytes, fullDerivationPath);
|
|
48
|
-
const derivedPrivateKey = await X25519.bytesToPrivateKey({ privateKeyBytes: derivedPrivateKeyBytes });
|
|
49
|
-
return await X25519.getPublicKey({ key: derivedPrivateKey });
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
// Call with the callback — get result B
|
|
40
|
+
const keyDeriver = createKeyDeriver(privateJwk, rootKeyId);
|
|
53
41
|
const resultB = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, keyDeriver);
|
|
54
|
-
|
|
55
|
-
expect(resultA.structure.thread.$
|
|
56
|
-
expect(resultB.structure.thread.$encryption).toBeDefined();
|
|
57
|
-
expect(resultA.structure.thread.$encryption.rootKeyId).toBe(resultB.structure.thread.$encryption.rootKeyId);
|
|
58
|
-
expect(resultA.structure.thread.$encryption.publicKeyJwk).toEqual(resultB.structure.thread.$encryption.publicKeyJwk);
|
|
42
|
+
expect(resultA.$keyAgreement.publicKeyJwk).toEqual(resultB.$keyAgreement.publicKeyJwk);
|
|
43
|
+
expect(resultA.structure.thread.$keyAgreement.publicKeyJwk).toEqual(resultB.structure.thread.$keyAgreement.publicKeyJwk);
|
|
59
44
|
const messageRuleSetA = resultA.structure.thread.message;
|
|
60
45
|
const messageRuleSetB = resultB.structure.thread.message;
|
|
61
|
-
expect(messageRuleSetA.$
|
|
62
|
-
expect(messageRuleSetB.$encryption).toBeDefined();
|
|
63
|
-
expect(messageRuleSetA.$encryption.rootKeyId).toBe(messageRuleSetB.$encryption.rootKeyId);
|
|
64
|
-
expect(messageRuleSetA.$encryption.publicKeyJwk).toEqual(messageRuleSetB.$encryption.publicKeyJwk);
|
|
46
|
+
expect(messageRuleSetA.$keyAgreement.publicKeyJwk).toEqual(messageRuleSetB.$keyAgreement.publicKeyJwk);
|
|
65
47
|
});
|
|
66
|
-
it('calls derivePublicKey with
|
|
48
|
+
it('calls derivePublicKey with protocol-root and full protocol-path derivation paths', async () => {
|
|
67
49
|
const protocolDefinition = {
|
|
68
50
|
protocol: 'https://example.com/protocol/bar',
|
|
69
51
|
published: true,
|
|
70
52
|
types: {
|
|
53
|
+
message: {
|
|
54
|
+
dataFormats: ['text/plain'],
|
|
55
|
+
encryptionRequired: true,
|
|
56
|
+
schema: 'https://example.com/schema/message',
|
|
57
|
+
},
|
|
71
58
|
thread: {
|
|
59
|
+
dataFormats: ['application/json'],
|
|
72
60
|
schema: 'https://example.com/schema/thread',
|
|
73
|
-
dataFormats: ['application/json']
|
|
74
61
|
},
|
|
75
|
-
message: {
|
|
76
|
-
schema: 'https://example.com/schema/message',
|
|
77
|
-
dataFormats: ['text/plain']
|
|
78
|
-
}
|
|
79
62
|
},
|
|
80
63
|
structure: {
|
|
81
64
|
thread: {
|
|
82
|
-
message: {}
|
|
83
|
-
}
|
|
65
|
+
message: {},
|
|
66
|
+
},
|
|
84
67
|
}
|
|
85
68
|
};
|
|
86
69
|
const calledPaths = [];
|
|
87
|
-
const keyDeriver =
|
|
88
|
-
rootKeyId,
|
|
89
|
-
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
90
|
-
derivePublicKey: async (fullDerivationPath) => {
|
|
91
|
-
calledPaths.push([...fullDerivationPath]);
|
|
92
|
-
const privateKeyBytes = await X25519.privateKeyToBytes({ privateKey: privateJwk });
|
|
93
|
-
const derivedPrivateKeyBytes = await HdKey.derivePrivateKeyBytes(privateKeyBytes, fullDerivationPath);
|
|
94
|
-
const derivedPrivateKey = await X25519.bytesToPrivateKey({ privateKeyBytes: derivedPrivateKeyBytes });
|
|
95
|
-
return await X25519.getPublicKey({ key: derivedPrivateKey });
|
|
96
|
-
}
|
|
97
|
-
};
|
|
70
|
+
const keyDeriver = createKeyDeriver(privateJwk, rootKeyId, calledPaths);
|
|
98
71
|
await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, keyDeriver);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
KeyDerivationScheme.ProtocolPath,
|
|
104
|
-
'https://example.com/protocol/bar',
|
|
105
|
-
'thread'
|
|
106
|
-
]);
|
|
107
|
-
expect(calledPaths[1]).toEqual([
|
|
108
|
-
KeyDerivationScheme.ProtocolPath,
|
|
109
|
-
'https://example.com/protocol/bar',
|
|
110
|
-
'thread',
|
|
111
|
-
'message'
|
|
72
|
+
expect(calledPaths).toEqual([
|
|
73
|
+
[KeyDerivationScheme.ProtocolPath, 'https://example.com/protocol/bar'],
|
|
74
|
+
[KeyDerivationScheme.ProtocolPath, 'https://example.com/protocol/bar', 'thread'],
|
|
75
|
+
[KeyDerivationScheme.ProtocolPath, 'https://example.com/protocol/bar', 'thread', 'message'],
|
|
112
76
|
]);
|
|
113
77
|
});
|
|
114
78
|
});
|
|
115
79
|
describe('Records.decrypt() with KeyDecrypter', () => {
|
|
116
80
|
it('produces the same plaintext as the raw-key overload', async () => {
|
|
117
|
-
const protocolDefinition = {
|
|
81
|
+
const protocolDefinition = await Protocols.deriveAndInjectPublicEncryptionKeys({
|
|
118
82
|
protocol: 'https://example.com/protocol/decrypt-test',
|
|
119
83
|
published: true,
|
|
120
84
|
types: {
|
|
121
85
|
note: {
|
|
86
|
+
dataFormats: ['text/plain'],
|
|
87
|
+
encryptionRequired: true,
|
|
122
88
|
schema: 'https://example.com/schema/note',
|
|
123
|
-
|
|
124
|
-
}
|
|
89
|
+
},
|
|
125
90
|
},
|
|
126
91
|
structure: {
|
|
127
|
-
note: {}
|
|
92
|
+
note: {},
|
|
128
93
|
}
|
|
129
|
-
};
|
|
130
|
-
// Derive and inject encryption keys
|
|
131
|
-
const encryptedProtocol = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, rootKeyId, privateJwk);
|
|
132
|
-
// Generate a test persona
|
|
94
|
+
}, rootKeyId, privateJwk);
|
|
133
95
|
const alice = await TestDataGenerator.generatePersona();
|
|
134
|
-
// Encrypt a record using the standard flow
|
|
135
96
|
const plaintext = 'This is a secret message';
|
|
136
97
|
const plaintextBytes = Encoder.stringToBytes(plaintext);
|
|
137
98
|
const encryptedRecord = await TestDataGenerator.generateProtocolEncryptedRecordsWrite({
|
|
138
|
-
plaintextBytes,
|
|
139
99
|
author: alice,
|
|
140
|
-
protocolDefinition: encryptedProtocol,
|
|
141
|
-
protocolPath: 'note',
|
|
142
100
|
encryptSymmetricKeyWithProtocolPathDerivedKey: true,
|
|
143
|
-
|
|
101
|
+
plaintextBytes,
|
|
102
|
+
protocolDefinition,
|
|
103
|
+
protocolPath: 'note',
|
|
144
104
|
});
|
|
145
|
-
// Decrypt with raw DerivedPrivateJwk — get plaintext A
|
|
146
105
|
const rootKey = {
|
|
147
|
-
|
|
106
|
+
derivedPrivateKey: privateJwk,
|
|
148
107
|
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
149
|
-
|
|
108
|
+
rootKeyId,
|
|
150
109
|
};
|
|
151
110
|
const decryptedStreamA = await Records.decrypt(encryptedRecord.message, rootKey, encryptedRecord.dataStream);
|
|
152
111
|
const plaintextA = await DataStream.toBytes(decryptedStreamA);
|
|
153
|
-
|
|
154
|
-
const keyDecrypter = {
|
|
155
|
-
rootKeyId,
|
|
156
|
-
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
157
|
-
decrypt: async (fullDerivationPath, jwePayload) => {
|
|
158
|
-
const privateKeyBytes = await X25519.privateKeyToBytes({ privateKey: privateJwk });
|
|
159
|
-
const leafPrivateKeyBytes = await HdKey.derivePrivateKeyBytes(privateKeyBytes, fullDerivationPath);
|
|
160
|
-
const leafPrivateKey = await X25519.bytesToPrivateKey({ privateKeyBytes: leafPrivateKeyBytes });
|
|
161
|
-
return Encryption.ecdhEsUnwrapKey(leafPrivateKey, jwePayload.ephemeralPublicKey, jwePayload.encryptedKey);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
// Decrypt with the callback — get plaintext B
|
|
165
|
-
// Note: Need to create a new stream since the first one was consumed
|
|
112
|
+
const keyDecrypter = createKeyDecrypter(privateJwk, rootKeyId);
|
|
166
113
|
const encryptedRecord2 = await TestDataGenerator.generateProtocolEncryptedRecordsWrite({
|
|
167
|
-
plaintextBytes,
|
|
168
114
|
author: alice,
|
|
169
|
-
protocolDefinition: encryptedProtocol,
|
|
170
|
-
protocolPath: 'note',
|
|
171
115
|
encryptSymmetricKeyWithProtocolPathDerivedKey: true,
|
|
172
|
-
|
|
116
|
+
plaintextBytes,
|
|
117
|
+
protocolDefinition,
|
|
118
|
+
protocolPath: 'note',
|
|
173
119
|
});
|
|
174
120
|
const decryptedStreamB = await Records.decrypt(encryptedRecord2.message, keyDecrypter, encryptedRecord2.dataStream);
|
|
175
121
|
const plaintextB = await DataStream.toBytes(decryptedStreamB);
|
|
176
|
-
// Assert A and B are identical
|
|
177
122
|
expect(Encoder.bytesToString(plaintextA)).toBe(plaintext);
|
|
178
123
|
expect(Encoder.bytesToString(plaintextB)).toBe(plaintext);
|
|
179
|
-
expect(plaintextA).toEqual(plaintextB);
|
|
180
124
|
});
|
|
181
|
-
it('throws if no matching
|
|
182
|
-
const protocolDefinition = {
|
|
125
|
+
it('throws if no matching key encryption entry is found', async () => {
|
|
126
|
+
const protocolDefinition = await Protocols.deriveAndInjectPublicEncryptionKeys({
|
|
183
127
|
protocol: 'https://example.com/protocol/mismatch-test',
|
|
184
128
|
published: true,
|
|
185
129
|
types: {
|
|
186
130
|
note: {
|
|
131
|
+
dataFormats: ['text/plain'],
|
|
132
|
+
encryptionRequired: true,
|
|
187
133
|
schema: 'https://example.com/schema/note',
|
|
188
|
-
|
|
189
|
-
}
|
|
134
|
+
},
|
|
190
135
|
},
|
|
191
136
|
structure: {
|
|
192
|
-
note: {}
|
|
137
|
+
note: {},
|
|
193
138
|
}
|
|
194
|
-
};
|
|
195
|
-
// Derive and inject encryption keys
|
|
196
|
-
const encryptedProtocol = await Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, rootKeyId, privateJwk);
|
|
139
|
+
}, rootKeyId, privateJwk);
|
|
197
140
|
const alice = await TestDataGenerator.generatePersona();
|
|
198
|
-
const plaintext = 'This is a secret message';
|
|
199
|
-
const plaintextBytes = Encoder.stringToBytes(plaintext);
|
|
200
141
|
const encryptedRecord = await TestDataGenerator.generateProtocolEncryptedRecordsWrite({
|
|
201
|
-
plaintextBytes,
|
|
202
142
|
author: alice,
|
|
203
|
-
protocolDefinition: encryptedProtocol,
|
|
204
|
-
protocolPath: 'note',
|
|
205
143
|
encryptSymmetricKeyWithProtocolPathDerivedKey: true,
|
|
206
|
-
|
|
144
|
+
plaintextBytes: Encoder.stringToBytes('secret'),
|
|
145
|
+
protocolDefinition,
|
|
146
|
+
protocolPath: 'note',
|
|
207
147
|
});
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
rootKeyId: 'did:example:bob#enc', // Wrong key ID
|
|
211
|
-
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
212
|
-
decrypt: async () => {
|
|
213
|
-
throw new Error('Should not be called');
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
// Attempt to decrypt — should throw
|
|
217
|
-
await expect(Records.decrypt(encryptedRecord.message, keyDecrypter, encryptedRecord.dataStream)).rejects.toThrow('Unable to find a JWE recipient matching key');
|
|
148
|
+
const otherPrivateKey = await X25519.generateKey();
|
|
149
|
+
await expect(Records.decrypt(encryptedRecord.message, { derivedPrivateKey: otherPrivateKey, derivationScheme: KeyDerivationScheme.ProtocolPath, rootKeyId: 'did:example:bob#enc' }, encryptedRecord.dataStream)).rejects.toThrow('Unable to find a matching key encryption entry');
|
|
218
150
|
});
|
|
219
151
|
});
|
|
220
152
|
});
|
|
153
|
+
function createKeyDeriver(privateJwk, rootKeyId, calledPaths = []) {
|
|
154
|
+
return {
|
|
155
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
156
|
+
derivePublicKey: async (fullDerivationPath) => {
|
|
157
|
+
calledPaths.push([...fullDerivationPath]);
|
|
158
|
+
const privateKeyBytes = await X25519.privateKeyToBytes({ privateKey: privateJwk });
|
|
159
|
+
const derivedPrivateKeyBytes = await HdKey.derivePrivateKeyBytes(privateKeyBytes, fullDerivationPath);
|
|
160
|
+
const derivedPrivateKey = await X25519.bytesToPrivateKey({ privateKeyBytes: derivedPrivateKeyBytes });
|
|
161
|
+
return await X25519.getPublicKey({ key: derivedPrivateKey });
|
|
162
|
+
},
|
|
163
|
+
rootKeyId,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function createKeyDecrypter(privateJwk, rootKeyId) {
|
|
167
|
+
return {
|
|
168
|
+
decrypt: async (fullDerivationPath, keyUnwrapPayload) => {
|
|
169
|
+
const privateKeyBytes = await X25519.privateKeyToBytes({ privateKey: privateJwk });
|
|
170
|
+
const leafPrivateKeyBytes = await HdKey.derivePrivateKeyBytes(privateKeyBytes, fullDerivationPath);
|
|
171
|
+
const leafPrivateKey = await X25519.bytesToPrivateKey({ privateKeyBytes: leafPrivateKeyBytes });
|
|
172
|
+
return Encryption.unwrapKey(leafPrivateKey, keyUnwrapPayload.keyEncryption);
|
|
173
|
+
},
|
|
174
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
175
|
+
derivePublicKey: async (fullDerivationPath) => {
|
|
176
|
+
const privateKeyBytes = await X25519.privateKeyToBytes({ privateKey: privateJwk });
|
|
177
|
+
const derivedPrivateKeyBytes = await HdKey.derivePrivateKeyBytes(privateKeyBytes, fullDerivationPath);
|
|
178
|
+
const derivedPrivateKey = await X25519.bytesToPrivateKey({ privateKeyBytes: derivedPrivateKeyBytes });
|
|
179
|
+
return await X25519.getPublicKey({ key: derivedPrivateKey });
|
|
180
|
+
},
|
|
181
|
+
rootKeyId,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
221
184
|
//# sourceMappingURL=encryption-callbacks.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption-callbacks.spec.js","sourceRoot":"","sources":["../../../../tests/utils/encryption-callbacks.spec.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"encryption-callbacks.spec.js","sourceRoot":"","sources":["../../../../tests/utils/encryption-callbacks.spec.ts"],"names":[],"mappings":"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"}
|