@dxos/client-services 0.4.10-main.3e35a2f → 0.4.10-main.403e461
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-S3G2RM7S.mjs → chunk-R4Y666JX.mjs} +163 -102
- package/dist/lib/browser/chunk-R4Y666JX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +3 -1
- package/dist/lib/browser/index.mjs.map +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +1 -1
- package/dist/lib/node/{chunk-3T6D6GIB.cjs → chunk-KGGJXJON.cjs} +167 -105
- package/dist/lib/node/chunk-KGGJXJON.cjs.map +7 -0
- package/dist/lib/node/index.cjs +43 -41
- package/dist/lib/node/index.cjs.map +1 -1
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +6 -6
- package/dist/types/src/packlets/invitations/invitation-extension.d.ts +1 -0
- package/dist/types/src/packlets/invitations/invitation-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/package.json +34 -34
- package/src/packlets/invitations/invitation-extension.ts +28 -1
- package/src/packlets/invitations/invitations-handler.ts +71 -23
- package/src/packlets/services/service-host.ts +2 -2
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-S3G2RM7S.mjs.map +0 -7
- package/dist/lib/node/chunk-3T6D6GIB.cjs.map +0 -7
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AuthenticatingInvitation, CancellableInvitation } from '@dxos/client-protocol';
|
|
2
|
-
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
2
|
+
import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
3
3
|
import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
4
4
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
5
5
|
/**
|
|
@@ -33,5 +33,8 @@ export declare class InvitationsHandler {
|
|
|
33
33
|
private readonly _networkManager;
|
|
34
34
|
createInvitation(protocol: InvitationProtocol, options?: Partial<Invitation>): CancellableInvitation;
|
|
35
35
|
acceptInvitation(protocol: InvitationProtocol, invitation: Invitation, deviceProfile?: DeviceProfileDocument): AuthenticatingInvitation;
|
|
36
|
+
private _handleGuestOtpAuth;
|
|
37
|
+
private _handleGuestKpkAuth;
|
|
36
38
|
}
|
|
39
|
+
export declare const createAdmissionKeypair: () => AdmissionKeypair;
|
|
37
40
|
//# sourceMappingURL=invitations-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invitations-handler.d.ts","sourceRoot":"","sources":["../../../../../src/packlets/invitations/invitations-handler.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,wBAAwB,EAExB,qBAAqB,EAEtB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"invitations-handler.d.ts","sourceRoot":"","sources":["../../../../../src/packlets/invitations/invitations-handler.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,wBAAwB,EAExB,qBAAqB,EAEtB,MAAM,uBAAuB,CAAC;AAc/B,OAAO,EAAE,KAAK,gBAAgB,EAAE,UAAU,EAAE,MAAM,4CAA4C,CAAC;AAC/F,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AASzF,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,kBAAkB;IAIjB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAE5C,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,qBAAqB;IAgLpG,gBAAgB,CACd,QAAQ,EAAE,kBAAkB,EAC5B,UAAU,EAAE,UAAU,EACtB,aAAa,CAAC,EAAE,qBAAqB,GACpC,wBAAwB;YA0Kb,mBAAmB;YA6BnB,mBAAmB;CAsBlC;AAED,eAAO,MAAM,sBAAsB,QAAO,gBAGzC,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const DXOS_VERSION = "0.4.10-main.
|
|
1
|
+
export declare const DXOS_VERSION = "0.4.10-main.403e461";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/client-services",
|
|
3
|
-
"version": "0.4.10-main.
|
|
3
|
+
"version": "0.4.10-main.403e461",
|
|
4
4
|
"description": "DXOS client services implementation",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -24,43 +24,43 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"level": "^8.0.1",
|
|
26
26
|
"platform": "^1.3.6",
|
|
27
|
-
"@dxos/async": "0.4.10-main.
|
|
28
|
-
"@dxos/client-protocol": "0.4.10-main.
|
|
29
|
-
"@dxos/automerge": "0.4.10-main.
|
|
30
|
-
"@dxos/codec-protobuf": "0.4.10-main.
|
|
31
|
-
"@dxos/
|
|
32
|
-
"@dxos/
|
|
33
|
-
"@dxos/
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/debug": "0.4.10-main.
|
|
36
|
-
"@dxos/echo-db": "0.4.10-main.
|
|
37
|
-
"@dxos/echo-
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/indexing": "0.4.10-main.
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/
|
|
43
|
-
"@dxos/
|
|
44
|
-
"@dxos/
|
|
45
|
-
"@dxos/log": "0.4.10-main.
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/random-access-storage": "0.4.10-main.
|
|
51
|
-
"@dxos/rpc": "0.4.10-main.
|
|
52
|
-
"@dxos/teleport": "0.4.10-main.
|
|
53
|
-
"@dxos/teleport-extension-gossip": "0.4.10-main.
|
|
54
|
-
"@dxos/teleport-extension-object-sync": "0.4.10-main.
|
|
55
|
-
"@dxos/timeframe": "0.4.10-main.
|
|
56
|
-
"@dxos/tracing": "0.4.10-main.
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
27
|
+
"@dxos/async": "0.4.10-main.403e461",
|
|
28
|
+
"@dxos/client-protocol": "0.4.10-main.403e461",
|
|
29
|
+
"@dxos/automerge": "0.4.10-main.403e461",
|
|
30
|
+
"@dxos/codec-protobuf": "0.4.10-main.403e461",
|
|
31
|
+
"@dxos/context": "0.4.10-main.403e461",
|
|
32
|
+
"@dxos/config": "0.4.10-main.403e461",
|
|
33
|
+
"@dxos/crypto": "0.4.10-main.403e461",
|
|
34
|
+
"@dxos/credentials": "0.4.10-main.403e461",
|
|
35
|
+
"@dxos/debug": "0.4.10-main.403e461",
|
|
36
|
+
"@dxos/echo-db": "0.4.10-main.403e461",
|
|
37
|
+
"@dxos/echo-schema": "0.4.10-main.403e461",
|
|
38
|
+
"@dxos/feed-store": "0.4.10-main.403e461",
|
|
39
|
+
"@dxos/echo-pipeline": "0.4.10-main.403e461",
|
|
40
|
+
"@dxos/indexing": "0.4.10-main.403e461",
|
|
41
|
+
"@dxos/invariant": "0.4.10-main.403e461",
|
|
42
|
+
"@dxos/keyring": "0.4.10-main.403e461",
|
|
43
|
+
"@dxos/keys": "0.4.10-main.403e461",
|
|
44
|
+
"@dxos/lock-file": "0.4.10-main.403e461",
|
|
45
|
+
"@dxos/log": "0.4.10-main.403e461",
|
|
46
|
+
"@dxos/messaging": "0.4.10-main.403e461",
|
|
47
|
+
"@dxos/network-manager": "0.4.10-main.403e461",
|
|
48
|
+
"@dxos/node-std": "0.4.10-main.403e461",
|
|
49
|
+
"@dxos/protocols": "0.4.10-main.403e461",
|
|
50
|
+
"@dxos/random-access-storage": "0.4.10-main.403e461",
|
|
51
|
+
"@dxos/rpc": "0.4.10-main.403e461",
|
|
52
|
+
"@dxos/teleport": "0.4.10-main.403e461",
|
|
53
|
+
"@dxos/teleport-extension-gossip": "0.4.10-main.403e461",
|
|
54
|
+
"@dxos/teleport-extension-object-sync": "0.4.10-main.403e461",
|
|
55
|
+
"@dxos/timeframe": "0.4.10-main.403e461",
|
|
56
|
+
"@dxos/tracing": "0.4.10-main.403e461",
|
|
57
|
+
"@dxos/websocket-rpc": "0.4.10-main.403e461",
|
|
58
|
+
"@dxos/util": "0.4.10-main.403e461"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@types/platform": "^1.3.4",
|
|
62
62
|
"@types/readable-stream": "^2.3.9",
|
|
63
|
-
"@dxos/signal": "0.4.10-main.
|
|
63
|
+
"@dxos/signal": "0.4.10-main.403e461"
|
|
64
64
|
},
|
|
65
65
|
"publishConfig": {
|
|
66
66
|
"access": "public"
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Trigger } from '@dxos/async';
|
|
6
6
|
import { cancelWithContext, Context } from '@dxos/context';
|
|
7
|
+
import { randomBytes, verify } from '@dxos/crypto';
|
|
7
8
|
import { invariant } from '@dxos/invariant';
|
|
8
9
|
import { PublicKey } from '@dxos/keys';
|
|
9
10
|
import { log } from '@dxos/log';
|
|
@@ -51,6 +52,8 @@ export class InvitationHostExtension extends RpcExtension<
|
|
|
51
52
|
private _remoteOptions?: Options;
|
|
52
53
|
private _remoteOptionsTrigger = new Trigger();
|
|
53
54
|
|
|
55
|
+
private _challenge?: Buffer = undefined;
|
|
56
|
+
|
|
54
57
|
public invitation?: Invitation = undefined;
|
|
55
58
|
|
|
56
59
|
public guestProfile?: ProfileDocument = undefined;
|
|
@@ -113,13 +116,17 @@ export class InvitationHostExtension extends RpcExtension<
|
|
|
113
116
|
|
|
114
117
|
this._callbacks.onStateUpdate({ ...this.invitation, state: Invitation.State.READY_FOR_AUTHENTICATION });
|
|
115
118
|
|
|
119
|
+
this._challenge =
|
|
120
|
+
this.invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY ? randomBytes(32) : undefined;
|
|
121
|
+
|
|
116
122
|
log.trace('dxos.sdk.invitation-handler.host.introduce', trace.end({ id: traceId }));
|
|
117
123
|
return {
|
|
118
124
|
authMethod: this.invitation.authMethod,
|
|
125
|
+
challenge: this._challenge,
|
|
119
126
|
};
|
|
120
127
|
},
|
|
121
128
|
|
|
122
|
-
authenticate: async ({ authCode: code }) => {
|
|
129
|
+
authenticate: async ({ authCode: code, signedChallenge }) => {
|
|
123
130
|
const traceId = PublicKey.random().toHex();
|
|
124
131
|
log.trace('dxos.sdk.invitation-handler.host.authenticate', trace.begin({ id: traceId }));
|
|
125
132
|
log('received authentication request', { authCode: code });
|
|
@@ -145,6 +152,26 @@ export class InvitationHostExtension extends RpcExtension<
|
|
|
145
152
|
break;
|
|
146
153
|
}
|
|
147
154
|
|
|
155
|
+
case Invitation.AuthMethod.KNOWN_PUBLIC_KEY: {
|
|
156
|
+
if (!this.invitation.guestKeypair) {
|
|
157
|
+
status = AuthenticationResponse.Status.INTERNAL_ERROR;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
const isSignatureValid =
|
|
161
|
+
this._challenge &&
|
|
162
|
+
verify(
|
|
163
|
+
this._challenge,
|
|
164
|
+
Buffer.from(signedChallenge ?? []),
|
|
165
|
+
this.invitation.guestKeypair.publicKey.asBuffer(),
|
|
166
|
+
);
|
|
167
|
+
if (isSignatureValid) {
|
|
168
|
+
this.authenticationPassed = true;
|
|
169
|
+
} else {
|
|
170
|
+
status = AuthenticationResponse.Status.INVALID_SIGNATURE;
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
|
|
148
175
|
default: {
|
|
149
176
|
log.error('invalid authentication method', { authMethod: this.invitation.authMethod });
|
|
150
177
|
status = AuthenticationResponse.Status.INTERNAL_ERROR;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from '@dxos/client-protocol';
|
|
12
12
|
import { Context } from '@dxos/context';
|
|
13
13
|
import { generatePasscode } from '@dxos/credentials';
|
|
14
|
+
import { createKeyPair, sign } from '@dxos/crypto';
|
|
14
15
|
import { invariant } from '@dxos/invariant';
|
|
15
16
|
import { PublicKey } from '@dxos/keys';
|
|
16
17
|
import { log } from '@dxos/log';
|
|
@@ -21,9 +22,9 @@ import {
|
|
|
21
22
|
type SwarmConnection,
|
|
22
23
|
} from '@dxos/network-manager';
|
|
23
24
|
import { InvalidInvitationExtensionRoleError, trace } from '@dxos/protocols';
|
|
24
|
-
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
25
|
+
import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
25
26
|
import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
26
|
-
import { AuthenticationResponse } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
27
|
+
import { AuthenticationResponse, type IntroductionResponse } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
27
28
|
|
|
28
29
|
import {
|
|
29
30
|
InvitationGuestExtension,
|
|
@@ -74,8 +75,9 @@ export class InvitationsHandler {
|
|
|
74
75
|
state = Invitation.State.INIT,
|
|
75
76
|
timeout = INVITATION_TIMEOUT,
|
|
76
77
|
swarmKey = PublicKey.random(),
|
|
77
|
-
persistent =
|
|
78
|
+
persistent = options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY, // default no not storing keypairs
|
|
78
79
|
created = new Date(),
|
|
80
|
+
guestKeypair = undefined,
|
|
79
81
|
lifetime = 86400, // 1 day,
|
|
80
82
|
multiUse = false,
|
|
81
83
|
} = options ?? {};
|
|
@@ -92,7 +94,9 @@ export class InvitationsHandler {
|
|
|
92
94
|
swarmKey,
|
|
93
95
|
authCode,
|
|
94
96
|
timeout,
|
|
95
|
-
persistent: persistent && type !== Invitation.Type.
|
|
97
|
+
persistent: persistent && type !== Invitation.Type.DELEGATED, // delegated invitations are persisted in control feed
|
|
98
|
+
guestKeypair:
|
|
99
|
+
guestKeypair ?? (authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY ? createAdmissionKeypair() : undefined),
|
|
96
100
|
created,
|
|
97
101
|
lifetime,
|
|
98
102
|
multiUse,
|
|
@@ -319,26 +323,13 @@ export class InvitationsHandler {
|
|
|
319
323
|
|
|
320
324
|
// 2. Get authentication code.
|
|
321
325
|
if (isAuthenticationRequired(invitation)) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
setState({ state: Invitation.State.AUTHENTICATING });
|
|
329
|
-
const response = await extension.rpc.InvitationHostService.authenticate({ authCode });
|
|
330
|
-
if (response.status === undefined || response.status === AuthenticationResponse.Status.OK) {
|
|
326
|
+
switch (invitation.authMethod) {
|
|
327
|
+
case Invitation.AuthMethod.SHARED_SECRET:
|
|
328
|
+
await this._handleGuestOtpAuth(extension, setState, authenticated, { timeout });
|
|
329
|
+
break;
|
|
330
|
+
case Invitation.AuthMethod.KNOWN_PUBLIC_KEY:
|
|
331
|
+
await this._handleGuestKpkAuth(extension, setState, invitation, introductionResponse);
|
|
331
332
|
break;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (response.status === AuthenticationResponse.Status.INVALID_OTP) {
|
|
335
|
-
if (attempt === MAX_OTP_ATTEMPTS) {
|
|
336
|
-
throw new Error(`Maximum retry attempts: ${MAX_OTP_ATTEMPTS}`);
|
|
337
|
-
} else {
|
|
338
|
-
log('retrying invalid code', { attempt });
|
|
339
|
-
authenticated.reset();
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
333
|
}
|
|
343
334
|
}
|
|
344
335
|
|
|
@@ -425,4 +416,61 @@ export class InvitationsHandler {
|
|
|
425
416
|
|
|
426
417
|
return observable;
|
|
427
418
|
}
|
|
419
|
+
|
|
420
|
+
private async _handleGuestOtpAuth(
|
|
421
|
+
extension: InvitationGuestExtension,
|
|
422
|
+
setState: (newState: Partial<Invitation>) => void,
|
|
423
|
+
authenticated: Trigger<string>,
|
|
424
|
+
options: { timeout: number },
|
|
425
|
+
) {
|
|
426
|
+
for (let attempt = 1; attempt <= MAX_OTP_ATTEMPTS; attempt++) {
|
|
427
|
+
log('guest waiting for authentication code...');
|
|
428
|
+
setState({ state: Invitation.State.READY_FOR_AUTHENTICATION });
|
|
429
|
+
const authCode = await authenticated.wait(options);
|
|
430
|
+
|
|
431
|
+
log('sending authentication request');
|
|
432
|
+
setState({ state: Invitation.State.AUTHENTICATING });
|
|
433
|
+
const response = await extension.rpc.InvitationHostService.authenticate({ authCode });
|
|
434
|
+
if (response.status === undefined || response.status === AuthenticationResponse.Status.OK) {
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (response.status === AuthenticationResponse.Status.INVALID_OTP) {
|
|
439
|
+
if (attempt === MAX_OTP_ATTEMPTS) {
|
|
440
|
+
throw new Error(`Maximum retry attempts: ${MAX_OTP_ATTEMPTS}`);
|
|
441
|
+
} else {
|
|
442
|
+
log('retrying invalid code', { attempt });
|
|
443
|
+
authenticated.reset();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
private async _handleGuestKpkAuth(
|
|
450
|
+
extension: InvitationGuestExtension,
|
|
451
|
+
setState: (newState: Partial<Invitation>) => void,
|
|
452
|
+
invitation: Invitation,
|
|
453
|
+
introductionResponse: IntroductionResponse,
|
|
454
|
+
) {
|
|
455
|
+
if (invitation.guestKeypair?.privateKey == null) {
|
|
456
|
+
throw new Error('keypair missing in the invitation');
|
|
457
|
+
}
|
|
458
|
+
if (introductionResponse.challenge == null) {
|
|
459
|
+
throw new Error('challenge missing in the introduction');
|
|
460
|
+
}
|
|
461
|
+
log('sending authentication request');
|
|
462
|
+
setState({ state: Invitation.State.AUTHENTICATING });
|
|
463
|
+
const signature = sign(Buffer.from(introductionResponse.challenge), invitation.guestKeypair.privateKey);
|
|
464
|
+
const response = await extension.rpc.InvitationHostService.authenticate({
|
|
465
|
+
signedChallenge: signature,
|
|
466
|
+
});
|
|
467
|
+
if (response.status !== AuthenticationResponse.Status.OK) {
|
|
468
|
+
throw new Error(`Authentication failed with code: ${response.status}`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
428
471
|
}
|
|
472
|
+
|
|
473
|
+
export const createAdmissionKeypair = (): AdmissionKeypair => {
|
|
474
|
+
const keypair = createKeyPair();
|
|
475
|
+
return { publicKey: PublicKey.from(keypair.publicKey), privateKey: keypair.secretKey };
|
|
476
|
+
};
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type SpaceDoc,
|
|
16
16
|
type MyLevel,
|
|
17
17
|
} from '@dxos/echo-pipeline';
|
|
18
|
-
import
|
|
18
|
+
import { getTypeReference } from '@dxos/echo-schema';
|
|
19
19
|
import { IndexServiceImpl } from '@dxos/indexing';
|
|
20
20
|
import { invariant } from '@dxos/invariant';
|
|
21
21
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -383,7 +383,7 @@ export class ClientServicesHost {
|
|
|
383
383
|
// TODO(dmaretskyi): Better API for low-level data access.
|
|
384
384
|
const properties: ObjectStructure = {
|
|
385
385
|
system: {
|
|
386
|
-
type: encodeReference(
|
|
386
|
+
type: encodeReference(getTypeReference(Properties)!),
|
|
387
387
|
},
|
|
388
388
|
data: {
|
|
389
389
|
[defaultKey]: identity.identityKey.toHex(),
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const DXOS_VERSION = "0.4.10-main.
|
|
1
|
+
export const DXOS_VERSION = "0.4.10-main.403e461";
|