@dxos/client-services 0.6.11 → 0.6.12-main.568932b
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-QYVLLBAA.mjs → chunk-AHZ7ASHC.mjs} +5619 -5143
- package/dist/lib/browser/chunk-AHZ7ASHC.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +3 -3
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +5 -6
- package/dist/lib/browser/testing/index.mjs.map +2 -2
- package/dist/lib/node/{chunk-F7G2TXVG.cjs → chunk-YJWFC43Y.cjs} +5391 -4915
- package/dist/lib/node/chunk-YJWFC43Y.cjs.map +7 -0
- package/dist/lib/node/index.cjs +46 -46
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +11 -12
- package/dist/lib/node/testing/index.cjs.map +2 -2
- package/dist/lib/node-esm/chunk-7ADUGZEP.mjs +8192 -0
- package/dist/lib/node-esm/chunk-7ADUGZEP.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +416 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/testing/index.mjs +418 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.node.test.d.ts +2 -0
- package/dist/types/src/packlets/identity/authenticator.node.test.d.ts.map +1 -0
- 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 +19 -7
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +8 -1
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +7 -6
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +1 -0
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +6 -3
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +4 -3
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +3 -0
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts +2 -0
- package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/epoch-migrations.d.ts +1 -1
- package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +31 -6
- 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/storage/storage.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +1 -2
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/testing/setup.d.ts +3 -0
- package/dist/types/src/testing/setup.d.ts.map +1 -0
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/package.json +43 -39
- package/src/packlets/devices/devices-service.test.ts +4 -5
- package/src/packlets/diagnostics/diagnostics-broadcast.ts +1 -0
- package/src/packlets/identity/{authenticator.test.ts → authenticator.node.test.ts} +2 -3
- package/src/packlets/identity/authenticator.ts +5 -2
- package/src/packlets/identity/contacts-service.ts +1 -1
- package/src/packlets/identity/identity-manager.test.ts +5 -6
- package/src/packlets/identity/identity-manager.ts +35 -19
- package/src/packlets/identity/identity-service.test.ts +4 -8
- package/src/packlets/identity/identity.test.ts +128 -239
- package/src/packlets/identity/identity.ts +42 -8
- package/src/packlets/invitations/device-invitation-protocol.test.ts +7 -4
- package/src/packlets/invitations/invitation-host-extension.ts +0 -3
- package/src/packlets/invitations/invitations-handler.test.ts +14 -7
- package/src/packlets/invitations/invitations-handler.ts +1 -1
- package/src/packlets/invitations/space-invitation-protocol.test.ts +4 -3
- package/src/packlets/logging/logging.test.ts +1 -2
- package/src/packlets/network/network-service.test.ts +2 -3
- package/src/packlets/services/service-context.test.ts +3 -1
- package/src/packlets/services/service-context.ts +64 -28
- package/src/packlets/services/service-host.test.ts +8 -12
- package/src/packlets/services/service-host.ts +8 -6
- package/src/packlets/services/service-registry.test.ts +1 -2
- package/src/packlets/spaces/data-space-manager.test.ts +2 -2
- package/src/packlets/spaces/data-space-manager.ts +38 -5
- package/src/packlets/spaces/data-space.ts +34 -6
- package/src/packlets/spaces/edge-feed-replicator.test.ts +251 -0
- package/src/packlets/spaces/edge-feed-replicator.ts +80 -22
- package/src/packlets/spaces/epoch-migrations.ts +2 -2
- package/src/packlets/spaces/notarization-plugin.test.ts +10 -7
- package/src/packlets/spaces/notarization-plugin.ts +169 -29
- package/src/packlets/spaces/spaces-service.test.ts +5 -9
- package/src/packlets/spaces/spaces-service.ts +6 -1
- package/src/packlets/storage/storage.ts +0 -1
- package/src/packlets/system/system-service.test.ts +1 -2
- package/src/packlets/testing/test-builder.ts +2 -3
- package/src/packlets/worker/worker-runtime.ts +2 -2
- package/src/testing/setup.ts +11 -0
- package/src/version.ts +1 -5
- package/dist/lib/browser/chunk-QYVLLBAA.mjs.map +0 -7
- package/dist/lib/node/chunk-F7G2TXVG.cjs.map +0 -7
- package/dist/types/src/packlets/identity/authenticator.test.d.ts +0 -2
- package/dist/types/src/packlets/identity/authenticator.test.d.ts.map +0 -1
- package/dist/types/src/packlets/services/automerge-host.test.d.ts +0 -2
- package/dist/types/src/packlets/services/automerge-host.test.d.ts.map +0 -1
- package/src/packlets/services/automerge-host.test.ts +0 -60
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import expect from '
|
|
5
|
+
import { describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Event } from '@dxos/async';
|
|
8
8
|
import { createCredentialSignerWithKey } from '@dxos/credentials';
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
10
|
import { Keyring } from '@dxos/keyring';
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
|
-
import { describe, test } from '@dxos/test';
|
|
13
12
|
import { ComplexSet } from '@dxos/util';
|
|
14
13
|
|
|
15
14
|
import { createAuthProvider, TrustedKeySetAuthVerifier } from './authenticator';
|
|
@@ -30,5 +29,5 @@ describe('identity/authenticator', () => {
|
|
|
30
29
|
const credential = await authProvider(nonce);
|
|
31
30
|
invariant(credential);
|
|
32
31
|
expect(await authVerifier.verifier(nonce, credential)).toBeTruthy();
|
|
33
|
-
})
|
|
32
|
+
});
|
|
34
33
|
});
|
|
@@ -67,7 +67,7 @@ export class TrustedKeySetAuthVerifier {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
if (this._isTrustedKey(credential.issuer)) {
|
|
70
|
-
log('key is
|
|
70
|
+
log('key is trusted -- auth success', { key: credential.issuer });
|
|
71
71
|
return true;
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -81,7 +81,10 @@ export class TrustedKeySetAuthVerifier {
|
|
|
81
81
|
log('auth success', { key: credential.issuer });
|
|
82
82
|
trigger.wake(true);
|
|
83
83
|
} else {
|
|
84
|
-
log('key is not currently in trusted set, waiting...', {
|
|
84
|
+
log('key is not currently in trusted set, waiting...', {
|
|
85
|
+
key: credential.issuer,
|
|
86
|
+
trusted: [...this._params.trustedKeysProvider()],
|
|
87
|
+
});
|
|
85
88
|
}
|
|
86
89
|
});
|
|
87
90
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { EventSubscriptions, scheduleTask, UpdateScheduler } from '@dxos/async';
|
|
6
6
|
import { Stream } from '@dxos/codec-protobuf';
|
|
7
7
|
import { type MemberInfo } from '@dxos/credentials';
|
|
8
|
-
import type
|
|
8
|
+
import { type SpaceManager } from '@dxos/echo-pipeline';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { type Contact, type ContactBook, type ContactsService } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
11
|
import { ComplexMap, ComplexSet } from '@dxos/util';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from '
|
|
5
|
+
import { describe, expect, test, onTestFinished } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Context } from '@dxos/context';
|
|
8
8
|
import { valueEncoding, MetadataStore, SpaceManager, AuthStatus } from '@dxos/echo-pipeline';
|
|
@@ -13,7 +13,6 @@ import { MemoryTransportFactory, SwarmNetworkManager } from '@dxos/network-manag
|
|
|
13
13
|
import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
14
14
|
import { createStorage, type Storage, StorageType } from '@dxos/random-access-storage';
|
|
15
15
|
import { BlobStore } from '@dxos/teleport-extension-object-sync';
|
|
16
|
-
import { describe, test, afterTest } from '@dxos/test';
|
|
17
16
|
|
|
18
17
|
import { IdentityManager } from './identity-manager';
|
|
19
18
|
|
|
@@ -39,7 +38,7 @@ describe('identity/identity-manager', () => {
|
|
|
39
38
|
}),
|
|
40
39
|
});
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
onTestFinished(() => feedStore.close());
|
|
43
42
|
|
|
44
43
|
const networkManager = new SwarmNetworkManager({
|
|
45
44
|
signalManager: new MemorySignalManager(signalContext),
|
|
@@ -51,7 +50,7 @@ describe('identity/identity-manager', () => {
|
|
|
51
50
|
blobStore,
|
|
52
51
|
metadataStore,
|
|
53
52
|
});
|
|
54
|
-
const identityManager = new IdentityManager(metadataStore, keyring, feedStore, spaceManager);
|
|
53
|
+
const identityManager = new IdentityManager({ metadataStore, keyring, feedStore, spaceManager });
|
|
55
54
|
|
|
56
55
|
return {
|
|
57
56
|
metadataStore,
|
|
@@ -64,7 +63,7 @@ describe('identity/identity-manager', () => {
|
|
|
64
63
|
test('creates identity', async () => {
|
|
65
64
|
const { identityManager } = await setupPeer();
|
|
66
65
|
await identityManager.open(new Context());
|
|
67
|
-
|
|
66
|
+
onTestFinished(() => identityManager.close());
|
|
68
67
|
|
|
69
68
|
const identity = await identityManager.createIdentity();
|
|
70
69
|
expect(identity).to.exist;
|
|
@@ -95,7 +94,7 @@ describe('identity/identity-manager', () => {
|
|
|
95
94
|
test('update profile', async () => {
|
|
96
95
|
const { identityManager } = await setupPeer();
|
|
97
96
|
await identityManager.open(new Context());
|
|
98
|
-
|
|
97
|
+
onTestFinished(() => identityManager.close());
|
|
99
98
|
|
|
100
99
|
const identity = await identityManager.createIdentity();
|
|
101
100
|
expect(identity.profileDocument?.displayName).to.be.undefined;
|
|
@@ -7,6 +7,7 @@ import { Event } from '@dxos/async';
|
|
|
7
7
|
import { Context } from '@dxos/context';
|
|
8
8
|
import { createCredentialSignerWithKey, CredentialGenerator } from '@dxos/credentials';
|
|
9
9
|
import { type MetadataStore, type SpaceManager, type SwarmIdentity } from '@dxos/echo-pipeline';
|
|
10
|
+
import { type EdgeConnection } from '@dxos/edge-client';
|
|
10
11
|
import { type FeedStore } from '@dxos/feed-store';
|
|
11
12
|
import { invariant } from '@dxos/invariant';
|
|
12
13
|
import { type Keyring } from '@dxos/keyring';
|
|
@@ -14,6 +15,7 @@ import { PublicKey } from '@dxos/keys';
|
|
|
14
15
|
import { log } from '@dxos/log';
|
|
15
16
|
import { trace } from '@dxos/protocols';
|
|
16
17
|
import { Device, DeviceKind } from '@dxos/protocols/proto/dxos/client/services';
|
|
18
|
+
import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
17
19
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
18
20
|
import { type IdentityRecord, type SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
19
21
|
import {
|
|
@@ -63,9 +65,20 @@ export type CreateIdentityOptions = {
|
|
|
63
65
|
deviceProfile?: DeviceProfileDocument;
|
|
64
66
|
};
|
|
65
67
|
|
|
66
|
-
export type
|
|
68
|
+
export type IdentityManagerCallbacks = {
|
|
69
|
+
onIdentityConstruction?: (identity: Identity) => void;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type IdentityManagerParams = {
|
|
73
|
+
metadataStore: MetadataStore;
|
|
74
|
+
keyring: Keyring;
|
|
75
|
+
feedStore: FeedStore<FeedMessage>;
|
|
76
|
+
spaceManager: SpaceManager;
|
|
77
|
+
edgeConnection?: EdgeConnection;
|
|
78
|
+
edgeFeatures?: Runtime.Client.EdgeFeatures;
|
|
67
79
|
devicePresenceAnnounceInterval?: number;
|
|
68
80
|
devicePresenceOfflineTimeout?: number;
|
|
81
|
+
callbacks?: IdentityManagerCallbacks;
|
|
69
82
|
};
|
|
70
83
|
|
|
71
84
|
// TODO(dmaretskyi): Rename: represents the peer's state machine.
|
|
@@ -73,28 +86,29 @@ export type IdentityManagerRuntimeParams = {
|
|
|
73
86
|
export class IdentityManager {
|
|
74
87
|
readonly stateUpdate = new Event();
|
|
75
88
|
|
|
76
|
-
private
|
|
89
|
+
private readonly _metadataStore: MetadataStore;
|
|
90
|
+
private readonly _keyring: Keyring;
|
|
91
|
+
private readonly _feedStore: FeedStore<FeedMessage>;
|
|
92
|
+
private readonly _spaceManager: SpaceManager;
|
|
77
93
|
private readonly _devicePresenceAnnounceInterval: number;
|
|
78
94
|
private readonly _devicePresenceOfflineTimeout: number;
|
|
95
|
+
private readonly _edgeConnection: EdgeConnection | undefined;
|
|
96
|
+
private readonly _edgeFeatures: Runtime.Client.EdgeFeatures | undefined;
|
|
97
|
+
private readonly _callbacks: IdentityManagerCallbacks | undefined;
|
|
98
|
+
|
|
99
|
+
private _identity?: Identity;
|
|
79
100
|
|
|
80
|
-
// TODO(burdon): IdentityManagerParams.
|
|
81
101
|
// TODO(dmaretskyi): Perhaps this should take/generate the peerKey outside of an initialized identity.
|
|
82
|
-
constructor(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
params
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const {
|
|
93
|
-
devicePresenceAnnounceInterval = DEVICE_PRESENCE_ANNOUNCE_INTERVAL,
|
|
94
|
-
devicePresenceOfflineTimeout = DEVICE_PRESENCE_OFFLINE_TIMEOUT,
|
|
95
|
-
} = params ?? {};
|
|
96
|
-
this._devicePresenceAnnounceInterval = devicePresenceAnnounceInterval;
|
|
97
|
-
this._devicePresenceOfflineTimeout = devicePresenceOfflineTimeout;
|
|
102
|
+
constructor(params: IdentityManagerParams) {
|
|
103
|
+
this._metadataStore = params.metadataStore;
|
|
104
|
+
this._keyring = params.keyring;
|
|
105
|
+
this._feedStore = params.feedStore;
|
|
106
|
+
this._spaceManager = params.spaceManager;
|
|
107
|
+
this._edgeConnection = params.edgeConnection;
|
|
108
|
+
this._edgeFeatures = params.edgeFeatures;
|
|
109
|
+
this._devicePresenceAnnounceInterval = params.devicePresenceAnnounceInterval ?? DEVICE_PRESENCE_ANNOUNCE_INTERVAL;
|
|
110
|
+
this._devicePresenceOfflineTimeout = params.devicePresenceOfflineTimeout ?? DEVICE_PRESENCE_OFFLINE_TIMEOUT;
|
|
111
|
+
this._callbacks = params.callbacks;
|
|
98
112
|
}
|
|
99
113
|
|
|
100
114
|
get identity() {
|
|
@@ -360,6 +374,8 @@ export class IdentityManager {
|
|
|
360
374
|
signer: this._keyring,
|
|
361
375
|
identityKey: identityRecord.identityKey,
|
|
362
376
|
deviceKey: identityRecord.deviceKey,
|
|
377
|
+
edgeConnection: this._edgeConnection,
|
|
378
|
+
edgeFeatures: this._edgeFeatures,
|
|
363
379
|
});
|
|
364
380
|
log('done', { identityKey: identityRecord.identityKey });
|
|
365
381
|
this._callbacks?.onIdentityConstruction?.(identity);
|
|
@@ -2,21 +2,17 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import chaiAsPromised from 'chai-as-promised';
|
|
5
|
+
import { afterEach, onTestFinished, beforeEach, describe, expect, test } from 'vitest';
|
|
7
6
|
|
|
8
7
|
import { Trigger } from '@dxos/async';
|
|
9
8
|
import { Context } from '@dxos/context';
|
|
10
9
|
import { PublicKey } from '@dxos/keys';
|
|
11
10
|
import { type Identity, type IdentityService } from '@dxos/protocols/proto/dxos/client/services';
|
|
12
|
-
import { afterEach, afterTest, beforeEach, describe, test } from '@dxos/test';
|
|
13
11
|
|
|
14
12
|
import { IdentityServiceImpl } from './identity-service';
|
|
15
13
|
import { type ServiceContext } from '../services';
|
|
16
14
|
import { createServiceContext } from '../testing';
|
|
17
15
|
|
|
18
|
-
chai.use(chaiAsPromised);
|
|
19
|
-
|
|
20
16
|
describe('IdentityService', () => {
|
|
21
17
|
let serviceContext: ServiceContext;
|
|
22
18
|
let identityService: IdentityService;
|
|
@@ -49,7 +45,7 @@ describe('IdentityService', () => {
|
|
|
49
45
|
|
|
50
46
|
test('fails to create identity if one already exists', async () => {
|
|
51
47
|
await identityService.createIdentity({});
|
|
52
|
-
await expect(identityService.createIdentity({})).
|
|
48
|
+
await expect(identityService.createIdentity({})).rejects.toThrowError('Identity already exists');
|
|
53
49
|
});
|
|
54
50
|
});
|
|
55
51
|
|
|
@@ -72,7 +68,7 @@ describe('IdentityService', () => {
|
|
|
72
68
|
query.subscribe(({ identity }) => {
|
|
73
69
|
result.wake(identity);
|
|
74
70
|
});
|
|
75
|
-
|
|
71
|
+
onTestFinished(() => query.close());
|
|
76
72
|
expect(await result.wait()).to.be.undefined;
|
|
77
73
|
});
|
|
78
74
|
|
|
@@ -82,7 +78,7 @@ describe('IdentityService', () => {
|
|
|
82
78
|
query.subscribe(({ identity }) => {
|
|
83
79
|
result.wake(identity);
|
|
84
80
|
});
|
|
85
|
-
|
|
81
|
+
onTestFinished(() => query.close());
|
|
86
82
|
expect(await result.wait()).to.be.undefined;
|
|
87
83
|
|
|
88
84
|
result = new Trigger<Identity | undefined>();
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import expect from '
|
|
5
|
+
import { onTestFinished, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
|
+
import { Event } from '@dxos/async';
|
|
7
8
|
import { Context } from '@dxos/context';
|
|
8
9
|
import { CredentialGenerator, verifyCredential } from '@dxos/credentials';
|
|
9
10
|
import {
|
|
@@ -15,7 +16,9 @@ import {
|
|
|
15
16
|
SpaceProtocol,
|
|
16
17
|
valueEncoding,
|
|
17
18
|
} from '@dxos/echo-pipeline';
|
|
19
|
+
import { type EdgeConnection, type MessageListener } from '@dxos/edge-client';
|
|
18
20
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
21
|
+
import { type FeedWrapper } from '@dxos/feed-store';
|
|
19
22
|
import { Keyring } from '@dxos/keyring';
|
|
20
23
|
import { type PublicKey } from '@dxos/keys';
|
|
21
24
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
@@ -24,7 +27,6 @@ import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
|
24
27
|
import { AdmittedFeed } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
25
28
|
import { createStorage, StorageType } from '@dxos/random-access-storage';
|
|
26
29
|
import { BlobStore } from '@dxos/teleport-extension-object-sync';
|
|
27
|
-
import { afterTest, describe, test } from '@dxos/test';
|
|
28
30
|
|
|
29
31
|
import { Identity } from './identity';
|
|
30
32
|
|
|
@@ -42,16 +44,108 @@ const createStores = () => {
|
|
|
42
44
|
|
|
43
45
|
describe('identity/identity', () => {
|
|
44
46
|
test('create', async () => {
|
|
47
|
+
const setup = await setupIdentity();
|
|
48
|
+
|
|
49
|
+
await writeGenesisCredential(setup);
|
|
50
|
+
|
|
51
|
+
// Wait for identity to be ready.
|
|
52
|
+
await setup.identity.ready();
|
|
53
|
+
const identitySigner = setup.identity.getIdentityCredentialSigner();
|
|
54
|
+
const credential = await identitySigner.createCredential({
|
|
55
|
+
subject: setup.identityKey,
|
|
56
|
+
assertion: {
|
|
57
|
+
'@type': 'dxos.halo.credentials.IdentityProfile',
|
|
58
|
+
profile: {
|
|
59
|
+
displayName: 'Alice',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
expect(credential.issuer).toEqual(setup.identityKey);
|
|
65
|
+
expect(await verifyCredential(credential)).toEqual({ kind: 'pass' });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('two devices', async () => {
|
|
69
|
+
const signalContext = new MemorySignalManagerContext();
|
|
70
|
+
|
|
71
|
+
const owner = await setupIdentity({ signalContext });
|
|
72
|
+
await writeGenesisCredential(owner);
|
|
73
|
+
await owner.identity.ready();
|
|
74
|
+
|
|
75
|
+
const secondDevice = (
|
|
76
|
+
await setupIdentity({
|
|
77
|
+
signalContext,
|
|
78
|
+
spaceKey: owner.spaceKey,
|
|
79
|
+
identityKey: owner.identityKey,
|
|
80
|
+
genesisFeedKey: owner.controlFeed.key,
|
|
81
|
+
})
|
|
82
|
+
).identity;
|
|
83
|
+
|
|
84
|
+
//
|
|
85
|
+
// Second device admission
|
|
86
|
+
//
|
|
87
|
+
{
|
|
88
|
+
const signer = owner.identity.getIdentityCredentialSigner();
|
|
89
|
+
void owner.identity.controlPipeline.writer.write({
|
|
90
|
+
credential: {
|
|
91
|
+
credential: await signer.createCredential({
|
|
92
|
+
subject: secondDevice.deviceKey,
|
|
93
|
+
assertion: {
|
|
94
|
+
'@type': 'dxos.halo.credentials.AuthorizedDevice',
|
|
95
|
+
identityKey: owner.identityKey,
|
|
96
|
+
deviceKey: secondDevice.deviceKey,
|
|
97
|
+
},
|
|
98
|
+
}),
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await secondDevice.ready();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
expect(Array.from(owner.identity.authorizedDeviceKeys.keys())).toEqual([owner.deviceKey, secondDevice.deviceKey]);
|
|
106
|
+
expect(Array.from(secondDevice.authorizedDeviceKeys.keys())).toEqual([owner.deviceKey, secondDevice.deviceKey]);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('edge feed replicator', async () => {
|
|
110
|
+
let replicationStarted = false;
|
|
111
|
+
const connectedEvent = new Event();
|
|
112
|
+
const setup = await setupIdentity({
|
|
113
|
+
edgeConnection: {
|
|
114
|
+
connected: connectedEvent,
|
|
115
|
+
open: async () => {},
|
|
116
|
+
close: async () => {},
|
|
117
|
+
addListener: (_: MessageListener): (() => void) => {
|
|
118
|
+
return () => {};
|
|
119
|
+
},
|
|
120
|
+
send: async (_) => {
|
|
121
|
+
replicationStarted = true;
|
|
122
|
+
},
|
|
123
|
+
} as EdgeConnection,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
await writeGenesisCredential(setup);
|
|
127
|
+
connectedEvent.emit();
|
|
128
|
+
|
|
129
|
+
await expect.poll(() => replicationStarted).toBeTruthy();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const setupIdentity = async (args?: {
|
|
133
|
+
signalContext?: MemorySignalManagerContext;
|
|
134
|
+
spaceKey?: PublicKey;
|
|
135
|
+
identityKey?: PublicKey;
|
|
136
|
+
genesisFeedKey?: PublicKey;
|
|
137
|
+
edgeConnection?: EdgeConnection;
|
|
138
|
+
}): Promise<TestIdentitySetup> => {
|
|
45
139
|
const { storage, metadataStore, blobStore } = createStores();
|
|
46
140
|
|
|
47
141
|
const keyring = new Keyring();
|
|
48
|
-
const identityKey = await keyring.createKey();
|
|
49
142
|
const deviceKey = await keyring.createKey();
|
|
50
|
-
const
|
|
143
|
+
const identityKey = args?.identityKey ?? (await keyring.createKey());
|
|
144
|
+
const spaceKey = args?.spaceKey ?? (await keyring.createKey());
|
|
51
145
|
|
|
52
146
|
const feedStore = new FeedStore<FeedMessage>({
|
|
53
147
|
factory: new FeedFactory<FeedMessage>({
|
|
54
|
-
root: storage.createDirectory(
|
|
148
|
+
root: storage.createDirectory(),
|
|
55
149
|
signer: keyring,
|
|
56
150
|
hypercore: {
|
|
57
151
|
valueEncoding,
|
|
@@ -77,7 +171,7 @@ describe('identity/identity', () => {
|
|
|
77
171
|
},
|
|
78
172
|
blobStore,
|
|
79
173
|
networkManager: new SwarmNetworkManager({
|
|
80
|
-
signalManager: new MemorySignalManager(new MemorySignalManagerContext()),
|
|
174
|
+
signalManager: new MemorySignalManager(args?.signalContext ?? new MemorySignalManagerContext()),
|
|
81
175
|
transportFactory: MemoryTransportFactory,
|
|
82
176
|
}),
|
|
83
177
|
});
|
|
@@ -87,7 +181,7 @@ describe('identity/identity', () => {
|
|
|
87
181
|
id: await createIdFromSpaceKey(spaceKey),
|
|
88
182
|
spaceKey,
|
|
89
183
|
protocol,
|
|
90
|
-
genesisFeed: controlFeed,
|
|
184
|
+
genesisFeed: args?.genesisFeedKey ? await feedStore.openFeed(args.genesisFeedKey) : controlFeed,
|
|
91
185
|
feedProvider: (feedKey) => feedStore.openFeed(feedKey),
|
|
92
186
|
memberKey: identityKey,
|
|
93
187
|
metadataStore,
|
|
@@ -103,242 +197,37 @@ describe('identity/identity', () => {
|
|
|
103
197
|
identityKey,
|
|
104
198
|
deviceKey,
|
|
105
199
|
space,
|
|
200
|
+
edgeFeatures: args?.edgeConnection && { feedReplicator: true },
|
|
201
|
+
edgeConnection: args?.edgeConnection,
|
|
106
202
|
});
|
|
107
203
|
|
|
108
204
|
await identity.open(new Context());
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// Identity genesis
|
|
113
|
-
//
|
|
114
|
-
{
|
|
115
|
-
const generator = new CredentialGenerator(keyring, identityKey, deviceKey);
|
|
116
|
-
const credentials = [
|
|
117
|
-
...(await generator.createSpaceGenesis(spaceKey, controlFeed.key)),
|
|
118
|
-
await generator.createDeviceAuthorization(deviceKey),
|
|
119
|
-
await generator.createFeedAdmission(spaceKey, dataFeed.key, AdmittedFeed.Designation.DATA),
|
|
120
|
-
];
|
|
121
|
-
|
|
122
|
-
for (const credential of credentials) {
|
|
123
|
-
await identity.controlPipeline.writer.write({
|
|
124
|
-
credential: { credential },
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Wait for identity to be ready.
|
|
130
|
-
await identity.ready();
|
|
131
|
-
const identitySigner = identity.getIdentityCredentialSigner();
|
|
132
|
-
const credential = await identitySigner.createCredential({
|
|
133
|
-
subject: identityKey,
|
|
134
|
-
assertion: {
|
|
135
|
-
'@type': 'dxos.halo.credentials.IdentityProfile',
|
|
136
|
-
profile: {
|
|
137
|
-
displayName: 'Alice',
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
expect(credential.issuer).toEqual(identityKey);
|
|
143
|
-
expect(await verifyCredential(credential)).toEqual({ kind: 'pass' });
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test('two devices', async () => {
|
|
147
|
-
const signalContext = new MemorySignalManagerContext();
|
|
148
|
-
|
|
149
|
-
let spaceKey: PublicKey;
|
|
150
|
-
let identityKey: PublicKey;
|
|
151
|
-
let genesisFeedKey: PublicKey;
|
|
152
|
-
let identity1: Identity;
|
|
153
|
-
let identity2: Identity;
|
|
154
|
-
|
|
155
|
-
//
|
|
156
|
-
// First device
|
|
157
|
-
//
|
|
158
|
-
{
|
|
159
|
-
const { storage, metadataStore, blobStore } = createStores();
|
|
160
|
-
|
|
161
|
-
const keyring = new Keyring();
|
|
162
|
-
identityKey = await keyring.createKey();
|
|
163
|
-
const deviceKey = await keyring.createKey();
|
|
164
|
-
spaceKey = await keyring.createKey();
|
|
165
|
-
|
|
166
|
-
const feedStore = new FeedStore<FeedMessage>({
|
|
167
|
-
factory: new FeedFactory<FeedMessage>({
|
|
168
|
-
root: storage.createDirectory(),
|
|
169
|
-
signer: keyring,
|
|
170
|
-
hypercore: {
|
|
171
|
-
valueEncoding,
|
|
172
|
-
},
|
|
173
|
-
}),
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
const createFeed = async () => {
|
|
177
|
-
const feedKey = await keyring.createKey();
|
|
178
|
-
return feedStore.openFeed(feedKey, { writable: true });
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
const controlFeed = await createFeed();
|
|
182
|
-
genesisFeedKey = controlFeed.key;
|
|
183
|
-
|
|
184
|
-
const dataFeed = await createFeed();
|
|
185
|
-
|
|
186
|
-
const protocol = new SpaceProtocol({
|
|
187
|
-
topic: spaceKey,
|
|
188
|
-
swarmIdentity: {
|
|
189
|
-
peerKey: deviceKey,
|
|
190
|
-
identityKey,
|
|
191
|
-
credentialProvider: MOCK_AUTH_PROVIDER, // createHaloAuthProvider(createCredentialSignerWithKey(keyring, device_key)),
|
|
192
|
-
credentialAuthenticator: MOCK_AUTH_VERIFIER, // createHaloAuthVerifier(() => identity.authorizedDeviceKeys),
|
|
193
|
-
},
|
|
194
|
-
blobStore,
|
|
195
|
-
networkManager: new SwarmNetworkManager({
|
|
196
|
-
signalManager: new MemorySignalManager(signalContext),
|
|
197
|
-
transportFactory: MemoryTransportFactory,
|
|
198
|
-
}),
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
await metadataStore.setIdentityRecord({ haloSpace: { key: spaceKey }, identityKey, deviceKey });
|
|
202
|
-
const space = new Space({
|
|
203
|
-
id: await createIdFromSpaceKey(spaceKey),
|
|
204
|
-
spaceKey,
|
|
205
|
-
protocol,
|
|
206
|
-
genesisFeed: controlFeed,
|
|
207
|
-
feedProvider: (feedKey) => feedStore.openFeed(feedKey),
|
|
208
|
-
memberKey: identityKey,
|
|
209
|
-
metadataStore,
|
|
210
|
-
onDelegatedInvitationStatusChange: async () => {},
|
|
211
|
-
onMemberRolesChanged: async () => {},
|
|
212
|
-
});
|
|
213
|
-
await space.setControlFeed(controlFeed);
|
|
214
|
-
await space.setDataFeed(dataFeed);
|
|
215
|
-
|
|
216
|
-
const identity = (identity1 = new Identity({
|
|
217
|
-
signer: keyring,
|
|
218
|
-
identityKey,
|
|
219
|
-
deviceKey,
|
|
220
|
-
space,
|
|
221
|
-
}));
|
|
222
|
-
|
|
223
|
-
await identity.open(new Context());
|
|
224
|
-
afterTest(() => identity.close(new Context()));
|
|
225
|
-
|
|
226
|
-
//
|
|
227
|
-
// Identity genesis
|
|
228
|
-
//
|
|
229
|
-
{
|
|
230
|
-
const generator = new CredentialGenerator(keyring, identityKey, deviceKey);
|
|
231
|
-
const credentials = [
|
|
232
|
-
...(await generator.createSpaceGenesis(spaceKey, controlFeed.key)),
|
|
233
|
-
await generator.createDeviceAuthorization(deviceKey),
|
|
234
|
-
await generator.createFeedAdmission(spaceKey, dataFeed.key, AdmittedFeed.Designation.DATA),
|
|
235
|
-
];
|
|
236
|
-
|
|
237
|
-
for (const credential of credentials) {
|
|
238
|
-
await identity.controlPipeline.writer.write({
|
|
239
|
-
credential: { credential },
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Wait for identity to be ready.
|
|
245
|
-
await identity.ready();
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
//
|
|
249
|
-
// Second device
|
|
250
|
-
//
|
|
251
|
-
{
|
|
252
|
-
const { storage, metadataStore, blobStore } = createStores();
|
|
253
|
-
|
|
254
|
-
const keyring = new Keyring();
|
|
255
|
-
const deviceKey = await keyring.createKey();
|
|
256
|
-
|
|
257
|
-
const feedStore = new FeedStore<FeedMessage>({
|
|
258
|
-
factory: new FeedFactory<FeedMessage>({
|
|
259
|
-
root: storage.createDirectory(),
|
|
260
|
-
signer: keyring,
|
|
261
|
-
hypercore: {
|
|
262
|
-
valueEncoding,
|
|
263
|
-
},
|
|
264
|
-
}),
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
const createFeed = async () => {
|
|
268
|
-
const feedKey = await keyring.createKey();
|
|
269
|
-
return feedStore.openFeed(feedKey, { writable: true });
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
const controlFeed = await createFeed();
|
|
273
|
-
const dataFeed = await createFeed();
|
|
274
|
-
|
|
275
|
-
const protocol = new SpaceProtocol({
|
|
276
|
-
topic: spaceKey,
|
|
277
|
-
swarmIdentity: {
|
|
278
|
-
peerKey: deviceKey,
|
|
279
|
-
identityKey,
|
|
280
|
-
credentialProvider: MOCK_AUTH_PROVIDER, // createHaloAuthProvider(createCredentialSignerWithKey(keyring, device_key)),
|
|
281
|
-
credentialAuthenticator: MOCK_AUTH_VERIFIER, // createHaloAuthVerifier(() => identity.authorizedDeviceKeys),
|
|
282
|
-
},
|
|
283
|
-
blobStore,
|
|
284
|
-
networkManager: new SwarmNetworkManager({
|
|
285
|
-
signalManager: new MemorySignalManager(signalContext),
|
|
286
|
-
transportFactory: MemoryTransportFactory,
|
|
287
|
-
}),
|
|
288
|
-
});
|
|
205
|
+
onTestFinished(() => identity.close(new Context()));
|
|
206
|
+
return { identity, identityKey, keyring, deviceKey, controlFeed, spaceKey, dataFeed };
|
|
207
|
+
};
|
|
289
208
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
memberKey: identityKey,
|
|
302
|
-
metadataStore,
|
|
303
|
-
onDelegatedInvitationStatusChange: async () => {},
|
|
304
|
-
onMemberRolesChanged: async () => {},
|
|
209
|
+
const writeGenesisCredential = async (setup: TestIdentitySetup) => {
|
|
210
|
+
const generator = new CredentialGenerator(setup.keyring, setup.identityKey, setup.deviceKey);
|
|
211
|
+
const credentials = [
|
|
212
|
+
...(await generator.createSpaceGenesis(setup.spaceKey, setup.controlFeed.key)),
|
|
213
|
+
await generator.createDeviceAuthorization(setup.deviceKey),
|
|
214
|
+
await generator.createFeedAdmission(setup.spaceKey, setup.dataFeed.key, AdmittedFeed.Designation.DATA),
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
for (const credential of credentials) {
|
|
218
|
+
await setup.identity.controlPipeline.writer.write({
|
|
219
|
+
credential: { credential },
|
|
305
220
|
});
|
|
306
|
-
await space.setControlFeed(controlFeed);
|
|
307
|
-
await space.setDataFeed(dataFeed);
|
|
308
|
-
|
|
309
|
-
const identity = (identity2 = new Identity({
|
|
310
|
-
signer: keyring,
|
|
311
|
-
identityKey: identity1.identityKey,
|
|
312
|
-
deviceKey,
|
|
313
|
-
space,
|
|
314
|
-
}));
|
|
315
|
-
|
|
316
|
-
await identity.open(new Context());
|
|
317
|
-
afterTest(() => identity.close(new Context()));
|
|
318
221
|
}
|
|
319
|
-
|
|
320
|
-
//
|
|
321
|
-
// Second device admission
|
|
322
|
-
//
|
|
323
|
-
{
|
|
324
|
-
const signer = identity1.getIdentityCredentialSigner();
|
|
325
|
-
void identity1.controlPipeline.writer.write({
|
|
326
|
-
credential: {
|
|
327
|
-
credential: await signer.createCredential({
|
|
328
|
-
subject: identity2.deviceKey,
|
|
329
|
-
assertion: {
|
|
330
|
-
'@type': 'dxos.halo.credentials.AuthorizedDevice',
|
|
331
|
-
identityKey: identity1.identityKey,
|
|
332
|
-
deviceKey: identity2.deviceKey,
|
|
333
|
-
},
|
|
334
|
-
}),
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
await identity2.ready();
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
expect(Array.from(identity1.authorizedDeviceKeys.keys())).toEqual([identity1.deviceKey, identity2.deviceKey]);
|
|
342
|
-
expect(Array.from(identity2.authorizedDeviceKeys.keys())).toEqual([identity1.deviceKey, identity2.deviceKey]);
|
|
343
|
-
});
|
|
222
|
+
};
|
|
344
223
|
});
|
|
224
|
+
|
|
225
|
+
type TestIdentitySetup = {
|
|
226
|
+
identity: Identity;
|
|
227
|
+
keyring: Keyring;
|
|
228
|
+
identityKey: PublicKey;
|
|
229
|
+
deviceKey: PublicKey;
|
|
230
|
+
spaceKey: PublicKey;
|
|
231
|
+
controlFeed: FeedWrapper<FeedMessage>;
|
|
232
|
+
dataFeed: FeedWrapper<FeedMessage>;
|
|
233
|
+
};
|