@dxos/client-services 0.7.4 → 0.7.5-labs.071a3e2
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-423GRVVV.mjs → chunk-SKOL3Q2R.mjs} +379 -267
- package/dist/lib/browser/chunk-SKOL3Q2R.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +1 -1
- package/dist/lib/node/{chunk-ZS24HRVA.cjs → chunk-XTM3FUCM.cjs} +405 -293
- package/dist/lib/node/chunk-XTM3FUCM.cjs.map +7 -0
- package/dist/lib/node/index.cjs +47 -47
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +8 -8
- package/dist/lib/node-esm/{chunk-OQOXRHWF.mjs → chunk-EQU6BG5J.mjs} +379 -267
- package/dist/lib/node-esm/chunk-EQU6BG5J.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1 -1
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +1 -1
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts +1 -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 +1 -1
- package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/keys.d.ts +1 -1
- package/dist/types/src/packlets/devtools/keys.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/metadata.d.ts +1 -1
- package/dist/types/src/packlets/devtools/metadata.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/spaces.d.ts +1 -1
- package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts +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 +0 -3
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +12 -4
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +9 -4
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +3 -1
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/utils.d.ts +1 -0
- package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts +9 -2
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +3 -0
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.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/version.d.ts +1 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +38 -38
- package/src/packlets/agents/edge-agent-service.ts +1 -1
- package/src/packlets/devices/devices-service.ts +1 -1
- package/src/packlets/devtools/devtools.ts +1 -1
- package/src/packlets/devtools/feeds.ts +1 -1
- package/src/packlets/devtools/keys.ts +1 -1
- package/src/packlets/devtools/metadata.ts +1 -1
- package/src/packlets/devtools/network.ts +1 -1
- package/src/packlets/devtools/spaces.ts +1 -1
- package/src/packlets/diagnostics/diagnostics.ts +17 -13
- package/src/packlets/identity/contacts-service.ts +1 -1
- package/src/packlets/identity/identity-manager.ts +3 -29
- package/src/packlets/identity/identity-recovery-manager.ts +86 -9
- package/src/packlets/identity/identity-service.ts +17 -4
- package/src/packlets/identity/identity.test.ts +2 -1
- package/src/packlets/identity/identity.ts +4 -1
- package/src/packlets/invitations/invitations-handler.ts +15 -6
- package/src/packlets/invitations/invitations-manager.ts +1 -1
- package/src/packlets/invitations/invitations-service.ts +1 -1
- package/src/packlets/invitations/space-invitation-protocol.ts +2 -3
- package/src/packlets/invitations/utils.ts +7 -0
- package/src/packlets/logging/logging-service.ts +1 -1
- package/src/packlets/network/network-service.ts +39 -1
- package/src/packlets/services/service-context.ts +3 -1
- package/src/packlets/spaces/data-space-manager.ts +1 -1
- package/src/packlets/spaces/edge-feed-replicator.ts +16 -10
- package/src/packlets/spaces/notarization-plugin.ts +32 -17
- package/src/packlets/spaces/spaces-service.ts +31 -21
- package/src/packlets/system/system-service.ts +1 -1
- package/src/version.ts +1 -5
- package/dist/lib/browser/chunk-423GRVVV.mjs.map +0 -7
- package/dist/lib/node/chunk-ZS24HRVA.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-OQOXRHWF.mjs.map +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/client-services",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5-labs.071a3e2",
|
|
4
4
|
"description": "DXOS client services implementation",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -42,48 +42,48 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"cbor-x": "^1.5.4",
|
|
44
44
|
"platform": "^1.3.6",
|
|
45
|
-
"@dxos/async": "0.7.
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/codec-protobuf": "0.7.
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/credentials": "0.7.
|
|
52
|
-
"@dxos/debug": "0.7.
|
|
53
|
-
"@dxos/crypto": "0.7.
|
|
54
|
-
"@dxos/echo-db": "0.7.
|
|
55
|
-
"@dxos/echo-pipeline": "0.7.
|
|
56
|
-
"@dxos/echo-
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/invariant": "0.7.
|
|
61
|
-
"@dxos/keyring": "0.7.
|
|
62
|
-
"@dxos/
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/lock-file": "0.7.
|
|
66
|
-
"@dxos/log": "0.7.
|
|
67
|
-
"@dxos/
|
|
68
|
-
"@dxos/node-std": "0.7.
|
|
69
|
-
"@dxos/protocols": "0.7.
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/teleport": "0.7.
|
|
74
|
-
"@dxos/teleport-extension-gossip": "0.7.
|
|
75
|
-
"@dxos/teleport-extension-object-sync": "0.7.
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
45
|
+
"@dxos/async": "0.7.5-labs.071a3e2",
|
|
46
|
+
"@dxos/automerge": "0.7.5-labs.071a3e2",
|
|
47
|
+
"@dxos/client-protocol": "0.7.5-labs.071a3e2",
|
|
48
|
+
"@dxos/codec-protobuf": "0.7.5-labs.071a3e2",
|
|
49
|
+
"@dxos/config": "0.7.5-labs.071a3e2",
|
|
50
|
+
"@dxos/context": "0.7.5-labs.071a3e2",
|
|
51
|
+
"@dxos/credentials": "0.7.5-labs.071a3e2",
|
|
52
|
+
"@dxos/debug": "0.7.5-labs.071a3e2",
|
|
53
|
+
"@dxos/crypto": "0.7.5-labs.071a3e2",
|
|
54
|
+
"@dxos/echo-db": "0.7.5-labs.071a3e2",
|
|
55
|
+
"@dxos/echo-pipeline": "0.7.5-labs.071a3e2",
|
|
56
|
+
"@dxos/echo-protocol": "0.7.5-labs.071a3e2",
|
|
57
|
+
"@dxos/echo-schema": "0.7.5-labs.071a3e2",
|
|
58
|
+
"@dxos/edge-client": "0.7.5-labs.071a3e2",
|
|
59
|
+
"@dxos/feed-store": "0.7.5-labs.071a3e2",
|
|
60
|
+
"@dxos/invariant": "0.7.5-labs.071a3e2",
|
|
61
|
+
"@dxos/keyring": "0.7.5-labs.071a3e2",
|
|
62
|
+
"@dxos/indexing": "0.7.5-labs.071a3e2",
|
|
63
|
+
"@dxos/keys": "0.7.5-labs.071a3e2",
|
|
64
|
+
"@dxos/kv-store": "0.7.5-labs.071a3e2",
|
|
65
|
+
"@dxos/lock-file": "0.7.5-labs.071a3e2",
|
|
66
|
+
"@dxos/log": "0.7.5-labs.071a3e2",
|
|
67
|
+
"@dxos/messaging": "0.7.5-labs.071a3e2",
|
|
68
|
+
"@dxos/node-std": "0.7.5-labs.071a3e2",
|
|
69
|
+
"@dxos/protocols": "0.7.5-labs.071a3e2",
|
|
70
|
+
"@dxos/network-manager": "0.7.5-labs.071a3e2",
|
|
71
|
+
"@dxos/random-access-storage": "0.7.5-labs.071a3e2",
|
|
72
|
+
"@dxos/rpc": "0.7.5-labs.071a3e2",
|
|
73
|
+
"@dxos/teleport": "0.7.5-labs.071a3e2",
|
|
74
|
+
"@dxos/teleport-extension-gossip": "0.7.5-labs.071a3e2",
|
|
75
|
+
"@dxos/teleport-extension-object-sync": "0.7.5-labs.071a3e2",
|
|
76
|
+
"@dxos/timeframe": "0.7.5-labs.071a3e2",
|
|
77
|
+
"@dxos/util": "0.7.5-labs.071a3e2",
|
|
78
|
+
"@dxos/tracing": "0.7.5-labs.071a3e2",
|
|
79
|
+
"@dxos/websocket-rpc": "0.7.5-labs.071a3e2"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@types/platform": "^1.3.4",
|
|
83
83
|
"@types/readable-stream": "^2.3.9",
|
|
84
84
|
"get-port-please": "^3.1.1",
|
|
85
|
-
"@dxos/signal": "0.7.
|
|
86
|
-
"@dxos/test-utils": "0.7.
|
|
85
|
+
"@dxos/signal": "0.7.5-labs.071a3e2",
|
|
86
|
+
"@dxos/test-utils": "0.7.5-labs.071a3e2"
|
|
87
87
|
},
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"access": "public"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { EventSubscriptions } from '@dxos/async';
|
|
6
|
-
import { Stream } from '@dxos/codec-protobuf';
|
|
6
|
+
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
7
7
|
import { type EdgeConnection } from '@dxos/edge-client';
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
9
|
import {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { EventSubscriptions } from '@dxos/async';
|
|
6
|
-
import { Stream } from '@dxos/codec-protobuf';
|
|
6
|
+
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
7
7
|
import { type SpaceManager } from '@dxos/echo-pipeline';
|
|
8
8
|
import { FeedIterator, type FeedStore, type FeedWrapper } from '@dxos/feed-store';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { scheduleTask } from '@dxos/async';
|
|
6
|
-
import { Stream } from '@dxos/codec-protobuf';
|
|
6
|
+
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
7
7
|
import { type Keyring } from '@dxos/keyring';
|
|
8
8
|
import { type SubscribeToKeyringKeysResponse } from '@dxos/protocols/proto/dxos/devtools/host';
|
|
9
9
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Stream } from '@dxos/codec-protobuf';
|
|
5
|
+
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
6
6
|
import { type SubscribeToMetadataResponse } from '@dxos/protocols/proto/dxos/devtools/host';
|
|
7
7
|
|
|
8
8
|
import { type ServiceContext } from '../services';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Stream } from '@dxos/codec-protobuf';
|
|
5
|
+
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
6
6
|
import { Context } from '@dxos/context';
|
|
7
7
|
import { PublicKey } from '@dxos/keys';
|
|
8
8
|
import { type SignalManager } from '@dxos/messaging';
|
|
@@ -6,7 +6,7 @@ import { asyncTimeout } from '@dxos/async';
|
|
|
6
6
|
import { type ClientServices } from '@dxos/client-protocol';
|
|
7
7
|
import { getFirstStreamValue } from '@dxos/codec-protobuf';
|
|
8
8
|
import { type Config, type ConfigProto } from '@dxos/config';
|
|
9
|
-
import { credentialTypeFilter } from '@dxos/credentials';
|
|
9
|
+
import { createDidFromIdentityKey, credentialTypeFilter } from '@dxos/credentials';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
11
|
import { type PublicKey } from '@dxos/keys';
|
|
12
12
|
import { STORAGE_VERSION } from '@dxos/protocols';
|
|
@@ -120,6 +120,7 @@ export const createDiagnostics = async (
|
|
|
120
120
|
if (identity) {
|
|
121
121
|
// Identity.
|
|
122
122
|
diagnostics.identity = {
|
|
123
|
+
did: identity.did,
|
|
123
124
|
identityKey: identity.identityKey,
|
|
124
125
|
spaceKey: identity.space.key,
|
|
125
126
|
profile: identity.profileDocument,
|
|
@@ -179,19 +180,22 @@ const getSpaceStats = async (space: DataSpace): Promise<SpaceStats> => {
|
|
|
179
180
|
id: credential.id,
|
|
180
181
|
})),
|
|
181
182
|
|
|
182
|
-
members:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
183
|
+
members: await Promise.all(
|
|
184
|
+
Array.from(space.inner.spaceState.members.values()).map(async (member) => ({
|
|
185
|
+
role: member.role,
|
|
186
|
+
identity: {
|
|
187
|
+
did: await createDidFromIdentityKey(member.key),
|
|
188
|
+
identityKey: member.key,
|
|
189
|
+
profile: {
|
|
190
|
+
displayName: member.assertion.profile?.displayName,
|
|
191
|
+
},
|
|
188
192
|
},
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
presence:
|
|
194
|
+
space.presence.getPeersOnline().filter(({ identityKey }) => identityKey.equals(member.key)).length > 0
|
|
195
|
+
? SpaceMember.PresenceState.ONLINE
|
|
196
|
+
: SpaceMember.PresenceState.OFFLINE,
|
|
197
|
+
})),
|
|
198
|
+
),
|
|
195
199
|
|
|
196
200
|
pipeline: {
|
|
197
201
|
// TODO(burdon): Pick properties from credentials if needed.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { EventSubscriptions, scheduleTask, UpdateScheduler } from '@dxos/async';
|
|
6
|
-
import { Stream } from '@dxos/codec-protobuf';
|
|
6
|
+
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
7
7
|
import { type MemberInfo } from '@dxos/credentials';
|
|
8
8
|
import { type SpaceManager } from '@dxos/echo-pipeline';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -5,12 +5,7 @@ import platform from 'platform';
|
|
|
5
5
|
|
|
6
6
|
import { Event } from '@dxos/async';
|
|
7
7
|
import { Context } from '@dxos/context';
|
|
8
|
-
import {
|
|
9
|
-
createCredentialSignerWithKey,
|
|
10
|
-
CredentialGenerator,
|
|
11
|
-
generateSeedPhrase,
|
|
12
|
-
keyPairFromSeedPhrase,
|
|
13
|
-
} from '@dxos/credentials';
|
|
8
|
+
import { createCredentialSignerWithKey, createDidFromIdentityKey, CredentialGenerator } from '@dxos/credentials';
|
|
14
9
|
import { type MetadataStore, type SpaceManager, type SwarmIdentity } from '@dxos/echo-pipeline';
|
|
15
10
|
import { type EdgeConnection } from '@dxos/edge-client';
|
|
16
11
|
import { type FeedStore } from '@dxos/feed-store';
|
|
@@ -335,29 +330,6 @@ export class IdentityManager {
|
|
|
335
330
|
};
|
|
336
331
|
}
|
|
337
332
|
|
|
338
|
-
async createRecoveryPhrase() {
|
|
339
|
-
const identity = this._identity;
|
|
340
|
-
invariant(identity);
|
|
341
|
-
|
|
342
|
-
const seedphrase = generateSeedPhrase();
|
|
343
|
-
const keypair = keyPairFromSeedPhrase(seedphrase);
|
|
344
|
-
const recoveryKey = PublicKey.from(keypair.publicKey);
|
|
345
|
-
const identityKey = identity.identityKey;
|
|
346
|
-
const credential = await identity.getIdentityCredentialSigner().createCredential({
|
|
347
|
-
subject: identityKey,
|
|
348
|
-
assertion: {
|
|
349
|
-
'@type': 'dxos.halo.credentials.IdentityRecovery',
|
|
350
|
-
recoveryKey,
|
|
351
|
-
identityKey,
|
|
352
|
-
},
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
const receipt = await identity.controlPipeline.writer.write({ credential: { credential } });
|
|
356
|
-
await identity.controlPipeline.state.waitUntilTimeframe(new Timeframe([[receipt.feedKey, receipt.seq]]));
|
|
357
|
-
|
|
358
|
-
return { seedphrase };
|
|
359
|
-
}
|
|
360
|
-
|
|
361
333
|
private async _constructIdentity(identityRecord: IdentityRecord) {
|
|
362
334
|
invariant(!this._identity);
|
|
363
335
|
log('constructing identity', { identityRecord });
|
|
@@ -397,10 +369,12 @@ export class IdentityManager {
|
|
|
397
369
|
await space.setControlFeed(controlFeed);
|
|
398
370
|
await space.setDataFeed(dataFeed);
|
|
399
371
|
|
|
372
|
+
const did = await createDidFromIdentityKey(identityRecord.identityKey);
|
|
400
373
|
const identity: Identity = new Identity({
|
|
401
374
|
space,
|
|
402
375
|
presence,
|
|
403
376
|
signer: this._keyring,
|
|
377
|
+
did,
|
|
404
378
|
identityKey: identityRecord.identityKey,
|
|
405
379
|
deviceKey: identityRecord.deviceKey,
|
|
406
380
|
edgeConnection: this._edgeConnection,
|
|
@@ -9,8 +9,16 @@ import { invariant } from '@dxos/invariant';
|
|
|
9
9
|
import { type Keyring } from '@dxos/keyring';
|
|
10
10
|
import { PublicKey } from '@dxos/keys';
|
|
11
11
|
import { log } from '@dxos/log';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
EdgeAuthChallengeError,
|
|
14
|
+
type RecoverIdentityRequest as EdgeRecoverIdentityRequest,
|
|
15
|
+
type RecoverIdentityResponseBody,
|
|
16
|
+
} from '@dxos/protocols';
|
|
13
17
|
import { schema } from '@dxos/protocols/proto';
|
|
18
|
+
import {
|
|
19
|
+
type CreateRecoveryCredentialRequest,
|
|
20
|
+
type RecoverIdentityRequest,
|
|
21
|
+
} from '@dxos/protocols/proto/dxos/client/services';
|
|
14
22
|
import { Timeframe } from '@dxos/timeframe';
|
|
15
23
|
|
|
16
24
|
import { type Identity } from './identity';
|
|
@@ -24,13 +32,19 @@ export class EdgeIdentityRecoveryManager {
|
|
|
24
32
|
private readonly _acceptRecoveredIdentity: (params: JoinIdentityParams) => Promise<Identity>,
|
|
25
33
|
) {}
|
|
26
34
|
|
|
27
|
-
public async
|
|
35
|
+
public async createRecoveryCredential({ recoveryKey, algorithm }: CreateRecoveryCredentialRequest) {
|
|
28
36
|
const identity = this._identityProvider();
|
|
29
37
|
invariant(identity);
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
let recoveryCode: string | undefined;
|
|
40
|
+
if (!recoveryKey) {
|
|
41
|
+
recoveryCode = generateSeedPhrase();
|
|
42
|
+
const keypair = keyPairFromSeedPhrase(recoveryCode);
|
|
43
|
+
recoveryKey = PublicKey.from(keypair.publicKey);
|
|
44
|
+
algorithm = -8; // Ed25519
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
invariant(algorithm, 'Algorithm is required.');
|
|
34
48
|
const identityKey = identity.identityKey;
|
|
35
49
|
const credential = await identity.getIdentityCredentialSigner().createCredential({
|
|
36
50
|
subject: identityKey,
|
|
@@ -38,23 +52,86 @@ export class EdgeIdentityRecoveryManager {
|
|
|
38
52
|
'@type': 'dxos.halo.credentials.IdentityRecovery',
|
|
39
53
|
recoveryKey,
|
|
40
54
|
identityKey,
|
|
55
|
+
algorithm,
|
|
41
56
|
},
|
|
42
57
|
});
|
|
43
58
|
|
|
44
59
|
const receipt = await identity.controlPipeline.writer.write({ credential: { credential } });
|
|
45
60
|
await identity.controlPipeline.state.waitUntilTimeframe(new Timeframe([[receipt.feedKey, receipt.seq]]));
|
|
46
61
|
|
|
47
|
-
return {
|
|
62
|
+
return { recoveryCode };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async requestRecoveryChallenge() {
|
|
66
|
+
invariant(this._edgeClient, 'Not connected to EDGE.');
|
|
67
|
+
|
|
68
|
+
const deviceKey = await this._keyring.createKey();
|
|
69
|
+
const controlFeedKey = await this._keyring.createKey();
|
|
70
|
+
const request: EdgeRecoverIdentityRequest = {
|
|
71
|
+
deviceKey: deviceKey.toHex(),
|
|
72
|
+
controlFeedKey: controlFeedKey.toHex(),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
await this._edgeClient.recoverIdentity(request);
|
|
77
|
+
throw new Error('No challenge received.');
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
if (!(error instanceof EdgeAuthChallengeError)) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
deviceKey,
|
|
84
|
+
controlFeedKey,
|
|
85
|
+
challenge: error.challenge,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public async recoverIdentityWithExternalSignature({
|
|
91
|
+
identityDid,
|
|
92
|
+
deviceKey,
|
|
93
|
+
controlFeedKey,
|
|
94
|
+
signature,
|
|
95
|
+
clientDataJson,
|
|
96
|
+
authenticatorData,
|
|
97
|
+
}: RecoverIdentityRequest.ExternalSignature) {
|
|
98
|
+
invariant(this._edgeClient, 'Not connected to EDGE.');
|
|
99
|
+
|
|
100
|
+
const request: EdgeRecoverIdentityRequest = {
|
|
101
|
+
identityDid,
|
|
102
|
+
deviceKey: deviceKey.toHex(),
|
|
103
|
+
controlFeedKey: controlFeedKey.toHex(),
|
|
104
|
+
signature:
|
|
105
|
+
clientDataJson && authenticatorData
|
|
106
|
+
? {
|
|
107
|
+
signature: Buffer.from(signature).toString('base64'),
|
|
108
|
+
clientDataJson: Buffer.from(clientDataJson).toString('base64'),
|
|
109
|
+
authenticatorData: Buffer.from(authenticatorData).toString('base64'),
|
|
110
|
+
}
|
|
111
|
+
: Buffer.from(signature).toString('base64'),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const response = await this._edgeClient.recoverIdentity(request);
|
|
115
|
+
|
|
116
|
+
await this._acceptRecoveredIdentity({
|
|
117
|
+
authorizedDeviceCredential: decodeCredential(response.deviceAuthCredential),
|
|
118
|
+
haloGenesisFeedKey: PublicKey.fromHex(response.genesisFeedKey),
|
|
119
|
+
haloSpaceKey: PublicKey.fromHex(response.haloSpaceKey),
|
|
120
|
+
identityKey: PublicKey.fromHex(response.identityKey),
|
|
121
|
+
deviceKey,
|
|
122
|
+
controlFeedKey,
|
|
123
|
+
dataFeedKey: await this._keyring.createKey(),
|
|
124
|
+
});
|
|
48
125
|
}
|
|
49
126
|
|
|
50
|
-
public async recoverIdentity(
|
|
127
|
+
public async recoverIdentity({ recoveryCode }: { recoveryCode: string }) {
|
|
51
128
|
invariant(this._edgeClient, 'Not connected to EDGE.');
|
|
52
129
|
|
|
53
|
-
const recoveryKeypair = keyPairFromSeedPhrase(
|
|
130
|
+
const recoveryKeypair = keyPairFromSeedPhrase(recoveryCode);
|
|
54
131
|
const recoveryKey = PublicKey.from(recoveryKeypair.publicKey);
|
|
55
132
|
const deviceKey = await this._keyring.createKey();
|
|
56
133
|
const controlFeedKey = await this._keyring.createKey();
|
|
57
|
-
const request:
|
|
134
|
+
const request: EdgeRecoverIdentityRequest = {
|
|
58
135
|
recoveryKey: recoveryKey.toHex(),
|
|
59
136
|
deviceKey: deviceKey.toHex(),
|
|
60
137
|
controlFeedKey: controlFeedKey.toHex(),
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Trigger, sleep } from '@dxos/async';
|
|
6
|
-
import { Stream } from '@dxos/codec-protobuf';
|
|
6
|
+
import { Stream } from '@dxos/codec-protobuf/stream';
|
|
7
7
|
import { Resource } from '@dxos/context';
|
|
8
8
|
import { createCredential, signPresentation } from '@dxos/credentials';
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
@@ -11,6 +11,7 @@ import { type Keyring } from '@dxos/keyring';
|
|
|
11
11
|
import { log } from '@dxos/log';
|
|
12
12
|
import {
|
|
13
13
|
type CreateIdentityRequest,
|
|
14
|
+
type CreateRecoveryCredentialRequest,
|
|
14
15
|
type Identity as IdentityProto,
|
|
15
16
|
type IdentityService,
|
|
16
17
|
type QueryIdentityResponse,
|
|
@@ -76,6 +77,7 @@ export class IdentityServiceImpl extends Resource implements IdentityService {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
return {
|
|
80
|
+
did: this._identityManager.identity.did,
|
|
79
81
|
identityKey: this._identityManager.identity.identityKey,
|
|
80
82
|
spaceKey: this._identityManager.identity.space.key,
|
|
81
83
|
profile: this._identityManager.identity.profileDocument,
|
|
@@ -89,12 +91,23 @@ export class IdentityServiceImpl extends Resource implements IdentityService {
|
|
|
89
91
|
return this._getIdentity()!;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
async
|
|
93
|
-
return this._recoveryManager.
|
|
94
|
+
async createRecoveryCredential(request: CreateRecoveryCredentialRequest) {
|
|
95
|
+
return this._recoveryManager.createRecoveryCredential(request);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async requestRecoveryChallenge() {
|
|
99
|
+
return this._recoveryManager.requestRecoveryChallenge();
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
async recoverIdentity(request: RecoverIdentityRequest): Promise<IdentityProto> {
|
|
97
|
-
|
|
103
|
+
if (request.recoveryCode) {
|
|
104
|
+
await this._recoveryManager.recoverIdentity({ recoveryCode: request.recoveryCode });
|
|
105
|
+
} else if (request.external) {
|
|
106
|
+
await this._recoveryManager.recoverIdentityWithExternalSignature(request.external);
|
|
107
|
+
} else {
|
|
108
|
+
throw new Error('Invalid request.');
|
|
109
|
+
}
|
|
110
|
+
|
|
98
111
|
return this._getIdentity()!;
|
|
99
112
|
}
|
|
100
113
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { onTestFinished, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Context } from '@dxos/context';
|
|
8
|
-
import { CredentialGenerator, verifyCredential } from '@dxos/credentials';
|
|
8
|
+
import { createDidFromIdentityKey, CredentialGenerator, verifyCredential } from '@dxos/credentials';
|
|
9
9
|
import {
|
|
10
10
|
createIdFromSpaceKey,
|
|
11
11
|
MetadataStore,
|
|
@@ -206,6 +206,7 @@ describe('identity/identity', () => {
|
|
|
206
206
|
|
|
207
207
|
const identity = new Identity({
|
|
208
208
|
signer: keyring,
|
|
209
|
+
did: await createDidFromIdentityKey(identityKey),
|
|
209
210
|
identityKey,
|
|
210
211
|
deviceKey,
|
|
211
212
|
space,
|
|
@@ -17,7 +17,7 @@ import { type Space } from '@dxos/echo-pipeline';
|
|
|
17
17
|
import { type EdgeConnection } from '@dxos/edge-client';
|
|
18
18
|
import { writeMessages, type FeedWrapper } from '@dxos/feed-store';
|
|
19
19
|
import { invariant } from '@dxos/invariant';
|
|
20
|
-
import { PublicKey, type SpaceId } from '@dxos/keys';
|
|
20
|
+
import { type IdentityDid, PublicKey, type SpaceId } 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';
|
|
@@ -38,6 +38,7 @@ import { DefaultSpaceStateMachine } from './default-space-state-machine';
|
|
|
38
38
|
import { EdgeFeedReplicator } from '../spaces';
|
|
39
39
|
|
|
40
40
|
export type IdentityParams = {
|
|
41
|
+
did: IdentityDid;
|
|
41
42
|
identityKey: PublicKey;
|
|
42
43
|
deviceKey: PublicKey;
|
|
43
44
|
signer: Signer;
|
|
@@ -63,6 +64,7 @@ export class Identity {
|
|
|
63
64
|
|
|
64
65
|
public readonly authVerifier: TrustedKeySetAuthVerifier;
|
|
65
66
|
|
|
67
|
+
public readonly did: IdentityDid;
|
|
66
68
|
public readonly identityKey: PublicKey;
|
|
67
69
|
public readonly deviceKey: PublicKey;
|
|
68
70
|
|
|
@@ -73,6 +75,7 @@ export class Identity {
|
|
|
73
75
|
this._signer = params.signer;
|
|
74
76
|
this._presence = params.presence;
|
|
75
77
|
|
|
78
|
+
this.did = params.did;
|
|
76
79
|
this.identityKey = params.identityKey;
|
|
77
80
|
this.deviceKey = params.deviceKey;
|
|
78
81
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type PushStream, scheduleTask, TimeoutError, type Trigger } from '@dxos/async';
|
|
6
|
-
import { INVITATION_TIMEOUT } from '@dxos/client-protocol';
|
|
6
|
+
import { INVITATION_TIMEOUT, getExpirationTime } from '@dxos/client-protocol';
|
|
7
7
|
import { type Context, ContextDisposedError } from '@dxos/context';
|
|
8
8
|
import { createKeyPair, sign } from '@dxos/crypto';
|
|
9
9
|
import { type EdgeHttpClient } from '@dxos/edge-client';
|
|
@@ -11,7 +11,7 @@ import { invariant } from '@dxos/invariant';
|
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
12
|
import { log } from '@dxos/log';
|
|
13
13
|
import { createTeleportProtocolFactory, type SwarmNetworkManager, type SwarmConnection } from '@dxos/network-manager';
|
|
14
|
-
import { InvalidInvitationExtensionRoleError, trace } from '@dxos/protocols';
|
|
14
|
+
import { InvalidInvitationError, InvalidInvitationExtensionRoleError, trace } from '@dxos/protocols';
|
|
15
15
|
import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
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';
|
|
@@ -188,8 +188,9 @@ export class InvitationsHandler {
|
|
|
188
188
|
return extension;
|
|
189
189
|
};
|
|
190
190
|
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
const expiresOn = getExpirationTime(invitation);
|
|
192
|
+
if (expiresOn) {
|
|
193
|
+
if (expiresOn.getTime() < Date.now()) {
|
|
193
194
|
log.warn('invitation has already expired');
|
|
194
195
|
guardedState.set(null, Invitation.State.EXPIRED);
|
|
195
196
|
void ctx.dispose().catch((err) => log.catch(err));
|
|
@@ -204,7 +205,7 @@ export class InvitationsHandler {
|
|
|
204
205
|
metrics.increment('dxos.invitation.expired');
|
|
205
206
|
await ctx.dispose();
|
|
206
207
|
},
|
|
207
|
-
|
|
208
|
+
expiresOn.getTime() - Date.now(),
|
|
208
209
|
);
|
|
209
210
|
}
|
|
210
211
|
|
|
@@ -397,7 +398,7 @@ export class InvitationsHandler {
|
|
|
397
398
|
edgeInvitationHandler.handle(ctx, guardedState, protocol, deviceProfile);
|
|
398
399
|
|
|
399
400
|
scheduleTask(ctx, async () => {
|
|
400
|
-
const error =
|
|
401
|
+
const error = checkInvitation(protocol, invitation);
|
|
401
402
|
if (error) {
|
|
402
403
|
stream.error(error);
|
|
403
404
|
await ctx.dispose();
|
|
@@ -499,6 +500,14 @@ export class InvitationsHandler {
|
|
|
499
500
|
}
|
|
500
501
|
}
|
|
501
502
|
|
|
503
|
+
const checkInvitation = (protocol: InvitationProtocol, invitation: Partial<Invitation>) => {
|
|
504
|
+
const expiresOn = getExpirationTime(invitation);
|
|
505
|
+
if (expiresOn && expiresOn.getTime() < Date.now()) {
|
|
506
|
+
return new InvalidInvitationError('Invitation already expired.');
|
|
507
|
+
}
|
|
508
|
+
return protocol.checkInvitation(invitation);
|
|
509
|
+
};
|
|
510
|
+
|
|
502
511
|
export const createAdmissionKeypair = (): AdmissionKeypair => {
|
|
503
512
|
const keypair = createKeyPair();
|
|
504
513
|
return { publicKey: PublicKey.from(keypair.publicKey), privateKey: keypair.secretKey };
|
|
@@ -202,7 +202,7 @@ export class InvitationsManager {
|
|
|
202
202
|
created = new Date(),
|
|
203
203
|
guestKeypair = undefined,
|
|
204
204
|
role = SpaceMember.Role.ADMIN,
|
|
205
|
-
lifetime = 86400, //
|
|
205
|
+
lifetime = 86400 * 7, // 7 days,
|
|
206
206
|
multiUse = false,
|
|
207
207
|
...options
|
|
208
208
|
} = _options ?? {};
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
} from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
29
29
|
|
|
30
30
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
31
|
+
import { computeExpirationTime } from './utils';
|
|
31
32
|
import { type DataSpaceManager, type SigningContext } from '../spaces';
|
|
32
33
|
|
|
33
34
|
export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
@@ -113,9 +114,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
113
114
|
authMethod: invitation.authMethod,
|
|
114
115
|
swarmKey: invitation.swarmKey,
|
|
115
116
|
role: invitation.role ?? SpaceMember.Role.ADMIN,
|
|
116
|
-
expiresOn: invitation
|
|
117
|
-
? new Date((invitation.created?.getTime() ?? Date.now()) + invitation.lifetime)
|
|
118
|
-
: undefined,
|
|
117
|
+
expiresOn: computeExpirationTime(invitation),
|
|
119
118
|
multiUse: invitation.multiUse ?? false,
|
|
120
119
|
guestKey:
|
|
121
120
|
invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY
|
|
@@ -10,6 +10,13 @@ export const stateToString = (state: Invitation.State): string => {
|
|
|
10
10
|
return Object.entries(Invitation.State).find(([key, val]) => val === state)?.[0] ?? 'unknown';
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
export const computeExpirationTime = (invitation: Partial<Invitation>): Date | undefined => {
|
|
14
|
+
if (!invitation.lifetime) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
return new Date((invitation.created?.getTime() ?? Date.now()) + invitation.lifetime * 1000);
|
|
18
|
+
};
|
|
19
|
+
|
|
13
20
|
export const tryAcquireBeforeContextDisposed = async (ctx: Context, mutex: Mutex): Promise<MutexGuard> => {
|
|
14
21
|
let guard: MutexGuard | undefined;
|
|
15
22
|
return cancelWithContext(
|