@dxos/echo-db 2.33.1 → 2.33.2-dev.0f8f9225

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.
Files changed (217) hide show
  1. package/dist/src/echo.d.ts +8 -8
  2. package/dist/src/echo.d.ts.map +1 -1
  3. package/dist/src/echo.js +15 -16
  4. package/dist/src/echo.js.map +1 -1
  5. package/dist/src/echo.test.js +7 -13
  6. package/dist/src/echo.test.js.map +1 -1
  7. package/dist/src/halo/contact-manager.d.ts +4 -4
  8. package/dist/src/halo/contact-manager.d.ts.map +1 -1
  9. package/dist/src/halo/contact-manager.js +10 -4
  10. package/dist/src/halo/contact-manager.js.map +1 -1
  11. package/dist/src/halo/halo-factory.d.ts +14 -9
  12. package/dist/src/halo/halo-factory.d.ts.map +1 -1
  13. package/dist/src/halo/halo-factory.js +47 -14
  14. package/dist/src/halo/halo-factory.js.map +1 -1
  15. package/dist/src/halo/halo-party.d.ts +35 -7
  16. package/dist/src/halo/halo-party.d.ts.map +1 -1
  17. package/dist/src/halo/halo-party.js +97 -18
  18. package/dist/src/halo/halo-party.js.map +1 -1
  19. package/dist/src/halo/halo.d.ts +14 -12
  20. package/dist/src/halo/halo.d.ts.map +1 -1
  21. package/dist/src/halo/halo.js +31 -29
  22. package/dist/src/halo/halo.js.map +1 -1
  23. package/dist/src/halo/halo.test.d.ts +2 -0
  24. package/dist/src/halo/halo.test.d.ts.map +1 -0
  25. package/dist/src/halo/halo.test.js +162 -0
  26. package/dist/src/halo/halo.test.js.map +1 -0
  27. package/dist/src/halo/identity-manager.d.ts +10 -8
  28. package/dist/src/halo/identity-manager.d.ts.map +1 -1
  29. package/dist/src/halo/identity-manager.js +24 -20
  30. package/dist/src/halo/identity-manager.js.map +1 -1
  31. package/dist/src/halo/identity.d.ts +12 -6
  32. package/dist/src/halo/identity.d.ts.map +1 -1
  33. package/dist/src/halo/identity.js +11 -15
  34. package/dist/src/halo/identity.js.map +1 -1
  35. package/dist/src/halo/index.d.ts +1 -1
  36. package/dist/src/halo/index.d.ts.map +1 -1
  37. package/dist/src/halo/index.js +1 -1
  38. package/dist/src/halo/index.js.map +1 -1
  39. package/dist/src/halo/party-opener.js +1 -1
  40. package/dist/src/halo/party-opener.js.map +1 -1
  41. package/dist/src/halo/preferences.d.ts +9 -9
  42. package/dist/src/halo/preferences.d.ts.map +1 -1
  43. package/dist/src/halo/preferences.js +25 -15
  44. package/dist/src/halo/preferences.js.map +1 -1
  45. package/dist/src/index.d.ts +1 -1
  46. package/dist/src/index.js +1 -1
  47. package/dist/src/invitations/greeting-initiator.d.ts +14 -4
  48. package/dist/src/invitations/greeting-initiator.d.ts.map +1 -1
  49. package/dist/src/invitations/greeting-initiator.js +15 -16
  50. package/dist/src/invitations/greeting-initiator.js.map +1 -1
  51. package/dist/src/invitations/greeting-responder.d.ts +3 -3
  52. package/dist/src/invitations/greeting-responder.d.ts.map +1 -1
  53. package/dist/src/invitations/greeting-responder.js +3 -4
  54. package/dist/src/invitations/greeting-responder.js.map +1 -1
  55. package/dist/src/invitations/halo-recovery-initiator.d.ts +6 -4
  56. package/dist/src/invitations/halo-recovery-initiator.d.ts.map +1 -1
  57. package/dist/src/invitations/halo-recovery-initiator.js +15 -26
  58. package/dist/src/invitations/halo-recovery-initiator.js.map +1 -1
  59. package/dist/src/invitations/index.d.ts +1 -1
  60. package/dist/src/invitations/index.js +1 -1
  61. package/dist/src/invitations/{invitation-manager.d.ts → invitation-factory.d.ts} +5 -6
  62. package/dist/src/invitations/invitation-factory.d.ts.map +1 -0
  63. package/dist/src/invitations/{invitation-manager.js → invitation-factory.js} +9 -15
  64. package/dist/src/invitations/invitation-factory.js.map +1 -0
  65. package/dist/src/invitations/offline-invitation-claimer.d.ts +3 -3
  66. package/dist/src/invitations/offline-invitation-claimer.js +1 -1
  67. package/dist/src/parties/{party-internal.d.ts → data-party.d.ts} +13 -11
  68. package/dist/src/parties/data-party.d.ts.map +1 -0
  69. package/dist/src/parties/{party-internal.js → data-party.js} +27 -37
  70. package/dist/src/parties/data-party.js.map +1 -0
  71. package/dist/src/parties/index.d.ts +1 -2
  72. package/dist/src/parties/index.d.ts.map +1 -1
  73. package/dist/src/parties/index.js +1 -2
  74. package/dist/src/parties/index.js.map +1 -1
  75. package/dist/src/parties/party-factory.d.ts +10 -11
  76. package/dist/src/parties/party-factory.d.ts.map +1 -1
  77. package/dist/src/parties/party-factory.js +25 -16
  78. package/dist/src/parties/party-factory.js.map +1 -1
  79. package/dist/src/parties/party-manager.d.ts +9 -9
  80. package/dist/src/parties/party-manager.d.ts.map +1 -1
  81. package/dist/src/parties/party-manager.js +13 -13
  82. package/dist/src/parties/party-manager.js.map +1 -1
  83. package/dist/src/parties/party-manager.test.js +69 -68
  84. package/dist/src/parties/party-manager.test.js.map +1 -1
  85. package/dist/src/{halo → parties}/party-preferences.d.ts +3 -3
  86. package/dist/src/parties/party-preferences.d.ts.map +1 -0
  87. package/dist/src/{halo → parties}/party-preferences.js +3 -3
  88. package/dist/src/parties/party-preferences.js.map +1 -0
  89. package/dist/src/pipeline/index.d.ts +3 -1
  90. package/dist/src/pipeline/index.d.ts.map +1 -1
  91. package/dist/src/pipeline/index.js +3 -1
  92. package/dist/src/pipeline/index.js.map +1 -1
  93. package/dist/src/{metadata → pipeline}/metadata-store.d.ts +0 -0
  94. package/dist/src/{metadata → pipeline}/metadata-store.d.ts.map +1 -1
  95. package/dist/src/{metadata → pipeline}/metadata-store.js +0 -0
  96. package/dist/src/{metadata → pipeline}/metadata-store.js.map +1 -1
  97. package/dist/src/{metadata → pipeline}/metadata-store.test.d.ts +0 -0
  98. package/dist/src/pipeline/metadata-store.test.d.ts.map +1 -0
  99. package/dist/src/{metadata → pipeline}/metadata-store.test.js +0 -0
  100. package/dist/src/{metadata → pipeline}/metadata-store.test.js.map +1 -1
  101. package/dist/src/{parties → pipeline}/party-core.d.ts +0 -0
  102. package/dist/src/pipeline/party-core.d.ts.map +1 -0
  103. package/dist/src/{parties → pipeline}/party-core.js +8 -4
  104. package/dist/src/pipeline/party-core.js.map +1 -0
  105. package/dist/src/{parties → pipeline}/party-core.test.d.ts +0 -0
  106. package/dist/src/pipeline/party-core.test.d.ts.map +1 -0
  107. package/dist/src/{parties → pipeline}/party-core.test.js +3 -4
  108. package/dist/src/pipeline/party-core.test.js.map +1 -0
  109. package/dist/src/pipeline/party-feed-provider.d.ts +3 -2
  110. package/dist/src/pipeline/party-feed-provider.d.ts.map +1 -1
  111. package/dist/src/pipeline/party-feed-provider.js +40 -19
  112. package/dist/src/pipeline/party-feed-provider.js.map +1 -1
  113. package/dist/src/protocol/auth-plugin.d.ts +7 -0
  114. package/dist/src/protocol/auth-plugin.d.ts.map +1 -0
  115. package/dist/src/protocol/auth-plugin.js +16 -0
  116. package/dist/src/protocol/auth-plugin.js.map +1 -0
  117. package/dist/src/protocol/authenticator.d.ts +14 -0
  118. package/dist/src/protocol/authenticator.d.ts.map +1 -0
  119. package/dist/src/protocol/authenticator.js +31 -0
  120. package/dist/src/protocol/authenticator.js.map +1 -0
  121. package/dist/src/protocol/authenticator.test.d.ts +2 -0
  122. package/dist/src/protocol/authenticator.test.d.ts.map +1 -0
  123. package/dist/src/protocol/authenticator.test.js +45 -0
  124. package/dist/src/protocol/authenticator.test.js.map +1 -0
  125. package/dist/src/protocol/credentials-signer.d.ts +31 -0
  126. package/dist/src/protocol/credentials-signer.d.ts.map +1 -0
  127. package/dist/src/protocol/credentials-signer.js +53 -0
  128. package/dist/src/protocol/credentials-signer.js.map +1 -0
  129. package/dist/src/protocol/halo-recovery-plugin.d.ts +10 -0
  130. package/dist/src/protocol/halo-recovery-plugin.d.ts.map +1 -0
  131. package/dist/src/protocol/halo-recovery-plugin.js +18 -0
  132. package/dist/src/protocol/halo-recovery-plugin.js.map +1 -0
  133. package/dist/src/protocol/index.d.ts +7 -0
  134. package/dist/src/protocol/index.d.ts.map +1 -0
  135. package/dist/src/{metadata → protocol}/index.js +7 -2
  136. package/dist/src/protocol/index.js.map +1 -0
  137. package/dist/src/protocol/offline-invitation-plugin.d.ts +9 -0
  138. package/dist/src/protocol/offline-invitation-plugin.d.ts.map +1 -0
  139. package/dist/src/protocol/offline-invitation-plugin.js +17 -0
  140. package/dist/src/protocol/offline-invitation-plugin.js.map +1 -0
  141. package/dist/src/{pipeline → protocol}/party-protocol-factory.d.ts +7 -17
  142. package/dist/src/protocol/party-protocol-factory.d.ts.map +1 -0
  143. package/dist/src/{pipeline → protocol}/party-protocol-factory.js +7 -47
  144. package/dist/src/protocol/party-protocol-factory.js.map +1 -0
  145. package/dist/src/snapshots/snapshot-generator.d.ts +1 -1
  146. package/dist/src/snapshots/snapshot-generator.d.ts.map +1 -1
  147. package/dist/src/testing/testing-factories.js.map +1 -1
  148. package/dist/src/testing/testing.d.ts +2 -2
  149. package/dist/src/testing/testing.d.ts.map +1 -1
  150. package/dist/src/testing/testing.js +1 -7
  151. package/dist/src/testing/testing.js.map +1 -1
  152. package/dist/tsconfig.tsbuildinfo +1 -1
  153. package/package.json +17 -17
  154. package/src/echo.test.ts +8 -14
  155. package/src/echo.ts +107 -109
  156. package/src/halo/contact-manager.ts +9 -5
  157. package/src/halo/halo-factory.ts +82 -19
  158. package/src/halo/halo-party.ts +137 -21
  159. package/src/halo/halo.test.ts +198 -0
  160. package/src/halo/halo.ts +40 -38
  161. package/src/halo/identity-manager.ts +33 -28
  162. package/src/halo/identity.ts +19 -23
  163. package/src/halo/index.ts +1 -1
  164. package/src/halo/party-opener.ts +1 -1
  165. package/src/halo/preferences.ts +29 -18
  166. package/src/index.ts +1 -1
  167. package/src/invitations/greeting-initiator.ts +37 -32
  168. package/src/invitations/greeting-responder.ts +4 -5
  169. package/src/invitations/halo-recovery-initiator.ts +16 -24
  170. package/src/invitations/index.ts +1 -1
  171. package/src/invitations/{invitation-manager.ts → invitation-factory.ts} +8 -15
  172. package/src/invitations/offline-invitation-claimer.ts +3 -3
  173. package/src/parties/{party-internal.ts → data-party.ts} +30 -55
  174. package/src/parties/index.ts +1 -2
  175. package/src/parties/party-factory.ts +31 -21
  176. package/src/parties/party-manager.test.ts +99 -73
  177. package/src/parties/party-manager.ts +17 -17
  178. package/src/{halo → parties}/party-preferences.ts +3 -3
  179. package/src/pipeline/index.ts +3 -1
  180. package/src/{metadata → pipeline}/metadata-store.test.ts +0 -0
  181. package/src/{metadata → pipeline}/metadata-store.ts +0 -0
  182. package/src/{parties → pipeline}/party-core.test.ts +1 -2
  183. package/src/{parties → pipeline}/party-core.ts +12 -7
  184. package/src/pipeline/party-feed-provider.ts +32 -21
  185. package/src/protocol/auth-plugin.ts +14 -0
  186. package/src/protocol/authenticator.test.ts +66 -0
  187. package/src/protocol/authenticator.ts +56 -0
  188. package/src/protocol/credentials-signer.ts +60 -0
  189. package/src/protocol/halo-recovery-plugin.ts +20 -0
  190. package/src/protocol/index.ts +10 -0
  191. package/src/protocol/offline-invitation-plugin.ts +19 -0
  192. package/src/{pipeline → protocol}/party-protocol-factory.ts +10 -82
  193. package/src/snapshots/snapshot-generator.ts +1 -1
  194. package/src/testing/testing-factories.ts +2 -2
  195. package/src/testing/testing.ts +3 -9
  196. package/dist/src/halo/party-preferences.d.ts.map +0 -1
  197. package/dist/src/halo/party-preferences.js.map +0 -1
  198. package/dist/src/invitations/invitation-manager.d.ts.map +0 -1
  199. package/dist/src/invitations/invitation-manager.js.map +0 -1
  200. package/dist/src/metadata/index.d.ts +0 -2
  201. package/dist/src/metadata/index.d.ts.map +0 -1
  202. package/dist/src/metadata/index.js.map +0 -1
  203. package/dist/src/metadata/metadata-store.test.d.ts.map +0 -1
  204. package/dist/src/parties/authenticator.d.ts +0 -5
  205. package/dist/src/parties/authenticator.d.ts.map +0 -1
  206. package/dist/src/parties/authenticator.js +0 -27
  207. package/dist/src/parties/authenticator.js.map +0 -1
  208. package/dist/src/parties/party-core.d.ts.map +0 -1
  209. package/dist/src/parties/party-core.js.map +0 -1
  210. package/dist/src/parties/party-core.test.d.ts.map +0 -1
  211. package/dist/src/parties/party-core.test.js.map +0 -1
  212. package/dist/src/parties/party-internal.d.ts.map +0 -1
  213. package/dist/src/parties/party-internal.js.map +0 -1
  214. package/dist/src/pipeline/party-protocol-factory.d.ts.map +0 -1
  215. package/dist/src/pipeline/party-protocol-factory.js.map +0 -1
  216. package/src/metadata/index.ts +0 -5
  217. package/src/parties/authenticator.ts +0 -31
@@ -6,11 +6,10 @@ import assert from 'assert';
6
6
  import debug from 'debug';
7
7
 
8
8
  import { Event, synchronized, waitForCondition } from '@dxos/async';
9
- import { Keyring, SecretProvider } from '@dxos/credentials';
9
+ import { Filter, KeyRecord, Keyring, KeyType, SecretProvider } from '@dxos/credentials';
10
10
 
11
11
  import { InvitationDescriptor } from '../invitations';
12
- import { MetadataStore } from '../metadata';
13
- import { PartyInternal } from '../parties';
12
+ import { MetadataStore } from '../pipeline';
14
13
  import { HaloCreationOptions, HaloFactory } from './halo-factory';
15
14
  import { HaloParty } from './halo-party';
16
15
  import { Identity } from './identity';
@@ -21,7 +20,7 @@ const log = debug('dxos:echo-db:identity-manager');
21
20
  * Manages the keyring and HALO party.
22
21
  */
23
22
  export class IdentityManager {
24
- private readonly _identity: Identity;
23
+ private _identity: Identity | undefined;
25
24
 
26
25
  public readonly ready = new Event();
27
26
 
@@ -29,30 +28,25 @@ export class IdentityManager {
29
28
  private readonly _keyring: Keyring,
30
29
  private readonly _haloFactory: HaloFactory,
31
30
  private readonly _metadataStore: MetadataStore
32
- ) {
33
- this._identity = Identity.fromKeyring(_keyring);
34
- }
31
+ ) {}
35
32
 
36
- get identity () {
33
+ get identity (): Identity | undefined {
37
34
  return this._identity;
38
35
  }
39
36
 
40
37
  get initialized (): boolean {
41
- const haloParty = this._identity.halo;
42
- return haloParty !== undefined &&
43
- haloParty.isOpen &&
44
- !!haloParty!.memberKeys.length &&
45
- !!haloParty!.identityGenesis &&
38
+ return this._identity !== undefined &&
39
+ !!this._identity.halo &&
40
+ this._identity.halo.isOpen &&
41
+ !!this._identity.halo!.memberKeys.length &&
42
+ !!this._identity.halo!.identityGenesis &&
46
43
  !!this._identity.deviceKeyChain;
47
44
  }
48
45
 
49
- private async _initialize (halo: PartyInternal) {
50
- assert(this._identity.identityKey, 'No identity key.');
51
- assert(this._identity.deviceKey, 'No device key.');
46
+ private async _initialize (halo: HaloParty) {
52
47
  assert(halo.isOpen, 'HALO must be open.');
53
48
 
54
- const haloParty = new HaloParty(halo, this._identity.identityKey!.publicKey, this._identity.deviceKey.publicKey);
55
- this._identity.setHalo(haloParty);
49
+ this._identity = new Identity(this._keyring, halo);
56
50
 
57
51
  // Wait for the minimum set of keys and messages we need for proper function.
58
52
  await waitForCondition(() => this.initialized);
@@ -61,16 +55,28 @@ export class IdentityManager {
61
55
  this.ready.emit();
62
56
  }
63
57
 
58
+ async close () {
59
+ const identity = this._identity;
60
+ this._identity = undefined;
61
+
62
+ await identity?.halo.close();
63
+ }
64
+
65
+ getIdentityKey (): KeyRecord | undefined {
66
+ return this._keyring.findKey(Filter.matches({ type: KeyType.IDENTITY, own: true, trusted: true }));
67
+ }
68
+
64
69
  @synchronized
65
70
  async loadFromStorage () {
66
- if (this._identity.identityKey) {
67
- if (this._metadataStore.getParty(this._identity.identityKey.publicKey)) {
71
+ const identityKey = this.getIdentityKey();
72
+ if (identityKey) {
73
+ if (this._metadataStore.getParty(identityKey.publicKey)) {
68
74
  // TODO(marik-d): Snapshots for halo party?
69
- const halo = await this._haloFactory.constructParty(this._identity.identityKey.publicKey);
75
+ const halo = await this._haloFactory.constructParty([]);
70
76
  // Always open the HALO.
71
77
  await halo.open();
72
78
  await this._initialize(halo);
73
- } else if (!this._identity.keyring.hasSecretKey(this._identity.identityKey)) {
79
+ } else if (!this._keyring.hasSecretKey(identityKey)) {
74
80
  throw new Error('HALO missing and identity key has no secret.');
75
81
  }
76
82
  }
@@ -80,8 +86,8 @@ export class IdentityManager {
80
86
  * Creates the Identity HALO.
81
87
  */
82
88
  @synchronized
83
- async createHalo (options: HaloCreationOptions = {}): Promise<PartyInternal> {
84
- assert(!this._identity.halo, 'HALO already exists.');
89
+ async createHalo (options: HaloCreationOptions = {}): Promise<HaloParty> {
90
+ assert(!this._identity, 'Identity already initialized.');
85
91
 
86
92
  const halo = await this._haloFactory.createHalo(options);
87
93
  await this._initialize(halo);
@@ -97,10 +103,9 @@ export class IdentityManager {
97
103
  */
98
104
  @synchronized
99
105
  async recoverHalo (seedPhrase: string) {
100
- assert(!this._identity.halo, 'HALO already exists.');
101
- assert(!this._identity.identityKey, 'Identity key already exists.');
106
+ assert(!this._identity, 'Identity already initialized.');
102
107
 
103
- const halo = await this._haloFactory.recoverHalo(this.identity, seedPhrase);
108
+ const halo = await this._haloFactory.recoverHalo(seedPhrase);
104
109
  await this._initialize(halo);
105
110
  return halo;
106
111
  }
@@ -110,7 +115,7 @@ export class IdentityManager {
110
115
  */
111
116
  @synchronized
112
117
  async joinHalo (invitationDescriptor: InvitationDescriptor, secretProvider: SecretProvider) {
113
- assert(!this._identity.halo, 'HALO already exists.');
118
+ assert(!this._identity, 'Identity already initialized.');
114
119
 
115
120
  const halo = await this._haloFactory.joinHalo(invitationDescriptor, secretProvider);
116
121
  await this._initialize(halo);
@@ -5,7 +5,10 @@
5
5
  import debug from 'debug';
6
6
 
7
7
  import { Filter, KeyChain, KeyRecord, Keyring, KeyType, Signer } from '@dxos/credentials';
8
+ import { raise } from '@dxos/debug';
8
9
 
10
+ import { IdentityNotInitializedError } from '../errors';
11
+ import { CredentialsSigner } from '../protocol/credentials-signer';
9
12
  import { ContactManager } from './contact-manager';
10
13
  import { HaloParty } from './halo-party';
11
14
  import { Preferences } from './preferences';
@@ -22,22 +25,12 @@ export class Identity {
22
25
  private _deviceKey?: KeyRecord;
23
26
  private _deviceKeyChain?: KeyChain;
24
27
 
25
- static fromKeyring (keyring: Keyring) {
26
- return new Identity(
27
- keyring,
28
- undefined
29
- );
30
- }
31
-
32
- static createFromHalo (keyring: Keyring, halo: HaloParty) {
33
- const identity = Identity.fromKeyring(keyring);
34
- identity.setHalo(halo);
35
- return identity;
36
- }
37
-
28
+ /**
29
+ * @param _halo HALO party. Must be open.
30
+ */
38
31
  constructor (
39
32
  private readonly _keyring: Keyring,
40
- private _halo: HaloParty | undefined
33
+ private readonly _halo: HaloParty
41
34
  ) {}
42
35
 
43
36
  get signer (): Signer {
@@ -88,7 +81,10 @@ export class Identity {
88
81
  return this._halo?.identityGenesis;
89
82
  }
90
83
 
91
- get halo (): HaloParty | undefined {
84
+ /**
85
+ * HALO party. Must be open.
86
+ */
87
+ get halo (): HaloParty {
92
88
  return this._halo;
93
89
  }
94
90
 
@@ -96,17 +92,17 @@ export class Identity {
96
92
  return this._keyring;
97
93
  }
98
94
 
99
- /**
100
- * @internal
101
- *
102
- * Called by `IdentityManager` when HALO party is initialized.
103
- */
104
- setHalo (halo: HaloParty) {
105
- this._halo = halo;
95
+ createCredentialsSigner (): CredentialsSigner {
96
+ return new CredentialsSigner(
97
+ this._keyring,
98
+ () => this.identityKey ?? raise(new IdentityNotInitializedError()),
99
+ () => this.deviceKey ?? raise(new IdentityNotInitializedError()),
100
+ () => this.deviceKeyChain ?? this.deviceKey ?? raise(new IdentityNotInitializedError())
101
+ );
106
102
  }
107
103
  }
108
104
 
109
- export type IdentityProvider = () => Identity;
105
+ export type IdentityProvider = () => Identity | undefined;
110
106
 
111
107
  function getDeviceKeyChainFromHalo (halo: HaloParty, deviceKey: KeyRecord) {
112
108
  try {
package/src/halo/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- export * from './party-preferences';
5
+ export * from '../parties/party-preferences';
6
6
  export * from './contact-manager';
7
7
  export * from './halo-factory';
8
8
  export * from './halo-party';
@@ -24,7 +24,7 @@ export function autoPartyOpener (preferences: Preferences, partyManager: PartyMa
24
24
 
25
25
  for (const partyDesc of values) {
26
26
  if (!partyManager.parties.some(x => x.key === partyDesc.partyKey)) {
27
- log(`Auto-opening new Party from HALO: ${partyDesc.partyKey.toHex()}`);
27
+ log(`Auto-opening new Party from HALO: ${partyDesc.partyKey.toHex()} hints=${JSON.stringify(partyDesc.keyHints)}`);
28
28
  await partyManager.addParty(partyDesc.partyKey, partyDesc.keyHints);
29
29
  }
30
30
  }
@@ -9,10 +9,12 @@ import defaultsDeep from 'lodash.defaultsdeep';
9
9
  import { Event } from '@dxos/async';
10
10
  import { KeyHint } from '@dxos/credentials';
11
11
  import { PublicKey } from '@dxos/crypto';
12
+ import { raise } from '@dxos/debug';
12
13
  import { ObjectModel } from '@dxos/object-model';
13
14
 
14
- import { Item, ResultSet } from '../api';
15
- import { PartyInternal } from '../parties';
15
+ import { Database, Item, ResultSet } from '../api';
16
+ import { IdentityNotInitializedError } from '../errors';
17
+ import { DataParty } from '../parties';
16
18
  import {
17
19
  HALO_PARTY_DESCRIPTOR_TYPE, HALO_PARTY_DEVICE_PREFERENCES_TYPE, HALO_PARTY_PREFERENCES_TYPE, JoinedParty
18
20
  } from './halo-party';
@@ -23,8 +25,7 @@ import {
23
25
  // TODO(burdon): Split into device settings, user preferences, etc. (Expose subset as public API).
24
26
  export class Preferences {
25
27
  constructor (
26
- // TODO(burdon): Only requires key.
27
- private readonly _party: PartyInternal,
28
+ private readonly _getDatabase: () => Database | undefined,
28
29
  private readonly _deviceKey: PublicKey
29
30
  ) {}
30
31
 
@@ -42,8 +43,10 @@ export class Preferences {
42
43
  }
43
44
 
44
45
  subscribeToPreferences (callback: (preferences: any) => void) {
45
- const globalResults = this._party.database.select({ type: HALO_PARTY_PREFERENCES_TYPE }).exec();
46
- const deviceResults = this._party.database.select({ type: HALO_PARTY_DEVICE_PREFERENCES_TYPE }).exec();
46
+ const database = this._getDatabase() ?? raise(new IdentityNotInitializedError());
47
+
48
+ const globalResults = database.select({ type: HALO_PARTY_PREFERENCES_TYPE }).exec();
49
+ const deviceResults = database.select({ type: HALO_PARTY_DEVICE_PREFERENCES_TYPE }).exec();
47
50
 
48
51
  const event = new Event<any>();
49
52
 
@@ -74,18 +77,20 @@ export class Preferences {
74
77
  }
75
78
 
76
79
  getGlobalPreferences () {
77
- if (!this._party.isOpen) {
78
- return null;
80
+ const database = this._getDatabase();
81
+ if (!database) {
82
+ return;
79
83
  }
80
- const [globalItem] = this._party.database.select({ type: HALO_PARTY_PREFERENCES_TYPE }).exec().entities;
84
+ const [globalItem] = database.select({ type: HALO_PARTY_PREFERENCES_TYPE }).exec().entities;
81
85
  return globalItem;
82
86
  }
83
87
 
84
88
  getDevicePreferences () {
85
- if (!this._party.isOpen) {
86
- return null;
89
+ const database = this._getDatabase();
90
+ if (!database) {
91
+ return;
87
92
  }
88
- const deviceItems = this._party.database.select({ type: HALO_PARTY_DEVICE_PREFERENCES_TYPE }).exec().entities;
93
+ const deviceItems = database.select({ type: HALO_PARTY_DEVICE_PREFERENCES_TYPE }).exec().entities;
89
94
  return deviceItems.find(item => this._deviceKey.equals(item.model.get('publicKey')));
90
95
  }
91
96
 
@@ -95,7 +100,7 @@ export class Preferences {
95
100
  return this._getPartyPreference(item, partyKey, key);
96
101
  }
97
102
 
98
- public async setGlobalPartyPreference (party: PartyInternal, key: string, value: any) {
103
+ public async setGlobalPartyPreference (party: DataParty, key: string, value: any) {
99
104
  const item = this.getGlobalPreferences();
100
105
  assert(item, 'Global preference item required.');
101
106
  return this._setPartyPreference(item, party, key, value);
@@ -107,7 +112,7 @@ export class Preferences {
107
112
  return this._getPartyPreference(item, partyKey, key);
108
113
  }
109
114
 
110
- public async setDevicePartyPreference (party: PartyInternal, key: string, value: any) {
115
+ public async setDevicePartyPreference (party: DataParty, key: string, value: any) {
111
116
  const item = this.getDevicePreferences();
112
117
  assert(item, 'Device preference item required.');
113
118
  return this._setPartyPreference(item, party, key, value);
@@ -121,7 +126,7 @@ export class Preferences {
121
126
  }
122
127
 
123
128
  // TODO(burdon): DO NOT USE THE PARTY KEY AS A TOP-LEVEL KEY!
124
- public async _setPartyPreference (preferences: Item<any>, party: PartyInternal, key: string, value: any) {
129
+ public async _setPartyPreference (preferences: Item<any>, party: DataParty, key: string, value: any) {
125
130
  const path = party.key.toHex();
126
131
  const partyPrefs = preferences.model.get(path, {});
127
132
  partyPrefs[key] = value;
@@ -130,13 +135,17 @@ export class Preferences {
130
135
  }
131
136
 
132
137
  async recordPartyJoining (joinedParty: JoinedParty) {
133
- const [partyDesc] = this._party.database
138
+ const database = this._getDatabase();
139
+ if (!database) {
140
+ return;
141
+ }
142
+ const [partyDesc] = database
134
143
  .select({ type: HALO_PARTY_DESCRIPTOR_TYPE })
135
144
  .filter(partyMarker => joinedParty.partyKey.equals(partyMarker.model.get('publicKey')))
136
145
  .exec().entities;
137
146
  assert(!partyDesc, `Descriptor already exists for Party: ${joinedParty.partyKey.toHex()}`);
138
147
 
139
- await this._party.database.createItem({
148
+ await database.createItem({
140
149
  model: ObjectModel,
141
150
  type: HALO_PARTY_DESCRIPTOR_TYPE,
142
151
  props: {
@@ -148,6 +157,8 @@ export class Preferences {
148
157
  }
149
158
 
150
159
  subscribeToJoinedPartyList (callback: (parties: JoinedParty[]) => void): () => void {
160
+ const database = this._getDatabase() ?? raise(new IdentityNotInitializedError());
161
+
151
162
  const converter = (partyDesc: Item<any>) => {
152
163
  // TODO(burdon): Define type.
153
164
  return {
@@ -159,7 +170,7 @@ export class Preferences {
159
170
  };
160
171
  };
161
172
 
162
- const result = this._party.database.select({ type: HALO_PARTY_DESCRIPTOR_TYPE }).exec();
173
+ const result = database.select({ type: HALO_PARTY_DESCRIPTOR_TYPE }).exec();
163
174
 
164
175
  // Wrap the query event so we can have manual control.
165
176
  const event = new Event();
package/src/index.ts CHANGED
@@ -10,7 +10,7 @@ export * from './echo';
10
10
  export * from './errors';
11
11
  export * from './halo';
12
12
  export * from './invitations';
13
- export * from './metadata';
13
+ export * from './protocol';
14
14
  export * from './parties';
15
15
  export * from './pipeline';
16
16
  export * from './snapshots';
@@ -19,12 +19,13 @@ import {
19
19
  Message,
20
20
  SecretProvider,
21
21
  WithTypeUrl,
22
- ERR_GREET_CONNECTED_TO_SWARM_TIMEOUT
22
+ ERR_GREET_CONNECTED_TO_SWARM_TIMEOUT,
23
+ SignedMessage
23
24
  } from '@dxos/credentials';
24
25
  import { keyToString, PublicKey } from '@dxos/crypto';
25
26
  import { FullyConnectedTopology, NetworkManager } from '@dxos/network-manager';
26
27
 
27
- import { Identity } from '../halo';
28
+ import { CredentialsSigner } from '../protocol/credentials-signer';
28
29
  import { greetingProtocolProvider } from './greeting-protocol-provider';
29
30
  import { GreetingState } from './greeting-responder';
30
31
  import { InvitationDescriptor, InvitationDescriptorType } from './invitation-descriptor';
@@ -48,11 +49,12 @@ export class GreetingInitiator {
48
49
  * @param _identity
49
50
  * @param _invitationDescriptor
50
51
  * @param _feedInitializer Callback to open or create a write feed for this party and return it's keypair.
52
+ * @param _getMessagesToNotarize Returns a list of credential messages that the inviter will be asked to write into the control feed.
51
53
  */
52
54
  constructor (
53
55
  private readonly _networkManager: NetworkManager,
54
- private readonly _identity: Identity,
55
- private readonly _invitationDescriptor: InvitationDescriptor
56
+ private readonly _invitationDescriptor: InvitationDescriptor,
57
+ private readonly _getMessagesToNotarize: (partyKey: PublicKey, nonce: Uint8Array) => Promise<Message[]>
56
58
  ) {
57
59
  assert(InvitationDescriptorType.INTERACTIVE === this._invitationDescriptor.type);
58
60
  }
@@ -112,7 +114,6 @@ export class GreetingInitiator {
112
114
  async redeemInvitation (secretProvider: SecretProvider) {
113
115
  assert(this._state === GreetingState.CONNECTED);
114
116
  const { swarmKey } = this._invitationDescriptor;
115
- const haloInvitation = !!this._invitationDescriptor.identityKey;
116
117
 
117
118
  const responderPeerId = Buffer.from(swarmKey);
118
119
 
@@ -146,33 +147,7 @@ export class GreetingInitiator {
146
147
  const { nonce } = handshakeResponse;
147
148
  const partyKey = handshakeResponse.partyKey;
148
149
 
149
- const credentialMessages = [];
150
- if (haloInvitation) {
151
- assert(this._identity.deviceKey, 'Device key required');
152
-
153
- // For the HALO, add the DEVICE directly.
154
- credentialMessages.push(
155
- createKeyAdmitMessage(
156
- this._identity.signer,
157
- partyKey,
158
- this._identity.deviceKey,
159
- [],
160
- nonce)
161
- );
162
- } else {
163
- assert(this._identity.deviceKeyChain, 'Device key required');
164
- assert(this._identity.identityGenesis, 'Identity genesis message required');
165
-
166
- // For any other Party, add the IDENTITY, signed by the DEVICE keychain, which links back to that IDENTITY.
167
- credentialMessages.push(
168
- createEnvelopeMessage(
169
- this._identity.signer,
170
- partyKey,
171
- wrapMessage(this._identity.identityGenesis),
172
- [this._identity.deviceKeyChain],
173
- nonce)
174
- );
175
- }
150
+ const credentialMessages = await this._getMessagesToNotarize(PublicKey.from(partyKey), nonce);
176
151
 
177
152
  // Send the signed payload to the greeting responder.
178
153
  const notarizeResponse = await this._greeterPlugin.send(responderPeerId,
@@ -213,3 +188,33 @@ export class GreetingInitiator {
213
188
  log('Destroyed');
214
189
  }
215
190
  }
191
+
192
+ /**
193
+ * Create credentials messages that should be written to invite new device to the HALO party.
194
+ */
195
+ export const createHaloPartyAdmissionMessage = (
196
+ credentialsSigner: CredentialsSigner,
197
+ nonce: Uint8Array
198
+ ): Message => createKeyAdmitMessage(
199
+ credentialsSigner.signer,
200
+ credentialsSigner.getIdentityKey().publicKey,
201
+ credentialsSigner.getDeviceKey(),
202
+ [],
203
+ Buffer.from(nonce)
204
+ );
205
+
206
+ /**
207
+ * Create credentials messages that should be written to invite member to the data party.
208
+ */
209
+ export const createDataPartyAdmissionMessages = (
210
+ credentialsSigner: CredentialsSigner,
211
+ partyKey: PublicKey,
212
+ identityGenesis: SignedMessage,
213
+ nonce: Uint8Array
214
+ ): Message => createEnvelopeMessage(
215
+ credentialsSigner.signer,
216
+ partyKey,
217
+ wrapMessage(identityGenesis),
218
+ [credentialsSigner.getDeviceSigningKeys()],
219
+ Buffer.from(nonce)
220
+ );
@@ -19,8 +19,8 @@ import { keyToString, randomBytes, PublicKey } from '@dxos/crypto';
19
19
  import { SwarmKey } from '@dxos/echo-protocol';
20
20
  import { FullyConnectedTopology, NetworkManager } from '@dxos/network-manager';
21
21
 
22
- import { Identity } from '../halo';
23
22
  import { PartyProcessor } from '../pipeline';
23
+ import { CredentialsSigner } from '../protocol/credentials-signer';
24
24
  import { InvitationOptions } from './common';
25
25
  import { greetingProtocolProvider } from './greeting-protocol-provider';
26
26
 
@@ -58,7 +58,7 @@ export class GreetingResponder {
58
58
  constructor (
59
59
  private readonly _networkManager: NetworkManager,
60
60
  private readonly _partyProcessor: PartyProcessor,
61
- private readonly _identity: Identity
61
+ private readonly _credentialsSigner: CredentialsSigner
62
62
  ) {
63
63
  this._greeter = new Greeter(
64
64
  this._partyProcessor.partyKey,
@@ -193,7 +193,6 @@ export class GreetingResponder {
193
193
  */
194
194
  async _writeCredentialsToParty (messages: any[]) {
195
195
  assert(this._state === GreetingState.CONNECTED);
196
- assert(this._identity.deviceKeyChain);
197
196
 
198
197
  /* These messages will be self-signed by keys not yet admitted to the Party,, so we cannot check
199
198
  * for a trusted key, only that the signatures are valid.
@@ -217,10 +216,10 @@ export class GreetingResponder {
217
216
  };
218
217
 
219
218
  const envelope = createEnvelopeMessage(
220
- this._identity.signer,
219
+ this._credentialsSigner.signer,
221
220
  this._partyProcessor.partyKey,
222
221
  message,
223
- [this._identity.deviceKeyChain]
222
+ [this._credentialsSigner.getDeviceSigningKeys()]
224
223
  );
225
224
 
226
225
  await this._partyProcessor.writeHaloMessage(envelope);
@@ -20,14 +20,14 @@ import {
20
20
  codec
21
21
  } from '@dxos/credentials';
22
22
  import { keyToBuffer, keyToString, PublicKey, randomBytes, verify } from '@dxos/crypto';
23
- import { raise } from '@dxos/debug';
24
23
  import { FullyConnectedTopology, NetworkManager } from '@dxos/network-manager';
25
24
 
26
- import { IdentityNotInitializedError, InvalidInvitationError } from '../errors';
27
- import { Identity, IdentityProvider } from '../halo';
25
+ import { InvalidInvitationError } from '../errors';
26
+ import { CredentialsSigner } from '../protocol/credentials-signer';
28
27
  import { greetingProtocolProvider } from './greeting-protocol-provider';
29
28
  import { GreetingState } from './greeting-responder';
30
29
  import { InvitationDescriptor, InvitationDescriptorType } from './invitation-descriptor';
30
+ import { InvitationFactory } from './invitation-factory';
31
31
 
32
32
  const log = debug('dxos:echo-db:halo-recovery-initiator');
33
33
 
@@ -47,7 +47,7 @@ export class HaloRecoveryInitiator {
47
47
 
48
48
  constructor (
49
49
  private readonly _networkManager: NetworkManager,
50
- private readonly _identity: Identity
50
+ private readonly _credentialsSigner: CredentialsSigner
51
51
  ) {
52
52
  this._state = GreetingState.INITIALIZED;
53
53
  }
@@ -67,8 +67,7 @@ export class HaloRecoveryInitiator {
67
67
  this._peerId = randomBytes();
68
68
  log('Local PeerId:', keyToString(this._peerId));
69
69
 
70
- assert(this._identity.identityKey);
71
- const swarmKey = this._identity.identityKey.publicKey.asBuffer();
70
+ const swarmKey = this._credentialsSigner.getIdentityKey().publicKey.asBuffer();
72
71
 
73
72
  this._greeterPlugin = new GreetingCommandPlugin(this._peerId, async () => false);
74
73
 
@@ -99,16 +98,15 @@ export class HaloRecoveryInitiator {
99
98
  assert(this._state === GreetingState.CONNECTED);
100
99
  assert(this._greeterPlugin);
101
100
  assert(this._peerId);
102
- assert(this._identity.identityKey);
103
101
 
104
102
  // Send to the first peer (any peer will do).
105
103
  const peer = this._greeterPlugin.peers[0];
106
104
  const responderPeerId = keyToBuffer(peer.getSession().peerId);
107
105
 
108
106
  // Synthesize an "invitationID" which is the signature of both peerIds signed by our Identity key.
109
- const signature = this._identity.signer.rawSign(
107
+ const signature = this._credentialsSigner.signer.rawSign(
110
108
  Buffer.concat([this._peerId, responderPeerId]),
111
- this._identity.identityKey
109
+ this._credentialsSigner.getIdentityKey()
112
110
  );
113
111
 
114
112
  // We expect to receive a new swarm/rendezvousKey to use for the full Greeting process.
@@ -124,13 +122,12 @@ export class HaloRecoveryInitiator {
124
122
  InvitationDescriptorType.INTERACTIVE,
125
123
  Buffer.from(rendezvousKey),
126
124
  Buffer.from(id),
127
- this._identity.identityKey.publicKey
125
+ this._credentialsSigner.getIdentityKey().publicKey
128
126
  );
129
127
  }
130
128
 
131
129
  async disconnect () {
132
- assert(this._identity.identityKey);
133
- const swarmKey = this._identity.identityKey.publicKey.asBuffer();
130
+ const swarmKey = this._credentialsSigner.getIdentityKey().publicKey.asBuffer();
134
131
  await this._networkManager.leaveProtocolSwarm(PublicKey.from(swarmKey));
135
132
  this._state = GreetingState.DISCONNECTED;
136
133
  }
@@ -149,23 +146,19 @@ export class HaloRecoveryInitiator {
149
146
  * by "info". These values will be validated on the other end.
150
147
  */
151
148
  createAuthMessage(
152
- this._identity.signer,
149
+ this._credentialsSigner.signer,
153
150
  info.id.value,
154
- this._identity.identityKey ?? raise(new IdentityNotInitializedError()),
155
- this._identity.identityKey ?? raise(new IdentityNotInitializedError()),
151
+ this._credentialsSigner.getIdentityKey(),
152
+ this._credentialsSigner.getIdentityKey(),
156
153
  undefined,
157
154
  info.authNonce.value)
158
155
  ));
159
156
  }
160
157
 
161
- static createHaloInvitationClaimHandler (identityProvider: IdentityProvider) {
158
+ static createHaloInvitationClaimHandler (identityKey: PublicKey, invitationManager: InvitationFactory) {
162
159
  const claimHandler = new PartyInvitationClaimHandler(async (invitationID: Buffer, remotePeerId: Buffer, peerId: Buffer) => {
163
- const identity = identityProvider();
164
- assert(identity.halo, 'HALO is required');
165
- assert(identity.identityKey);
166
-
167
160
  // The invitationtId is the signature of both peerIds, signed by the Identity key.
168
- const ok = verify(Buffer.concat([remotePeerId, peerId]), invitationID, identity.identityKey.publicKey.asBuffer());
161
+ const ok = verify(Buffer.concat([remotePeerId, peerId]), invitationID, identityKey.asBuffer());
169
162
  if (!ok) {
170
163
  throw new InvalidInvitationError();
171
164
  }
@@ -175,7 +168,7 @@ export class HaloRecoveryInitiator {
175
168
  */
176
169
  const keyring = new Keyring();
177
170
  await keyring.addPublicKey({
178
- publicKey: identity.identityKey.publicKey,
171
+ publicKey: identityKey,
179
172
  type: KeyType.IDENTITY,
180
173
  trusted: true,
181
174
  own: false
@@ -190,8 +183,7 @@ export class HaloRecoveryInitiator {
190
183
  };
191
184
 
192
185
  // TODO(telackey): Configure expiration.
193
- return identity.halo.invitationManager
194
- .createInvitation({ secretValidator }, { expiration: Date.now() + 60_000 });
186
+ return invitationManager.createInvitation({ secretValidator }, { expiration: Date.now() + 60_000 });
195
187
  });
196
188
 
197
189
  return claimHandler.createMessageHandler();
@@ -8,5 +8,5 @@ export * from './greeting-initiator';
8
8
  export * from './greeting-responder';
9
9
  export * from './halo-recovery-initiator';
10
10
  export * from './invitation-descriptor';
11
- export * from './invitation-manager';
11
+ export * from './invitation-factory';
12
12
  export * from './offline-invitation-claimer';