@dxos/client-services 0.6.13 → 0.6.14-main.1366248

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.
Files changed (145) hide show
  1. package/dist/lib/browser/{chunk-CRXXOI45.mjs → chunk-KQURG5PQ.mjs} +6537 -5279
  2. package/dist/lib/browser/chunk-KQURG5PQ.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +7 -3
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +20 -9
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/{chunk-PZ3JJJ3K.cjs → chunk-WNXJ7EP5.cjs} +6324 -5068
  9. package/dist/lib/node/chunk-WNXJ7EP5.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +50 -46
  11. package/dist/lib/node/index.cjs.map +3 -3
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +26 -14
  14. package/dist/lib/node/testing/index.cjs.map +3 -3
  15. package/dist/lib/node-esm/chunk-OQSP5ADY.mjs +8982 -0
  16. package/dist/lib/node-esm/chunk-OQSP5ADY.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +420 -0
  18. package/dist/lib/node-esm/index.mjs.map +7 -0
  19. package/dist/lib/node-esm/meta.json +1 -0
  20. package/dist/lib/node-esm/testing/index.mjs +431 -0
  21. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  22. package/dist/types/src/index.d.ts +1 -0
  23. package/dist/types/src/index.d.ts.map +1 -1
  24. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +35 -0
  25. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -0
  26. package/dist/types/src/packlets/agents/edge-agent-service.d.ts +10 -0
  27. package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -0
  28. package/dist/types/src/packlets/agents/index.d.ts +3 -0
  29. package/dist/types/src/packlets/agents/index.d.ts.map +1 -0
  30. package/dist/types/src/packlets/devices/devices-service.d.ts +3 -1
  31. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  32. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
  33. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  34. package/dist/types/src/packlets/identity/authenticator.node.test.d.ts +2 -0
  35. package/dist/types/src/packlets/identity/authenticator.node.test.d.ts.map +1 -0
  36. package/dist/types/src/packlets/identity/contacts-service.d.ts +1 -1
  37. package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
  38. package/dist/types/src/packlets/identity/identity-manager.d.ts +28 -9
  39. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  40. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +18 -0
  41. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -0
  42. package/dist/types/src/packlets/identity/identity-service.d.ts +7 -2
  43. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  44. package/dist/types/src/packlets/identity/identity.d.ts +12 -3
  45. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  46. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  47. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts +31 -0
  48. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -0
  49. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts +2 -1
  50. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
  51. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts +2 -1
  52. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
  53. package/dist/types/src/packlets/invitations/invitation-state.d.ts +19 -0
  54. package/dist/types/src/packlets/invitations/invitation-state.d.ts.map +1 -0
  55. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +8 -8
  56. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  57. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  58. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  59. package/dist/types/src/packlets/services/service-context.d.ts +14 -9
  60. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  61. package/dist/types/src/packlets/services/service-host.d.ts +2 -0
  62. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  63. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +7 -3
  64. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  65. package/dist/types/src/packlets/spaces/data-space.d.ts +5 -3
  66. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  67. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +4 -0
  68. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  69. package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts +2 -0
  70. package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts.map +1 -0
  71. package/dist/types/src/packlets/spaces/epoch-migrations.d.ts +1 -1
  72. package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -1
  73. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +35 -6
  74. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  75. package/dist/types/src/packlets/spaces/spaces-service.d.ts +1 -1
  76. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  77. package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
  78. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  79. package/dist/types/src/packlets/testing/test-builder.d.ts +1 -2
  80. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  81. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  82. package/dist/types/src/testing/setup.d.ts +3 -0
  83. package/dist/types/src/testing/setup.d.ts.map +1 -0
  84. package/dist/types/src/version.d.ts +1 -1
  85. package/dist/types/src/version.d.ts.map +1 -1
  86. package/package.json +44 -45
  87. package/src/index.ts +1 -0
  88. package/src/packlets/agents/edge-agent-manager.ts +163 -0
  89. package/src/packlets/agents/edge-agent-service.ts +42 -0
  90. package/src/packlets/agents/index.ts +6 -0
  91. package/src/packlets/devices/devices-service.test.ts +4 -5
  92. package/src/packlets/devices/devices-service.ts +18 -7
  93. package/src/packlets/diagnostics/diagnostics-broadcast.ts +1 -0
  94. package/src/packlets/identity/{authenticator.test.ts → authenticator.node.test.ts} +2 -3
  95. package/src/packlets/identity/authenticator.ts +5 -2
  96. package/src/packlets/identity/contacts-service.ts +1 -1
  97. package/src/packlets/identity/identity-manager.test.ts +31 -16
  98. package/src/packlets/identity/identity-manager.ts +76 -32
  99. package/src/packlets/identity/identity-recovery-manager.ts +95 -0
  100. package/src/packlets/identity/identity-service.test.ts +5 -8
  101. package/src/packlets/identity/identity-service.ts +11 -5
  102. package/src/packlets/identity/identity.test.ts +141 -239
  103. package/src/packlets/identity/identity.ts +60 -17
  104. package/src/packlets/invitations/device-invitation-protocol.test.ts +7 -4
  105. package/src/packlets/invitations/device-invitation-protocol.ts +8 -2
  106. package/src/packlets/invitations/edge-invitation-handler.ts +188 -0
  107. package/src/packlets/invitations/invitation-guest-extenstion.ts +13 -9
  108. package/src/packlets/invitations/invitation-host-extension.ts +15 -17
  109. package/src/packlets/invitations/invitation-state.ts +112 -0
  110. package/src/packlets/invitations/invitations-handler.test.ts +19 -15
  111. package/src/packlets/invitations/invitations-handler.ts +91 -126
  112. package/src/packlets/invitations/invitations-service.ts +5 -1
  113. package/src/packlets/invitations/space-invitation-protocol.test.ts +4 -3
  114. package/src/packlets/invitations/space-invitation-protocol.ts +5 -0
  115. package/src/packlets/logging/logging.test.ts +1 -2
  116. package/src/packlets/network/network-service.test.ts +2 -3
  117. package/src/packlets/services/service-context.test.ts +3 -1
  118. package/src/packlets/services/service-context.ts +113 -35
  119. package/src/packlets/services/service-host.test.ts +8 -12
  120. package/src/packlets/services/service-host.ts +26 -8
  121. package/src/packlets/services/service-registry.test.ts +1 -2
  122. package/src/packlets/spaces/data-space-manager.test.ts +2 -2
  123. package/src/packlets/spaces/data-space-manager.ts +44 -7
  124. package/src/packlets/spaces/data-space.ts +37 -6
  125. package/src/packlets/spaces/edge-feed-replicator.test.ts +257 -0
  126. package/src/packlets/spaces/edge-feed-replicator.ts +84 -22
  127. package/src/packlets/spaces/epoch-migrations.ts +2 -2
  128. package/src/packlets/spaces/notarization-plugin.test.ts +10 -7
  129. package/src/packlets/spaces/notarization-plugin.ts +196 -29
  130. package/src/packlets/spaces/spaces-service.test.ts +5 -9
  131. package/src/packlets/spaces/spaces-service.ts +6 -1
  132. package/src/packlets/storage/storage.ts +0 -1
  133. package/src/packlets/system/system-service.test.ts +1 -2
  134. package/src/packlets/testing/invitation-utils.ts +7 -0
  135. package/src/packlets/testing/test-builder.ts +7 -4
  136. package/src/packlets/worker/worker-runtime.ts +2 -2
  137. package/src/testing/setup.ts +11 -0
  138. package/src/version.ts +1 -5
  139. package/dist/lib/browser/chunk-CRXXOI45.mjs.map +0 -7
  140. package/dist/lib/node/chunk-PZ3JJJ3K.cjs.map +0 -7
  141. package/dist/types/src/packlets/identity/authenticator.test.d.ts +0 -2
  142. package/dist/types/src/packlets/identity/authenticator.test.d.ts.map +0 -1
  143. package/dist/types/src/packlets/services/automerge-host.test.d.ts +0 -2
  144. package/dist/types/src/packlets/services/automerge-host.test.d.ts.map +0 -1
  145. package/src/packlets/services/automerge-host.test.ts +0 -60
@@ -2,21 +2,17 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import chai, { expect } from 'chai';
6
- import chaiAsPromised from 'chai-as-promised';
5
+ import { afterEach, onTestFinished, beforeEach, describe, expect, test } from 'vitest';
7
6
 
8
7
  import { Trigger } from '@dxos/async';
9
8
  import { Context } from '@dxos/context';
10
9
  import { PublicKey } from '@dxos/keys';
11
10
  import { type Identity, type IdentityService } from '@dxos/protocols/proto/dxos/client/services';
12
- import { afterEach, afterTest, beforeEach, describe, test } from '@dxos/test';
13
11
 
14
12
  import { IdentityServiceImpl } from './identity-service';
15
13
  import { type ServiceContext } from '../services';
16
14
  import { createServiceContext } from '../testing';
17
15
 
18
- chai.use(chaiAsPromised);
19
-
20
16
  describe('IdentityService', () => {
21
17
  let serviceContext: ServiceContext;
22
18
  let identityService: IdentityService;
@@ -49,7 +45,7 @@ describe('IdentityService', () => {
49
45
 
50
46
  test('fails to create identity if one already exists', async () => {
51
47
  await identityService.createIdentity({});
52
- await expect(identityService.createIdentity({})).to.be.rejectedWith('Identity already exists');
48
+ await expect(identityService.createIdentity({})).rejects.toThrowError('Identity already exists');
53
49
  });
54
50
  });
55
51
 
@@ -72,7 +68,7 @@ describe('IdentityService', () => {
72
68
  query.subscribe(({ identity }) => {
73
69
  result.wake(identity);
74
70
  });
75
- afterTest(() => query.close());
71
+ onTestFinished(() => query.close());
76
72
  expect(await result.wait()).to.be.undefined;
77
73
  });
78
74
 
@@ -82,7 +78,7 @@ describe('IdentityService', () => {
82
78
  query.subscribe(({ identity }) => {
83
79
  result.wake(identity);
84
80
  });
85
- afterTest(() => query.close());
81
+ onTestFinished(() => query.close());
86
82
  expect(await result.wait()).to.be.undefined;
87
83
 
88
84
  result = new Trigger<Identity | undefined>();
@@ -120,6 +116,7 @@ describe('open', () => {
120
116
  const createIdentityService = (serviceContext: ServiceContext) => {
121
117
  return new IdentityServiceImpl(
122
118
  serviceContext.identityManager,
119
+ serviceContext.recoveryManager,
123
120
  serviceContext.keyring,
124
121
  () => serviceContext.dataSpaceManager!,
125
122
  (options) => serviceContext.createIdentity(options),
@@ -6,7 +6,6 @@ import { Trigger, sleep } from '@dxos/async';
6
6
  import { Stream } from '@dxos/codec-protobuf';
7
7
  import { Resource } from '@dxos/context';
8
8
  import { signPresentation } from '@dxos/credentials';
9
- import { todo } from '@dxos/debug';
10
9
  import { invariant } from '@dxos/invariant';
11
10
  import { type Keyring } from '@dxos/keyring';
12
11
  import { log } from '@dxos/log';
@@ -24,6 +23,7 @@ import { safeAwaitAll } from '@dxos/util';
24
23
 
25
24
  import { type Identity } from './identity';
26
25
  import { type CreateIdentityOptions, type IdentityManager } from './identity-manager';
26
+ import { type EdgeIdentityRecoveryManager } from './identity-recovery-manager';
27
27
  import { type DataSpaceManager } from '../spaces';
28
28
 
29
29
  const DEFAULT_SPACE_SEARCH_TIMEOUT = 10_000;
@@ -31,6 +31,7 @@ const DEFAULT_SPACE_SEARCH_TIMEOUT = 10_000;
31
31
  export class IdentityServiceImpl extends Resource implements IdentityService {
32
32
  constructor(
33
33
  private readonly _identityManager: IdentityManager,
34
+ private readonly _recoveryManager: EdgeIdentityRecoveryManager,
34
35
  private readonly _keyring: Keyring,
35
36
  private readonly _dataSpaceManagerProvider: () => DataSpaceManager,
36
37
  private readonly _createIdentity: (params: CreateIdentityOptions) => Promise<Identity>,
@@ -60,10 +61,6 @@ export class IdentityServiceImpl extends Resource implements IdentityService {
60
61
  await identity.updateDefaultSpace(space.id);
61
62
  }
62
63
 
63
- async recoverIdentity(request: RecoverIdentityRequest): Promise<IdentityProto> {
64
- return todo();
65
- }
66
-
67
64
  queryIdentity(): Stream<QueryIdentityResponse> {
68
65
  return new Stream(({ next }) => {
69
66
  const emitNext = () => next({ identity: this._getIdentity() });
@@ -92,6 +89,15 @@ export class IdentityServiceImpl extends Resource implements IdentityService {
92
89
  return this._getIdentity()!;
93
90
  }
94
91
 
92
+ async createRecoveryPhrase() {
93
+ return this._recoveryManager.createRecoveryPhrase();
94
+ }
95
+
96
+ async recoverIdentity(request: RecoverIdentityRequest): Promise<IdentityProto> {
97
+ await this._recoveryManager.recoverIdentity(request);
98
+ return this._getIdentity()!;
99
+ }
100
+
95
101
  // TODO(burdon): Rename createPresentation?
96
102
  async signPresentation({ presentation, nonce }: SignPresentationRequest): Promise<Presentation> {
97
103
  invariant(this._identityManager.identity, 'Identity not initialized.');
@@ -2,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import expect from 'expect';
5
+ import { onTestFinished, describe, expect, test } from 'vitest';
6
6
 
7
7
  import { Context } from '@dxos/context';
8
8
  import { CredentialGenerator, verifyCredential } from '@dxos/credentials';
@@ -15,7 +15,9 @@ import {
15
15
  SpaceProtocol,
16
16
  valueEncoding,
17
17
  } from '@dxos/echo-pipeline';
18
+ import { type EdgeConnection, type MessageListener } from '@dxos/edge-client';
18
19
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
20
+ import { type FeedWrapper } from '@dxos/feed-store';
19
21
  import { Keyring } from '@dxos/keyring';
20
22
  import { type PublicKey } from '@dxos/keys';
21
23
  import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
@@ -24,7 +26,6 @@ import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
24
26
  import { AdmittedFeed } from '@dxos/protocols/proto/dxos/halo/credentials';
25
27
  import { createStorage, StorageType } from '@dxos/random-access-storage';
26
28
  import { BlobStore } from '@dxos/teleport-extension-object-sync';
27
- import { afterTest, describe, test } from '@dxos/test';
28
29
 
29
30
  import { Identity } from './identity';
30
31
 
@@ -42,16 +43,120 @@ const createStores = () => {
42
43
 
43
44
  describe('identity/identity', () => {
44
45
  test('create', async () => {
46
+ const setup = await setupIdentity();
47
+
48
+ await writeGenesisCredential(setup);
49
+
50
+ // Wait for identity to be ready.
51
+ await setup.identity.ready();
52
+ const identitySigner = setup.identity.getIdentityCredentialSigner();
53
+ const credential = await identitySigner.createCredential({
54
+ subject: setup.identityKey,
55
+ assertion: {
56
+ '@type': 'dxos.halo.credentials.IdentityProfile',
57
+ profile: {
58
+ displayName: 'Alice',
59
+ },
60
+ },
61
+ });
62
+
63
+ expect(credential.issuer).toEqual(setup.identityKey);
64
+ expect(await verifyCredential(credential)).toEqual({ kind: 'pass' });
65
+ });
66
+
67
+ test('two devices', async () => {
68
+ const signalContext = new MemorySignalManagerContext();
69
+
70
+ const owner = await setupIdentity({ signalContext });
71
+ await writeGenesisCredential(owner);
72
+ await owner.identity.ready();
73
+
74
+ const secondDevice = (
75
+ await setupIdentity({
76
+ signalContext,
77
+ spaceKey: owner.spaceKey,
78
+ identityKey: owner.identityKey,
79
+ genesisFeedKey: owner.controlFeed.key,
80
+ })
81
+ ).identity;
82
+
83
+ //
84
+ // Second device admission
85
+ //
86
+ {
87
+ const signer = owner.identity.getIdentityCredentialSigner();
88
+ void owner.identity.controlPipeline.writer.write({
89
+ credential: {
90
+ credential: await signer.createCredential({
91
+ subject: secondDevice.deviceKey,
92
+ assertion: {
93
+ '@type': 'dxos.halo.credentials.AuthorizedDevice',
94
+ identityKey: owner.identityKey,
95
+ deviceKey: secondDevice.deviceKey,
96
+ },
97
+ }),
98
+ },
99
+ });
100
+
101
+ await secondDevice.ready();
102
+ }
103
+
104
+ expect(Array.from(owner.identity.authorizedDeviceKeys.keys())).toEqual([owner.deviceKey, secondDevice.deviceKey]);
105
+ expect(Array.from(secondDevice.authorizedDeviceKeys.keys())).toEqual([owner.deviceKey, secondDevice.deviceKey]);
106
+ });
107
+
108
+ test('edge feed replicator', async () => {
109
+ let replicationStarted = false;
110
+ let isConnected = false;
111
+ const listeners: Array<() => void> = [];
112
+ const setup = await setupIdentity({
113
+ edgeConnection: {
114
+ onReconnected: (listener) => {
115
+ if (isConnected) {
116
+ listener();
117
+ } else {
118
+ listeners.push(listener);
119
+ }
120
+ return () => {};
121
+ },
122
+ get isConnected() {
123
+ return isConnected;
124
+ },
125
+ open: async () => {},
126
+ close: async () => {},
127
+ onMessage: (_: MessageListener): (() => void) => {
128
+ return () => {};
129
+ },
130
+ send: async (_) => {
131
+ replicationStarted = true;
132
+ },
133
+ } as EdgeConnection,
134
+ });
135
+
136
+ await writeGenesisCredential(setup);
137
+ listeners.forEach((callback) => callback());
138
+ isConnected = true;
139
+
140
+ await expect.poll(() => replicationStarted).toBeTruthy();
141
+ });
142
+
143
+ const setupIdentity = async (args?: {
144
+ signalContext?: MemorySignalManagerContext;
145
+ spaceKey?: PublicKey;
146
+ identityKey?: PublicKey;
147
+ genesisFeedKey?: PublicKey;
148
+ edgeConnection?: EdgeConnection;
149
+ }): Promise<TestIdentitySetup> => {
45
150
  const { storage, metadataStore, blobStore } = createStores();
46
151
 
47
152
  const keyring = new Keyring();
48
- const identityKey = await keyring.createKey();
49
153
  const deviceKey = await keyring.createKey();
50
- const spaceKey = await keyring.createKey();
154
+ const identityKey = args?.identityKey ?? (await keyring.createKey());
155
+ const spaceKey = args?.spaceKey ?? (await keyring.createKey());
51
156
 
52
157
  const feedStore = new FeedStore<FeedMessage>({
53
158
  factory: new FeedFactory<FeedMessage>({
54
- root: storage.createDirectory('feeds'),
159
+ root: storage.createDirectory(),
55
160
  signer: keyring,
56
161
  hypercore: {
57
162
  valueEncoding,
@@ -77,8 +182,9 @@ describe('identity/identity', () => {
77
182
  },
78
183
  blobStore,
79
184
  networkManager: new SwarmNetworkManager({
80
- signalManager: new MemorySignalManager(new MemorySignalManagerContext()),
185
+ signalManager: new MemorySignalManager(args?.signalContext ?? new MemorySignalManagerContext()),
81
186
  transportFactory: MemoryTransportFactory,
187
+ peerInfo: { identityKey: identityKey.toHex(), peerKey: deviceKey.toHex() },
82
188
  }),
83
189
  });
84
190
 
@@ -87,7 +193,7 @@ describe('identity/identity', () => {
87
193
  id: await createIdFromSpaceKey(spaceKey),
88
194
  spaceKey,
89
195
  protocol,
90
- genesisFeed: controlFeed,
196
+ genesisFeed: args?.genesisFeedKey ? await feedStore.openFeed(args.genesisFeedKey) : controlFeed,
91
197
  feedProvider: (feedKey) => feedStore.openFeed(feedKey),
92
198
  memberKey: identityKey,
93
199
  metadataStore,
@@ -103,242 +209,38 @@ describe('identity/identity', () => {
103
209
  identityKey,
104
210
  deviceKey,
105
211
  space,
212
+ edgeFeatures: args?.edgeConnection && { feedReplicator: true },
213
+ edgeConnection: args?.edgeConnection,
106
214
  });
107
215
 
108
216
  await identity.open(new Context());
109
- afterTest(() => identity.close(new Context()));
110
-
111
- //
112
- // Identity genesis
113
- //
114
- {
115
- const generator = new CredentialGenerator(keyring, identityKey, deviceKey);
116
- const credentials = [
117
- ...(await generator.createSpaceGenesis(spaceKey, controlFeed.key)),
118
- await generator.createDeviceAuthorization(deviceKey),
119
- await generator.createFeedAdmission(spaceKey, dataFeed.key, AdmittedFeed.Designation.DATA),
120
- ];
121
-
122
- for (const credential of credentials) {
123
- await identity.controlPipeline.writer.write({
124
- credential: { credential },
125
- });
126
- }
127
- }
128
-
129
- // Wait for identity to be ready.
130
- await identity.ready();
131
- const identitySigner = identity.getIdentityCredentialSigner();
132
- const credential = await identitySigner.createCredential({
133
- subject: identityKey,
134
- assertion: {
135
- '@type': 'dxos.halo.credentials.IdentityProfile',
136
- profile: {
137
- displayName: 'Alice',
138
- },
139
- },
140
- });
141
-
142
- expect(credential.issuer).toEqual(identityKey);
143
- expect(await verifyCredential(credential)).toEqual({ kind: 'pass' });
144
- });
145
-
146
- test('two devices', async () => {
147
- const signalContext = new MemorySignalManagerContext();
148
-
149
- let spaceKey: PublicKey;
150
- let identityKey: PublicKey;
151
- let genesisFeedKey: PublicKey;
152
- let identity1: Identity;
153
- let identity2: Identity;
154
-
155
- //
156
- // First device
157
- //
158
- {
159
- const { storage, metadataStore, blobStore } = createStores();
160
-
161
- const keyring = new Keyring();
162
- identityKey = await keyring.createKey();
163
- const deviceKey = await keyring.createKey();
164
- spaceKey = await keyring.createKey();
165
-
166
- const feedStore = new FeedStore<FeedMessage>({
167
- factory: new FeedFactory<FeedMessage>({
168
- root: storage.createDirectory(),
169
- signer: keyring,
170
- hypercore: {
171
- valueEncoding,
172
- },
173
- }),
174
- });
175
-
176
- const createFeed = async () => {
177
- const feedKey = await keyring.createKey();
178
- return feedStore.openFeed(feedKey, { writable: true });
179
- };
180
-
181
- const controlFeed = await createFeed();
182
- genesisFeedKey = controlFeed.key;
183
-
184
- const dataFeed = await createFeed();
185
-
186
- const protocol = new SpaceProtocol({
187
- topic: spaceKey,
188
- swarmIdentity: {
189
- peerKey: deviceKey,
190
- identityKey,
191
- credentialProvider: MOCK_AUTH_PROVIDER, // createHaloAuthProvider(createCredentialSignerWithKey(keyring, device_key)),
192
- credentialAuthenticator: MOCK_AUTH_VERIFIER, // createHaloAuthVerifier(() => identity.authorizedDeviceKeys),
193
- },
194
- blobStore,
195
- networkManager: new SwarmNetworkManager({
196
- signalManager: new MemorySignalManager(signalContext),
197
- transportFactory: MemoryTransportFactory,
198
- }),
199
- });
200
-
201
- await metadataStore.setIdentityRecord({ haloSpace: { key: spaceKey }, identityKey, deviceKey });
202
- const space = new Space({
203
- id: await createIdFromSpaceKey(spaceKey),
204
- spaceKey,
205
- protocol,
206
- genesisFeed: controlFeed,
207
- feedProvider: (feedKey) => feedStore.openFeed(feedKey),
208
- memberKey: identityKey,
209
- metadataStore,
210
- onDelegatedInvitationStatusChange: async () => {},
211
- onMemberRolesChanged: async () => {},
212
- });
213
- await space.setControlFeed(controlFeed);
214
- await space.setDataFeed(dataFeed);
215
-
216
- const identity = (identity1 = new Identity({
217
- signer: keyring,
218
- identityKey,
219
- deviceKey,
220
- space,
221
- }));
222
-
223
- await identity.open(new Context());
224
- afterTest(() => identity.close(new Context()));
225
-
226
- //
227
- // Identity genesis
228
- //
229
- {
230
- const generator = new CredentialGenerator(keyring, identityKey, deviceKey);
231
- const credentials = [
232
- ...(await generator.createSpaceGenesis(spaceKey, controlFeed.key)),
233
- await generator.createDeviceAuthorization(deviceKey),
234
- await generator.createFeedAdmission(spaceKey, dataFeed.key, AdmittedFeed.Designation.DATA),
235
- ];
236
-
237
- for (const credential of credentials) {
238
- await identity.controlPipeline.writer.write({
239
- credential: { credential },
240
- });
241
- }
242
- }
243
-
244
- // Wait for identity to be ready.
245
- await identity.ready();
246
- }
247
-
248
- //
249
- // Second device
250
- //
251
- {
252
- const { storage, metadataStore, blobStore } = createStores();
253
-
254
- const keyring = new Keyring();
255
- const deviceKey = await keyring.createKey();
256
-
257
- const feedStore = new FeedStore<FeedMessage>({
258
- factory: new FeedFactory<FeedMessage>({
259
- root: storage.createDirectory(),
260
- signer: keyring,
261
- hypercore: {
262
- valueEncoding,
263
- },
264
- }),
265
- });
266
-
267
- const createFeed = async () => {
268
- const feedKey = await keyring.createKey();
269
- return feedStore.openFeed(feedKey, { writable: true });
270
- };
271
-
272
- const controlFeed = await createFeed();
273
- const dataFeed = await createFeed();
274
-
275
- const protocol = new SpaceProtocol({
276
- topic: spaceKey,
277
- swarmIdentity: {
278
- peerKey: deviceKey,
279
- identityKey,
280
- credentialProvider: MOCK_AUTH_PROVIDER, // createHaloAuthProvider(createCredentialSignerWithKey(keyring, device_key)),
281
- credentialAuthenticator: MOCK_AUTH_VERIFIER, // createHaloAuthVerifier(() => identity.authorizedDeviceKeys),
282
- },
283
- blobStore,
284
- networkManager: new SwarmNetworkManager({
285
- signalManager: new MemorySignalManager(signalContext),
286
- transportFactory: MemoryTransportFactory,
287
- }),
288
- });
289
-
290
- await metadataStore.setIdentityRecord({
291
- haloSpace: { key: spaceKey },
292
- identityKey: identity1.identityKey,
293
- deviceKey,
294
- });
295
- const space = new Space({
296
- id: await createIdFromSpaceKey(spaceKey),
297
- spaceKey,
298
- protocol,
299
- genesisFeed: await feedStore.openFeed(genesisFeedKey),
300
- feedProvider: (feedKey) => feedStore.openFeed(feedKey),
301
- memberKey: identityKey,
302
- metadataStore,
303
- onDelegatedInvitationStatusChange: async () => {},
304
- onMemberRolesChanged: async () => {},
305
- });
306
- await space.setControlFeed(controlFeed);
307
- await space.setDataFeed(dataFeed);
308
-
309
- const identity = (identity2 = new Identity({
310
- signer: keyring,
311
- identityKey: identity1.identityKey,
312
- deviceKey,
313
- space,
314
- }));
315
-
316
- await identity.open(new Context());
317
- afterTest(() => identity.close(new Context()));
318
- }
217
+ await identity.joinNetwork();
218
+ onTestFinished(() => identity.close(new Context()));
219
+ return { identity, identityKey, keyring, deviceKey, controlFeed, spaceKey, dataFeed };
220
+ };
319
221
 
320
- //
321
- // Second device admission
322
- //
323
- {
324
- const signer = identity1.getIdentityCredentialSigner();
325
- void identity1.controlPipeline.writer.write({
326
- credential: {
327
- credential: await signer.createCredential({
328
- subject: identity2.deviceKey,
329
- assertion: {
330
- '@type': 'dxos.halo.credentials.AuthorizedDevice',
331
- identityKey: identity1.identityKey,
332
- deviceKey: identity2.deviceKey,
333
- },
334
- }),
335
- },
222
+ const writeGenesisCredential = async (setup: TestIdentitySetup) => {
223
+ const generator = new CredentialGenerator(setup.keyring, setup.identityKey, setup.deviceKey);
224
+ const credentials = [
225
+ ...(await generator.createSpaceGenesis(setup.spaceKey, setup.controlFeed.key)),
226
+ await generator.createDeviceAuthorization(setup.deviceKey),
227
+ await generator.createFeedAdmission(setup.spaceKey, setup.dataFeed.key, AdmittedFeed.Designation.DATA),
228
+ ];
229
+
230
+ for (const credential of credentials) {
231
+ await setup.identity.controlPipeline.writer.write({
232
+ credential: { credential },
336
233
  });
337
-
338
- await identity2.ready();
339
234
  }
340
-
341
- expect(Array.from(identity1.authorizedDeviceKeys.keys())).toEqual([identity1.deviceKey, identity2.deviceKey]);
342
- expect(Array.from(identity2.authorizedDeviceKeys.keys())).toEqual([identity1.deviceKey, identity2.deviceKey]);
343
- });
235
+ };
344
236
  });
237
+
238
+ type TestIdentitySetup = {
239
+ identity: Identity;
240
+ keyring: Keyring;
241
+ identityKey: PublicKey;
242
+ deviceKey: PublicKey;
243
+ spaceKey: PublicKey;
244
+ controlFeed: FeedWrapper<FeedMessage>;
245
+ dataFeed: FeedWrapper<FeedMessage>;
246
+ };