@dxos/echo-db 2.33.3-dev.1cc72521 → 2.33.3-dev.762b75aa
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/src/echo.js +2 -2
- package/dist/src/echo.js.map +1 -1
- package/dist/src/echo.test.js +10 -10
- package/dist/src/echo.test.js.map +1 -1
- package/dist/src/halo/halo-party.d.ts.map +1 -1
- package/dist/src/halo/halo-party.js +1 -1
- package/dist/src/halo/halo-party.js.map +1 -1
- package/dist/src/halo/halo.d.ts +1 -0
- package/dist/src/halo/halo.d.ts.map +1 -1
- package/dist/src/halo/halo.js +10 -1
- package/dist/src/halo/halo.js.map +1 -1
- package/dist/src/halo/identity-manager.d.ts +0 -1
- package/dist/src/halo/identity-manager.d.ts.map +1 -1
- package/dist/src/halo/identity-manager.js +11 -11
- package/dist/src/halo/identity-manager.js.map +1 -1
- package/dist/src/halo/identity.d.ts +18 -13
- package/dist/src/halo/identity.d.ts.map +1 -1
- package/dist/src/halo/identity.js +24 -27
- package/dist/src/halo/identity.js.map +1 -1
- package/dist/src/invitations/offline-invitation-claimer.d.ts +2 -2
- package/dist/src/invitations/offline-invitation-claimer.d.ts.map +1 -1
- package/dist/src/invitations/offline-invitation-claimer.js +2 -4
- package/dist/src/invitations/offline-invitation-claimer.js.map +1 -1
- package/dist/src/parties/data-party.d.ts.map +1 -1
- package/dist/src/parties/data-party.js +1 -1
- package/dist/src/parties/data-party.js.map +1 -1
- package/dist/src/parties/data-party.test.d.ts +2 -0
- package/dist/src/parties/data-party.test.d.ts.map +1 -0
- package/dist/src/parties/data-party.test.js +129 -0
- package/dist/src/parties/data-party.test.js.map +1 -0
- package/dist/src/parties/party-factory.d.ts +2 -2
- package/dist/src/parties/party-factory.d.ts.map +1 -1
- package/dist/src/parties/party-factory.js +12 -20
- package/dist/src/parties/party-factory.js.map +1 -1
- package/dist/src/parties/party-manager.d.ts +2 -2
- package/dist/src/parties/party-manager.d.ts.map +1 -1
- package/dist/src/parties/party-manager.js +2 -1
- package/dist/src/parties/party-manager.js.map +1 -1
- package/dist/src/parties/party-manager.test.js +7 -22
- package/dist/src/parties/party-manager.test.js.map +1 -1
- package/dist/src/pipeline/party-core.test.js +1 -1
- package/dist/src/pipeline/party-core.test.js.map +1 -1
- package/dist/src/pipeline/party-processor.d.ts +0 -5
- package/dist/src/pipeline/party-processor.d.ts.map +1 -1
- package/dist/src/pipeline/party-processor.js +0 -7
- package/dist/src/pipeline/party-processor.js.map +1 -1
- package/dist/src/protocol/credentials-signer.d.ts +4 -4
- package/dist/src/protocol/credentials-signer.d.ts.map +1 -1
- package/dist/src/protocol/credentials-signer.js +8 -8
- package/dist/src/protocol/credentials-signer.js.map +1 -1
- package/dist/src/protocol/identity-credentials.d.ts +22 -0
- package/dist/src/protocol/identity-credentials.d.ts.map +1 -0
- package/dist/src/protocol/identity-credentials.js +50 -0
- package/dist/src/protocol/identity-credentials.js.map +1 -0
- package/dist/src/protocol/party-protocol-factory.d.ts +3 -4
- package/dist/src/protocol/party-protocol-factory.d.ts.map +1 -1
- package/dist/src/protocol/party-protocol-factory.js +12 -15
- package/dist/src/protocol/party-protocol-factory.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -17
- package/src/echo.test.ts +10 -10
- package/src/echo.ts +1 -1
- package/src/halo/halo-party.ts +1 -2
- package/src/halo/halo.ts +8 -1
- package/src/halo/identity-manager.ts +13 -14
- package/src/halo/identity.ts +39 -41
- package/src/invitations/offline-invitation-claimer.ts +6 -7
- package/src/parties/data-party.test.ts +212 -0
- package/src/parties/data-party.ts +1 -2
- package/src/parties/party-factory.ts +14 -20
- package/src/parties/party-manager.test.ts +8 -42
- package/src/parties/party-manager.ts +4 -3
- package/src/pipeline/party-core.test.ts +2 -4
- package/src/pipeline/party-processor.ts +0 -13
- package/src/protocol/credentials-signer.ts +9 -9
- package/src/protocol/identity-credentials.ts +78 -0
- package/src/protocol/party-protocol-factory.ts +13 -17
|
@@ -22,12 +22,12 @@ import { NetworkManager } from '@dxos/network-manager';
|
|
|
22
22
|
import { ObjectModel } from '@dxos/object-model';
|
|
23
23
|
|
|
24
24
|
import { IdentityNotInitializedError } from '../errors';
|
|
25
|
-
import { IdentityProvider } from '../halo';
|
|
26
25
|
import {
|
|
27
26
|
createDataPartyAdmissionMessages,
|
|
28
27
|
GreetingInitiator, InvitationDescriptor, InvitationDescriptorType, OfflineInvitationClaimer
|
|
29
28
|
} from '../invitations';
|
|
30
29
|
import { PartyFeedProvider, PartyOptions } from '../pipeline';
|
|
30
|
+
import { IdentityCredentialsProvider } from '../protocol/identity-credentials';
|
|
31
31
|
import { SnapshotStore } from '../snapshots';
|
|
32
32
|
import { DataParty, PARTY_ITEM_TYPE } from './data-party';
|
|
33
33
|
|
|
@@ -38,7 +38,7 @@ const log = debug('dxos:echo-db:party-factory');
|
|
|
38
38
|
*/
|
|
39
39
|
export class PartyFactory {
|
|
40
40
|
constructor (
|
|
41
|
-
private readonly _identityProvider:
|
|
41
|
+
private readonly _identityProvider: IdentityCredentialsProvider,
|
|
42
42
|
private readonly _networkManager: NetworkManager,
|
|
43
43
|
private readonly _modelFactory: ModelFactory,
|
|
44
44
|
private readonly _snapshotStore: SnapshotStore,
|
|
@@ -52,8 +52,6 @@ export class PartyFactory {
|
|
|
52
52
|
@timed(5_000)
|
|
53
53
|
async createParty (): Promise<DataParty> {
|
|
54
54
|
const identity = this._identityProvider() ?? raise(new IdentityNotInitializedError());
|
|
55
|
-
assert(identity.identityGenesis, 'HALO not initialized.');
|
|
56
|
-
assert(identity.deviceKeyChain, 'Device KeyChain not initialized.');
|
|
57
55
|
assert(!this._options.readOnly, 'PartyFactory is read-only.');
|
|
58
56
|
|
|
59
57
|
const partyKey = await identity.keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
@@ -66,7 +64,7 @@ export class PartyFactory {
|
|
|
66
64
|
|
|
67
65
|
// PartyGenesis (self-signed by Party).
|
|
68
66
|
await party.processor.writeHaloMessage(createPartyGenesisMessage(
|
|
69
|
-
identity.
|
|
67
|
+
identity.keyring,
|
|
70
68
|
partyKey,
|
|
71
69
|
writableFeed.key,
|
|
72
70
|
partyKey)
|
|
@@ -74,15 +72,16 @@ export class PartyFactory {
|
|
|
74
72
|
|
|
75
73
|
// KeyAdmit (IdentityGenesis in an Envelope signed by Party).
|
|
76
74
|
await party.processor.writeHaloMessage(createEnvelopeMessage(
|
|
77
|
-
identity.
|
|
75
|
+
identity.keyring,
|
|
78
76
|
partyKey.publicKey,
|
|
79
77
|
wrapMessage(identity.identityGenesis),
|
|
80
78
|
[partyKey])
|
|
81
79
|
);
|
|
82
80
|
|
|
83
81
|
// FeedAdmit (signed by the Device KeyChain).
|
|
82
|
+
// TODO(dmaretskyi): Is this really needed since a feed is already admitted by party genesis message.
|
|
84
83
|
await party.processor.writeHaloMessage(createFeedAdmitMessage(
|
|
85
|
-
identity.
|
|
84
|
+
identity.keyring,
|
|
86
85
|
partyKey.publicKey,
|
|
87
86
|
writableFeed.key,
|
|
88
87
|
[identity.deviceKeyChain]
|
|
@@ -91,7 +90,7 @@ export class PartyFactory {
|
|
|
91
90
|
// IdentityInfo in an Envelope signed by the Device KeyChain.
|
|
92
91
|
if (identity.identityInfo) {
|
|
93
92
|
await party.processor.writeHaloMessage(createEnvelopeMessage(
|
|
94
|
-
identity.
|
|
93
|
+
identity.keyring,
|
|
95
94
|
partyKey.publicKey,
|
|
96
95
|
wrapMessage(identity.identityInfo),
|
|
97
96
|
[identity.deviceKeyChain]
|
|
@@ -138,13 +137,12 @@ export class PartyFactory {
|
|
|
138
137
|
);
|
|
139
138
|
|
|
140
139
|
await party.open();
|
|
141
|
-
assert(identity.identityKey, 'No identity key.');
|
|
142
140
|
const isHalo = identity.identityKey.publicKey.equals(partyKey);
|
|
143
141
|
const signingKey = isHalo ? identity.deviceKey : identity.deviceKeyChain;
|
|
144
142
|
assert(signingKey, 'No device key or keychain.');
|
|
145
143
|
// Write the Feed genesis message.
|
|
146
144
|
await party.processor.writeHaloMessage(createFeedAdmitMessage(
|
|
147
|
-
identity.
|
|
145
|
+
identity.keyring,
|
|
148
146
|
partyKey,
|
|
149
147
|
feedKeyPair.publicKey,
|
|
150
148
|
[signingKey]
|
|
@@ -213,7 +211,7 @@ export class PartyFactory {
|
|
|
213
211
|
async (partyKey, nonce) => [createDataPartyAdmissionMessages(
|
|
214
212
|
identity.createCredentialsSigner(),
|
|
215
213
|
partyKey,
|
|
216
|
-
identity.identityGenesis
|
|
214
|
+
identity.identityGenesis,
|
|
217
215
|
nonce
|
|
218
216
|
)]
|
|
219
217
|
);
|
|
@@ -223,13 +221,11 @@ export class PartyFactory {
|
|
|
223
221
|
const party = await this.addParty(partyKey, hints);
|
|
224
222
|
await initiator.destroy();
|
|
225
223
|
if (!haloInvitation) {
|
|
226
|
-
assert(identity.deviceKeyChain);
|
|
227
|
-
|
|
228
224
|
// Copy our signed IdentityInfo into the new Party.
|
|
229
225
|
const infoMessage = identity.identityInfo;
|
|
230
226
|
if (infoMessage) {
|
|
231
227
|
await party.processor.writeHaloMessage(createEnvelopeMessage(
|
|
232
|
-
identity.
|
|
228
|
+
identity.keyring,
|
|
233
229
|
partyKey,
|
|
234
230
|
wrapMessage(infoMessage),
|
|
235
231
|
[identity.deviceKeyChain]
|
|
@@ -244,8 +240,6 @@ export class PartyFactory {
|
|
|
244
240
|
const identity = this._identityProvider() ?? raise(new IdentityNotInitializedError());
|
|
245
241
|
|
|
246
242
|
assert(!this._options.readOnly, 'PartyFactory is read-only');
|
|
247
|
-
assert(identity.identityGenesis, 'IdentityGenesis must exist');
|
|
248
|
-
assert(identity.deviceKeyChain, 'Device KeyChain must exist');
|
|
249
243
|
|
|
250
244
|
const partyKey = await identity.keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
251
245
|
const party = await this.constructParty(partyKey.publicKey);
|
|
@@ -257,7 +251,7 @@ export class PartyFactory {
|
|
|
257
251
|
|
|
258
252
|
// PartyGenesis (self-signed by Party).
|
|
259
253
|
await party.processor.writeHaloMessage(createPartyGenesisMessage(
|
|
260
|
-
identity.
|
|
254
|
+
identity.keyring,
|
|
261
255
|
partyKey,
|
|
262
256
|
writableFeed.key,
|
|
263
257
|
partyKey)
|
|
@@ -265,7 +259,7 @@ export class PartyFactory {
|
|
|
265
259
|
|
|
266
260
|
// KeyAdmit (IdentityGenesis in an Envelope signed by Party).
|
|
267
261
|
await party.processor.writeHaloMessage(createEnvelopeMessage(
|
|
268
|
-
identity.
|
|
262
|
+
identity.keyring,
|
|
269
263
|
partyKey.publicKey,
|
|
270
264
|
wrapMessage(identity.identityGenesis),
|
|
271
265
|
[partyKey]
|
|
@@ -273,7 +267,7 @@ export class PartyFactory {
|
|
|
273
267
|
|
|
274
268
|
// FeedAdmit (signed by the Device KeyChain).
|
|
275
269
|
await party.processor.writeHaloMessage(createFeedAdmitMessage(
|
|
276
|
-
identity.
|
|
270
|
+
identity.keyring,
|
|
277
271
|
partyKey.publicKey,
|
|
278
272
|
writableFeed.key,
|
|
279
273
|
[identity.deviceKeyChain]
|
|
@@ -282,7 +276,7 @@ export class PartyFactory {
|
|
|
282
276
|
// IdentityInfo in an Envelope signed by the Device KeyChain.
|
|
283
277
|
if (identity.identityInfo) {
|
|
284
278
|
await party.processor.writeHaloMessage(createEnvelopeMessage(
|
|
285
|
-
identity.
|
|
279
|
+
identity.keyring,
|
|
286
280
|
partyKey.publicKey,
|
|
287
281
|
wrapMessage(identity.identityInfo),
|
|
288
282
|
[identity.deviceKeyChain]
|
|
@@ -33,9 +33,9 @@ import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
|
|
|
33
33
|
import { afterTest, testTimeout } from '@dxos/testutils';
|
|
34
34
|
|
|
35
35
|
import { Item } from '../api';
|
|
36
|
-
import { HaloFactory, Identity, IdentityManager } from '../halo';
|
|
37
36
|
import { defaultInvitationAuthenticator, OfflineInvitationClaimer } from '../invitations';
|
|
38
37
|
import { MetadataStore, PartyFeedProvider } from '../pipeline';
|
|
38
|
+
import { createTestIdentityCredentials } from '../protocol/identity-credentials';
|
|
39
39
|
import { SnapshotStore } from '../snapshots';
|
|
40
40
|
import { messageLogger } from '../testing';
|
|
41
41
|
import { createRamStorage } from '../util';
|
|
@@ -58,33 +58,12 @@ const setup = async () => {
|
|
|
58
58
|
const keyring = new Keyring();
|
|
59
59
|
const metadataStore = new MetadataStore(createRamStorage());
|
|
60
60
|
const feedStore = new FeedStore(createStorage('', StorageType.RAM), { valueEncoding: codec });
|
|
61
|
-
|
|
62
|
-
const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
|
|
63
|
-
|
|
64
|
-
assert(keyring.keys.length === 1);
|
|
65
|
-
|
|
66
61
|
const snapshotStore = new SnapshotStore(createStorage('', StorageType.RAM));
|
|
67
62
|
const modelFactory = new ModelFactory().registerModel(ObjectModel);
|
|
68
63
|
const networkManager = new NetworkManager();
|
|
69
64
|
const feedProviderFactory = (partyKey: PublicKey) => new PartyFeedProvider(metadataStore, keyring, feedStore, partyKey);
|
|
70
65
|
|
|
71
|
-
const
|
|
72
|
-
networkManager,
|
|
73
|
-
modelFactory,
|
|
74
|
-
snapshotStore,
|
|
75
|
-
feedProviderFactory,
|
|
76
|
-
keyring,
|
|
77
|
-
{
|
|
78
|
-
writeLogger: messageLogger('<<<'),
|
|
79
|
-
readLogger: messageLogger('>>>')
|
|
80
|
-
}
|
|
81
|
-
);
|
|
82
|
-
const haloParty = await haloFactory.createHalo({
|
|
83
|
-
identityDisplayName: identityKey.publicKey.humanize()
|
|
84
|
-
});
|
|
85
|
-
afterTest(() => haloParty.close());
|
|
86
|
-
const identity = new Identity(keyring, haloParty);
|
|
87
|
-
|
|
66
|
+
const identity = await createTestIdentityCredentials(keyring);
|
|
88
67
|
const partyFactory = new PartyFactory(
|
|
89
68
|
() => identity,
|
|
90
69
|
networkManager,
|
|
@@ -171,33 +150,22 @@ describe('Party manager', () => {
|
|
|
171
150
|
test('Create from cold start', async () => {
|
|
172
151
|
const storage = createStorage('', StorageType.RAM);
|
|
173
152
|
const feedStore = new FeedStore(storage, { valueEncoding: codec });
|
|
174
|
-
|
|
175
153
|
const keyring = new Keyring();
|
|
176
154
|
const metadataStore = new MetadataStore(createRamStorage());
|
|
177
|
-
|
|
178
|
-
const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
|
|
179
|
-
await keyring.createKeyRecord({ type: KeyType.DEVICE });
|
|
180
|
-
|
|
181
155
|
const modelFactory = new ModelFactory().registerModel(ObjectModel);
|
|
182
156
|
const snapshotStore = new SnapshotStore(createStorage('', StorageType.RAM));
|
|
183
157
|
const networkManager = new NetworkManager();
|
|
184
158
|
const feedProviderFactory = (partyKey: PublicKey) => new PartyFeedProvider(metadataStore, keyring, feedStore, partyKey);
|
|
159
|
+
|
|
160
|
+
const identity = await createTestIdentityCredentials(keyring);
|
|
185
161
|
const partyFactory = new PartyFactory(
|
|
186
|
-
() =>
|
|
162
|
+
() => identity,
|
|
187
163
|
networkManager,
|
|
188
164
|
modelFactory,
|
|
189
165
|
snapshotStore,
|
|
190
166
|
feedProviderFactory
|
|
191
167
|
);
|
|
192
|
-
const
|
|
193
|
-
networkManager,
|
|
194
|
-
modelFactory,
|
|
195
|
-
snapshotStore,
|
|
196
|
-
feedProviderFactory,
|
|
197
|
-
keyring
|
|
198
|
-
);
|
|
199
|
-
const identityManager = new IdentityManager(keyring, haloFactory, metadataStore);
|
|
200
|
-
const partyManager = new PartyManager(metadataStore, snapshotStore, () => identityManager.identity, partyFactory);
|
|
168
|
+
const partyManager = new PartyManager(metadataStore, snapshotStore, () => identity, partyFactory);
|
|
201
169
|
|
|
202
170
|
/* TODO(telackey): Injecting "raw" Parties into the feeds behind the scenes seems fishy to me, as it writes the
|
|
203
171
|
* Party messages in a slightly different way than the code inside PartyFactory does, and so could easily diverge
|
|
@@ -221,7 +189,7 @@ describe('Party manager', () => {
|
|
|
221
189
|
assert(feedKey);
|
|
222
190
|
|
|
223
191
|
const feedStream = createWritableFeedStream(feed);
|
|
224
|
-
feedStream.write({ halo: createPartyGenesisMessage(keyring, partyKey, feedKey.publicKey, identityKey) });
|
|
192
|
+
feedStream.write({ halo: createPartyGenesisMessage(keyring, partyKey, feedKey.publicKey, identity.identityKey) });
|
|
225
193
|
feedStream.write({
|
|
226
194
|
echo: checkType<EchoEnvelope>({
|
|
227
195
|
itemId: 'foo',
|
|
@@ -235,8 +203,6 @@ describe('Party manager', () => {
|
|
|
235
203
|
}
|
|
236
204
|
|
|
237
205
|
// Open.
|
|
238
|
-
await identityManager.createHalo();
|
|
239
|
-
afterTest(() => identityManager.close());
|
|
240
206
|
await partyManager.open();
|
|
241
207
|
expect(partyManager.parties).toHaveLength(numParties);
|
|
242
208
|
await partyManager.close();
|
|
@@ -450,7 +416,7 @@ describe('Party manager', () => {
|
|
|
450
416
|
// Redeem the invitation on B.
|
|
451
417
|
expect(partyManagerB.parties).toHaveLength(0);
|
|
452
418
|
const partyB = await partyManagerB.joinParty(invitationDescriptor,
|
|
453
|
-
OfflineInvitationClaimer.createSecretProvider(identityB));
|
|
419
|
+
OfflineInvitationClaimer.createSecretProvider(identityB.createCredentialsSigner()));
|
|
454
420
|
expect(partyB).toBeDefined();
|
|
455
421
|
log(`Joined ${partyB.key.toHex()}`);
|
|
456
422
|
|
|
@@ -13,9 +13,9 @@ import { timed } from '@dxos/debug';
|
|
|
13
13
|
import { PartyKey, PartySnapshot } from '@dxos/echo-protocol';
|
|
14
14
|
import { ComplexMap, boolGuard } from '@dxos/util';
|
|
15
15
|
|
|
16
|
-
import { IdentityProvider } from '../halo';
|
|
17
16
|
import { InvitationDescriptor } from '../invitations';
|
|
18
17
|
import { MetadataStore } from '../pipeline';
|
|
18
|
+
import { IdentityCredentialsProvider } from '../protocol/identity-credentials';
|
|
19
19
|
import { SnapshotStore } from '../snapshots';
|
|
20
20
|
import { DataParty, PARTY_ITEM_TYPE, PARTY_TITLE_PROPERTY } from './data-party';
|
|
21
21
|
import { PartyFactory } from './party-factory';
|
|
@@ -51,7 +51,7 @@ export class PartyManager {
|
|
|
51
51
|
constructor (
|
|
52
52
|
private readonly _metadataStore: MetadataStore,
|
|
53
53
|
private readonly _snapshotStore: SnapshotStore,
|
|
54
|
-
private readonly _identityProvider:
|
|
54
|
+
private readonly _identityProvider: IdentityCredentialsProvider,
|
|
55
55
|
private readonly _partyFactory: PartyFactory
|
|
56
56
|
) {}
|
|
57
57
|
|
|
@@ -74,10 +74,11 @@ export class PartyManager {
|
|
|
74
74
|
|
|
75
75
|
let partyKeys = this._metadataStore.parties.map(party => party.key).filter(boolGuard);
|
|
76
76
|
|
|
77
|
+
// Identity may be undefined, for example, on the first start.
|
|
77
78
|
const identity = this._identityProvider();
|
|
78
79
|
|
|
79
80
|
// TODO(telackey): Does it make any sense to load other parties if we don't have an HALO?
|
|
80
|
-
if (identity
|
|
81
|
+
if (identity) {
|
|
81
82
|
partyKeys = partyKeys.filter(partyKey => !partyKey.equals(identity.identityKey!.publicKey));
|
|
82
83
|
}
|
|
83
84
|
|
|
@@ -325,12 +325,10 @@ describe('PartyCore', () => {
|
|
|
325
325
|
|
|
326
326
|
createTestProtocolPair(
|
|
327
327
|
new ReplicatorProtocolPluginFactory(
|
|
328
|
-
peer1.partyFeedProvider
|
|
329
|
-
peer1.party.processor.getActiveFeedSet()
|
|
328
|
+
peer1.partyFeedProvider
|
|
330
329
|
).createPlugins().map(r => r.createExtension()),
|
|
331
330
|
new ReplicatorProtocolPluginFactory(
|
|
332
|
-
partyFeedProvider
|
|
333
|
-
peer1.party.processor.getActiveFeedSet()
|
|
331
|
+
partyFeedProvider
|
|
334
332
|
).createPlugins().map(r => r.createExtension())
|
|
335
333
|
);
|
|
336
334
|
|
|
@@ -20,11 +20,6 @@ import { jsonReplacer } from '@dxos/util';
|
|
|
20
20
|
|
|
21
21
|
const log = debug('dxos:echo-db:party-processor');
|
|
22
22
|
|
|
23
|
-
export interface FeedSetProvider {
|
|
24
|
-
get(): FeedKey[]
|
|
25
|
-
added: Event<FeedKey>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
23
|
/**
|
|
29
24
|
* TODO(burdon): Wrapper/Bridge between HALO APIs.
|
|
30
25
|
*/
|
|
@@ -108,14 +103,6 @@ export class PartyProcessor {
|
|
|
108
103
|
return this._state.getAdmittedBy(feedKey);
|
|
109
104
|
}
|
|
110
105
|
|
|
111
|
-
// TODO(burdon): Rename xxxProvider.
|
|
112
|
-
getActiveFeedSet (): FeedSetProvider {
|
|
113
|
-
return {
|
|
114
|
-
get: () => this.feedKeys,
|
|
115
|
-
added: this.feedAdded
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
106
|
getOfflineInvitation (invitationID: Buffer) {
|
|
120
107
|
return this._state.getInvitation(invitationID);
|
|
121
108
|
}
|
|
@@ -19,17 +19,17 @@ export class CredentialsSigner {
|
|
|
19
19
|
|
|
20
20
|
return new CredentialsSigner(
|
|
21
21
|
keyring,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
identityKey,
|
|
23
|
+
deviceKey,
|
|
24
|
+
deviceKey
|
|
25
25
|
);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
constructor (
|
|
29
29
|
private readonly _signer: Signer,
|
|
30
|
-
private readonly
|
|
31
|
-
private readonly
|
|
32
|
-
private readonly
|
|
30
|
+
private readonly _identityKey: KeyRecord,
|
|
31
|
+
private readonly _deviceKey: KeyRecord,
|
|
32
|
+
private readonly _signingKeys: KeyRecord | KeyChain
|
|
33
33
|
) {}
|
|
34
34
|
|
|
35
35
|
get signer (): Signer {
|
|
@@ -37,11 +37,11 @@ export class CredentialsSigner {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
getIdentityKey (): KeyRecord {
|
|
40
|
-
return this.
|
|
40
|
+
return this._identityKey;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
getDeviceKey (): KeyRecord {
|
|
44
|
-
return this.
|
|
44
|
+
return this._deviceKey;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -55,6 +55,6 @@ export class CredentialsSigner {
|
|
|
55
55
|
* Devices need to sign with their keyChain including the device key admission credential in the signature.
|
|
56
56
|
*/
|
|
57
57
|
getDeviceSigningKeys (): KeyRecord | KeyChain {
|
|
58
|
-
return this.
|
|
58
|
+
return this._signingKeys;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createIdentityInfoMessage, createKeyAdmitMessage, createPartyGenesisMessage, KeyChain, KeyRecord, Keyring, KeyType, SignedMessage } from '@dxos/credentials';
|
|
6
|
+
|
|
7
|
+
import { ContactManager, Preferences } from '../halo';
|
|
8
|
+
import { CredentialsSigner } from './credentials-signer';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Provides access to identity credentials without revealing the underlying mechanism (HALO party).
|
|
12
|
+
*/
|
|
13
|
+
export interface IdentityCredentials {
|
|
14
|
+
keyring: Keyring
|
|
15
|
+
identityKey: KeyRecord
|
|
16
|
+
deviceKey: KeyRecord
|
|
17
|
+
deviceKeyChain: KeyChain
|
|
18
|
+
identityGenesis: SignedMessage
|
|
19
|
+
identityInfo: SignedMessage | undefined
|
|
20
|
+
displayName: string | undefined
|
|
21
|
+
createCredentialsSigner(): CredentialsSigner
|
|
22
|
+
preferences: Preferences | undefined
|
|
23
|
+
contacts: ContactManager | undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type IdentityCredentialsProvider = () => IdentityCredentials | undefined
|
|
27
|
+
|
|
28
|
+
export async function createTestIdentityCredentials (keyring: Keyring): Promise<IdentityCredentials> {
|
|
29
|
+
const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
|
|
30
|
+
const deviceKey = await keyring.createKeyRecord({ type: KeyType.DEVICE });
|
|
31
|
+
const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
|
|
32
|
+
|
|
33
|
+
const partyGenesis = createPartyGenesisMessage(keyring, identityKey, feedKey.publicKey, deviceKey);
|
|
34
|
+
const keyAdmit = createKeyAdmitMessage(keyring, identityKey.publicKey, identityKey);
|
|
35
|
+
|
|
36
|
+
const messageMap = new Map();
|
|
37
|
+
messageMap.set(identityKey.publicKey.toHex(), keyAdmit);
|
|
38
|
+
messageMap.set(deviceKey.publicKey.toHex(), partyGenesis);
|
|
39
|
+
const deviceKeyChain = Keyring.buildKeyChain(deviceKey.publicKey, messageMap, [feedKey.publicKey]);
|
|
40
|
+
|
|
41
|
+
const displayName = identityKey.publicKey.humanize();
|
|
42
|
+
const identityInfo = createIdentityInfoMessage(keyring, displayName, identityKey);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
keyring,
|
|
46
|
+
identityKey,
|
|
47
|
+
deviceKey,
|
|
48
|
+
deviceKeyChain,
|
|
49
|
+
identityGenesis: keyAdmit.payload as SignedMessage,
|
|
50
|
+
identityInfo: identityInfo.payload as SignedMessage,
|
|
51
|
+
displayName,
|
|
52
|
+
createCredentialsSigner: () => new CredentialsSigner(keyring, identityKey, deviceKey, deviceKeyChain),
|
|
53
|
+
preferences: undefined,
|
|
54
|
+
contacts: undefined
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function deriveTestDeviceCredentials (identity: IdentityCredentials): Promise<IdentityCredentials> {
|
|
59
|
+
const deviceKey = await identity.keyring.createKeyRecord({ type: KeyType.DEVICE });
|
|
60
|
+
const keyAdmit = createKeyAdmitMessage(identity.keyring, identity.identityKey.publicKey, deviceKey, [identity.identityKey]);
|
|
61
|
+
|
|
62
|
+
const messageMap = new Map();
|
|
63
|
+
messageMap.set(identity.identityKey.publicKey.toHex(), identity.identityGenesis);
|
|
64
|
+
messageMap.set(deviceKey.publicKey.toHex(), keyAdmit);
|
|
65
|
+
const deviceKeyChain = Keyring.buildKeyChain(deviceKey.publicKey, messageMap, []);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
...identity,
|
|
69
|
+
deviceKey,
|
|
70
|
+
deviceKeyChain,
|
|
71
|
+
createCredentialsSigner: () => new CredentialsSigner(
|
|
72
|
+
identity.keyring,
|
|
73
|
+
identity.identityKey,
|
|
74
|
+
deviceKey,
|
|
75
|
+
deviceKeyChain
|
|
76
|
+
)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -6,7 +6,7 @@ import debug from 'debug';
|
|
|
6
6
|
|
|
7
7
|
import { synchronized } from '@dxos/async';
|
|
8
8
|
import { discoveryKey, keyToString, PublicKey } from '@dxos/crypto';
|
|
9
|
-
import { FeedKey,
|
|
9
|
+
import { FeedKey, PartyKey } from '@dxos/echo-protocol';
|
|
10
10
|
import type { HypercoreFeed } from '@dxos/feed-store';
|
|
11
11
|
import { Protocol } from '@dxos/mesh-protocol';
|
|
12
12
|
import { MMSTTopology, NetworkManager, Plugin } from '@dxos/network-manager';
|
|
@@ -32,12 +32,11 @@ export class PartyProtocolFactory {
|
|
|
32
32
|
private readonly _networkManager: NetworkManager,
|
|
33
33
|
private readonly _feedProvider: PartyFeedProvider,
|
|
34
34
|
private readonly _peerId: PublicKey,
|
|
35
|
-
private readonly _credentials: CredentialsProvider
|
|
36
|
-
activeFeeds: FeedSetProvider
|
|
35
|
+
private readonly _credentials: CredentialsProvider
|
|
37
36
|
) {
|
|
38
37
|
// Replication.
|
|
39
38
|
this._replicatorProtocolPluginFactory =
|
|
40
|
-
new ReplicatorProtocolPluginFactory(this._feedProvider
|
|
39
|
+
new ReplicatorProtocolPluginFactory(this._feedProvider);
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
async start (plugins: Plugin[]) {
|
|
@@ -125,34 +124,31 @@ export class PartyProtocolFactory {
|
|
|
125
124
|
*/
|
|
126
125
|
export class ReplicatorProtocolPluginFactory {
|
|
127
126
|
constructor (
|
|
128
|
-
private readonly _feedProvider: PartyFeedProvider
|
|
129
|
-
private readonly _activeFeeds: FeedSetProvider
|
|
127
|
+
private readonly _feedProvider: PartyFeedProvider
|
|
130
128
|
) {}
|
|
131
129
|
|
|
132
130
|
createPlugins () {
|
|
133
131
|
return [
|
|
134
132
|
new Replicator({
|
|
135
133
|
load: async () => {
|
|
136
|
-
const
|
|
137
|
-
log(`Loading feeds: ${
|
|
138
|
-
return
|
|
139
|
-
return { discoveryKey: feed.discoveryKey };
|
|
140
|
-
});
|
|
134
|
+
const feeds = this._feedProvider.getFeeds();
|
|
135
|
+
log(`Loading feeds: ${feeds.map(feed => keyToString(feed.key))}`);
|
|
136
|
+
return feeds.map((feed) => ({ discoveryKey: feed.feed.discoveryKey }));
|
|
141
137
|
},
|
|
142
138
|
|
|
143
139
|
subscribe: (addFeedToReplicatedSet: (feed: any) => void) => {
|
|
144
|
-
return this.
|
|
145
|
-
log(`Adding feed: ${
|
|
146
|
-
|
|
147
|
-
addFeedToReplicatedSet({ discoveryKey: feed.discoveryKey });
|
|
140
|
+
return this._feedProvider.feedOpened.on(async (feed) => {
|
|
141
|
+
log(`Adding feed: ${feed.key.toHex()}`);
|
|
142
|
+
addFeedToReplicatedSet({ discoveryKey: feed.feed.discoveryKey });
|
|
148
143
|
});
|
|
149
144
|
},
|
|
150
145
|
|
|
151
146
|
replicate: async (remoteFeeds, info) => {
|
|
152
147
|
// We can ignore remoteFeeds entirely, since the set of feeds we want to replicate is dictated by the Party.
|
|
153
148
|
// TODO(telackey): Why are we opening feeds? Necessary or belt/braces thinking, or because open party does it?
|
|
154
|
-
|
|
155
|
-
|
|
149
|
+
const feeds = this._feedProvider.getFeeds();
|
|
150
|
+
log(`Replicating: peerId=${info.session}; feeds=${feeds.map(feed => feed.key.toHex())}`);
|
|
151
|
+
return feeds.map(feed => feed.feed);
|
|
156
152
|
}
|
|
157
153
|
})
|
|
158
154
|
];
|