@dxos/client-services 0.1.21 → 0.1.23
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/index.mjs +79 -38
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +82 -41
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts +8 -8
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +2 -2
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.test.d.ts +2 -0
- package/dist/types/src/packlets/spaces/data-space-manager.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/data-space.d.ts +2 -0
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +30 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/package.json +28 -28
- package/src/packlets/identity/authenticator.test.ts +4 -4
- package/src/packlets/identity/authenticator.ts +18 -13
- package/src/packlets/identity/identity-manager.ts +2 -4
- package/src/packlets/identity/identity.ts +4 -4
- package/src/packlets/services/service-context.ts +0 -4
- package/src/packlets/spaces/data-space-manager.test.ts +74 -0
- package/src/packlets/spaces/data-space-manager.ts +8 -3
- package/src/packlets/spaces/data-space.ts +12 -0
- package/src/packlets/testing/test-builder.ts +87 -1
|
@@ -11,7 +11,7 @@ import { log } from '@dxos/log';
|
|
|
11
11
|
import { schema } from '@dxos/protocols';
|
|
12
12
|
import { ComplexSet } from '@dxos/util';
|
|
13
13
|
|
|
14
|
-
export const
|
|
14
|
+
export const createAuthProvider =
|
|
15
15
|
(signer: CredentialSigner): AuthProvider =>
|
|
16
16
|
async (nonce) => {
|
|
17
17
|
const credential = await signer.createCredential({
|
|
@@ -25,8 +25,9 @@ export const createHaloAuthProvider =
|
|
|
25
25
|
return schema.getCodecForType('dxos.halo.credentials.Credential').encode(credential);
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
export type
|
|
29
|
-
|
|
28
|
+
export type TrustedKeySetAuthVerifierParams = {
|
|
29
|
+
// TODO(dmaretskyi): Change to `isTrusted: (key) => bool`.
|
|
30
|
+
trustedKeysProvider: () => ComplexSet<PublicKey>;
|
|
30
31
|
update: Event<void>;
|
|
31
32
|
/**
|
|
32
33
|
* Timeout to wait for the device key to be added to the trusted set.
|
|
@@ -35,26 +36,27 @@ export type HaloAuthVerifierParams = {
|
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
|
-
* Verifies credentials of another
|
|
39
|
-
* Will wait up to `authTimeout` for the
|
|
39
|
+
* Verifies credentials of another member in the space based on a set of trusted key.
|
|
40
|
+
* Will wait up to `authTimeout` for the key to be added to the trusted set.
|
|
40
41
|
*/
|
|
41
|
-
export class
|
|
42
|
+
export class TrustedKeySetAuthVerifier {
|
|
42
43
|
private _ctx = new Context();
|
|
43
44
|
|
|
44
|
-
constructor(private readonly _params:
|
|
45
|
+
constructor(private readonly _params: TrustedKeySetAuthVerifierParams) {}
|
|
45
46
|
|
|
46
47
|
async close() {
|
|
47
48
|
await this._ctx.dispose();
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
private
|
|
51
|
-
const deviceSet = this._params.
|
|
51
|
+
private _isTrustedKey(deviceKey: PublicKey) {
|
|
52
|
+
const deviceSet = this._params.trustedKeysProvider();
|
|
52
53
|
return deviceSet.has(deviceKey);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
get verifier(): AuthVerifier {
|
|
56
57
|
return async (nonce, auth) => {
|
|
57
58
|
const credential = schema.getCodecForType('dxos.halo.credentials.Credential').decode(auth);
|
|
59
|
+
log('authenticating...', { credential });
|
|
58
60
|
|
|
59
61
|
const result = await verifyCredential(credential);
|
|
60
62
|
if (result.kind === 'fail') {
|
|
@@ -67,7 +69,8 @@ export class HaloAuthVerifier {
|
|
|
67
69
|
return false;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
if (this.
|
|
72
|
+
if (this._isTrustedKey(credential.issuer)) {
|
|
73
|
+
log('key is not currently in trusted set, waiting...', { key: credential.issuer });
|
|
71
74
|
return true;
|
|
72
75
|
}
|
|
73
76
|
|
|
@@ -76,13 +79,15 @@ export class HaloAuthVerifier {
|
|
|
76
79
|
trigger.wake(false);
|
|
77
80
|
});
|
|
78
81
|
const clear = this._params.update.on(this._ctx, () => {
|
|
79
|
-
if (this.
|
|
82
|
+
if (this._isTrustedKey(credential.issuer)) {
|
|
83
|
+
log('auth success', { key: credential.issuer });
|
|
80
84
|
trigger.wake(true);
|
|
85
|
+
} else {
|
|
86
|
+
log('key is not currently in trusted set, waiting...', { key: credential.issuer });
|
|
81
87
|
}
|
|
82
88
|
});
|
|
83
89
|
try {
|
|
84
|
-
await trigger.wait({ timeout: this._params.authTimeout });
|
|
85
|
-
return true;
|
|
90
|
+
return await trigger.wait({ timeout: this._params.authTimeout });
|
|
86
91
|
} catch {
|
|
87
92
|
return false;
|
|
88
93
|
} finally {
|
|
@@ -14,7 +14,7 @@ import { AdmittedFeed, IdentityRecord, SpaceRecord } from '@dxos/protocols/proto
|
|
|
14
14
|
import { deferFunction } from '@dxos/util';
|
|
15
15
|
|
|
16
16
|
import { Identity } from '../identity';
|
|
17
|
-
import {
|
|
17
|
+
import { createAuthProvider } from './authenticator';
|
|
18
18
|
|
|
19
19
|
interface ConstructSpaceParams {
|
|
20
20
|
spaceRecord: SpaceRecord;
|
|
@@ -166,9 +166,7 @@ export class IdentityManager {
|
|
|
166
166
|
spaceRecord: identityRecord.haloSpace,
|
|
167
167
|
swarmIdentity: {
|
|
168
168
|
peerKey: identityRecord.deviceKey,
|
|
169
|
-
credentialProvider:
|
|
170
|
-
createCredentialSignerWithKey(this._keyring, identityRecord.deviceKey)
|
|
171
|
-
),
|
|
169
|
+
credentialProvider: createAuthProvider(createCredentialSignerWithKey(this._keyring, identityRecord.deviceKey)),
|
|
172
170
|
credentialAuthenticator: deferFunction(() => identity.authVerifier.verifier)
|
|
173
171
|
},
|
|
174
172
|
identityKey: identityRecord.identityKey
|
|
@@ -23,7 +23,7 @@ import { AdmittedFeed, ProfileDocument } from '@dxos/protocols/proto/dxos/halo/c
|
|
|
23
23
|
import { HaloAdmissionCredentials } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
24
24
|
import { ComplexSet } from '@dxos/util';
|
|
25
25
|
|
|
26
|
-
import {
|
|
26
|
+
import { TrustedKeySetAuthVerifier } from './authenticator';
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Timeout for the device to be added to the trusted set during auth.
|
|
@@ -45,7 +45,7 @@ export class Identity {
|
|
|
45
45
|
private readonly _signer: Signer;
|
|
46
46
|
private readonly _deviceStateMachine: CredentialConsumer<DeviceStateMachine>;
|
|
47
47
|
private readonly _profileStateMachine: CredentialConsumer<ProfileStateMachine>;
|
|
48
|
-
public readonly authVerifier:
|
|
48
|
+
public readonly authVerifier: TrustedKeySetAuthVerifier;
|
|
49
49
|
|
|
50
50
|
public readonly identityKey: PublicKey;
|
|
51
51
|
public readonly deviceKey: PublicKey;
|
|
@@ -73,8 +73,8 @@ export class Identity {
|
|
|
73
73
|
})
|
|
74
74
|
);
|
|
75
75
|
|
|
76
|
-
this.authVerifier = new
|
|
77
|
-
|
|
76
|
+
this.authVerifier = new TrustedKeySetAuthVerifier({
|
|
77
|
+
trustedKeysProvider: () => this.authorizedDeviceKeys,
|
|
78
78
|
update: this.stateUpdate,
|
|
79
79
|
authTimeout: AUTH_TIMEOUT
|
|
80
80
|
});
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
import { Trigger } from '@dxos/async';
|
|
6
6
|
import { failUndefined } from '@dxos/debug';
|
|
7
7
|
import {
|
|
8
|
-
MOCK_AUTH_PROVIDER,
|
|
9
|
-
MOCK_AUTH_VERIFIER,
|
|
10
8
|
valueEncoding,
|
|
11
9
|
DataServiceSubscriptions,
|
|
12
10
|
MetadataStore,
|
|
@@ -122,8 +120,6 @@ export class ServiceContext {
|
|
|
122
120
|
log('initializing spaces...');
|
|
123
121
|
const identity = this.identityManager.identity ?? failUndefined();
|
|
124
122
|
const signingContext: SigningContext = {
|
|
125
|
-
credentialProvider: MOCK_AUTH_PROVIDER,
|
|
126
|
-
credentialAuthenticator: MOCK_AUTH_VERIFIER,
|
|
127
123
|
credentialSigner: identity.getIdentityCredentialSigner(),
|
|
128
124
|
identityKey: identity.identityKey,
|
|
129
125
|
deviceKey: identity.deviceKey,
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
|
|
7
|
+
import { createAdmissionCredentials } from '@dxos/credentials';
|
|
8
|
+
import { AuthStatus, DataServiceSubscriptions } from '@dxos/echo-db';
|
|
9
|
+
import { writeMessages } from '@dxos/feed-store';
|
|
10
|
+
import { ModelFactory } from '@dxos/model-factory';
|
|
11
|
+
import { ObjectModel } from '@dxos/object-model';
|
|
12
|
+
import { test, describe } from '@dxos/test';
|
|
13
|
+
|
|
14
|
+
import { createSigningContext, syncItems, TestBuilder } from '../testing';
|
|
15
|
+
import { DataSpaceManager } from './data-space-manager';
|
|
16
|
+
|
|
17
|
+
describe('DataSpaceManager', () => {
|
|
18
|
+
test('sync between peers', async () => {
|
|
19
|
+
const builder = new TestBuilder();
|
|
20
|
+
|
|
21
|
+
const peer1 = builder.createPeer();
|
|
22
|
+
const identity1 = await createSigningContext(peer1.keyring);
|
|
23
|
+
const dataSpaceManager1 = new DataSpaceManager(
|
|
24
|
+
peer1.spaceManager,
|
|
25
|
+
peer1.metadataStore,
|
|
26
|
+
new DataServiceSubscriptions(),
|
|
27
|
+
peer1.keyring,
|
|
28
|
+
identity1,
|
|
29
|
+
new ModelFactory().registerModel(ObjectModel),
|
|
30
|
+
peer1.snapshotStore
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const peer2 = builder.createPeer();
|
|
34
|
+
const identity2 = await createSigningContext(peer2.keyring);
|
|
35
|
+
const dataSpaceManager2 = new DataSpaceManager(
|
|
36
|
+
peer2.spaceManager,
|
|
37
|
+
peer2.metadataStore,
|
|
38
|
+
new DataServiceSubscriptions(),
|
|
39
|
+
peer2.keyring,
|
|
40
|
+
identity2,
|
|
41
|
+
new ModelFactory().registerModel(ObjectModel),
|
|
42
|
+
peer1.snapshotStore
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const space1 = await dataSpaceManager1.createSpace();
|
|
46
|
+
const space2 = await dataSpaceManager2.acceptSpace({
|
|
47
|
+
spaceKey: space1.key,
|
|
48
|
+
genesisFeedKey: space1.inner.genesisFeedKey,
|
|
49
|
+
controlFeedKey: await peer2.keyring.createKey(),
|
|
50
|
+
dataFeedKey: await peer2.keyring.createKey()
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Admit peer2 to space1.
|
|
54
|
+
await writeMessages(
|
|
55
|
+
space1.inner.controlPipeline.writer,
|
|
56
|
+
await createAdmissionCredentials(
|
|
57
|
+
identity1.credentialSigner,
|
|
58
|
+
identity2.identityKey,
|
|
59
|
+
identity2.deviceKey,
|
|
60
|
+
space1.key,
|
|
61
|
+
space2.inner.controlFeedKey,
|
|
62
|
+
space2.inner.dataFeedKey,
|
|
63
|
+
space2.inner.genesisFeedKey
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
await syncItems(space1, space2);
|
|
68
|
+
|
|
69
|
+
expect(space1.inner.protocol.sessions.get(identity2.deviceKey)).to.exist;
|
|
70
|
+
expect(space1.inner.protocol.sessions.get(identity2.deviceKey)?.authStatus).to.equal(AuthStatus.SUCCESS);
|
|
71
|
+
expect(space2.inner.protocol.sessions.get(identity1.deviceKey)).to.exist;
|
|
72
|
+
expect(space2.inner.protocol.sessions.get(identity1.deviceKey)?.authStatus).to.equal(AuthStatus.SUCCESS);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
|
|
5
7
|
import { Event, synchronized, trackLeaks } from '@dxos/async';
|
|
6
8
|
import { Context } from '@dxos/context';
|
|
7
9
|
import {
|
|
@@ -21,8 +23,9 @@ import { log } from '@dxos/log';
|
|
|
21
23
|
import { ModelFactory } from '@dxos/model-factory';
|
|
22
24
|
import { SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
23
25
|
import { Presence } from '@dxos/teleport-extension-presence';
|
|
24
|
-
import { ComplexMap } from '@dxos/util';
|
|
26
|
+
import { ComplexMap, deferFunction } from '@dxos/util';
|
|
25
27
|
|
|
28
|
+
import { createAuthProvider } from '../identity';
|
|
26
29
|
import { DataSpace } from './data-space';
|
|
27
30
|
|
|
28
31
|
@trackLeaks('open', 'close')
|
|
@@ -99,6 +102,8 @@ export class DataSpaceManager {
|
|
|
99
102
|
// TODO(burdon): Rename join space.
|
|
100
103
|
@synchronized
|
|
101
104
|
async acceptSpace(opts: AcceptSpaceOptions): Promise<DataSpace> {
|
|
105
|
+
assert(!this._spaces.has(opts.spaceKey), 'Space already exists.');
|
|
106
|
+
|
|
102
107
|
const metadata: SpaceMetadata = {
|
|
103
108
|
key: opts.spaceKey,
|
|
104
109
|
genesisFeedKey: opts.genesisFeedKey,
|
|
@@ -125,8 +130,8 @@ export class DataSpaceManager {
|
|
|
125
130
|
metadata,
|
|
126
131
|
swarmIdentity: {
|
|
127
132
|
peerKey: this._signingContext.deviceKey,
|
|
128
|
-
credentialProvider: this._signingContext.
|
|
129
|
-
credentialAuthenticator:
|
|
133
|
+
credentialProvider: createAuthProvider(this._signingContext.credentialSigner),
|
|
134
|
+
credentialAuthenticator: deferFunction(() => dataSpace.authVerifier.verifier)
|
|
130
135
|
},
|
|
131
136
|
onNetworkConnection: (session) => {
|
|
132
137
|
session.addExtension(
|
|
@@ -10,6 +10,11 @@ import { Database, DataPipelineControllerImpl, ISpace, MetadataStore, Space, Sna
|
|
|
10
10
|
import { PublicKey } from '@dxos/keys';
|
|
11
11
|
import { ModelFactory } from '@dxos/model-factory';
|
|
12
12
|
import { Presence } from '@dxos/teleport-extension-presence';
|
|
13
|
+
import { ComplexSet } from '@dxos/util';
|
|
14
|
+
|
|
15
|
+
import { TrustedKeySetAuthVerifier } from '../identity';
|
|
16
|
+
|
|
17
|
+
const AUTH_TIMEOUT = 30000;
|
|
13
18
|
|
|
14
19
|
export type DataSpaceParams = {
|
|
15
20
|
inner: Space;
|
|
@@ -27,6 +32,7 @@ export class DataSpace implements ISpace {
|
|
|
27
32
|
private readonly _dataPipelineController: DataPipelineControllerImpl;
|
|
28
33
|
private readonly _inner: Space;
|
|
29
34
|
private readonly _presence: Presence;
|
|
35
|
+
public readonly authVerifier: TrustedKeySetAuthVerifier;
|
|
30
36
|
|
|
31
37
|
constructor(params: DataSpaceParams) {
|
|
32
38
|
this._inner = params.inner;
|
|
@@ -40,6 +46,11 @@ export class DataSpace implements ISpace {
|
|
|
40
46
|
feedInfoProvider: (feedKey) => this._inner.spaceState.feeds.get(feedKey),
|
|
41
47
|
snapshotId: params.snapshotId
|
|
42
48
|
});
|
|
49
|
+
this.authVerifier = new TrustedKeySetAuthVerifier({
|
|
50
|
+
trustedKeysProvider: () => new ComplexSet(PublicKey.hash, Array.from(this._inner.spaceState.members.keys())),
|
|
51
|
+
update: this._inner.stateUpdate,
|
|
52
|
+
authTimeout: AUTH_TIMEOUT
|
|
53
|
+
});
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
get key() {
|
|
@@ -78,6 +89,7 @@ export class DataSpace implements ISpace {
|
|
|
78
89
|
|
|
79
90
|
async close() {
|
|
80
91
|
await this._ctx.dispose();
|
|
92
|
+
await this.authVerifier.close();
|
|
81
93
|
await this._inner.close();
|
|
82
94
|
await this._presence.destroy();
|
|
83
95
|
}
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
import { expect } from 'chai';
|
|
6
6
|
|
|
7
7
|
import { Config } from '@dxos/config';
|
|
8
|
-
import {
|
|
8
|
+
import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
|
|
9
|
+
import { ISpace, MetadataStore, SigningContext, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-db';
|
|
10
|
+
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
11
|
+
import { Keyring } from '@dxos/keyring';
|
|
9
12
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
10
13
|
import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
11
14
|
import { createStorage, Storage, StorageType } from '@dxos/random-access-storage';
|
|
@@ -78,3 +81,86 @@ export const syncItems = async (space1: ISpace, space2: ISpace) => {
|
|
|
78
81
|
expect(item1.id).to.eq(item2.id);
|
|
79
82
|
}
|
|
80
83
|
};
|
|
84
|
+
|
|
85
|
+
export class TestBuilder {
|
|
86
|
+
public readonly signalContext = new MemorySignalManagerContext();
|
|
87
|
+
|
|
88
|
+
createPeer(): TestPeer {
|
|
89
|
+
return new TestPeer(this.signalContext);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type TestPeerProps = {
|
|
94
|
+
storage?: Storage;
|
|
95
|
+
feedStore?: FeedStore<any>;
|
|
96
|
+
metadataStore?: MetadataStore;
|
|
97
|
+
keyring?: Keyring;
|
|
98
|
+
networkManager?: NetworkManager;
|
|
99
|
+
spaceManager?: SpaceManager;
|
|
100
|
+
snapshotStore?: SnapshotStore;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export class TestPeer {
|
|
104
|
+
private _props: TestPeerProps = {};
|
|
105
|
+
|
|
106
|
+
constructor(private readonly signalContext: MemorySignalManagerContext) {}
|
|
107
|
+
|
|
108
|
+
get storage() {
|
|
109
|
+
return (this._props.storage ??= createStorage({ type: StorageType.RAM }));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
get keyring() {
|
|
113
|
+
return (this._props.keyring ??= new Keyring(this.storage.createDirectory('keyring')));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
get feedStore() {
|
|
117
|
+
return (this._props.feedStore ??= new FeedStore({
|
|
118
|
+
factory: new FeedFactory({
|
|
119
|
+
root: this.storage.createDirectory('feeds'),
|
|
120
|
+
signer: this.keyring,
|
|
121
|
+
hypercore: {
|
|
122
|
+
valueEncoding
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
get metadataStore() {
|
|
129
|
+
return (this._props.metadataStore ??= new MetadataStore(this.storage.createDirectory('metadata')));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get snapshotStore() {
|
|
133
|
+
return (this._props.snapshotStore ??= new SnapshotStore(this.storage.createDirectory('snapshots')));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
get networkManager() {
|
|
137
|
+
return (this._props.networkManager ??= new NetworkManager({
|
|
138
|
+
signalManager: new MemorySignalManager(this.signalContext),
|
|
139
|
+
transportFactory: MemoryTransportFactory
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get spaceManager() {
|
|
144
|
+
return (this._props.spaceManager ??= new SpaceManager({
|
|
145
|
+
feedStore: this.feedStore,
|
|
146
|
+
networkManager: this.networkManager
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export const createSigningContext = async (keyring: Keyring): Promise<SigningContext> => {
|
|
152
|
+
const identityKey = await keyring.createKey();
|
|
153
|
+
const deviceKey = await keyring.createKey();
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
identityKey,
|
|
157
|
+
deviceKey,
|
|
158
|
+
credentialSigner: createCredentialSignerWithChain(
|
|
159
|
+
keyring,
|
|
160
|
+
{
|
|
161
|
+
credential: await new CredentialGenerator(keyring, identityKey, deviceKey).createDeviceAuthorization(deviceKey)
|
|
162
|
+
},
|
|
163
|
+
deviceKey
|
|
164
|
+
)
|
|
165
|
+
};
|
|
166
|
+
};
|