@dxos/echo-db 2.33.8-dev.8609bc45 → 2.33.9-dev.002e8917
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/src/api/result-set.js +4 -4
- package/dist/src/api/result-set.js.map +1 -1
- package/dist/src/echo.js +2 -2
- package/dist/src/echo.js.map +1 -1
- package/dist/src/echo.test.js +13 -13
- package/dist/src/echo.test.js.map +1 -1
- package/dist/src/halo/halo-factory.d.ts +1 -1
- package/dist/src/halo/halo-factory.d.ts.map +1 -1
- package/dist/src/halo/halo-factory.js +16 -16
- package/dist/src/halo/halo-factory.js.map +1 -1
- package/dist/src/halo/halo-party.d.ts +4 -6
- package/dist/src/halo/halo-party.d.ts.map +1 -1
- package/dist/src/halo/halo-party.js +12 -6
- package/dist/src/halo/halo-party.js.map +1 -1
- package/dist/src/halo/halo.d.ts.map +1 -1
- package/dist/src/halo/halo.js +11 -10
- package/dist/src/halo/halo.js.map +1 -1
- package/dist/src/halo/identity-manager.d.ts.map +1 -1
- package/dist/src/halo/identity-manager.js +13 -7
- package/dist/src/halo/identity-manager.js.map +1 -1
- package/dist/src/halo/identity.js +2 -2
- package/dist/src/halo/identity.js.map +1 -1
- package/dist/src/halo/party-opener.d.ts.map +1 -1
- package/dist/src/halo/party-opener.js +2 -4
- package/dist/src/halo/party-opener.js.map +1 -1
- package/dist/src/halo/preferences.d.ts.map +1 -1
- package/dist/src/halo/preferences.js +9 -12
- package/dist/src/halo/preferences.js.map +1 -1
- package/dist/src/invitations/greeting-initiator.d.ts +5 -4
- package/dist/src/invitations/greeting-initiator.d.ts.map +1 -1
- package/dist/src/invitations/greeting-initiator.js +9 -10
- package/dist/src/invitations/greeting-initiator.js.map +1 -1
- package/dist/src/invitations/greeting-protocol-provider.js +2 -2
- package/dist/src/invitations/greeting-protocol-provider.js.map +1 -1
- package/dist/src/invitations/greeting-responder.d.ts +4 -7
- package/dist/src/invitations/greeting-responder.d.ts.map +1 -1
- package/dist/src/invitations/greeting-responder.js +12 -26
- package/dist/src/invitations/greeting-responder.js.map +1 -1
- package/dist/src/invitations/halo-recovery-initiator.js +8 -8
- package/dist/src/invitations/halo-recovery-initiator.js.map +1 -1
- package/dist/src/invitations/invitation-descriptor.js +12 -12
- package/dist/src/invitations/invitation-descriptor.js.map +1 -1
- package/dist/src/invitations/invitation-factory.d.ts +2 -1
- package/dist/src/invitations/invitation-factory.d.ts.map +1 -1
- package/dist/src/invitations/invitation-factory.js +6 -8
- package/dist/src/invitations/invitation-factory.js.map +1 -1
- package/dist/src/invitations/offline-invitation-claimer.js +9 -9
- package/dist/src/invitations/offline-invitation-claimer.js.map +1 -1
- package/dist/src/packlets/database/data-mirror.js +8 -8
- package/dist/src/packlets/database/data-mirror.js.map +1 -1
- package/dist/src/packlets/database/data-mirror.test.js +1 -1
- package/dist/src/packlets/database/data-mirror.test.js.map +1 -1
- package/dist/src/packlets/database/data-service-host.js +3 -3
- package/dist/src/packlets/database/data-service-host.js.map +1 -1
- package/dist/src/packlets/database/data-service-router.js +5 -5
- package/dist/src/packlets/database/data-service-router.js.map +1 -1
- package/dist/src/packlets/database/database-backend.js +3 -3
- package/dist/src/packlets/database/database-backend.js.map +1 -1
- package/dist/src/packlets/database/database.js +2 -2
- package/dist/src/packlets/database/database.js.map +1 -1
- package/dist/src/packlets/database/item-demuxer.js +14 -14
- package/dist/src/packlets/database/item-demuxer.js.map +1 -1
- package/dist/src/packlets/database/item-demuxer.test.js +1 -1
- package/dist/src/packlets/database/item-demuxer.test.js.map +1 -1
- package/dist/src/packlets/database/item-manager.js +18 -18
- package/dist/src/packlets/database/item-manager.js.map +1 -1
- package/dist/src/packlets/database/link.js +3 -3
- package/dist/src/packlets/database/link.js.map +1 -1
- package/dist/src/packlets/database/selection/result.js +2 -2
- package/dist/src/packlets/database/selection/result.js.map +1 -1
- package/dist/src/packlets/database/testing.js +1 -1
- package/dist/src/packlets/database/testing.js.map +1 -1
- package/dist/src/packlets/database/timeframe-clock.d.ts +2 -1
- package/dist/src/packlets/database/timeframe-clock.d.ts.map +1 -1
- package/dist/src/packlets/database/timeframe-clock.js +15 -5
- package/dist/src/packlets/database/timeframe-clock.js.map +1 -1
- package/dist/src/parties/data-party.d.ts +4 -3
- package/dist/src/parties/data-party.d.ts.map +1 -1
- package/dist/src/parties/data-party.js +18 -14
- package/dist/src/parties/data-party.js.map +1 -1
- package/dist/src/parties/data-party.test.js +12 -12
- package/dist/src/parties/data-party.test.js.map +1 -1
- package/dist/src/parties/party-factory.d.ts +2 -4
- package/dist/src/parties/party-factory.d.ts.map +1 -1
- package/dist/src/parties/party-factory.js +18 -15
- package/dist/src/parties/party-factory.js.map +1 -1
- package/dist/src/parties/party-manager.d.ts +1 -1
- package/dist/src/parties/party-manager.d.ts.map +1 -1
- package/dist/src/parties/party-manager.js +19 -19
- package/dist/src/parties/party-manager.js.map +1 -1
- package/dist/src/parties/party-manager.test.js +22 -18
- package/dist/src/parties/party-manager.test.js.map +1 -1
- package/dist/src/parties/party-preferences.js +2 -2
- package/dist/src/parties/party-preferences.js.map +1 -1
- package/dist/src/pipeline/feed-muxer.d.ts.map +1 -1
- package/dist/src/pipeline/feed-muxer.js +5 -5
- package/dist/src/pipeline/feed-muxer.js.map +1 -1
- package/dist/src/pipeline/feed-muxer.test.js +2 -2
- package/dist/src/pipeline/feed-muxer.test.js.map +1 -1
- package/dist/src/pipeline/message-selector.d.ts +1 -2
- package/dist/src/pipeline/message-selector.d.ts.map +1 -1
- package/dist/src/pipeline/message-selector.js +6 -33
- package/dist/src/pipeline/message-selector.js.map +1 -1
- package/dist/src/pipeline/metadata-store.d.ts +7 -2
- package/dist/src/pipeline/metadata-store.d.ts.map +1 -1
- package/dist/src/pipeline/metadata-store.js +12 -3
- package/dist/src/pipeline/metadata-store.js.map +1 -1
- package/dist/src/pipeline/party-feed-provider.d.ts +2 -2
- package/dist/src/pipeline/party-feed-provider.d.ts.map +1 -1
- package/dist/src/pipeline/party-feed-provider.js +5 -4
- package/dist/src/pipeline/party-feed-provider.js.map +1 -1
- package/dist/src/pipeline/party-pipeline.d.ts +5 -5
- package/dist/src/pipeline/party-pipeline.d.ts.map +1 -1
- package/dist/src/pipeline/party-pipeline.js +19 -20
- package/dist/src/pipeline/party-pipeline.js.map +1 -1
- package/dist/src/pipeline/party-pipeline.test.js +13 -18
- package/dist/src/pipeline/party-pipeline.test.js.map +1 -1
- package/dist/src/pipeline/party-processor.js +3 -3
- package/dist/src/pipeline/party-processor.js.map +1 -1
- package/dist/src/protocol/authenticator.test.js +53 -12
- package/dist/src/protocol/authenticator.test.js.map +1 -1
- package/dist/src/protocol/identity-credentials.d.ts.map +1 -1
- package/dist/src/protocol/identity-credentials.js +2 -2
- package/dist/src/protocol/identity-credentials.js.map +1 -1
- package/dist/src/protocol/party-protocol-factory.js +1 -1
- package/dist/src/protocol/party-protocol-factory.js.map +1 -1
- package/dist/src/protocol/replicator-plugin.d.ts.map +1 -1
- package/dist/src/protocol/replicator-plugin.js +1 -2
- package/dist/src/protocol/replicator-plugin.js.map +1 -1
- package/dist/src/snapshots/snapshot-generator.js +2 -2
- package/dist/src/snapshots/snapshot-generator.js.map +1 -1
- package/dist/src/snapshots/snapshot-store.d.ts.map +1 -1
- package/dist/src/snapshots/snapshot-store.js +4 -4
- package/dist/src/snapshots/snapshot-store.js.map +1 -1
- package/dist/src/testing/testing-factories.js +2 -2
- package/dist/src/testing/testing-factories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +24 -20
- package/src/api/result-set.ts +1 -1
- package/src/echo.test.ts +3 -3
- package/src/echo.ts +1 -1
- package/src/halo/halo-factory.ts +8 -9
- package/src/halo/halo-party.ts +15 -7
- package/src/halo/halo.ts +4 -2
- package/src/halo/identity-manager.ts +12 -3
- package/src/halo/identity.ts +1 -1
- package/src/halo/party-opener.ts +2 -4
- package/src/halo/preferences.ts +5 -9
- package/src/invitations/greeting-initiator.ts +11 -6
- package/src/invitations/greeting-protocol-provider.ts +2 -2
- package/src/invitations/greeting-responder.ts +12 -31
- package/src/invitations/halo-recovery-initiator.ts +4 -4
- package/src/invitations/invitation-descriptor.ts +6 -6
- package/src/invitations/invitation-factory.ts +3 -3
- package/src/invitations/offline-invitation-claimer.ts +4 -4
- package/src/packlets/database/data-mirror.test.ts +2 -2
- package/src/packlets/database/data-mirror.ts +1 -1
- package/src/packlets/database/data-service-host.ts +1 -1
- package/src/packlets/database/data-service-router.ts +1 -1
- package/src/packlets/database/database-backend.ts +1 -1
- package/src/packlets/database/database.ts +1 -1
- package/src/packlets/database/item-demuxer.test.ts +2 -2
- package/src/packlets/database/item-demuxer.ts +1 -1
- package/src/packlets/database/item-manager.ts +1 -1
- package/src/packlets/database/link.ts +1 -1
- package/src/packlets/database/selection/result.ts +1 -1
- package/src/packlets/database/testing.ts +2 -2
- package/src/packlets/database/timeframe-clock.ts +4 -1
- package/src/parties/data-party.test.ts +12 -12
- package/src/parties/data-party.ts +15 -7
- package/src/parties/party-factory.ts +21 -13
- package/src/parties/party-manager.test.ts +13 -9
- package/src/parties/party-manager.ts +15 -13
- package/src/parties/party-preferences.ts +1 -1
- package/src/pipeline/feed-muxer.test.ts +2 -2
- package/src/pipeline/feed-muxer.ts +5 -5
- package/src/pipeline/message-selector.ts +5 -36
- package/src/pipeline/metadata-store.ts +53 -31
- package/src/pipeline/party-feed-provider.ts +3 -3
- package/src/pipeline/party-pipeline.test.ts +13 -19
- package/src/pipeline/party-pipeline.ts +14 -13
- package/src/pipeline/party-processor.ts +1 -1
- package/src/protocol/authenticator.test.ts +102 -17
- package/src/protocol/identity-credentials.ts +5 -2
- package/src/protocol/party-protocol-factory.ts +2 -2
- package/src/protocol/replicator-plugin.ts +1 -2
- package/src/snapshots/snapshot-generator.ts +1 -1
- package/src/snapshots/snapshot-store.ts +3 -3
- package/src/testing/testing-factories.ts +1 -1
|
@@ -2,17 +2,16 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
8
|
import { Event } from '@dxos/async';
|
|
9
9
|
import { Message as HaloMessage } from '@dxos/credentials';
|
|
10
|
-
import { keyToString } from '@dxos/crypto';
|
|
11
10
|
import { checkType } from '@dxos/debug';
|
|
12
11
|
import {
|
|
13
|
-
createFeedMeta, EchoEnvelope, FeedMessage, FeedStoreIterator, FeedWriter, IEchoStream, mapFeedWriter
|
|
12
|
+
createFeedMeta, EchoEnvelope, FeedMessage, FeedStoreIterator, FeedWriter, IEchoStream, mapFeedWriter
|
|
14
13
|
} from '@dxos/echo-protocol';
|
|
15
|
-
import { PublicKey } from '@dxos/protocols';
|
|
14
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
16
15
|
import { jsonReplacer } from '@dxos/util';
|
|
17
16
|
|
|
18
17
|
import { EchoProcessor, TimeframeClock } from '../packlets/database';
|
|
@@ -139,7 +138,8 @@ export class FeedMuxer {
|
|
|
139
138
|
|
|
140
139
|
if (message.echo) {
|
|
141
140
|
const memberKey = this._partyProcessor.getFeedOwningMember(PublicKey.from(block.key));
|
|
142
|
-
|
|
141
|
+
// TODO(wittjosiah): Is actually a Buffer for some reason. See todo in IFeedGenericBlock.
|
|
142
|
+
assert(memberKey, `Ownership of feed ${PublicKey.stringify(block.key as unknown as Buffer)} could not be determined.`);
|
|
143
143
|
|
|
144
144
|
// Validate messge.
|
|
145
145
|
const { itemId } = message.echo;
|
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
// Copyright 2020 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
|
-
import { getPartyCredentialMessageType, PartyCredential } from '@dxos/credentials';
|
|
9
8
|
import { MessageSelector } from '@dxos/echo-protocol';
|
|
10
|
-
import { PublicKey } from '@dxos/protocols';
|
|
11
9
|
|
|
12
10
|
import { TimeframeClock } from '../packlets/database';
|
|
13
|
-
import { PartyStateProvider } from './party-processor';
|
|
14
11
|
|
|
15
12
|
const log = debug('dxos:echo-db:message-selector');
|
|
16
13
|
|
|
@@ -23,44 +20,16 @@ const log = debug('dxos:echo-db:message-selector');
|
|
|
23
20
|
* @param partyProcessor
|
|
24
21
|
* @param timeframeClock
|
|
25
22
|
*/
|
|
26
|
-
export const createMessageSelector = (
|
|
27
|
-
//
|
|
23
|
+
export const createMessageSelector = (timeframeClock: TimeframeClock): MessageSelector => candidates => {
|
|
24
|
+
// Pick the first candidate with a valid timeframe that has no gaps.
|
|
28
25
|
for (let i = 0; i < candidates.length; i++) {
|
|
29
|
-
const { data: { timeframe
|
|
30
|
-
const feedKey = PublicKey.from(candidates[i].key);
|
|
31
|
-
if (!echo) {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
assert(timeframe);
|
|
36
|
-
if (partyProcessor.isFeedAdmitted(feedKey) && !timeframeClock.hasGaps(timeframe)) {
|
|
37
|
-
return i;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Check HALO message candidates.
|
|
42
|
-
for (let i = 0; i < candidates.length; i++) {
|
|
43
|
-
const { data: { timeframe, halo } } = candidates[i];
|
|
44
|
-
const feedKey = PublicKey.from(candidates[i].key);
|
|
45
|
-
if (!halo) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
26
|
+
const { data: { timeframe } } = candidates[i];
|
|
48
27
|
|
|
49
28
|
assert(timeframe);
|
|
50
|
-
if (
|
|
29
|
+
if (!timeframeClock.hasGaps(timeframe)) {
|
|
51
30
|
return i;
|
|
52
31
|
}
|
|
53
|
-
|
|
54
|
-
if (partyProcessor.genesisRequired) {
|
|
55
|
-
try { // TODO(dmaretskyi): Get getPartyCredentialMessageType crashes for some reason.
|
|
56
|
-
// TODO(telackey): Add check that this is for the right Party.
|
|
57
|
-
if (getPartyCredentialMessageType(halo) === PartyCredential.Type.PARTY_GENESIS) {
|
|
58
|
-
return i;
|
|
59
|
-
}
|
|
60
|
-
} catch { }
|
|
61
|
-
}
|
|
62
32
|
}
|
|
63
|
-
|
|
64
33
|
// Not ready for this message yet.
|
|
65
34
|
log('Skipping...');
|
|
66
35
|
};
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
8
|
import { synchronized } from '@dxos/async';
|
|
9
9
|
import { failUndefined } from '@dxos/debug';
|
|
10
|
-
import { EchoMetadata, PartyMetadata, schema
|
|
11
|
-
import { PublicKey } from '@dxos/protocols';
|
|
10
|
+
import { EchoMetadata, PartyMetadata, schema } from '@dxos/echo-protocol';
|
|
11
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
12
12
|
import { Directory } from '@dxos/random-access-multi-storage';
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -20,13 +20,20 @@ export const STORAGE_VERSION = 1;
|
|
|
20
20
|
|
|
21
21
|
const log = debug('dxos:snapshot-store');
|
|
22
22
|
|
|
23
|
+
export interface AddPartyOptions {
|
|
24
|
+
key: PublicKey
|
|
25
|
+
genesisFeed: PublicKey
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const emptyEchoMetadata = (): EchoMetadata => ({
|
|
29
|
+
version: STORAGE_VERSION,
|
|
30
|
+
parties: [],
|
|
31
|
+
created: new Date(),
|
|
32
|
+
updated: new Date()
|
|
33
|
+
});
|
|
34
|
+
|
|
23
35
|
export class MetadataStore {
|
|
24
|
-
private _metadata: EchoMetadata =
|
|
25
|
-
version: STORAGE_VERSION,
|
|
26
|
-
parties: [],
|
|
27
|
-
created: new Date(),
|
|
28
|
-
updated: new Date()
|
|
29
|
-
};
|
|
36
|
+
private _metadata: EchoMetadata = emptyEchoMetadata();
|
|
30
37
|
|
|
31
38
|
constructor (
|
|
32
39
|
private readonly _directory: Directory
|
|
@@ -51,19 +58,26 @@ export class MetadataStore {
|
|
|
51
58
|
async load (): Promise<void> {
|
|
52
59
|
const file = this._directory.createOrOpen('EchoMetadata');
|
|
53
60
|
try {
|
|
54
|
-
const { size } = await file.stat();
|
|
55
|
-
if (
|
|
61
|
+
const { size: fileLength } = await file.stat();
|
|
62
|
+
if (fileLength < 4) {
|
|
56
63
|
return;
|
|
57
64
|
}
|
|
65
|
+
// Loading file size from first 4 bytes.
|
|
66
|
+
const dataSize = fromBytesInt32(await file.read(0, 4));
|
|
67
|
+
log(`Load: data size ${dataSize}`);
|
|
68
|
+
|
|
69
|
+
// Sanity check.
|
|
70
|
+
{
|
|
71
|
+
if (fileLength < dataSize + 4) {
|
|
72
|
+
throw new Error('Metadata storage is corrupted');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
58
75
|
|
|
59
|
-
const data = await file.read(
|
|
76
|
+
const data = await file.read(4, dataSize);
|
|
60
77
|
this._metadata = schema.getCodecForType('dxos.echo.metadata.EchoMetadata').decode(data);
|
|
61
78
|
} catch (err: any) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
} else {
|
|
65
|
-
throw err;
|
|
66
|
-
}
|
|
79
|
+
log(`Error loading metadata: ${err}`);
|
|
80
|
+
this._metadata = emptyEchoMetadata();
|
|
67
81
|
} finally {
|
|
68
82
|
await file.close();
|
|
69
83
|
}
|
|
@@ -82,22 +96,14 @@ export class MetadataStore {
|
|
|
82
96
|
|
|
83
97
|
try {
|
|
84
98
|
const encoded = Buffer.from(schema.getCodecForType('dxos.echo.metadata.EchoMetadata').encode(data));
|
|
85
|
-
await file.write(0, encoded);
|
|
86
99
|
|
|
87
|
-
//
|
|
88
|
-
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
100
|
+
// Saving file size at first 4 bytes.
|
|
101
|
+
log(`Save: data size ${encoded.length}`);
|
|
102
|
+
await file.write(0, toBytesInt32(encoded.length));
|
|
103
|
+
|
|
104
|
+
// Saving data.
|
|
105
|
+
await file.write(4, encoded);
|
|
94
106
|
|
|
95
|
-
// Sanity check.
|
|
96
|
-
const { size } = await file.stat();
|
|
97
|
-
if (size !== encoded.length) {
|
|
98
|
-
console.log('SANITY!');
|
|
99
|
-
}
|
|
100
|
-
assert(size === encoded.length);
|
|
101
107
|
} finally {
|
|
102
108
|
await file.close();
|
|
103
109
|
}
|
|
@@ -147,6 +153,14 @@ export class MetadataStore {
|
|
|
147
153
|
await this._save();
|
|
148
154
|
}
|
|
149
155
|
|
|
156
|
+
async setGenesisFeed (partyKey: PublicKey, feedKey: PublicKey): Promise<void> {
|
|
157
|
+
assert(PublicKey.isPublicKey(feedKey));
|
|
158
|
+
await this.addPartyFeed(partyKey, feedKey);
|
|
159
|
+
const party = this.getParty(partyKey) ?? failUndefined();
|
|
160
|
+
party.genesisFeedKey = feedKey;
|
|
161
|
+
await this._save();
|
|
162
|
+
}
|
|
163
|
+
|
|
150
164
|
/**
|
|
151
165
|
* Sets the data feed key in the party specified by public key and saves updated data in persistent storage.
|
|
152
166
|
* Update party's feed list.
|
|
@@ -183,3 +197,11 @@ export class MetadataStore {
|
|
|
183
197
|
await this._save();
|
|
184
198
|
}
|
|
185
199
|
}
|
|
200
|
+
|
|
201
|
+
const toBytesInt32 = (num: number) => {
|
|
202
|
+
const buf = Buffer.alloc(4);
|
|
203
|
+
buf.writeInt32LE(num, 0);
|
|
204
|
+
return buf;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const fromBytesInt32 = (buf: Buffer) => buf.readInt32LE(0);
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
6
5
|
import debug from 'debug';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
7
|
|
|
8
8
|
import { Event, synchronized } from '@dxos/async';
|
|
9
9
|
import { Keyring, KeyType } from '@dxos/credentials';
|
|
10
|
-
import { FeedSelector, FeedStoreIterator, MessageSelector
|
|
10
|
+
import { FeedSelector, FeedStoreIterator, MessageSelector } from '@dxos/echo-protocol';
|
|
11
11
|
import { FeedDescriptor, FeedStore } from '@dxos/feed-store';
|
|
12
|
-
import { PublicKey } from '@dxos/protocols';
|
|
12
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
13
13
|
import { ComplexMap } from '@dxos/util';
|
|
14
14
|
|
|
15
15
|
import { MetadataStore } from './metadata-store';
|
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
import expect from 'expect';
|
|
6
6
|
import { it as test } from 'mocha';
|
|
7
7
|
|
|
8
|
-
import { promiseTimeout } from '@dxos/async';
|
|
8
|
+
import { promiseTimeout, sleep } from '@dxos/async';
|
|
9
9
|
import { createFeedAdmitMessage, createPartyGenesisMessage, Keyring, KeyType } from '@dxos/credentials';
|
|
10
10
|
import { createId } from '@dxos/crypto';
|
|
11
11
|
import { checkType } from '@dxos/debug';
|
|
12
|
-
import { codec, FeedMessage
|
|
12
|
+
import { codec, FeedMessage } from '@dxos/echo-protocol';
|
|
13
13
|
import { FeedStore } from '@dxos/feed-store';
|
|
14
14
|
import { createTestProtocolPair } from '@dxos/mesh-protocol';
|
|
15
15
|
import { ModelFactory } from '@dxos/model-factory';
|
|
16
16
|
import { ObjectModel } from '@dxos/object-model';
|
|
17
|
-
import { PublicKey } from '@dxos/protocols';
|
|
17
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
18
18
|
import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
|
|
19
19
|
import { afterTest } from '@dxos/testutils';
|
|
20
20
|
|
|
@@ -49,7 +49,7 @@ describe('PartyPipeline', () => {
|
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
const feed = await partyFeedProvider.createOrOpenWritableFeed();
|
|
52
|
-
await party.open({
|
|
52
|
+
await party.open({ genesisFeedKey: feed.key });
|
|
53
53
|
afterTest(async () => party.close());
|
|
54
54
|
|
|
55
55
|
// PartyGenesis (self-signed by Party).
|
|
@@ -104,7 +104,7 @@ describe('PartyPipeline', () => {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
await party.close();
|
|
107
|
-
await party.open({
|
|
107
|
+
await party.open({ genesisFeedKey: feedKey });
|
|
108
108
|
|
|
109
109
|
{
|
|
110
110
|
await party.database.select().exec().update.waitFor(result => result.entities.length === 2);
|
|
@@ -132,7 +132,7 @@ describe('PartyPipeline', () => {
|
|
|
132
132
|
expect(partyFeedProvider.getFeeds().find(k => k.key.equals(feedKey.publicKey))).toBeTruthy();
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
test('
|
|
135
|
+
test('does not open unrelated feeds', async () => {
|
|
136
136
|
const storage = createStorage('', StorageType.RAM);
|
|
137
137
|
const feedStore = new FeedStore(storage.directory('feed'), { valueEncoding: codec });
|
|
138
138
|
afterTest(async () => feedStore.close());
|
|
@@ -158,21 +158,19 @@ describe('PartyPipeline', () => {
|
|
|
158
158
|
PublicKey.random()
|
|
159
159
|
);
|
|
160
160
|
|
|
161
|
-
await partyFeedProvider.createOrOpenWritableFeed();
|
|
161
|
+
const writeFeed = await partyFeedProvider.createOrOpenWritableFeed();
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
await party.open({ feedHints: [otherFeedKey] });
|
|
163
|
+
await party.open({ genesisFeedKey: writeFeed.key });
|
|
166
164
|
afterTest(async () => party.close());
|
|
167
165
|
|
|
168
|
-
|
|
166
|
+
// Wait for events to be processed.
|
|
167
|
+
await sleep(5);
|
|
169
168
|
|
|
170
|
-
expect(partyFeedProvider.getFeeds().some(k => k.key.equals(otherFeedKey))).toEqual(
|
|
169
|
+
expect(partyFeedProvider.getFeeds().some(k => k.key.equals(otherFeedKey))).toEqual(false);
|
|
171
170
|
});
|
|
172
171
|
|
|
173
172
|
test('manually create item', async () => {
|
|
174
173
|
const { party, partyFeedProvider } = await setup();
|
|
175
|
-
await party.open();
|
|
176
174
|
|
|
177
175
|
const feed = await partyFeedProvider.createOrOpenWritableFeed();
|
|
178
176
|
|
|
@@ -193,7 +191,6 @@ describe('PartyPipeline', () => {
|
|
|
193
191
|
|
|
194
192
|
test('admit a second feed to the party', async () => {
|
|
195
193
|
const { party, keyring, partyKey, feedStore } = await setup();
|
|
196
|
-
await party.open();
|
|
197
194
|
|
|
198
195
|
const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
|
|
199
196
|
const fullKey = keyring.getFullKey(feedKey.publicKey);
|
|
@@ -223,7 +220,6 @@ describe('PartyPipeline', () => {
|
|
|
223
220
|
|
|
224
221
|
test('admit feed and then open it', async () => {
|
|
225
222
|
const { party, keyring, partyKey, feedStore } = await setup();
|
|
226
|
-
await party.open();
|
|
227
223
|
|
|
228
224
|
const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
|
|
229
225
|
const fullKey = keyring.getFullKey(feedKey.publicKey);
|
|
@@ -270,7 +266,7 @@ describe('PartyPipeline', () => {
|
|
|
270
266
|
expect(timeframe.isEmpty()).toBeFalsy();
|
|
271
267
|
|
|
272
268
|
await party.close();
|
|
273
|
-
await party.open({
|
|
269
|
+
await party.open({ genesisFeedKey: feedKey, targetTimeframe: timeframe });
|
|
274
270
|
});
|
|
275
271
|
|
|
276
272
|
test('two instances replicating', async () => {
|
|
@@ -304,9 +300,7 @@ describe('PartyPipeline', () => {
|
|
|
304
300
|
[peer1.partyKey]
|
|
305
301
|
));
|
|
306
302
|
|
|
307
|
-
await party2.open({
|
|
308
|
-
feedHints: [peer1.feedKey]
|
|
309
|
-
});
|
|
303
|
+
await party2.open({ genesisFeedKey: peer1.feedKey });
|
|
310
304
|
afterTest(async () => party2.close());
|
|
311
305
|
|
|
312
306
|
createTestProtocolPair(
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import assert from 'assert';
|
|
5
|
+
import assert from 'node:assert';
|
|
6
6
|
|
|
7
7
|
import { synchronized } from '@dxos/async';
|
|
8
8
|
import { KeyType, Message as HaloMessage } from '@dxos/credentials';
|
|
9
9
|
import { timed } from '@dxos/debug';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
createFeedWriter, DatabaseSnapshot, FeedSelector, FeedWriter, PartyKey, PartySnapshot
|
|
12
|
+
} from '@dxos/echo-protocol';
|
|
11
13
|
import { ModelFactory } from '@dxos/model-factory';
|
|
12
|
-
import { PublicKey } from '@dxos/protocols';
|
|
14
|
+
import { PublicKey, Timeframe } from '@dxos/protocols';
|
|
13
15
|
import { SubscriptionGroup } from '@dxos/util';
|
|
14
16
|
|
|
15
17
|
import { createMessageSelector, PartyProcessor, PartyFeedProvider, FeedMuxer } from '.';
|
|
@@ -30,9 +32,9 @@ export interface PipelineOptions {
|
|
|
30
32
|
|
|
31
33
|
export interface OpenOptions {
|
|
32
34
|
/**
|
|
33
|
-
*
|
|
35
|
+
* Initial feed that contains PartyGenesis message and acts as the root for the feed DAG.
|
|
34
36
|
*/
|
|
35
|
-
|
|
37
|
+
genesisFeedKey: PublicKey
|
|
36
38
|
/**
|
|
37
39
|
* Timeframe to start processing feed messages from.
|
|
38
40
|
*/
|
|
@@ -123,9 +125,9 @@ export class PartyPipeline {
|
|
|
123
125
|
*/
|
|
124
126
|
@synchronized
|
|
125
127
|
@timed(1_000)
|
|
126
|
-
async open (options: OpenOptions
|
|
128
|
+
async open (options: OpenOptions) {
|
|
127
129
|
const {
|
|
128
|
-
|
|
130
|
+
genesisFeedKey,
|
|
129
131
|
initialTimeframe,
|
|
130
132
|
targetTimeframe
|
|
131
133
|
} = options;
|
|
@@ -147,17 +149,16 @@ export class PartyPipeline {
|
|
|
147
149
|
void this._feedProvider.createOrOpenReadOnlyFeed(feed);
|
|
148
150
|
}));
|
|
149
151
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
152
|
+
// TODO(dmaretskyi): We still need to hint at the genesis feed for some reason, not doing this breaks invitation tests.
|
|
153
|
+
await this._partyProcessor.takeHints([{ type: KeyType.FEED, publicKey: genesisFeedKey }]);
|
|
153
154
|
|
|
154
155
|
//
|
|
155
156
|
// Pipeline
|
|
156
157
|
//
|
|
157
158
|
|
|
158
159
|
const iterator = await this._feedProvider.createIterator(
|
|
159
|
-
createMessageSelector(this.
|
|
160
|
-
createFeedSelector(this._partyProcessor,
|
|
160
|
+
createMessageSelector(this._timeframeClock),
|
|
161
|
+
createFeedSelector(this._partyProcessor, genesisFeedKey),
|
|
161
162
|
initialTimeframe
|
|
162
163
|
);
|
|
163
164
|
|
|
@@ -256,4 +257,4 @@ export class PartyPipeline {
|
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
|
|
259
|
-
const createFeedSelector = (partyProcessor: PartyProcessor,
|
|
260
|
+
const createFeedSelector = (partyProcessor: PartyProcessor, genesisFeed: PublicKey): FeedSelector => feed => genesisFeed.equals(feed.key) || partyProcessor.isFeedAdmitted(feed.key);
|
|
@@ -5,21 +5,18 @@
|
|
|
5
5
|
import expect from 'expect';
|
|
6
6
|
import { it as test } from 'mocha';
|
|
7
7
|
|
|
8
|
-
import { createAuthMessage, createKeyAdmitMessage, createPartyGenesisMessage, Keyring, KeyType } from '@dxos/credentials';
|
|
8
|
+
import { createAuthMessage, createEnvelopeMessage, createFeedAdmitMessage, createKeyAdmitMessage, createPartyGenesisMessage, Keyring, KeyType, wrapMessage } from '@dxos/credentials';
|
|
9
9
|
|
|
10
10
|
import { PartyProcessor } from '../pipeline';
|
|
11
11
|
import { createAuthenticator } from './authenticator';
|
|
12
|
-
import {
|
|
12
|
+
import { createTestIdentityCredentials } from './identity-credentials';
|
|
13
13
|
|
|
14
14
|
describe('authenticator', () => {
|
|
15
|
-
|
|
16
|
-
test.skip('authenticates admitted peer', async () => {
|
|
15
|
+
test('authenticates party creator', async () => {
|
|
17
16
|
const keyring = new Keyring();
|
|
17
|
+
const identity = await createTestIdentityCredentials(keyring);
|
|
18
18
|
const partyKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
19
|
-
const
|
|
20
|
-
const deviceKey = await keyring.createKeyRecord({ type: KeyType.DEVICE });
|
|
21
|
-
const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
|
|
22
|
-
const signer = CredentialsSigner.createDirectDeviceSigner(keyring);
|
|
19
|
+
const feedKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
23
20
|
|
|
24
21
|
const partyProcessor = new PartyProcessor(partyKey.publicKey);
|
|
25
22
|
await partyProcessor.processMessage({
|
|
@@ -27,16 +24,106 @@ describe('authenticator', () => {
|
|
|
27
24
|
keyring,
|
|
28
25
|
partyKey,
|
|
29
26
|
feedKey.publicKey,
|
|
30
|
-
|
|
27
|
+
partyKey
|
|
31
28
|
),
|
|
32
29
|
meta: {} as any
|
|
33
30
|
});
|
|
31
|
+
await partyProcessor.processMessage({
|
|
32
|
+
data: createEnvelopeMessage(
|
|
33
|
+
identity.keyring,
|
|
34
|
+
partyKey.publicKey,
|
|
35
|
+
wrapMessage(identity.identityGenesis),
|
|
36
|
+
[partyKey]
|
|
37
|
+
),
|
|
38
|
+
meta: {} as any
|
|
39
|
+
});
|
|
40
|
+
await partyProcessor.processMessage({
|
|
41
|
+
data: createFeedAdmitMessage(
|
|
42
|
+
keyring,
|
|
43
|
+
partyKey.publicKey,
|
|
44
|
+
feedKey.publicKey,
|
|
45
|
+
[identity.deviceKeyChain]
|
|
46
|
+
),
|
|
47
|
+
meta: {} as any
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const authenticator = createAuthenticator(partyProcessor, identity.createCredentialsSigner(), null as any);
|
|
51
|
+
|
|
52
|
+
//
|
|
53
|
+
// This test follows the same party creation routing as party factory.
|
|
54
|
+
// Oddly, it does not admit the device key to the party.
|
|
55
|
+
// This means that authentication is actually done using the signature created using the feed key.
|
|
56
|
+
//
|
|
57
|
+
|
|
58
|
+
// Does not authenticate without the feed key.
|
|
59
|
+
{
|
|
60
|
+
const credential = createAuthMessage(
|
|
61
|
+
keyring,
|
|
62
|
+
partyKey.publicKey,
|
|
63
|
+
identity.identityKey,
|
|
64
|
+
identity.deviceKey
|
|
65
|
+
);
|
|
66
|
+
expect(await authenticator.authenticate(credential.payload)).toEqual(false);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Does authenticate with the feed key.
|
|
70
|
+
{
|
|
71
|
+
const credential = createAuthMessage(
|
|
72
|
+
keyring,
|
|
73
|
+
partyKey.publicKey,
|
|
74
|
+
identity.identityKey,
|
|
75
|
+
identity.deviceKey,
|
|
76
|
+
feedKey.publicKey
|
|
77
|
+
);
|
|
78
|
+
expect(await authenticator.authenticate(credential.payload)).toEqual(true);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('authenticates another identity', async () => {
|
|
83
|
+
const keyring = new Keyring();
|
|
84
|
+
const identity = await createTestIdentityCredentials(keyring);
|
|
85
|
+
const partyKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
86
|
+
const feedKey = await keyring.createKeyRecord({ type: KeyType.PARTY });
|
|
87
|
+
|
|
88
|
+
const partyProcessor = new PartyProcessor(partyKey.publicKey);
|
|
89
|
+
await partyProcessor.processMessage({
|
|
90
|
+
data: createPartyGenesisMessage(
|
|
91
|
+
keyring,
|
|
92
|
+
partyKey,
|
|
93
|
+
feedKey.publicKey,
|
|
94
|
+
partyKey
|
|
95
|
+
),
|
|
96
|
+
meta: {} as any
|
|
97
|
+
});
|
|
98
|
+
await partyProcessor.processMessage({
|
|
99
|
+
data: createEnvelopeMessage(
|
|
100
|
+
identity.keyring,
|
|
101
|
+
partyKey.publicKey,
|
|
102
|
+
wrapMessage(identity.identityGenesis),
|
|
103
|
+
[partyKey]
|
|
104
|
+
),
|
|
105
|
+
meta: {} as any
|
|
106
|
+
});
|
|
107
|
+
await partyProcessor.processMessage({
|
|
108
|
+
data: createFeedAdmitMessage(
|
|
109
|
+
keyring,
|
|
110
|
+
partyKey.publicKey,
|
|
111
|
+
feedKey.publicKey,
|
|
112
|
+
[identity.deviceKeyChain]
|
|
113
|
+
),
|
|
114
|
+
meta: {} as any
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const authenticator = createAuthenticator(partyProcessor, identity.createCredentialsSigner(), null as any);
|
|
118
|
+
|
|
119
|
+
const identity2 = await createTestIdentityCredentials(keyring);
|
|
120
|
+
|
|
34
121
|
await partyProcessor.processMessage({
|
|
35
122
|
data: createKeyAdmitMessage(
|
|
36
123
|
keyring,
|
|
37
124
|
partyKey.publicKey,
|
|
38
|
-
identityKey,
|
|
39
|
-
[
|
|
125
|
+
identity2.identityKey,
|
|
126
|
+
[identity.deviceKeyChain]
|
|
40
127
|
),
|
|
41
128
|
meta: {} as any
|
|
42
129
|
});
|
|
@@ -44,20 +131,18 @@ describe('authenticator', () => {
|
|
|
44
131
|
data: createKeyAdmitMessage(
|
|
45
132
|
keyring,
|
|
46
133
|
partyKey.publicKey,
|
|
47
|
-
deviceKey,
|
|
48
|
-
[
|
|
134
|
+
identity2.deviceKey,
|
|
135
|
+
[identity.deviceKeyChain]
|
|
49
136
|
),
|
|
50
137
|
meta: {} as any
|
|
51
138
|
});
|
|
52
139
|
|
|
53
|
-
const authenticator = createAuthenticator(partyProcessor, signer, null as any);
|
|
54
140
|
const credential = createAuthMessage(
|
|
55
141
|
keyring,
|
|
56
142
|
partyKey.publicKey,
|
|
57
|
-
identityKey,
|
|
58
|
-
deviceKey
|
|
143
|
+
identity2.identityKey,
|
|
144
|
+
identity2.deviceKey
|
|
59
145
|
);
|
|
60
|
-
|
|
61
146
|
expect(await authenticator.authenticate(credential.payload)).toEqual(true);
|
|
62
147
|
});
|
|
63
148
|
});
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
createIdentityInfoMessage, createKeyAdmitMessage, createPartyGenesisMessage,
|
|
7
|
+
KeyChain, KeyRecord, Keyring, KeyType, SignedMessage
|
|
8
|
+
} from '@dxos/credentials';
|
|
9
|
+
import { humanize } from '@dxos/util';
|
|
7
10
|
|
|
8
11
|
import { ContactManager, Preferences } from '../halo';
|
|
9
12
|
import { CredentialsSigner } from './credentials-signer';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import debug from 'debug';
|
|
6
6
|
|
|
7
|
-
import { discoveryKey
|
|
7
|
+
import { discoveryKey } from '@dxos/crypto';
|
|
8
8
|
import { PartyKey } from '@dxos/echo-protocol';
|
|
9
9
|
import { Protocol } from '@dxos/mesh-protocol';
|
|
10
10
|
import { MMSTTopology, NetworkManager, Plugin } from '@dxos/network-manager';
|
|
@@ -93,7 +93,7 @@ export class PartyProtocolFactory {
|
|
|
93
93
|
|
|
94
94
|
userSession: {
|
|
95
95
|
// TODO(burdon): See deprecated `protocolFactory` in HALO.
|
|
96
|
-
peerId:
|
|
96
|
+
peerId: this._peerId.toHex(),
|
|
97
97
|
// TODO(telackey): This ought to be the CredentialsProvider itself, so that fresh credentials can be minted.
|
|
98
98
|
credentials: this._credentials.get().toString('base64')
|
|
99
99
|
},
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import debug from 'debug';
|
|
6
6
|
|
|
7
|
-
import { keyToString } from '@dxos/crypto';
|
|
8
7
|
import { Replicator } from '@dxos/protocol-plugin-replicator';
|
|
9
8
|
|
|
10
9
|
import { PartyFeedProvider } from '../pipeline';
|
|
@@ -18,7 +17,7 @@ export const createReplicatorPlugin = (feedProvider: PartyFeedProvider) =>
|
|
|
18
17
|
new Replicator({
|
|
19
18
|
load: async () => {
|
|
20
19
|
const feeds = feedProvider.getFeeds();
|
|
21
|
-
log(`Loading feeds: ${feeds.map(feed =>
|
|
20
|
+
log(`Loading feeds: ${feeds.map(feed => feed.key.toHex())}`);
|
|
22
21
|
return feeds.map((feed) => ({ discoveryKey: feed.feed.discoveryKey }));
|
|
23
22
|
},
|
|
24
23
|
|