@dxos/edge-client 0.6.12-main.78ddbdf → 0.6.12-main.89e9959

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.
@@ -1 +1 @@
1
- {"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytes":10334,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/defs.ts":{"bytes":1607,"imports":[{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/errors.ts":{"bytes":1265,"imports":[],"format":"esm"},"packages/core/mesh/edge-client/src/persistent-lifecycle.ts":{"bytes":10868,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/edge-client.ts":{"bytes":27085,"imports":[{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"./defs"},{"path":"packages/core/mesh/edge-client/src/errors.ts","kind":"import-statement","original":"./errors"},{"path":"packages/core/mesh/edge-client/src/persistent-lifecycle.ts","kind":"import-statement","original":"./persistent-lifecycle"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/index.ts":{"bytes":935,"imports":[{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/edge-client.ts","kind":"import-statement","original":"./edge-client"},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"./defs"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"},{"path":"packages/core/mesh/edge-client/src/errors.ts","kind":"import-statement","original":"./errors"}],"format":"esm"},"packages/core/mesh/edge-client/src/testing/test-utils.ts":{"bytes":12455,"imports":[{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"../defs"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"../protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/testing/index.ts":{"bytes":516,"imports":[{"path":"packages/core/mesh/edge-client/src/testing/test-utils.ts","kind":"import-statement","original":"./test-utils"}],"format":"esm"}},"outputs":{"packages/core/mesh/edge-client/dist/lib/node-esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":18218},"packages/core/mesh/edge-client/dist/lib/node-esm/index.mjs":{"imports":[{"path":"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs","kind":"import-statement"},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"exports":["EdgeClient","EdgeConnectionClosedError","EdgeIdentityChangedError","Protocol","getTypename","protocol","toUint8Array"],"entryPoint":"packages/core/mesh/edge-client/src/index.ts","inputs":{"packages/core/mesh/edge-client/src/index.ts":{"bytesInOutput":60},"packages/core/mesh/edge-client/src/edge-client.ts":{"bytesInOutput":6943},"packages/core/mesh/edge-client/src/errors.ts":{"bytesInOutput":232},"packages/core/mesh/edge-client/src/persistent-lifecycle.ts":{"bytesInOutput":3015}},"bytes":10876},"packages/core/mesh/edge-client/dist/lib/node-esm/testing/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":6342},"packages/core/mesh/edge-client/dist/lib/node-esm/testing/index.mjs":{"imports":[{"path":"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs","kind":"import-statement"},{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true}],"exports":["DEFAULT_PORT","createTestEdgeWsServer"],"entryPoint":"packages/core/mesh/edge-client/src/testing/index.ts","inputs":{"packages/core/mesh/edge-client/src/testing/test-utils.ts":{"bytesInOutput":3276},"packages/core/mesh/edge-client/src/testing/index.ts":{"bytesInOutput":0}},"bytes":3585},"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":5678},"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs":{"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true}],"exports":["Protocol","getTypename","protocol","toUint8Array"],"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytesInOutput":2600},"packages/core/mesh/edge-client/src/defs.ts":{"bytesInOutput":298}},"bytes":3199}}}
1
+ {"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytes":10334,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/defs.ts":{"bytes":1607,"imports":[{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/errors.ts":{"bytes":1265,"imports":[],"format":"esm"},"packages/core/mesh/edge-client/src/persistent-lifecycle.ts":{"bytes":10868,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/edge-client.ts":{"bytes":32385,"imports":[{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/crypto","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/protocols/proto","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"./defs"},{"path":"packages/core/mesh/edge-client/src/errors.ts","kind":"import-statement","original":"./errors"},{"path":"packages/core/mesh/edge-client/src/persistent-lifecycle.ts","kind":"import-statement","original":"./persistent-lifecycle"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/auth.ts":{"bytes":11621,"imports":[{"path":"@dxos/credentials","kind":"import-statement","external":true},{"path":"@dxos/keyring","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/edge-http-client.ts":{"bytes":15155,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/index.ts":{"bytes":1127,"imports":[{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/edge-client.ts","kind":"import-statement","original":"./edge-client"},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"./defs"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"},{"path":"packages/core/mesh/edge-client/src/errors.ts","kind":"import-statement","original":"./errors"},{"path":"packages/core/mesh/edge-client/src/auth.ts","kind":"import-statement","original":"./auth"},{"path":"packages/core/mesh/edge-client/src/edge-http-client.ts","kind":"import-statement","original":"./edge-http-client"}],"format":"esm"},"packages/core/mesh/edge-client/src/testing/test-utils.ts":{"bytes":12455,"imports":[{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"../defs"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"../protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/testing/index.ts":{"bytes":516,"imports":[{"path":"packages/core/mesh/edge-client/src/testing/test-utils.ts","kind":"import-statement","original":"./test-utils"}],"format":"esm"}},"outputs":{"packages/core/mesh/edge-client/dist/lib/node-esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":34450},"packages/core/mesh/edge-client/dist/lib/node-esm/index.mjs":{"imports":[{"path":"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs","kind":"import-statement"},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/crypto","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/protocols/proto","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/credentials","kind":"import-statement","external":true},{"path":"@dxos/keyring","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true}],"exports":["EdgeClient","EdgeConnectionClosedError","EdgeHttpClient","EdgeIdentityChangedError","Protocol","createChainEdgeIdentity","createDeviceEdgeIdentity","createEphemeralEdgeIdentity","createStubEdgeIdentity","createTestHaloEdgeIdentity","getTypename","protocol","toUint8Array"],"entryPoint":"packages/core/mesh/edge-client/src/index.ts","inputs":{"packages/core/mesh/edge-client/src/index.ts":{"bytesInOutput":60},"packages/core/mesh/edge-client/src/edge-client.ts":{"bytesInOutput":7977},"packages/core/mesh/edge-client/src/errors.ts":{"bytesInOutput":232},"packages/core/mesh/edge-client/src/persistent-lifecycle.ts":{"bytesInOutput":3015},"packages/core/mesh/edge-client/src/auth.ts":{"bytesInOutput":2681},"packages/core/mesh/edge-client/src/edge-http-client.ts":{"bytesInOutput":3649}},"bytes":18506},"packages/core/mesh/edge-client/dist/lib/node-esm/testing/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":6342},"packages/core/mesh/edge-client/dist/lib/node-esm/testing/index.mjs":{"imports":[{"path":"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs","kind":"import-statement"},{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true}],"exports":["DEFAULT_PORT","createTestEdgeWsServer"],"entryPoint":"packages/core/mesh/edge-client/src/testing/index.ts","inputs":{"packages/core/mesh/edge-client/src/testing/test-utils.ts":{"bytesInOutput":3276},"packages/core/mesh/edge-client/src/testing/index.ts":{"bytesInOutput":0}},"bytes":3585},"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":5678},"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs":{"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true}],"exports":["Protocol","getTypename","protocol","toUint8Array"],"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytesInOutput":2600},"packages/core/mesh/edge-client/src/defs.ts":{"bytesInOutput":298}},"bytes":3199}}}
@@ -0,0 +1,22 @@
1
+ import { type Signer } from '@dxos/crypto';
2
+ import { PublicKey } from '@dxos/keys';
3
+ import { type Chain, type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
4
+ import type { EdgeIdentity } from './edge-client';
5
+ /**
6
+ * Edge identity backed by a device key without a credential chain.
7
+ */
8
+ export declare const createDeviceEdgeIdentity: (signer: Signer, key: PublicKey) => Promise<EdgeIdentity>;
9
+ /**
10
+ * Edge identity backed by a chain of credentials.
11
+ */
12
+ export declare const createChainEdgeIdentity: (signer: Signer, identityKey: PublicKey, peerKey: PublicKey, chain: Chain, credentials: Credential[]) => Promise<EdgeIdentity>;
13
+ /**
14
+ * Edge identity backed by a random ephemeral key without HALO.
15
+ */
16
+ export declare const createEphemeralEdgeIdentity: () => Promise<EdgeIdentity>;
17
+ /**
18
+ * Creates a HALO chain of credentials to act as an edge identity.
19
+ */
20
+ export declare const createTestHaloEdgeIdentity: (signer: Signer, identityKey: PublicKey, deviceKey: PublicKey) => Promise<EdgeIdentity>;
21
+ export declare const createStubEdgeIdentity: () => EdgeIdentity;
22
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/auth.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,6CAA6C,CAAC;AAE1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,wBAAwB,WAAkB,MAAM,OAAO,SAAS,KAAG,OAAO,CAAC,YAAY,CAyBnG,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,WAC1B,MAAM,eACD,SAAS,WACb,SAAS,SACX,KAAK,eACC,UAAU,EAAE,KACxB,OAAO,CAAC,YAAY,CAgCtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,2BAA2B,QAAa,OAAO,CAAC,YAAY,CAIxE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,WAC7B,MAAM,eACD,SAAS,aACX,SAAS,KACnB,OAAO,CAAC,YAAY,CAqBtB,CAAC;AAEF,eAAO,MAAM,sBAAsB,QAAO,YAUzC,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { Event } from '@dxos/async';
2
2
  import { Resource, type Lifecycle } from '@dxos/context';
3
3
  import { type Message } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
4
+ import { type Presentation } from '@dxos/protocols/proto/dxos/halo/credentials';
4
5
  import { type Protocol } from './protocol';
5
6
  export type MessageListener = (message: Message) => void | Promise<void>;
6
7
  export interface EdgeConnection extends Required<Lifecycle> {
@@ -10,10 +11,8 @@ export interface EdgeConnection extends Required<Lifecycle> {
10
11
  get identityKey(): string;
11
12
  get peerKey(): string;
12
13
  get isOpen(): boolean;
13
- setIdentity(params: {
14
- peerKey: string;
15
- identityKey: string;
16
- }): void;
14
+ get isConnected(): boolean;
15
+ setIdentity(identity: EdgeIdentity): void;
17
16
  addListener(listener: MessageListener): () => void;
18
17
  send(message: Message): Promise<void>;
19
18
  }
@@ -22,12 +21,23 @@ export type MessengerConfig = {
22
21
  timeout?: number;
23
22
  protocol?: Protocol;
24
23
  };
24
+ export interface EdgeIdentity {
25
+ peerKey: string;
26
+ identityKey: string;
27
+ /**
28
+ * Returns credential presentation issued by the identity key.
29
+ * Presentation must have the provided challenge.
30
+ * Presentation may include ServiceAccess credentials.
31
+ */
32
+ presentCredentials({ challenge }: {
33
+ challenge: Uint8Array;
34
+ }): Promise<Presentation>;
35
+ }
25
36
  /**
26
37
  * Messenger client.
27
38
  */
28
39
  export declare class EdgeClient extends Resource implements EdgeConnection {
29
- private _identityKey;
30
- private _peerKey;
40
+ private _identity;
31
41
  private readonly _config;
32
42
  readonly reconnect: Event<void>;
33
43
  readonly connected: Event<void>;
@@ -37,18 +47,16 @@ export declare class EdgeClient extends Resource implements EdgeConnection {
37
47
  private _ws?;
38
48
  private _keepaliveCtx?;
39
49
  private _heartBeatContext?;
40
- constructor(_identityKey: string, _peerKey: string, _config: MessengerConfig);
50
+ constructor(_identity: EdgeIdentity, _config: MessengerConfig);
41
51
  get info(): {
42
52
  open: boolean;
43
53
  identity: string;
44
54
  device: string;
45
55
  };
56
+ get isConnected(): boolean;
46
57
  get identityKey(): string;
47
58
  get peerKey(): string;
48
- setIdentity({ peerKey, identityKey }: {
49
- peerKey: string;
50
- identityKey: string;
51
- }): void;
59
+ setIdentity(identity: EdgeIdentity): void;
52
60
  addListener(listener: MessageListener): () => void;
53
61
  /**
54
62
  * Open connection to messaging service.
@@ -1 +1 @@
1
- {"version":3,"file":"edge-client.d.ts","sourceRoot":"","sources":["../../../src/edge-client.ts"],"names":[],"mappings":"AAMA,OAAO,EAAW,KAAK,EAAoD,MAAM,aAAa,CAAC;AAC/F,OAAO,EAA2B,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlF,OAAO,EAAE,KAAK,OAAO,EAAiB,MAAM,4CAA4C,CAAC;AAKzF,OAAO,EAAE,KAAK,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAKzD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzE,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAAC,SAAS,CAAC;IACzD,SAAS,EAAE,KAAK,CAAC;IACjB,SAAS,EAAE,KAAK,CAAC;IAEjB,IAAI,IAAI,IAAI,GAAG,CAAC;IAChB,IAAI,WAAW,IAAI,MAAM,CAAC;IAC1B,IAAI,OAAO,IAAI,MAAM,CAAC;IACtB,IAAI,MAAM,IAAI,OAAO,CAAC;IACtB,WAAW,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpE,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,qBAAa,UAAW,SAAQ,QAAS,YAAW,cAAc;IAgB9D,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAjB1B,SAAgB,SAAS,cAAe;IACxC,SAAgB,SAAS,cAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAIlC;IAEH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,GAAG,CAAC,CAAwB;IACpC,OAAO,CAAC,aAAa,CAAC,CAAsB;IAC5C,OAAO,CAAC,iBAAiB,CAAC,CAAsB;gBAGtC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EACP,OAAO,EAAE,eAAe;IAM3C,IAAW,IAAI;;;;MAMd;IAED,IAAI,WAAW,WAEd;IAED,IAAI,OAAO,WAEV;IAED,WAAW,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;IAMvE,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI;IAKzD;;OAEG;cACsB,KAAK;IAO9B;;OAEG;cACsB,MAAM;YAKjB,cAAc;YAsDd,eAAe;IA0B7B;;;OAGG;IACU,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlD,OAAO,CAAC,YAAY;CAcrB"}
1
+ {"version":3,"file":"edge-client.d.ts","sourceRoot":"","sources":["../../../src/edge-client.ts"],"names":[],"mappings":"AAMA,OAAO,EAAW,KAAK,EAAoD,MAAM,aAAa,CAAC;AAC/F,OAAO,EAA2B,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAIlF,OAAO,EAAE,KAAK,OAAO,EAAiB,MAAM,4CAA4C,CAAC;AAEzF,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,6CAA6C,CAAC;AAKhF,OAAO,EAAE,KAAK,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAKzD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzE,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAAC,SAAS,CAAC;IACzD,SAAS,EAAE,KAAK,CAAC;IACjB,SAAS,EAAE,KAAK,CAAC;IAEjB,IAAI,IAAI,IAAI,GAAG,CAAC;IAChB,IAAI,WAAW,IAAI,MAAM,CAAC;IAC1B,IAAI,OAAO,IAAI,MAAM,CAAC;IACtB,IAAI,MAAM,IAAI,OAAO,CAAC;IACtB,IAAI,WAAW,IAAI,OAAO,CAAC;IAC3B,WAAW,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1C,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE;QAAE,SAAS,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACrF;AAID;;GAEG;AACH,qBAAa,UAAW,SAAQ,QAAS,YAAW,cAAc;IAgB9D,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAhB1B,SAAgB,SAAS,cAAe;IACxC,SAAgB,SAAS,cAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAIlC;IAEH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,GAAG,CAAC,CAAwB;IACpC,OAAO,CAAC,aAAa,CAAC,CAAsB;IAC5C,OAAO,CAAC,iBAAiB,CAAC,CAAsB;gBAGtC,SAAS,EAAE,YAAY,EACd,OAAO,EAAE,eAAe;IAM3C,IAAW,IAAI;;;;MAMd;IAED,IAAI,WAAW,YAEd;IAED,IAAI,WAAW,WAEd;IAED,IAAI,OAAO,WAEV;IAED,WAAW,CAAC,QAAQ,EAAE,YAAY;IAK3B,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI;IAKzD;;OAEG;cACsB,KAAK;IAO9B;;OAEG;cACsB,MAAM;YAKjB,cAAc;YAmEd,eAAe;IA0B7B;;;OAGG;IACU,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlD,OAAO,CAAC,YAAY;CAcrB"}
@@ -0,0 +1,34 @@
1
+ import { Context } from '@dxos/context';
2
+ import { type SpaceId } from '@dxos/keys';
3
+ import { type GetNotarizationResponseBody, type PostNotarizationRequestBody } from '@dxos/protocols';
4
+ export declare class EdgeHttpClient {
5
+ private readonly _baseUrl;
6
+ constructor(baseUrl: string);
7
+ getCredentialsForNotarization(spaceId: SpaceId, args?: EdgeHttpGetArgs): Promise<GetNotarizationResponseBody>;
8
+ notarizeCredentials(spaceId: SpaceId, body: PostNotarizationRequestBody, args?: EdgeHttpGetArgs): Promise<void>;
9
+ private _call;
10
+ }
11
+ export type RetryConfig = {
12
+ /**
13
+ * A number of call retries, not counting the initial request.
14
+ */
15
+ count: number;
16
+ /**
17
+ * Delay before retries in ms.
18
+ */
19
+ timeout?: number;
20
+ /**
21
+ * A random amount of time before retrying to help prevent large bursts of requests.
22
+ */
23
+ jitter?: number;
24
+ };
25
+ export type EdgeHttpGetArgs = {
26
+ context?: Context;
27
+ retry?: RetryConfig;
28
+ };
29
+ export type EdgeHttpPostArgs = {
30
+ context?: Context;
31
+ body?: any;
32
+ retry?: RetryConfig;
33
+ };
34
+ //# sourceMappingURL=edge-http-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-http-client.d.ts","sourceRoot":"","sources":["../../../src/edge-http-client.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAGL,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EACjC,MAAM,iBAAiB,CAAC;AAMzB,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,EAAE,MAAM;IAOpB,6BAA6B,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAIvG,mBAAmB,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,2BAA2B,EACjC,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC;YAIF,KAAK;CA6CpB;AA0CD,MAAM,MAAM,WAAW,GAAG;IACxB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC;AAEzE,MAAM,MAAM,gBAAgB,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,KAAK,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC"}
@@ -3,4 +3,6 @@ export * from './edge-client';
3
3
  export * from './defs';
4
4
  export * from './protocol';
5
5
  export * from './errors';
6
+ export * from './auth';
7
+ export * from './edge-http-client';
6
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,4CAA4C,CAAC;AAE3D,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,4CAA4C,CAAC;AAE3D,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/edge-client",
3
- "version": "0.6.12-main.78ddbdf",
3
+ "version": "0.6.12-main.89e9959",
4
4
  "description": "EDGE Client",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -40,18 +40,21 @@
40
40
  "dependencies": {
41
41
  "isomorphic-ws": "^5.0.0",
42
42
  "ws": "^8.14.2",
43
- "@dxos/async": "0.6.12-main.78ddbdf",
44
- "@dxos/context": "0.6.12-main.78ddbdf",
45
- "@dxos/debug": "0.6.12-main.78ddbdf",
46
- "@dxos/invariant": "0.6.12-main.78ddbdf",
47
- "@dxos/log": "0.6.12-main.78ddbdf",
48
- "@dxos/protocols": "0.6.12-main.78ddbdf",
49
- "@dxos/node-std": "0.6.12-main.78ddbdf",
50
- "@dxos/util": "0.6.12-main.78ddbdf"
43
+ "@dxos/async": "0.6.12-main.89e9959",
44
+ "@dxos/context": "0.6.12-main.89e9959",
45
+ "@dxos/credentials": "0.6.12-main.89e9959",
46
+ "@dxos/debug": "0.6.12-main.89e9959",
47
+ "@dxos/crypto": "0.6.12-main.89e9959",
48
+ "@dxos/keyring": "0.6.12-main.89e9959",
49
+ "@dxos/invariant": "0.6.12-main.89e9959",
50
+ "@dxos/log": "0.6.12-main.89e9959",
51
+ "@dxos/keys": "0.6.12-main.89e9959",
52
+ "@dxos/node-std": "0.6.12-main.89e9959",
53
+ "@dxos/protocols": "0.6.12-main.89e9959",
54
+ "@dxos/util": "0.6.12-main.89e9959"
51
55
  },
52
56
  "devDependencies": {
53
- "@dxos/test-utils": "0.6.12-main.78ddbdf",
54
- "@dxos/keys": "0.6.12-main.78ddbdf"
57
+ "@dxos/test-utils": "0.6.12-main.89e9959"
55
58
  },
56
59
  "publishConfig": {
57
60
  "access": "public"
package/src/auth.ts ADDED
@@ -0,0 +1,135 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { createCredential, signPresentation } from '@dxos/credentials';
6
+ import { type Signer } from '@dxos/crypto';
7
+ import { Keyring } from '@dxos/keyring';
8
+ import { PublicKey } from '@dxos/keys';
9
+ import { type Chain, type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
10
+
11
+ import type { EdgeIdentity } from './edge-client';
12
+
13
+ /**
14
+ * Edge identity backed by a device key without a credential chain.
15
+ */
16
+ export const createDeviceEdgeIdentity = async (signer: Signer, key: PublicKey): Promise<EdgeIdentity> => {
17
+ return {
18
+ identityKey: key.toHex(),
19
+ peerKey: key.toHex(),
20
+ presentCredentials: async ({ challenge }) => {
21
+ return signPresentation({
22
+ presentation: {
23
+ credentials: [
24
+ // Verifier requires at least one credential in the presentation to establish the subject.
25
+ await createCredential({
26
+ assertion: {
27
+ '@type': 'dxos.halo.credentials.Auth',
28
+ },
29
+ issuer: key,
30
+ subject: key,
31
+ signer,
32
+ }),
33
+ ],
34
+ },
35
+ signer,
36
+ signerKey: key,
37
+ nonce: challenge,
38
+ });
39
+ },
40
+ };
41
+ };
42
+
43
+ /**
44
+ * Edge identity backed by a chain of credentials.
45
+ */
46
+ export const createChainEdgeIdentity = async (
47
+ signer: Signer,
48
+ identityKey: PublicKey,
49
+ peerKey: PublicKey,
50
+ chain: Chain,
51
+ credentials: Credential[],
52
+ ): Promise<EdgeIdentity> => {
53
+ const credentialsToSign =
54
+ credentials.length > 0
55
+ ? credentials
56
+ : [
57
+ await createCredential({
58
+ assertion: {
59
+ '@type': 'dxos.halo.credentials.Auth',
60
+ },
61
+ issuer: identityKey,
62
+ subject: identityKey,
63
+ signer,
64
+ chain,
65
+ signingKey: peerKey,
66
+ }),
67
+ ];
68
+
69
+ return {
70
+ identityKey: identityKey.toHex(),
71
+ peerKey: peerKey.toHex(),
72
+ presentCredentials: async ({ challenge }) => {
73
+ return signPresentation({
74
+ presentation: {
75
+ credentials: credentialsToSign,
76
+ },
77
+ signer,
78
+ nonce: challenge,
79
+ signerKey: peerKey,
80
+ chain,
81
+ });
82
+ },
83
+ };
84
+ };
85
+
86
+ /**
87
+ * Edge identity backed by a random ephemeral key without HALO.
88
+ */
89
+ export const createEphemeralEdgeIdentity = async (): Promise<EdgeIdentity> => {
90
+ const keyring = new Keyring();
91
+ const key = await keyring.createKey();
92
+ return createDeviceEdgeIdentity(keyring, key);
93
+ };
94
+
95
+ /**
96
+ * Creates a HALO chain of credentials to act as an edge identity.
97
+ */
98
+ export const createTestHaloEdgeIdentity = async (
99
+ signer: Signer,
100
+ identityKey: PublicKey,
101
+ deviceKey: PublicKey,
102
+ ): Promise<EdgeIdentity> => {
103
+ const deviceAdmission = await createCredential({
104
+ assertion: {
105
+ '@type': 'dxos.halo.credentials.AuthorizedDevice',
106
+ deviceKey,
107
+ identityKey,
108
+ },
109
+ issuer: identityKey,
110
+ subject: deviceKey,
111
+ signer,
112
+ });
113
+ return createChainEdgeIdentity(signer, identityKey, deviceKey, { credential: deviceAdmission }, [
114
+ await createCredential({
115
+ assertion: {
116
+ '@type': 'dxos.halo.credentials.Auth',
117
+ },
118
+ issuer: identityKey,
119
+ subject: identityKey,
120
+ signer,
121
+ }),
122
+ ]);
123
+ };
124
+
125
+ export const createStubEdgeIdentity = (): EdgeIdentity => {
126
+ const identityKey = PublicKey.random();
127
+ const deviceKey = PublicKey.random();
128
+ return {
129
+ identityKey: identityKey.toHex(),
130
+ peerKey: deviceKey.toHex(),
131
+ presentCredentials: async () => {
132
+ throw new Error('Stub identity does not support authentication.');
133
+ },
134
+ };
135
+ };
@@ -2,12 +2,14 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { test, expect, describe, onTestFinished } from 'vitest';
5
+ import { describe, expect, onTestFinished, test } from 'vitest';
6
6
 
7
- import { PublicKey } from '@dxos/keys';
7
+ import { Trigger } from '@dxos/async';
8
+ import { Keyring } from '@dxos/keyring';
8
9
  import { TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
9
10
  import { openAndClose } from '@dxos/test-utils';
10
11
 
12
+ import { createEphemeralEdgeIdentity, createTestHaloEdgeIdentity } from './auth';
11
13
  import { protocol } from './defs';
12
14
  import { EdgeClient } from './edge-client';
13
15
  import { createTestEdgeWsServer } from './testing';
@@ -19,8 +21,7 @@ describe('EdgeClient', () => {
19
21
  const { closeConnection, endpoint, cleanup } = await createTestEdgeWsServer(8001);
20
22
  onTestFinished(cleanup);
21
23
 
22
- const id = PublicKey.random().toHex();
23
- const client = new EdgeClient(id, id, { socketEndpoint: endpoint });
24
+ const client = new EdgeClient(await createEphemeralEdgeIdentity(), { socketEndpoint: endpoint });
24
25
  await openAndClose(client);
25
26
  await client.send(textMessage('Hello world 1'));
26
27
  expect(client.isOpen).is.true;
@@ -31,20 +32,51 @@ describe('EdgeClient', () => {
31
32
  await expect(client.send(textMessage('Hello world 2'))).resolves.not.toThrow();
32
33
  });
33
34
 
35
+ test('isConnected', async () => {
36
+ const admitConnection = new Trigger();
37
+ const { closeConnection, endpoint, cleanup } = await createTestEdgeWsServer(8001, { admitConnection });
38
+ onTestFinished(cleanup);
39
+
40
+ const client = new EdgeClient(await createEphemeralEdgeIdentity(), { socketEndpoint: endpoint });
41
+ await openAndClose(client);
42
+
43
+ expect(client.isConnected).toBeFalsy();
44
+ admitConnection.wake();
45
+ await expect.poll(() => client.isConnected).toBeTruthy();
46
+
47
+ admitConnection.reset();
48
+ await closeConnection();
49
+ expect(client.isOpen).is.true;
50
+ await expect.poll(() => client.isConnected).toBeFalsy();
51
+
52
+ admitConnection.wake();
53
+ await expect.poll(() => client.isConnected).toBeTruthy();
54
+ });
55
+
34
56
  test('set identity reconnects', async () => {
35
57
  const { endpoint, cleanup } = await createTestEdgeWsServer(8002);
36
58
  onTestFinished(cleanup);
37
59
 
38
- const id = PublicKey.random().toHex();
39
- const client = new EdgeClient(id, id, { socketEndpoint: endpoint });
60
+ const client = new EdgeClient(await createEphemeralEdgeIdentity(), { socketEndpoint: endpoint });
40
61
  await openAndClose(client);
41
62
  await client.send(textMessage('Hello world 1'));
42
63
  expect(client.isOpen).is.true;
43
64
 
44
- const newId = PublicKey.random().toHex();
45
65
  const reconnected = client.reconnect.waitForCount(1);
46
- client.setIdentity({ peerKey: newId, identityKey: newId });
66
+ client.setIdentity(await createEphemeralEdgeIdentity());
47
67
  await reconnected;
48
68
  await expect(client.send(textMessage('Hello world 2'))).resolves.not.toThrow();
49
69
  });
70
+
71
+ test.skipIf(!process.env.EDGE_ENDPOINT)('connect to local edge server', async () => {
72
+ // const identity = await createEphemeralEdgeIdentity();
73
+
74
+ const keyring = new Keyring();
75
+ const identity = await createTestHaloEdgeIdentity(keyring, await keyring.createKey(), await keyring.createKey());
76
+
77
+ const client = new EdgeClient(identity, { socketEndpoint: process.env.EDGE_ENDPOINT! });
78
+ await openAndClose(client);
79
+ await client.send(textMessage('Hello world 1'));
80
+ expect(client.isOpen).is.true;
81
+ });
50
82
  });
@@ -6,9 +6,12 @@ import WebSocket from 'isomorphic-ws';
6
6
 
7
7
  import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from '@dxos/async';
8
8
  import { Context, LifecycleState, Resource, type Lifecycle } from '@dxos/context';
9
+ import { randomBytes } from '@dxos/crypto';
9
10
  import { log } from '@dxos/log';
10
11
  import { buf } from '@dxos/protocols/buf';
11
12
  import { type Message, MessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
13
+ import { schema } from '@dxos/protocols/proto';
14
+ import { type Presentation } from '@dxos/protocols/proto/dxos/halo/credentials';
12
15
 
13
16
  import { protocol } from './defs';
14
17
  import { EdgeConnectionClosedError, EdgeIdentityChangedError } from './errors';
@@ -28,7 +31,8 @@ export interface EdgeConnection extends Required<Lifecycle> {
28
31
  get identityKey(): string;
29
32
  get peerKey(): string;
30
33
  get isOpen(): boolean;
31
- setIdentity(params: { peerKey: string; identityKey: string }): void;
34
+ get isConnected(): boolean;
35
+ setIdentity(identity: EdgeIdentity): void;
32
36
  addListener(listener: MessageListener): () => void;
33
37
  send(message: Message): Promise<void>;
34
38
  }
@@ -39,6 +43,19 @@ export type MessengerConfig = {
39
43
  protocol?: Protocol;
40
44
  };
41
45
 
46
+ export interface EdgeIdentity {
47
+ peerKey: string;
48
+ identityKey: string;
49
+ /**
50
+ * Returns credential presentation issued by the identity key.
51
+ * Presentation must have the provided challenge.
52
+ * Presentation may include ServiceAccess credentials.
53
+ */
54
+ presentCredentials({ challenge }: { challenge: Uint8Array }): Promise<Presentation>;
55
+ }
56
+
57
+ const DISABLE_AUTH = true;
58
+
42
59
  /**
43
60
  * Messenger client.
44
61
  */
@@ -58,8 +75,7 @@ export class EdgeClient extends Resource implements EdgeConnection {
58
75
  private _heartBeatContext?: Context = undefined;
59
76
 
60
77
  constructor(
61
- private _identityKey: string,
62
- private _peerKey: string,
78
+ private _identity: EdgeIdentity,
63
79
  private readonly _config: MessengerConfig,
64
80
  ) {
65
81
  super();
@@ -69,22 +85,25 @@ export class EdgeClient extends Resource implements EdgeConnection {
69
85
  public get info() {
70
86
  return {
71
87
  open: this.isOpen,
72
- identity: this._identityKey,
73
- device: this._peerKey,
88
+ identity: this._identity.identityKey,
89
+ device: this._identity.peerKey,
74
90
  };
75
91
  }
76
92
 
93
+ get isConnected() {
94
+ return Boolean(this._ws) && this._ready.state === TriggerState.RESOLVED;
95
+ }
96
+
77
97
  get identityKey() {
78
- return this._identityKey;
98
+ return this._identity.identityKey;
79
99
  }
80
100
 
81
101
  get peerKey() {
82
- return this._peerKey;
102
+ return this._identity.peerKey;
83
103
  }
84
104
 
85
- setIdentity({ peerKey, identityKey }: { peerKey: string; identityKey: string }) {
86
- this._peerKey = peerKey;
87
- this._identityKey = identityKey;
105
+ setIdentity(identity: EdgeIdentity) {
106
+ this._identity = identity;
88
107
  this._persistentLifecycle.scheduleRestart();
89
108
  }
90
109
 
@@ -107,13 +126,23 @@ export class EdgeClient extends Resource implements EdgeConnection {
107
126
  * Close connection and free resources.
108
127
  */
109
128
  protected override async _close() {
110
- log('closing...', { peerKey: this._peerKey });
129
+ log('closing...', { peerKey: this._identity.peerKey });
111
130
  await this._persistentLifecycle.close();
112
131
  }
113
132
 
114
133
  private async _openWebSocket() {
115
- const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);
116
- this._ws = new WebSocket(url);
134
+ let protocolHeader: string | undefined;
135
+
136
+ if (!DISABLE_AUTH) {
137
+ // TODO(dmaretskyi): Get challenge from the WWW-Authenticate header returned by the endpoint.
138
+ const challenge = randomBytes(32);
139
+ const credential = await this._identity.presentCredentials({ challenge });
140
+ protocolHeader = encodePresentationIntoAuthHeader(credential);
141
+ }
142
+
143
+ const url = new URL(`/ws/${this._identity.identityKey}/${this._identity.peerKey}`, this._config.socketEndpoint);
144
+ log('Opening websocket', { url: url.toString(), protocolHeader });
145
+ this._ws = new WebSocket(url, protocolHeader ? [protocolHeader] : []);
117
146
 
118
147
  this._ws.onopen = () => {
119
148
  log('opened', this.info);
@@ -138,7 +167,7 @@ export class EdgeClient extends Resource implements EdgeConnection {
138
167
  }
139
168
  const data = await toUint8Array(event.data);
140
169
  const message = buf.fromBinary(MessageSchema, data);
141
- log('received', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });
170
+ log('received', { peerKey: this._identity.peerKey, payload: protocol.getPayloadType(message) });
142
171
  if (message) {
143
172
  for (const listener of this._listeners) {
144
173
  try {
@@ -150,7 +179,10 @@ export class EdgeClient extends Resource implements EdgeConnection {
150
179
  }
151
180
  };
152
181
 
182
+ // TODO(dmaretskyi): Potential race condition here since web socket errors don't resolve this trigger.
153
183
  await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });
184
+
185
+ // TODO(dmaretskyi): Potential leak: context re-assigned without disposing the previous one.
154
186
  this._keepaliveCtx = new Context();
155
187
  scheduleTaskInterval(
156
188
  this._keepaliveCtx,
@@ -205,12 +237,12 @@ export class EdgeClient extends Resource implements EdgeConnection {
205
237
  }
206
238
  if (
207
239
  message.source &&
208
- (message.source.peerKey !== this._peerKey || message.source.identityKey !== this.identityKey)
240
+ (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)
209
241
  ) {
210
242
  throw new EdgeIdentityChangedError();
211
243
  }
212
244
 
213
- log('sending...', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });
245
+ log('sending...', { peerKey: this._identity.peerKey, payload: protocol.getPayloadType(message) });
214
246
  this._ws.send(buf.toBinary(MessageSchema, message));
215
247
  }
216
248
 
@@ -229,3 +261,11 @@ export class EdgeClient extends Resource implements EdgeConnection {
229
261
  );
230
262
  }
231
263
  }
264
+
265
+ const encodePresentationIntoAuthHeader = (presentation: Presentation): string => {
266
+ const encoded = schema.getCodecForType('dxos.halo.credentials.Presentation').encode(presentation);
267
+ // = and / characters are not allowed in the WebSocket subprotocol header.
268
+ const encodedToken = Buffer.from(encoded).toString('base64').replace(/=*$/, '').replaceAll('/', '|');
269
+
270
+ return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
271
+ };