@dxos/client-services 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0
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/lib/browser/{chunk-HJH6BNTN.mjs → chunk-3LSLNVKQ.mjs} +2102 -1870
- package/dist/lib/browser/chunk-3LSLNVKQ.mjs.map +7 -0
- package/dist/lib/browser/chunk-NQSC7HOE.mjs +22 -0
- package/dist/lib/browser/chunk-NQSC7HOE.mjs.map +7 -0
- package/dist/lib/browser/chunk-QCWEHHJW.mjs +24 -0
- package/dist/lib/browser/chunk-QCWEHHJW.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +451 -67
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/browser/packlets/locks/browser.mjs +126 -0
- package/dist/lib/browser/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/browser/packlets/locks/node.mjs +66 -0
- package/dist/lib/browser/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +36 -17
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs +24 -0
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-ONQM6RQH.mjs → chunk-5S7PIHLS.mjs} +1942 -1579
- package/dist/lib/node-esm/chunk-5S7PIHLS.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs +22 -0
- package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +451 -67
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/locks/browser.mjs +126 -0
- package/dist/lib/node-esm/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs +66 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +36 -17
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +3 -2
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts +2 -2
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/index.d.ts +1 -1
- package/dist/types/src/packlets/diagnostics/index.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts +2 -2
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +6 -6
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +7 -6
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +1 -6
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +8 -11
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +4 -4
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +2 -3
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -4
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts +3 -3
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +2 -2
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/locks/index.d.ts +1 -1
- package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts +4 -0
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +2 -2
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
- package/dist/types/src/packlets/services/feed-syncer.d.ts +59 -0
- package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts +2 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/platform.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +13 -8
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +20 -6
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -1
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +6 -0
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive.test.d.ts +2 -0
- package/dist/types/src/packlets/space-export/space-archive.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +27 -15
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +24 -8
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +2 -2
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts +2 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +6 -6
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -2
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +6 -3
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +6 -5
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts +31 -4
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-session.d.ts +2 -2
- package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +70 -48
- package/src/index.ts +1 -0
- package/src/packlets/agents/edge-agent-manager.ts +8 -5
- package/src/packlets/agents/edge-agent-service.ts +2 -1
- package/src/packlets/devices/devices-service.test.ts +0 -1
- package/src/packlets/devtools/devtools.ts +2 -3
- package/src/packlets/diagnostics/index.ts +1 -1
- package/src/packlets/identity/authenticator.ts +2 -2
- package/src/packlets/identity/contacts-service.ts +0 -1
- package/src/packlets/identity/identity-manager.test.ts +5 -5
- package/src/packlets/identity/identity-manager.ts +21 -18
- package/src/packlets/identity/identity-recovery-manager.ts +22 -18
- package/src/packlets/identity/identity-service.test.ts +6 -27
- package/src/packlets/identity/identity-service.ts +5 -76
- package/src/packlets/identity/identity.test.ts +2 -2
- package/src/packlets/identity/identity.ts +9 -32
- package/src/packlets/invitations/device-invitation-protocol.ts +5 -6
- package/src/packlets/invitations/edge-invitation-handler.ts +4 -3
- package/src/packlets/invitations/invitation-guest-extenstion.ts +6 -4
- package/src/packlets/invitations/invitation-host-extension.ts +6 -4
- package/src/packlets/invitations/invitation-protocol.ts +2 -3
- package/src/packlets/invitations/invitations-handler.test.ts +4 -5
- package/src/packlets/invitations/invitations-handler.ts +10 -10
- package/src/packlets/invitations/invitations-manager.ts +37 -14
- package/src/packlets/invitations/invitations-service.ts +4 -4
- package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
- package/src/packlets/invitations/space-invitation-protocol.ts +10 -15
- package/src/packlets/locks/index.ts +1 -1
- package/src/packlets/logging/logging-service.ts +4 -0
- package/src/packlets/network/network-service.test.ts +0 -1
- package/src/packlets/network/network-service.ts +5 -4
- package/src/packlets/services/client-rpc-server.ts +4 -4
- package/src/packlets/services/feed-syncer.test.ts +340 -0
- package/src/packlets/services/feed-syncer.ts +337 -0
- package/src/packlets/services/platform.ts +7 -1
- package/src/packlets/services/service-context.test.ts +3 -2
- package/src/packlets/services/service-context.ts +129 -44
- package/src/packlets/services/service-host.test.ts +8 -8
- package/src/packlets/services/service-host.ts +63 -22
- package/src/packlets/services/service-registry.test.ts +0 -1
- package/src/packlets/space-export/space-archive-reader.ts +64 -3
- package/src/packlets/space-export/space-archive-writer.ts +39 -2
- package/src/packlets/space-export/space-archive.test.ts +287 -0
- package/src/packlets/spaces/data-space-manager.test.ts +79 -13
- package/src/packlets/spaces/data-space-manager.ts +97 -107
- package/src/packlets/spaces/data-space.ts +52 -29
- package/src/packlets/spaces/edge-feed-replicator.test.ts +1 -1
- package/src/packlets/spaces/edge-feed-replicator.ts +10 -9
- package/src/packlets/spaces/epoch-migrations.ts +5 -5
- package/src/packlets/spaces/genesis.ts +6 -1
- package/src/packlets/spaces/notarization-plugin.test.ts +2 -2
- package/src/packlets/spaces/notarization-plugin.ts +10 -9
- package/src/packlets/spaces/spaces-service.test.ts +9 -7
- package/src/packlets/spaces/spaces-service.ts +40 -16
- package/src/packlets/storage/storage.ts +4 -4
- package/src/packlets/testing/invitation-utils.ts +10 -6
- package/src/packlets/testing/test-builder.ts +36 -10
- package/src/packlets/worker/worker-runtime.ts +150 -13
- package/src/packlets/worker/worker-session.ts +8 -8
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-HJH6BNTN.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ONQM6RQH.mjs.map +0 -7
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +0 -19
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +0 -1
- package/src/packlets/identity/default-space-state-machine.ts +0 -44
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Trigger, sleep } from '@dxos/async';
|
|
6
5
|
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
7
|
-
import { Resource } from '@dxos/context';
|
|
6
|
+
import { Context, Resource } from '@dxos/context';
|
|
8
7
|
import { createCredential, signPresentation } from '@dxos/credentials';
|
|
9
8
|
import { invariant } from '@dxos/invariant';
|
|
10
9
|
import { type Keyring } from '@dxos/keyring';
|
|
11
|
-
import { log } from '@dxos/log';
|
|
12
10
|
import {
|
|
13
11
|
type CreateIdentityRequest,
|
|
14
12
|
type CreateRecoveryCredentialRequest,
|
|
@@ -17,52 +15,29 @@ import {
|
|
|
17
15
|
type QueryIdentityResponse,
|
|
18
16
|
type RecoverIdentityRequest,
|
|
19
17
|
type SignPresentationRequest,
|
|
20
|
-
SpaceState,
|
|
21
18
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
22
19
|
import { type Presentation, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
23
|
-
import { safeAwaitAll } from '@dxos/util';
|
|
24
|
-
|
|
25
|
-
import { type DataSpaceManager } from '../spaces';
|
|
26
20
|
|
|
27
21
|
import { type Identity } from './identity';
|
|
28
22
|
import { type CreateIdentityOptions, type IdentityManager } from './identity-manager';
|
|
29
23
|
import { type EdgeIdentityRecoveryManager } from './identity-recovery-manager';
|
|
30
24
|
|
|
31
|
-
const DEFAULT_SPACE_SEARCH_TIMEOUT = 10_000;
|
|
32
|
-
|
|
33
25
|
export class IdentityServiceImpl extends Resource implements IdentityService {
|
|
34
26
|
constructor(
|
|
35
27
|
private readonly _identityManager: IdentityManager,
|
|
36
28
|
private readonly _recoveryManager: EdgeIdentityRecoveryManager,
|
|
37
29
|
private readonly _keyring: Keyring,
|
|
38
|
-
private readonly _dataSpaceManagerProvider: () => DataSpaceManager,
|
|
39
30
|
private readonly _createIdentity: (params: CreateIdentityOptions) => Promise<Identity>,
|
|
40
31
|
private readonly _onProfileUpdate?: (profile: ProfileDocument | undefined) => Promise<void>,
|
|
41
32
|
) {
|
|
42
33
|
super();
|
|
43
34
|
}
|
|
44
35
|
|
|
45
|
-
protected override async _open(): Promise<void> {
|
|
46
|
-
const identity = this._identityManager.identity;
|
|
47
|
-
if (identity && !identity.defaultSpaceId) {
|
|
48
|
-
await this._fixIdentityWithoutDefaultSpace(identity);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
36
|
async createIdentity(request: CreateIdentityRequest): Promise<IdentityProto> {
|
|
53
37
|
await this._createIdentity({ profile: request.profile, deviceProfile: request.deviceProfile });
|
|
54
|
-
const dataSpaceManager = this._dataSpaceManagerProvider();
|
|
55
|
-
await this._createDefaultSpace(dataSpaceManager);
|
|
56
38
|
return this._getIdentity()!;
|
|
57
39
|
}
|
|
58
40
|
|
|
59
|
-
private async _createDefaultSpace(dataSpaceManager: DataSpaceManager): Promise<void> {
|
|
60
|
-
const space = await dataSpaceManager!.createDefaultSpace();
|
|
61
|
-
const identity = this._identityManager.identity;
|
|
62
|
-
invariant(identity);
|
|
63
|
-
await identity.updateDefaultSpace(space.id);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
41
|
queryIdentity(): Stream<QueryIdentityResponse> {
|
|
67
42
|
return new Stream(({ next }) => {
|
|
68
43
|
const emitNext = () => next({ identity: this._getIdentity() });
|
|
@@ -97,16 +72,16 @@ export class IdentityServiceImpl extends Resource implements IdentityService {
|
|
|
97
72
|
}
|
|
98
73
|
|
|
99
74
|
async requestRecoveryChallenge() {
|
|
100
|
-
return this._recoveryManager.requestRecoveryChallenge();
|
|
75
|
+
return this._recoveryManager.requestRecoveryChallenge(Context.default());
|
|
101
76
|
}
|
|
102
77
|
|
|
103
78
|
async recoverIdentity(request: RecoverIdentityRequest): Promise<IdentityProto> {
|
|
104
79
|
if (request.recoveryCode) {
|
|
105
|
-
await this._recoveryManager.recoverIdentity({ recoveryCode: request.recoveryCode });
|
|
80
|
+
await this._recoveryManager.recoverIdentity(Context.default(), { recoveryCode: request.recoveryCode });
|
|
106
81
|
} else if (request.external) {
|
|
107
|
-
await this._recoveryManager.recoverIdentityWithExternalSignature(request.external);
|
|
82
|
+
await this._recoveryManager.recoverIdentityWithExternalSignature(Context.default(), request.external);
|
|
108
83
|
} else if (request.token) {
|
|
109
|
-
await this._recoveryManager.recoverIdentityWithToken({ token: request.token });
|
|
84
|
+
await this._recoveryManager.recoverIdentityWithToken(Context.default(), { token: request.token });
|
|
110
85
|
} else {
|
|
111
86
|
throw new Error('Invalid request.');
|
|
112
87
|
}
|
|
@@ -141,50 +116,4 @@ export class IdentityServiceImpl extends Resource implements IdentityService {
|
|
|
141
116
|
signer: this._keyring,
|
|
142
117
|
});
|
|
143
118
|
}
|
|
144
|
-
|
|
145
|
-
private async _fixIdentityWithoutDefaultSpace(identity: Identity): Promise<void> {
|
|
146
|
-
let recodedDefaultSpace = false;
|
|
147
|
-
let foundDefaultSpace = false;
|
|
148
|
-
const dataSpaceManager = this._dataSpaceManagerProvider();
|
|
149
|
-
|
|
150
|
-
const recordedDefaultSpaceTrigger = new Trigger();
|
|
151
|
-
|
|
152
|
-
const allProcessed = safeAwaitAll(
|
|
153
|
-
dataSpaceManager.spaces.values(),
|
|
154
|
-
async (space) => {
|
|
155
|
-
if (space.state === SpaceState.SPACE_CLOSED) {
|
|
156
|
-
await space.open();
|
|
157
|
-
|
|
158
|
-
// Wait until the space is either READY or REQUIRES_MIGRATION.
|
|
159
|
-
// NOTE: Space could potentially never initialize if the space data is corrupted.
|
|
160
|
-
const requiresMigration = space.stateUpdate.waitForCondition(
|
|
161
|
-
() => space.state === SpaceState.SPACE_REQUIRES_MIGRATION,
|
|
162
|
-
);
|
|
163
|
-
await Promise.race([space.initializeDataPipeline(), requiresMigration]);
|
|
164
|
-
}
|
|
165
|
-
if (await dataSpaceManager.isDefaultSpace(space)) {
|
|
166
|
-
if (foundDefaultSpace) {
|
|
167
|
-
log.warn('Multiple default spaces found. Using the first one.', { duplicate: space.id });
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
foundDefaultSpace = true;
|
|
172
|
-
await identity.updateDefaultSpace(space.id);
|
|
173
|
-
recodedDefaultSpace = true;
|
|
174
|
-
recordedDefaultSpaceTrigger.wake();
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
(err) => {
|
|
178
|
-
log.catch(err);
|
|
179
|
-
},
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
// Wait for all spaces to be processed or until the default space is recorded.
|
|
183
|
-
// If the timeout is reached, create a new default space.
|
|
184
|
-
await Promise.race([allProcessed, recordedDefaultSpaceTrigger.wait(), sleep(DEFAULT_SPACE_SEARCH_TIMEOUT)]);
|
|
185
|
-
|
|
186
|
-
if (!recodedDefaultSpace) {
|
|
187
|
-
await this._createDefaultSpace(dataSpaceManager);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
119
|
}
|
|
@@ -130,7 +130,7 @@ describe('identity/identity', () => {
|
|
|
130
130
|
onMessage: (_: MessageListener): (() => void) => {
|
|
131
131
|
return () => {};
|
|
132
132
|
},
|
|
133
|
-
send: async (_) => {
|
|
133
|
+
send: async (..._) => {
|
|
134
134
|
replicationStarted = true;
|
|
135
135
|
},
|
|
136
136
|
} as EdgeConnection,
|
|
@@ -218,7 +218,7 @@ describe('identity/identity', () => {
|
|
|
218
218
|
});
|
|
219
219
|
|
|
220
220
|
await identity.open(new Context());
|
|
221
|
-
await identity.joinNetwork();
|
|
221
|
+
await identity.joinNetwork(Context.default());
|
|
222
222
|
onTestFinished(() => identity.close(new Context()));
|
|
223
223
|
return { identity, identityKey, keyring, deviceKey, controlFeed, spaceKey, dataFeed };
|
|
224
224
|
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Event } from '@dxos/async';
|
|
6
6
|
import { AUTH_TIMEOUT, LOAD_CONTROL_FEEDS_TIMEOUT } from '@dxos/client-protocol';
|
|
7
|
-
import { type Context } from '@dxos/context';
|
|
7
|
+
import { type Context as DxosContext } from '@dxos/context';
|
|
8
8
|
import {
|
|
9
9
|
type CredentialSigner,
|
|
10
10
|
DeviceStateMachine,
|
|
@@ -17,7 +17,7 @@ import { type Space } from '@dxos/echo-pipeline';
|
|
|
17
17
|
import { type EdgeConnection } from '@dxos/edge-client';
|
|
18
18
|
import { type FeedWrapper, writeMessages } from '@dxos/feed-store';
|
|
19
19
|
import { invariant } from '@dxos/invariant';
|
|
20
|
-
import { type IdentityDid, PublicKey
|
|
20
|
+
import { type IdentityDid, PublicKey } from '@dxos/keys';
|
|
21
21
|
import { log } from '@dxos/log';
|
|
22
22
|
import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
23
23
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
@@ -29,16 +29,13 @@ import {
|
|
|
29
29
|
} from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
30
30
|
import { type DeviceAdmissionRequest } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
31
31
|
import { type Presence } from '@dxos/teleport-extension-gossip';
|
|
32
|
-
import { Timeframe } from '@dxos/timeframe';
|
|
33
32
|
import { trace } from '@dxos/tracing';
|
|
34
33
|
import { type ComplexMap, ComplexSet } from '@dxos/util';
|
|
35
34
|
|
|
36
35
|
import { EdgeFeedReplicator } from '../spaces';
|
|
37
|
-
|
|
38
36
|
import { TrustedKeySetAuthVerifier } from './authenticator';
|
|
39
|
-
import { DefaultSpaceStateMachine } from './default-space-state-machine';
|
|
40
37
|
|
|
41
|
-
export type
|
|
38
|
+
export type IdentityProps = {
|
|
42
39
|
did: IdentityDid;
|
|
43
40
|
identityKey: PublicKey;
|
|
44
41
|
deviceKey: PublicKey;
|
|
@@ -60,7 +57,6 @@ export class Identity {
|
|
|
60
57
|
private readonly _presence?: Presence;
|
|
61
58
|
private readonly _deviceStateMachine: DeviceStateMachine;
|
|
62
59
|
private readonly _profileStateMachine: ProfileStateMachine;
|
|
63
|
-
private readonly _defaultSpaceStateMachine: DefaultSpaceStateMachine;
|
|
64
60
|
private readonly _edgeFeedReplicator?: EdgeFeedReplicator = undefined;
|
|
65
61
|
|
|
66
62
|
public readonly authVerifier: TrustedKeySetAuthVerifier;
|
|
@@ -71,7 +67,7 @@ export class Identity {
|
|
|
71
67
|
|
|
72
68
|
public readonly stateUpdate = new Event();
|
|
73
69
|
|
|
74
|
-
constructor(params:
|
|
70
|
+
constructor(params: IdentityProps) {
|
|
75
71
|
this.space = params.space;
|
|
76
72
|
this._signer = params.signer;
|
|
77
73
|
this._presence = params.presence;
|
|
@@ -91,10 +87,6 @@ export class Identity {
|
|
|
91
87
|
identityKey: this.identityKey,
|
|
92
88
|
onUpdate: () => this.stateUpdate.emit(),
|
|
93
89
|
});
|
|
94
|
-
this._defaultSpaceStateMachine = new DefaultSpaceStateMachine({
|
|
95
|
-
identityKey: this.identityKey,
|
|
96
|
-
onUpdate: () => this.stateUpdate.emit(),
|
|
97
|
-
});
|
|
98
90
|
|
|
99
91
|
this.authVerifier = new TrustedKeySetAuthVerifier({
|
|
100
92
|
trustedKeysProvider: () => new ComplexSet(PublicKey.hash, this.authorizedDeviceKeys.keys()),
|
|
@@ -112,32 +104,26 @@ export class Identity {
|
|
|
112
104
|
return this._deviceStateMachine.authorizedDeviceKeys;
|
|
113
105
|
}
|
|
114
106
|
|
|
115
|
-
get defaultSpaceId(): SpaceId | undefined {
|
|
116
|
-
return this._defaultSpaceStateMachine.spaceId;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
107
|
@trace.span()
|
|
120
|
-
async open(ctx:
|
|
108
|
+
async open(ctx: DxosContext): Promise<void> {
|
|
121
109
|
await this._presence?.open();
|
|
122
110
|
await this.space.spaceState.addCredentialProcessor(this._deviceStateMachine);
|
|
123
111
|
await this.space.spaceState.addCredentialProcessor(this._profileStateMachine);
|
|
124
|
-
await this.space.spaceState.addCredentialProcessor(this._defaultSpaceStateMachine);
|
|
125
112
|
if (this._edgeFeedReplicator) {
|
|
126
113
|
this.space.protocol.feedAdded.append(this._onFeedAdded);
|
|
127
114
|
}
|
|
128
115
|
await this.space.open(ctx);
|
|
129
116
|
}
|
|
130
117
|
|
|
131
|
-
public async joinNetwork(): Promise<void> {
|
|
132
|
-
await this.space.startProtocol();
|
|
118
|
+
public async joinNetwork(ctx: DxosContext): Promise<void> {
|
|
119
|
+
await this.space.startProtocol(ctx);
|
|
133
120
|
await this._edgeFeedReplicator?.open();
|
|
134
121
|
}
|
|
135
122
|
|
|
136
123
|
@trace.span()
|
|
137
|
-
async close(ctx:
|
|
124
|
+
async close(ctx: DxosContext): Promise<void> {
|
|
138
125
|
await this._presence?.close();
|
|
139
126
|
await this.authVerifier.close();
|
|
140
|
-
await this.space.spaceState.removeCredentialProcessor(this._defaultSpaceStateMachine);
|
|
141
127
|
await this.space.spaceState.removeCredentialProcessor(this._profileStateMachine);
|
|
142
128
|
await this.space.spaceState.removeCredentialProcessor(this._deviceStateMachine);
|
|
143
129
|
|
|
@@ -147,7 +133,7 @@ export class Identity {
|
|
|
147
133
|
|
|
148
134
|
await this._edgeFeedReplicator?.close();
|
|
149
135
|
|
|
150
|
-
await this.space.close();
|
|
136
|
+
await this.space.close(ctx);
|
|
151
137
|
}
|
|
152
138
|
|
|
153
139
|
async ready(): Promise<void> {
|
|
@@ -211,15 +197,6 @@ export class Identity {
|
|
|
211
197
|
return createCredentialSignerWithKey(this._signer, this.deviceKey);
|
|
212
198
|
}
|
|
213
199
|
|
|
214
|
-
async updateDefaultSpace(spaceId: SpaceId): Promise<void> {
|
|
215
|
-
const credential = await this.getDeviceCredentialSigner().createCredential({
|
|
216
|
-
subject: this.identityKey,
|
|
217
|
-
assertion: { '@type': 'dxos.halo.credentials.DefaultSpace', spaceId },
|
|
218
|
-
});
|
|
219
|
-
const receipt = await this.controlPipeline.writer.write({ credential: { credential } });
|
|
220
|
-
await this.controlPipeline.state.waitUntilTimeframe(new Timeframe([[receipt.feedKey, receipt.seq]]));
|
|
221
|
-
}
|
|
222
|
-
|
|
223
200
|
async admitDevice({ deviceKey, controlFeedKey, dataFeedKey }: DeviceAdmissionRequest): Promise<Credential> {
|
|
224
201
|
log('Admitting device:', {
|
|
225
202
|
identityKey: this.identityKey,
|
|
@@ -6,7 +6,7 @@ import { getCredentialAssertion } from '@dxos/credentials';
|
|
|
6
6
|
import { invariant } from '@dxos/invariant';
|
|
7
7
|
import { type Keyring } from '@dxos/keyring';
|
|
8
8
|
import { type PublicKey } from '@dxos/keys';
|
|
9
|
-
import { AlreadyJoinedError
|
|
9
|
+
import { AlreadyJoinedError } from '@dxos/protocols';
|
|
10
10
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
11
|
import type { DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
12
12
|
import {
|
|
@@ -15,15 +15,14 @@ import {
|
|
|
15
15
|
type IntroductionRequest,
|
|
16
16
|
} from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
17
17
|
|
|
18
|
-
import { type Identity, type
|
|
19
|
-
|
|
18
|
+
import { type Identity, type JoinIdentityProps } from '../identity';
|
|
20
19
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
21
20
|
|
|
22
21
|
export class DeviceInvitationProtocol implements InvitationProtocol {
|
|
23
22
|
constructor(
|
|
24
23
|
private readonly _keyring: Keyring,
|
|
25
24
|
private readonly _getIdentity: () => Identity,
|
|
26
|
-
private readonly _acceptIdentity: (identity:
|
|
25
|
+
private readonly _acceptIdentity: (identity: JoinIdentityProps) => Promise<Identity>,
|
|
27
26
|
) {}
|
|
28
27
|
|
|
29
28
|
toJSON(): object {
|
|
@@ -32,7 +31,7 @@ export class DeviceInvitationProtocol implements InvitationProtocol {
|
|
|
32
31
|
};
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
checkCanInviteNewMembers():
|
|
34
|
+
checkCanInviteNewMembers(): Error | undefined {
|
|
36
35
|
return undefined;
|
|
37
36
|
}
|
|
38
37
|
|
|
@@ -71,7 +70,7 @@ export class DeviceInvitationProtocol implements InvitationProtocol {
|
|
|
71
70
|
try {
|
|
72
71
|
const identity = this._getIdentity();
|
|
73
72
|
if (identity) {
|
|
74
|
-
return new AlreadyJoinedError('Currently only one identity per client is supported.');
|
|
73
|
+
return new AlreadyJoinedError({ message: 'Currently only one identity per client is supported.' });
|
|
75
74
|
}
|
|
76
75
|
} catch {
|
|
77
76
|
// No identity.
|
|
@@ -126,7 +126,7 @@ export class EdgeInvitationHandler implements FlowLockHolder {
|
|
|
126
126
|
|
|
127
127
|
guardedState.set(this, Invitation.State.CONNECTING);
|
|
128
128
|
|
|
129
|
-
const response = await this._joinSpaceByInvitation(guardedState, spaceId, {
|
|
129
|
+
const response = await this._joinSpaceByInvitation(ctx, guardedState, spaceId, {
|
|
130
130
|
identityKey: admissionRequest.identityKey.toHex(),
|
|
131
131
|
invitationId: guardedState.current.invitationId,
|
|
132
132
|
});
|
|
@@ -153,13 +153,14 @@ export class EdgeInvitationHandler implements FlowLockHolder {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
private async _joinSpaceByInvitation(
|
|
156
|
+
ctx: Context,
|
|
156
157
|
guardedState: GuardedInvitationState,
|
|
157
158
|
spaceId: SpaceId,
|
|
158
159
|
request: JoinSpaceRequest,
|
|
159
160
|
): Promise<JoinSpaceResponseBody> {
|
|
160
161
|
invariant(this._client);
|
|
161
162
|
try {
|
|
162
|
-
return await this._client.joinSpaceByInvitation(spaceId, request);
|
|
163
|
+
return await this._client.joinSpaceByInvitation(ctx, spaceId, request);
|
|
163
164
|
} catch (error: any) {
|
|
164
165
|
if (error instanceof EdgeAuthChallengeError) {
|
|
165
166
|
const publicKey = guardedState.current.guestKeypair?.publicKey;
|
|
@@ -168,7 +169,7 @@ export class EdgeInvitationHandler implements FlowLockHolder {
|
|
|
168
169
|
throw error;
|
|
169
170
|
}
|
|
170
171
|
const signature = sign(Buffer.from(error.challenge, 'base64'), privateKey);
|
|
171
|
-
return this._client.joinSpaceByInvitation(spaceId, {
|
|
172
|
+
return this._client.joinSpaceByInvitation(ctx, spaceId, {
|
|
172
173
|
...request,
|
|
173
174
|
signature: Buffer.from(signature).toString('base64'),
|
|
174
175
|
});
|
|
@@ -97,10 +97,12 @@ export class InvitationGuestExtension
|
|
|
97
97
|
await cancelWithContext(this._ctx, this._remoteOptionsTrigger.wait({ timeout: OPTIONS_TIMEOUT }));
|
|
98
98
|
log.verbose('options received');
|
|
99
99
|
if (this._remoteOptions?.role !== InvitationOptions.Role.HOST) {
|
|
100
|
-
throw new InvalidInvitationExtensionRoleError(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
throw new InvalidInvitationExtensionRoleError({
|
|
101
|
+
context: {
|
|
102
|
+
expected: InvitationOptions.Role.HOST,
|
|
103
|
+
remoteOptions: this._remoteOptions,
|
|
104
|
+
remotePeerId: context.remotePeerId,
|
|
105
|
+
},
|
|
104
106
|
});
|
|
105
107
|
}
|
|
106
108
|
|
|
@@ -245,10 +245,12 @@ export class InvitationHostExtension
|
|
|
245
245
|
await cancelWithContext(this._ctx, this._remoteOptionsTrigger.wait({ timeout: OPTIONS_TIMEOUT }));
|
|
246
246
|
log.verbose('options received');
|
|
247
247
|
if (this._remoteOptions?.role !== InvitationOptions.Role.GUEST) {
|
|
248
|
-
throw new InvalidInvitationExtensionRoleError(
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
248
|
+
throw new InvalidInvitationExtensionRoleError({
|
|
249
|
+
context: {
|
|
250
|
+
expected: InvitationOptions.Role.GUEST,
|
|
251
|
+
remoteOptions: this._remoteOptions,
|
|
252
|
+
remotePeerId: context.remotePeerId,
|
|
253
|
+
},
|
|
252
254
|
});
|
|
253
255
|
}
|
|
254
256
|
this._callbacks.onStateUpdate(Invitation.State.CONNECTED);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type PublicKey } from '@dxos/keys';
|
|
6
|
-
import type { ApiError } from '@dxos/protocols';
|
|
7
6
|
import type { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
8
7
|
import type { DeviceProfileDocument, ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
9
8
|
import type {
|
|
@@ -26,7 +25,7 @@ export interface InvitationProtocol {
|
|
|
26
25
|
// Host
|
|
27
26
|
//
|
|
28
27
|
|
|
29
|
-
checkCanInviteNewMembers():
|
|
28
|
+
checkCanInviteNewMembers(): Error | undefined;
|
|
30
29
|
|
|
31
30
|
/**
|
|
32
31
|
* Protocol-specific information to include in the invitation.
|
|
@@ -58,7 +57,7 @@ export interface InvitationProtocol {
|
|
|
58
57
|
*
|
|
59
58
|
* For example, the guest may already be a member of the space.
|
|
60
59
|
*/
|
|
61
|
-
checkInvitation(invitation: Partial<Invitation>):
|
|
60
|
+
checkInvitation(invitation: Partial<Invitation>): Error | undefined;
|
|
62
61
|
|
|
63
62
|
/**
|
|
64
63
|
* Get profile information to send to the host to identify the guest.
|
|
@@ -12,7 +12,6 @@ import { openAndClose } from '@dxos/test-utils';
|
|
|
12
12
|
import { range } from '@dxos/util';
|
|
13
13
|
|
|
14
14
|
import { TestBuilder, type TestPeer } from '../testing';
|
|
15
|
-
|
|
16
15
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
17
16
|
import { InvitationsHandler } from './invitations-handler';
|
|
18
17
|
import { SpaceInvitationProtocol } from './space-invitation-protocol';
|
|
@@ -95,7 +94,7 @@ describe.skipIf(process.env.CI && !process.env.RUN_FLAKY_TESTS)(
|
|
|
95
94
|
await acceptInvitation(guest, invitation);
|
|
96
95
|
|
|
97
96
|
await guest.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
98
|
-
await guest.peer.networkManager.close();
|
|
97
|
+
await guest.peer.networkManager.close(Context.default());
|
|
99
98
|
await host.sink.waitFor(Invitation.State.CONNECTING);
|
|
100
99
|
|
|
101
100
|
await sleep(10);
|
|
@@ -254,9 +253,9 @@ describe.skipIf(process.env.CI && !process.env.RUN_FLAKY_TESTS)(
|
|
|
254
253
|
const peer = testBuilder.createPeer();
|
|
255
254
|
await peer.createIdentity();
|
|
256
255
|
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
257
|
-
await peer.echoHost.addReplicator(peer.meshEchoReplicator);
|
|
256
|
+
await peer.echoHost.addReplicator(Context.default(), peer.meshEchoReplicator);
|
|
258
257
|
if (spaceKey == null) {
|
|
259
|
-
const space = await peer.dataSpaceManager.createSpace();
|
|
258
|
+
const space = await peer.dataSpaceManager.createSpace(new Context());
|
|
260
259
|
spaceKey = space.key;
|
|
261
260
|
}
|
|
262
261
|
const invitationHandler = new InvitationsHandler(peer.networkManager, undefined, {
|
|
@@ -359,7 +358,7 @@ describe.skipIf(process.env.CI && !process.env.RUN_FLAKY_TESTS)(
|
|
|
359
358
|
};
|
|
360
359
|
|
|
361
360
|
const createInvitation = async (setup: PeerSetup, options?: Partial<Invitation>): Promise<Invitation> => {
|
|
362
|
-
const observable = await setup.peer.invitationsManager.createInvitation({
|
|
361
|
+
const observable = await setup.peer.invitationsManager.createInvitation(setup.ctx, {
|
|
363
362
|
type: Invitation.Type.DELEGATED,
|
|
364
363
|
kind: Invitation.Kind.SPACE,
|
|
365
364
|
authMethod: Invitation.AuthMethod.SHARED_SECRET,
|
|
@@ -16,7 +16,7 @@ import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/cl
|
|
|
16
16
|
import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
17
17
|
import { AuthenticationResponse, type IntroductionResponse } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
18
18
|
import { InvitationOptions } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
19
|
-
import { type ExtensionContext, type TeleportExtension, type
|
|
19
|
+
import { type ExtensionContext, type TeleportExtension, type TeleportProps } from '@dxos/teleport';
|
|
20
20
|
import { trace as _trace } from '@dxos/tracing';
|
|
21
21
|
import { ComplexSet } from '@dxos/util';
|
|
22
22
|
|
|
@@ -31,8 +31,8 @@ const metrics = _trace.metrics;
|
|
|
31
31
|
|
|
32
32
|
const MAX_DELEGATED_INVITATION_HOST_TRIES = 3;
|
|
33
33
|
|
|
34
|
-
export type
|
|
35
|
-
teleport: Partial<
|
|
34
|
+
export type InvitationConnectionProps = {
|
|
35
|
+
teleport: Partial<TeleportProps>;
|
|
36
36
|
edgeInvitations?: EdgeInvitationConfig;
|
|
37
37
|
};
|
|
38
38
|
|
|
@@ -71,7 +71,7 @@ export class InvitationsHandler {
|
|
|
71
71
|
constructor(
|
|
72
72
|
private readonly _networkManager: SwarmNetworkManager,
|
|
73
73
|
private readonly _edgeClient?: EdgeHttpClient,
|
|
74
|
-
private readonly
|
|
74
|
+
private readonly _connectionProps?: InvitationConnectionProps,
|
|
75
75
|
) {}
|
|
76
76
|
|
|
77
77
|
handleInvitationFlow(
|
|
@@ -200,7 +200,7 @@ export class InvitationsHandler {
|
|
|
200
200
|
ctx,
|
|
201
201
|
async () => {
|
|
202
202
|
// ensure the swarm is closed before changing state and closing the stream.
|
|
203
|
-
await swarmConnection.close();
|
|
203
|
+
await swarmConnection.close(ctx);
|
|
204
204
|
guardedState.set(null, Invitation.State.EXPIRED);
|
|
205
205
|
metrics.increment('dxos.invitation.expired');
|
|
206
206
|
await ctx.dispose();
|
|
@@ -388,7 +388,7 @@ export class InvitationsHandler {
|
|
|
388
388
|
return extension;
|
|
389
389
|
};
|
|
390
390
|
|
|
391
|
-
const edgeInvitationHandler = new EdgeInvitationHandler(this.
|
|
391
|
+
const edgeInvitationHandler = new EdgeInvitationHandler(this._connectionProps?.edgeInvitations, this._edgeClient, {
|
|
392
392
|
onInvitationSuccess: async (admissionResponse, admissionRequest) => {
|
|
393
393
|
const result = await protocol.accept(admissionResponse, admissionRequest);
|
|
394
394
|
log.info('admitted by edge', { ...protocol.toJSON() });
|
|
@@ -436,15 +436,15 @@ export class InvitationsHandler {
|
|
|
436
436
|
} else {
|
|
437
437
|
label = `invitation host for space ${invitation.spaceKey?.truncate()}`;
|
|
438
438
|
}
|
|
439
|
-
const swarmConnection = await this._networkManager.joinSwarm({
|
|
439
|
+
const swarmConnection = await this._networkManager.joinSwarm(ctx, {
|
|
440
440
|
topic: invitation.swarmKey,
|
|
441
441
|
protocolProvider: createTeleportProtocolFactory(async (teleport) => {
|
|
442
442
|
teleport.addExtension('dxos.halo.invitations', extensionFactory());
|
|
443
|
-
}, this.
|
|
443
|
+
}, this._connectionProps?.teleport),
|
|
444
444
|
topology: new InvitationTopology(role),
|
|
445
445
|
label,
|
|
446
446
|
});
|
|
447
|
-
ctx.onDispose(() => swarmConnection.close());
|
|
447
|
+
ctx.onDispose(() => swarmConnection.close(ctx));
|
|
448
448
|
return swarmConnection;
|
|
449
449
|
}
|
|
450
450
|
|
|
@@ -503,7 +503,7 @@ export class InvitationsHandler {
|
|
|
503
503
|
const checkInvitation = (protocol: InvitationProtocol, invitation: Partial<Invitation>) => {
|
|
504
504
|
const expiresOn = getExpirationTime(invitation);
|
|
505
505
|
if (expiresOn && expiresOn.getTime() < Date.now()) {
|
|
506
|
-
return new InvalidInvitationError('Invitation already expired.');
|
|
506
|
+
return new InvalidInvitationError({ message: 'Invitation already expired.' });
|
|
507
507
|
}
|
|
508
508
|
return protocol.checkInvitation(invitation);
|
|
509
509
|
};
|