@dxos/client-services 0.8.4-main.a4bbb77 → 0.8.4-main.abd8ff62ef
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-FZDVFED2.mjs → chunk-KW4WMU5R.mjs} +2698 -4599
- package/dist/lib/browser/chunk-KW4WMU5R.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/chunk-XJRPB3GA.mjs +22 -0
- package/dist/lib/browser/chunk-XJRPB3GA.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +490 -228
- 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 +88 -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 +86 -0
- package/dist/lib/browser/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/browser/packlets/locks/node.mjs +48 -0
- package/dist/lib/browser/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +60 -90
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-2DT3MZRL.mjs +22 -0
- package/dist/lib/node-esm/chunk-2DT3MZRL.mjs.map +7 -0
- 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-JDTIU3EP.mjs → chunk-NDMKP2CH.mjs} +2621 -4391
- package/dist/lib/node-esm/chunk-NDMKP2CH.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +490 -228
- 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 +88 -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 +86 -0
- package/dist/lib/node-esm/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs +48 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +60 -90
- 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 +2 -1
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devices/devices-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/devtools/feeds.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/keys.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/metadata.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-collector.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts +2 -3
- package/dist/types/src/packlets/diagnostics/diagnostics.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 +8 -7
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +6 -10
- 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 +6 -5
- 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 +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 +7 -4
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-state.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-topology.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/invitations-service.d.ts +3 -3
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +4 -3
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -1
- package/dist/types/src/packlets/locks/browser.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/locks/node.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 +5 -4
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +5 -5
- 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 -9
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +20 -7
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/packlets/services/util.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/archive-format.d.ts +9 -0
- package/dist/types/src/packlets/space-export/archive-format.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/index.d.ts +4 -1
- package/dist/types/src/packlets/space-export/index.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +23 -0
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts +36 -0
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -0
- 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 +7 -1
- 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/automerge-space-state.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +28 -17
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +26 -9
- 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/epoch-migrations.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 -9
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +10 -7
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/level.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/profile-archive.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/util.d.ts.map +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/credential-utils.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 +41 -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 -4
- package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
- package/dist/types/src/testing/setup.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 -55
- package/src/index.ts +1 -0
- package/src/packlets/agents/edge-agent-manager.ts +8 -5
- package/src/packlets/agents/edge-agent-service.ts +15 -3
- package/src/packlets/devices/devices-service.test.ts +0 -1
- package/src/packlets/devices/devices-service.ts +1 -1
- package/src/packlets/devtools/devtools.ts +2 -3
- package/src/packlets/diagnostics/diagnostics.ts +1 -2
- 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 +23 -22
- 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 +13 -81
- package/src/packlets/identity/identity.test.ts +6 -6
- package/src/packlets/identity/identity.ts +11 -34
- package/src/packlets/invitations/device-invitation-protocol.ts +8 -7
- package/src/packlets/invitations/edge-invitation-handler.ts +9 -5
- package/src/packlets/invitations/invitation-guest-extenstion.ts +6 -4
- package/src/packlets/invitations/invitation-host-extension.ts +13 -14
- package/src/packlets/invitations/invitation-protocol.ts +7 -4
- package/src/packlets/invitations/invitation-state.ts +1 -15
- package/src/packlets/invitations/invitations-handler.test.ts +4 -5
- package/src/packlets/invitations/invitations-handler.ts +74 -22
- package/src/packlets/invitations/invitations-manager.ts +40 -15
- package/src/packlets/invitations/invitations-service.ts +9 -9
- package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
- package/src/packlets/invitations/space-invitation-protocol.ts +11 -16
- package/src/packlets/locks/index.ts +1 -1
- package/src/packlets/logging/logging-service.ts +20 -16
- package/src/packlets/network/network-service.test.ts +0 -1
- package/src/packlets/network/network-service.ts +10 -8
- package/src/packlets/services/client-rpc-server.ts +19 -16
- 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 +138 -56
- package/src/packlets/services/service-host.test.ts +8 -8
- package/src/packlets/services/service-host.ts +70 -40
- package/src/packlets/services/service-registry.test.ts +0 -1
- package/src/packlets/space-export/archive-format.ts +42 -0
- package/src/packlets/space-export/index.ts +4 -1
- package/src/packlets/space-export/serialized-space-reader.ts +111 -0
- package/src/packlets/space-export/serialized-space-writer.ts +253 -0
- package/src/packlets/space-export/space-archive-reader.ts +64 -3
- package/src/packlets/space-export/space-archive-writer.ts +41 -3
- package/src/packlets/space-export/space-archive.test.ts +461 -0
- package/src/packlets/spaces/data-space-manager.test.ts +79 -13
- package/src/packlets/spaces/data-space-manager.ts +115 -115
- package/src/packlets/spaces/data-space.ts +58 -33
- package/src/packlets/spaces/edge-feed-replicator.test.ts +2 -2
- package/src/packlets/spaces/edge-feed-replicator.ts +12 -10
- 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 +18 -11
- package/src/packlets/spaces/spaces-service.ts +123 -24
- 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 +188 -17
- package/src/packlets/worker/worker-session.ts +12 -18
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-FZDVFED2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JDTIU3EP.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,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Context } from '@dxos/context';
|
|
5
6
|
import { generateSeedPhrase, keyPairFromSeedPhrase } from '@dxos/credentials';
|
|
6
7
|
import { sign } from '@dxos/crypto';
|
|
7
8
|
import { type EdgeHttpClient } from '@dxos/edge-client';
|
|
@@ -22,14 +23,14 @@ import {
|
|
|
22
23
|
import { Timeframe } from '@dxos/timeframe';
|
|
23
24
|
|
|
24
25
|
import { type Identity } from './identity';
|
|
25
|
-
import { type
|
|
26
|
+
import { type JoinIdentityProps } from './identity-manager';
|
|
26
27
|
|
|
27
28
|
export class EdgeIdentityRecoveryManager {
|
|
28
29
|
constructor(
|
|
29
30
|
private readonly _keyring: Keyring,
|
|
30
31
|
private readonly _edgeClient: EdgeHttpClient | undefined,
|
|
31
32
|
private readonly _identityProvider: () => Identity | undefined,
|
|
32
|
-
private readonly _acceptRecoveredIdentity: (params:
|
|
33
|
+
private readonly _acceptRecoveredIdentity: (params: JoinIdentityProps) => Promise<Identity>,
|
|
33
34
|
) {}
|
|
34
35
|
|
|
35
36
|
public async createRecoveryCredential({
|
|
@@ -72,7 +73,7 @@ export class EdgeIdentityRecoveryManager {
|
|
|
72
73
|
return { recoveryCode };
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
public async requestRecoveryChallenge() {
|
|
76
|
+
public async requestRecoveryChallenge(ctx: Context) {
|
|
76
77
|
invariant(this._edgeClient, 'Not connected to EDGE.');
|
|
77
78
|
|
|
78
79
|
const deviceKey = await this._keyring.createKey();
|
|
@@ -83,7 +84,7 @@ export class EdgeIdentityRecoveryManager {
|
|
|
83
84
|
};
|
|
84
85
|
|
|
85
86
|
try {
|
|
86
|
-
await this._edgeClient.recoverIdentity(request);
|
|
87
|
+
await this._edgeClient.recoverIdentity(ctx, request);
|
|
87
88
|
throw new Error('No challenge received.');
|
|
88
89
|
} catch (error: any) {
|
|
89
90
|
if (!(error instanceof EdgeAuthChallengeError)) {
|
|
@@ -97,14 +98,17 @@ export class EdgeIdentityRecoveryManager {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
public async recoverIdentityWithExternalSignature(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
public async recoverIdentityWithExternalSignature(
|
|
102
|
+
ctx: Context,
|
|
103
|
+
{
|
|
104
|
+
lookupKey,
|
|
105
|
+
deviceKey,
|
|
106
|
+
controlFeedKey,
|
|
107
|
+
signature,
|
|
108
|
+
clientDataJson,
|
|
109
|
+
authenticatorData,
|
|
110
|
+
}: RecoverIdentityRequest.ExternalSignature,
|
|
111
|
+
): Promise<void> {
|
|
108
112
|
invariant(this._edgeClient, 'Not connected to EDGE.');
|
|
109
113
|
|
|
110
114
|
const request: EdgeRecoverIdentityRequest = {
|
|
@@ -121,7 +125,7 @@ export class EdgeIdentityRecoveryManager {
|
|
|
121
125
|
: Buffer.from(signature).toString('base64'),
|
|
122
126
|
};
|
|
123
127
|
|
|
124
|
-
const response = await this._edgeClient.recoverIdentity(request);
|
|
128
|
+
const response = await this._edgeClient.recoverIdentity(ctx, request);
|
|
125
129
|
|
|
126
130
|
await this._acceptRecoveredIdentity({
|
|
127
131
|
authorizedDeviceCredential: decodeCredential(response.deviceAuthCredential),
|
|
@@ -137,7 +141,7 @@ export class EdgeIdentityRecoveryManager {
|
|
|
137
141
|
/**
|
|
138
142
|
* Recovery identity using an opaque token sent to the user's email.
|
|
139
143
|
*/
|
|
140
|
-
public async recoverIdentityWithToken({ token }: { token: string }): Promise<void> {
|
|
144
|
+
public async recoverIdentityWithToken(ctx: Context, { token }: { token: string }): Promise<void> {
|
|
141
145
|
invariant(this._edgeClient, 'Not connected to EDGE.');
|
|
142
146
|
|
|
143
147
|
const deviceKey = await this._keyring.createKey();
|
|
@@ -148,7 +152,7 @@ export class EdgeIdentityRecoveryManager {
|
|
|
148
152
|
token,
|
|
149
153
|
};
|
|
150
154
|
|
|
151
|
-
const response = await this._edgeClient.recoverIdentity(request);
|
|
155
|
+
const response = await this._edgeClient.recoverIdentity(ctx, request);
|
|
152
156
|
|
|
153
157
|
await this._acceptRecoveredIdentity({
|
|
154
158
|
authorizedDeviceCredential: decodeCredential(response.deviceAuthCredential),
|
|
@@ -161,7 +165,7 @@ export class EdgeIdentityRecoveryManager {
|
|
|
161
165
|
});
|
|
162
166
|
}
|
|
163
167
|
|
|
164
|
-
public async recoverIdentity({ recoveryCode }: { recoveryCode: string }): Promise<void> {
|
|
168
|
+
public async recoverIdentity(ctx: Context, { recoveryCode }: { recoveryCode: string }): Promise<void> {
|
|
165
169
|
invariant(this._edgeClient, 'Not connected to EDGE.');
|
|
166
170
|
|
|
167
171
|
const recoveryKeypair = keyPairFromSeedPhrase(recoveryCode);
|
|
@@ -176,13 +180,13 @@ export class EdgeIdentityRecoveryManager {
|
|
|
176
180
|
|
|
177
181
|
let response: RecoverIdentityResponseBody;
|
|
178
182
|
try {
|
|
179
|
-
response = await this._edgeClient.recoverIdentity(request);
|
|
183
|
+
response = await this._edgeClient.recoverIdentity(ctx, request);
|
|
180
184
|
} catch (error: any) {
|
|
181
185
|
if (!(error instanceof EdgeAuthChallengeError)) {
|
|
182
186
|
throw error;
|
|
183
187
|
}
|
|
184
188
|
const signature = sign(Buffer.from(error.challenge, 'base64'), recoveryKeypair.secretKey);
|
|
185
|
-
response = await this._edgeClient.recoverIdentity({
|
|
189
|
+
response = await this._edgeClient.recoverIdentity(ctx, {
|
|
186
190
|
...request,
|
|
187
191
|
signature: Buffer.from(signature).toString('base64'),
|
|
188
192
|
});
|
|
@@ -11,7 +11,6 @@ import { type Identity, type IdentityService } from '@dxos/protocols/proto/dxos/
|
|
|
11
11
|
|
|
12
12
|
import { type ServiceContext } from '../services';
|
|
13
13
|
import { createServiceContext } from '../testing';
|
|
14
|
-
|
|
15
14
|
import { IdentityServiceImpl } from './identity-service';
|
|
16
15
|
|
|
17
16
|
describe('IdentityService', () => {
|
|
@@ -48,6 +47,12 @@ describe('IdentityService', () => {
|
|
|
48
47
|
await identityService.createIdentity({});
|
|
49
48
|
await expect(identityService.createIdentity({})).rejects.toThrowError('Identity already exists');
|
|
50
49
|
});
|
|
50
|
+
|
|
51
|
+
test('creates identity with no spaces', async () => {
|
|
52
|
+
await identityService.createIdentity({});
|
|
53
|
+
const dataSpaces = [...(serviceContext.dataSpaceManager?.spaces?.values() ?? [])];
|
|
54
|
+
expect(dataSpaces.length).to.eq(0);
|
|
55
|
+
});
|
|
51
56
|
});
|
|
52
57
|
|
|
53
58
|
describe.skip('recoverIdentity', () => {});
|
|
@@ -89,37 +94,11 @@ describe('IdentityService', () => {
|
|
|
89
94
|
});
|
|
90
95
|
});
|
|
91
96
|
|
|
92
|
-
describe('open', () => {
|
|
93
|
-
test('identity without default space fixed', async () => {
|
|
94
|
-
const serviceContext = await createServiceContext();
|
|
95
|
-
await serviceContext.open(new Context());
|
|
96
|
-
const identity = await serviceContext.createIdentity();
|
|
97
|
-
const identityService = createIdentityService(serviceContext);
|
|
98
|
-
const getDataSpaces = () => [...(serviceContext.dataSpaceManager?.spaces?.values() ?? [])];
|
|
99
|
-
expect(getDataSpaces().length).to.eq(0);
|
|
100
|
-
expect(identity.defaultSpaceId).to.be.undefined;
|
|
101
|
-
await identityService.open();
|
|
102
|
-
expect(getDataSpaces()[0].id === identity.defaultSpaceId).to.be.true;
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test('identity without default space credential fixed', async () => {
|
|
106
|
-
const serviceContext = await createServiceContext();
|
|
107
|
-
await serviceContext.open(new Context());
|
|
108
|
-
const identity = await serviceContext.createIdentity();
|
|
109
|
-
const space = await serviceContext.dataSpaceManager!.createDefaultSpace();
|
|
110
|
-
const identityService = createIdentityService(serviceContext);
|
|
111
|
-
expect(identity.defaultSpaceId).to.be.undefined;
|
|
112
|
-
await identityService.open();
|
|
113
|
-
expect(identity.defaultSpaceId === space.id).to.be.true;
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
97
|
const createIdentityService = (serviceContext: ServiceContext) => {
|
|
118
98
|
return new IdentityServiceImpl(
|
|
119
99
|
serviceContext.identityManager,
|
|
120
100
|
serviceContext.recoveryManager,
|
|
121
101
|
serviceContext.keyring,
|
|
122
|
-
() => serviceContext.dataSpaceManager!,
|
|
123
102
|
(options) => serviceContext.createIdentity(options),
|
|
124
103
|
);
|
|
125
104
|
};
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { type RequestOptions } from '@dxos/codec-protobuf';
|
|
6
6
|
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
7
|
-
import { Resource } from '@dxos/context';
|
|
7
|
+
import { Context, Resource } from '@dxos/context';
|
|
8
8
|
import { createCredential, signPresentation } from '@dxos/credentials';
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
10
|
import { type Keyring } from '@dxos/keyring';
|
|
11
|
-
import { log } from '@dxos/log';
|
|
12
11
|
import {
|
|
13
12
|
type CreateIdentityRequest,
|
|
14
13
|
type CreateRecoveryCredentialRequest,
|
|
@@ -17,52 +16,30 @@ import {
|
|
|
17
16
|
type QueryIdentityResponse,
|
|
18
17
|
type RecoverIdentityRequest,
|
|
19
18
|
type SignPresentationRequest,
|
|
20
|
-
SpaceState,
|
|
21
19
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
22
20
|
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
21
|
|
|
27
22
|
import { type Identity } from './identity';
|
|
28
23
|
import { type CreateIdentityOptions, type IdentityManager } from './identity-manager';
|
|
29
24
|
import { type EdgeIdentityRecoveryManager } from './identity-recovery-manager';
|
|
30
25
|
|
|
31
|
-
const DEFAULT_SPACE_SEARCH_TIMEOUT = 10_000;
|
|
32
|
-
|
|
33
26
|
export class IdentityServiceImpl extends Resource implements IdentityService {
|
|
34
27
|
constructor(
|
|
35
28
|
private readonly _identityManager: IdentityManager,
|
|
36
29
|
private readonly _recoveryManager: EdgeIdentityRecoveryManager,
|
|
37
30
|
private readonly _keyring: Keyring,
|
|
38
|
-
private readonly
|
|
39
|
-
private readonly _createIdentity: (params: CreateIdentityOptions) => Promise<Identity>,
|
|
31
|
+
private readonly _createIdentity: (params: CreateIdentityOptions, ctx?: Context) => Promise<Identity>,
|
|
40
32
|
private readonly _onProfileUpdate?: (profile: ProfileDocument | undefined) => Promise<void>,
|
|
41
33
|
) {
|
|
42
34
|
super();
|
|
43
35
|
}
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
await this._fixIdentityWithoutDefaultSpace(identity);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async createIdentity(request: CreateIdentityRequest): Promise<IdentityProto> {
|
|
53
|
-
await this._createIdentity({ profile: request.profile, deviceProfile: request.deviceProfile });
|
|
54
|
-
const dataSpaceManager = this._dataSpaceManagerProvider();
|
|
55
|
-
await this._createDefaultSpace(dataSpaceManager);
|
|
37
|
+
async createIdentity(request: CreateIdentityRequest, options?: RequestOptions): Promise<IdentityProto> {
|
|
38
|
+
const ctx = options?.ctx ?? Context.default();
|
|
39
|
+
await this._createIdentity({ profile: request.profile, deviceProfile: request.deviceProfile }, ctx);
|
|
56
40
|
return this._getIdentity()!;
|
|
57
41
|
}
|
|
58
42
|
|
|
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
43
|
queryIdentity(): Stream<QueryIdentityResponse> {
|
|
67
44
|
return new Stream(({ next }) => {
|
|
68
45
|
const emitNext = () => next({ identity: this._getIdentity() });
|
|
@@ -96,17 +73,18 @@ export class IdentityServiceImpl extends Resource implements IdentityService {
|
|
|
96
73
|
return this._recoveryManager.createRecoveryCredential(request);
|
|
97
74
|
}
|
|
98
75
|
|
|
99
|
-
async requestRecoveryChallenge() {
|
|
100
|
-
return this._recoveryManager.requestRecoveryChallenge();
|
|
76
|
+
async requestRecoveryChallenge(_request: void, options?: RequestOptions) {
|
|
77
|
+
return this._recoveryManager.requestRecoveryChallenge(options?.ctx ?? Context.default());
|
|
101
78
|
}
|
|
102
79
|
|
|
103
|
-
async recoverIdentity(request: RecoverIdentityRequest): Promise<IdentityProto> {
|
|
80
|
+
async recoverIdentity(request: RecoverIdentityRequest, options?: RequestOptions): Promise<IdentityProto> {
|
|
81
|
+
const ctx = options?.ctx ?? Context.default();
|
|
104
82
|
if (request.recoveryCode) {
|
|
105
|
-
await this._recoveryManager.recoverIdentity({ recoveryCode: request.recoveryCode });
|
|
83
|
+
await this._recoveryManager.recoverIdentity(ctx, { recoveryCode: request.recoveryCode });
|
|
106
84
|
} else if (request.external) {
|
|
107
|
-
await this._recoveryManager.recoverIdentityWithExternalSignature(request.external);
|
|
85
|
+
await this._recoveryManager.recoverIdentityWithExternalSignature(ctx, request.external);
|
|
108
86
|
} else if (request.token) {
|
|
109
|
-
await this._recoveryManager.recoverIdentityWithToken({ token: request.token });
|
|
87
|
+
await this._recoveryManager.recoverIdentityWithToken(ctx, { token: request.token });
|
|
110
88
|
} else {
|
|
111
89
|
throw new Error('Invalid request.');
|
|
112
90
|
}
|
|
@@ -141,50 +119,4 @@ export class IdentityServiceImpl extends Resource implements IdentityService {
|
|
|
141
119
|
signer: this._keyring,
|
|
142
120
|
});
|
|
143
121
|
}
|
|
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
122
|
}
|
|
@@ -109,16 +109,16 @@ describe('identity/identity', () => {
|
|
|
109
109
|
|
|
110
110
|
test('edge feed replicator', async () => {
|
|
111
111
|
let replicationStarted = false;
|
|
112
|
-
let status = EdgeStatus.NOT_CONNECTED;
|
|
112
|
+
let status = EdgeStatus.ConnectionState.NOT_CONNECTED;
|
|
113
113
|
const listeners: Array<() => void> = [];
|
|
114
114
|
const setup = await setupIdentity({
|
|
115
115
|
edgeConnection: {
|
|
116
116
|
statusChanged: new Event(),
|
|
117
117
|
get status() {
|
|
118
|
-
return status;
|
|
118
|
+
return { state: status };
|
|
119
119
|
},
|
|
120
120
|
onReconnected: (listener) => {
|
|
121
|
-
if (status === EdgeStatus.CONNECTED) {
|
|
121
|
+
if (status === EdgeStatus.ConnectionState.CONNECTED) {
|
|
122
122
|
listener();
|
|
123
123
|
} else {
|
|
124
124
|
listeners.push(listener);
|
|
@@ -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,
|
|
@@ -138,7 +138,7 @@ describe('identity/identity', () => {
|
|
|
138
138
|
|
|
139
139
|
await writeGenesisCredential(setup);
|
|
140
140
|
listeners.forEach((callback) => callback());
|
|
141
|
-
status = EdgeStatus.CONNECTED;
|
|
141
|
+
status = EdgeStatus.ConnectionState.CONNECTED;
|
|
142
142
|
|
|
143
143
|
await expect.poll(() => replicationStarted).toBeTruthy();
|
|
144
144
|
});
|
|
@@ -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
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@trace.span()
|
|
120
|
-
async open(ctx: Context): Promise<void> {
|
|
107
|
+
@trace.span({ op: 'lifecycle' })
|
|
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
|
-
@trace.span()
|
|
137
|
-
async close(ctx:
|
|
123
|
+
@trace.span({ op: 'lifecycle' })
|
|
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,
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Context } from '@dxos/context';
|
|
5
6
|
import { getCredentialAssertion } from '@dxos/credentials';
|
|
6
7
|
import { invariant } from '@dxos/invariant';
|
|
7
8
|
import { type Keyring } from '@dxos/keyring';
|
|
8
9
|
import { type PublicKey } from '@dxos/keys';
|
|
9
|
-
import { AlreadyJoinedError
|
|
10
|
+
import { AlreadyJoinedError } from '@dxos/protocols';
|
|
10
11
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
12
|
import type { DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
12
13
|
import {
|
|
@@ -15,15 +16,14 @@ import {
|
|
|
15
16
|
type IntroductionRequest,
|
|
16
17
|
} from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
17
18
|
|
|
18
|
-
import { type Identity, type
|
|
19
|
-
|
|
19
|
+
import { type Identity, type JoinIdentityProps } from '../identity';
|
|
20
20
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
21
21
|
|
|
22
22
|
export class DeviceInvitationProtocol implements InvitationProtocol {
|
|
23
23
|
constructor(
|
|
24
24
|
private readonly _keyring: Keyring,
|
|
25
25
|
private readonly _getIdentity: () => Identity,
|
|
26
|
-
private readonly _acceptIdentity: (identity:
|
|
26
|
+
private readonly _acceptIdentity: (identity: JoinIdentityProps) => Promise<Identity>,
|
|
27
27
|
) {}
|
|
28
28
|
|
|
29
29
|
toJSON(): object {
|
|
@@ -32,7 +32,7 @@ export class DeviceInvitationProtocol implements InvitationProtocol {
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
checkCanInviteNewMembers():
|
|
35
|
+
checkCanInviteNewMembers(): Error | undefined {
|
|
36
36
|
return undefined;
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -71,7 +71,7 @@ export class DeviceInvitationProtocol implements InvitationProtocol {
|
|
|
71
71
|
try {
|
|
72
72
|
const identity = this._getIdentity();
|
|
73
73
|
if (identity) {
|
|
74
|
-
return new AlreadyJoinedError('Currently only one identity per client is supported.');
|
|
74
|
+
return new AlreadyJoinedError({ message: 'Currently only one identity per client is supported.' });
|
|
75
75
|
}
|
|
76
76
|
} catch {
|
|
77
77
|
// No identity.
|
|
@@ -97,7 +97,7 @@ export class DeviceInvitationProtocol implements InvitationProtocol {
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
async accept(response: AdmissionResponse, request: AdmissionRequest): Promise<Partial<Invitation>> {
|
|
100
|
+
async accept(_ctx: Context, response: AdmissionResponse, request: AdmissionRequest): Promise<Partial<Invitation>> {
|
|
101
101
|
invariant(response.device);
|
|
102
102
|
const { identityKey, haloSpaceKey, genesisFeedKey, controlTimeframe } = response.device;
|
|
103
103
|
|
|
@@ -105,6 +105,7 @@ export class DeviceInvitationProtocol implements InvitationProtocol {
|
|
|
105
105
|
const { deviceKey, controlFeedKey, dataFeedKey, profile } = request.device;
|
|
106
106
|
|
|
107
107
|
// TODO(wittjosiah): When multiple identities are supported, verify identity doesn't already exist before accepting.
|
|
108
|
+
// ctx is unused here because _acceptIdentity uses ServiceContext's lifecycle ctx internally.
|
|
108
109
|
|
|
109
110
|
await this._acceptIdentity({
|
|
110
111
|
identityKey,
|
|
@@ -23,13 +23,14 @@ import {
|
|
|
23
23
|
type AdmissionResponse,
|
|
24
24
|
type SpaceAdmissionRequest,
|
|
25
25
|
} from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
26
|
+
import { trace } from '@dxos/tracing';
|
|
26
27
|
|
|
27
28
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
28
29
|
import { type FlowLockHolder, type GuardedInvitationState } from './invitation-state';
|
|
29
30
|
import { tryAcquireBeforeContextDisposed } from './utils';
|
|
30
31
|
|
|
31
32
|
export interface EdgeInvitationHandlerCallbacks {
|
|
32
|
-
onInvitationSuccess(response: AdmissionResponse, request: AdmissionRequest): Promise<void>;
|
|
33
|
+
onInvitationSuccess(ctx: Context, response: AdmissionResponse, request: AdmissionRequest): Promise<void>;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export const MAX_RETRIES_PER_INVITATION = 5;
|
|
@@ -41,6 +42,7 @@ export type EdgeInvitationConfig = {
|
|
|
41
42
|
retryJitter?: number;
|
|
42
43
|
};
|
|
43
44
|
|
|
45
|
+
@trace.resource()
|
|
44
46
|
export class EdgeInvitationHandler implements FlowLockHolder {
|
|
45
47
|
private _flowLock: MutexGuard | undefined;
|
|
46
48
|
|
|
@@ -113,6 +115,7 @@ export class EdgeInvitationHandler implements FlowLockHolder {
|
|
|
113
115
|
scheduleMicroTask(ctx, tryHandleInvitation);
|
|
114
116
|
}
|
|
115
117
|
|
|
118
|
+
@trace.span({ op: 'invitation.edge' })
|
|
116
119
|
private async _handleSpaceInvitationFlow(
|
|
117
120
|
ctx: Context,
|
|
118
121
|
guardedState: GuardedInvitationState,
|
|
@@ -126,13 +129,13 @@ export class EdgeInvitationHandler implements FlowLockHolder {
|
|
|
126
129
|
|
|
127
130
|
guardedState.set(this, Invitation.State.CONNECTING);
|
|
128
131
|
|
|
129
|
-
const response = await this._joinSpaceByInvitation(guardedState, spaceId, {
|
|
132
|
+
const response = await this._joinSpaceByInvitation(ctx, guardedState, spaceId, {
|
|
130
133
|
identityKey: admissionRequest.identityKey.toHex(),
|
|
131
134
|
invitationId: guardedState.current.invitationId,
|
|
132
135
|
});
|
|
133
136
|
|
|
134
137
|
const admissionResponse = await this._mapToAdmissionResponse(response);
|
|
135
|
-
await this._callbacks.onInvitationSuccess(admissionResponse, { space: admissionRequest });
|
|
138
|
+
await this._callbacks.onInvitationSuccess(ctx, admissionResponse, { space: admissionRequest });
|
|
136
139
|
} catch (error) {
|
|
137
140
|
guardedState.set(this, Invitation.State.ERROR);
|
|
138
141
|
throw error;
|
|
@@ -153,13 +156,14 @@ export class EdgeInvitationHandler implements FlowLockHolder {
|
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
private async _joinSpaceByInvitation(
|
|
159
|
+
ctx: Context,
|
|
156
160
|
guardedState: GuardedInvitationState,
|
|
157
161
|
spaceId: SpaceId,
|
|
158
162
|
request: JoinSpaceRequest,
|
|
159
163
|
): Promise<JoinSpaceResponseBody> {
|
|
160
164
|
invariant(this._client);
|
|
161
165
|
try {
|
|
162
|
-
return await this._client.joinSpaceByInvitation(spaceId, request);
|
|
166
|
+
return await this._client.joinSpaceByInvitation(ctx, spaceId, request);
|
|
163
167
|
} catch (error: any) {
|
|
164
168
|
if (error instanceof EdgeAuthChallengeError) {
|
|
165
169
|
const publicKey = guardedState.current.guestKeypair?.publicKey;
|
|
@@ -168,7 +172,7 @@ export class EdgeInvitationHandler implements FlowLockHolder {
|
|
|
168
172
|
throw error;
|
|
169
173
|
}
|
|
170
174
|
const signature = sign(Buffer.from(error.challenge, 'base64'), privateKey);
|
|
171
|
-
return this._client.joinSpaceByInvitation(spaceId, {
|
|
175
|
+
return this._client.joinSpaceByInvitation(ctx, spaceId, {
|
|
172
176
|
...request,
|
|
173
177
|
signature: Buffer.from(signature).toString('base64'),
|
|
174
178
|
});
|
|
@@ -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
|
|