cojson 0.0.10 → 0.0.12
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/README.md +2 -2
- package/dist/account.d.ts +57 -0
- package/dist/account.js +76 -0
- package/dist/account.js.map +1 -0
- package/dist/account.test.d.ts +1 -0
- package/dist/account.test.js +40 -0
- package/dist/account.test.js.map +1 -0
- package/dist/coValue.d.ts +16 -35
- package/dist/coValue.js +49 -112
- package/dist/coValue.js.map +1 -1
- package/dist/coValue.test.js +16 -16
- package/dist/coValue.test.js.map +1 -1
- package/dist/contentType.d.ts +9 -9
- package/dist/contentType.js.map +1 -1
- package/dist/contentType.test.js +13 -17
- package/dist/contentType.test.js.map +1 -1
- package/dist/contentTypes/coList.d.ts +3 -3
- package/dist/contentTypes/coList.js.map +1 -1
- package/dist/contentTypes/coMap.d.ts +31 -21
- package/dist/contentTypes/coMap.js +28 -0
- package/dist/contentTypes/coMap.js.map +1 -1
- package/dist/contentTypes/coStream.d.ts +3 -3
- package/dist/contentTypes/coStream.js.map +1 -1
- package/dist/contentTypes/static.d.ts +4 -4
- package/dist/contentTypes/static.js.map +1 -1
- package/dist/crypto.d.ts +45 -39
- package/dist/crypto.js +68 -49
- package/dist/crypto.js.map +1 -1
- package/dist/crypto.test.js +45 -49
- package/dist/crypto.test.js.map +1 -1
- package/dist/ids.d.ts +5 -3
- package/dist/ids.js +3 -1
- package/dist/ids.js.map +1 -1
- package/dist/index.d.ts +12 -14
- package/dist/index.js +6 -8
- package/dist/index.js.map +1 -1
- package/dist/jsonValue.d.ts +2 -2
- package/dist/node.d.ts +25 -15
- package/dist/node.js +88 -33
- package/dist/node.js.map +1 -1
- package/dist/permissions.d.ts +27 -33
- package/dist/permissions.js +55 -47
- package/dist/permissions.js.map +1 -1
- package/dist/permissions.test.js +231 -314
- package/dist/permissions.test.js.map +1 -1
- package/dist/sync.d.ts +26 -28
- package/dist/sync.js +81 -67
- package/dist/sync.js.map +1 -1
- package/dist/sync.test.js +194 -293
- package/dist/sync.test.js.map +1 -1
- package/dist/testUtils.d.ts +37 -0
- package/dist/testUtils.js +157 -0
- package/dist/testUtils.js.map +1 -0
- package/package.json +1 -1
- package/src/account.test.ts +67 -0
- package/src/account.ts +152 -0
- package/src/coValue.test.ts +17 -31
- package/src/coValue.ts +93 -179
- package/src/contentType.test.ts +18 -45
- package/src/contentType.ts +15 -13
- package/src/contentTypes/coList.ts +4 -4
- package/src/contentTypes/coMap.ts +55 -29
- package/src/contentTypes/coStream.ts +4 -4
- package/src/contentTypes/static.ts +5 -5
- package/src/crypto.test.ts +53 -59
- package/src/crypto.ts +123 -95
- package/src/ids.ts +9 -3
- package/src/index.ts +14 -25
- package/src/jsonValue.ts +2 -2
- package/src/node.ts +189 -61
- package/src/permissions.test.ts +370 -404
- package/src/permissions.ts +126 -109
- package/src/sync.test.ts +284 -426
- package/src/sync.ts +115 -105
- package/src/testUtils.ts +229 -0
package/src/coValue.test.ts
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
newRandomAgentCredential,
|
|
6
|
-
newRandomSessionID,
|
|
7
|
-
} from './coValue.js';
|
|
8
|
-
import { LocalNode } from './node.js';
|
|
9
|
-
import { createdNowUnique, sign } from './crypto.js';
|
|
1
|
+
import { Transaction } from "./coValue.js";
|
|
2
|
+
import { LocalNode } from "./node.js";
|
|
3
|
+
import { createdNowUnique, getAgentSignerSecret, newRandomAgentSecret, sign } from "./crypto.js";
|
|
4
|
+
import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
|
|
10
5
|
|
|
11
6
|
test("Can create coValue with new agent credentials and add transaction to it", () => {
|
|
12
|
-
const
|
|
13
|
-
const node = new LocalNode(
|
|
14
|
-
agentCredential,
|
|
15
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
16
|
-
);
|
|
7
|
+
const [account, sessionID] = randomAnonymousAccountAndSessionID();
|
|
8
|
+
const node = new LocalNode(account, sessionID);
|
|
17
9
|
|
|
18
10
|
const coValue = node.createCoValue({
|
|
19
11
|
type: "costream",
|
|
20
12
|
ruleset: { type: "unsafeAllowAll" },
|
|
21
13
|
meta: null,
|
|
22
|
-
...createdNowUnique()
|
|
14
|
+
...createdNowUnique(),
|
|
23
15
|
});
|
|
24
16
|
|
|
25
17
|
const transaction: Transaction = {
|
|
@@ -42,24 +34,21 @@ test("Can create coValue with new agent credentials and add transaction to it",
|
|
|
42
34
|
node.ownSessionID,
|
|
43
35
|
[transaction],
|
|
44
36
|
expectedNewHash,
|
|
45
|
-
sign(
|
|
37
|
+
sign(account.currentSignerSecret(), expectedNewHash)
|
|
46
38
|
)
|
|
47
39
|
).toBe(true);
|
|
48
40
|
});
|
|
49
41
|
|
|
50
42
|
test("transactions with wrong signature are rejected", () => {
|
|
51
|
-
const wrongAgent =
|
|
52
|
-
const
|
|
53
|
-
const node = new LocalNode(
|
|
54
|
-
agentCredential,
|
|
55
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
56
|
-
);
|
|
43
|
+
const wrongAgent = newRandomAgentSecret();
|
|
44
|
+
const [agentSecret, sessionID] = randomAnonymousAccountAndSessionID();
|
|
45
|
+
const node = new LocalNode(agentSecret, sessionID);
|
|
57
46
|
|
|
58
47
|
const coValue = node.createCoValue({
|
|
59
48
|
type: "costream",
|
|
60
49
|
ruleset: { type: "unsafeAllowAll" },
|
|
61
50
|
meta: null,
|
|
62
|
-
...createdNowUnique()
|
|
51
|
+
...createdNowUnique(),
|
|
63
52
|
});
|
|
64
53
|
|
|
65
54
|
const transaction: Transaction = {
|
|
@@ -82,23 +71,20 @@ test("transactions with wrong signature are rejected", () => {
|
|
|
82
71
|
node.ownSessionID,
|
|
83
72
|
[transaction],
|
|
84
73
|
expectedNewHash,
|
|
85
|
-
sign(wrongAgent
|
|
74
|
+
sign(getAgentSignerSecret(wrongAgent), expectedNewHash)
|
|
86
75
|
)
|
|
87
76
|
).toBe(false);
|
|
88
77
|
});
|
|
89
78
|
|
|
90
79
|
test("transactions with correctly signed, but wrong hash are rejected", () => {
|
|
91
|
-
const
|
|
92
|
-
const node = new LocalNode(
|
|
93
|
-
agentCredential,
|
|
94
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
95
|
-
);
|
|
80
|
+
const [account, sessionID] = randomAnonymousAccountAndSessionID();
|
|
81
|
+
const node = new LocalNode(account, sessionID);
|
|
96
82
|
|
|
97
83
|
const coValue = node.createCoValue({
|
|
98
84
|
type: "costream",
|
|
99
85
|
ruleset: { type: "unsafeAllowAll" },
|
|
100
86
|
meta: null,
|
|
101
|
-
...createdNowUnique()
|
|
87
|
+
...createdNowUnique(),
|
|
102
88
|
});
|
|
103
89
|
|
|
104
90
|
const transaction: Transaction = {
|
|
@@ -131,7 +117,7 @@ test("transactions with correctly signed, but wrong hash are rejected", () => {
|
|
|
131
117
|
node.ownSessionID,
|
|
132
118
|
[transaction],
|
|
133
119
|
expectedNewHash,
|
|
134
|
-
sign(
|
|
120
|
+
sign(account.currentSignerSecret(), expectedNewHash)
|
|
135
121
|
)
|
|
136
122
|
).toBe(false);
|
|
137
123
|
});
|
package/src/coValue.ts
CHANGED
|
@@ -1,74 +1,65 @@
|
|
|
1
1
|
import { randomBytes } from "@noble/hashes/utils";
|
|
2
|
-
import { ContentType } from
|
|
3
|
-
import { Static } from
|
|
4
|
-
import { CoStream } from
|
|
5
|
-
import { CoMap } from
|
|
2
|
+
import { ContentType } from "./contentType.js";
|
|
3
|
+
import { Static } from "./contentTypes/static.js";
|
|
4
|
+
import { CoStream } from "./contentTypes/coStream.js";
|
|
5
|
+
import { CoMap } from "./contentTypes/coMap.js";
|
|
6
6
|
import {
|
|
7
7
|
Encrypted,
|
|
8
8
|
Hash,
|
|
9
9
|
KeySecret,
|
|
10
|
-
RecipientID,
|
|
11
|
-
RecipientSecret,
|
|
12
|
-
SignatoryID,
|
|
13
|
-
SignatorySecret,
|
|
14
10
|
Signature,
|
|
15
11
|
StreamingHash,
|
|
16
|
-
|
|
17
|
-
getSignatoryID,
|
|
18
|
-
newRandomRecipient,
|
|
19
|
-
newRandomSignatory,
|
|
20
|
-
openAs,
|
|
12
|
+
unseal,
|
|
21
13
|
shortHash,
|
|
22
14
|
sign,
|
|
23
15
|
verify,
|
|
24
16
|
encryptForTransaction,
|
|
25
17
|
decryptForTransaction,
|
|
26
18
|
KeyID,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from './crypto.js';
|
|
33
|
-
import { JsonValue } from './jsonValue.js';
|
|
19
|
+
decryptKeySecret,
|
|
20
|
+
getAgentSignerID,
|
|
21
|
+
getAgentSealerID,
|
|
22
|
+
} from "./crypto.js";
|
|
23
|
+
import { JsonObject, JsonValue } from "./jsonValue.js";
|
|
34
24
|
import { base58 } from "@scure/base";
|
|
35
25
|
import {
|
|
36
26
|
PermissionsDef as RulesetDef,
|
|
37
27
|
Team,
|
|
38
28
|
determineValidTransactions,
|
|
39
29
|
expectTeamContent,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
30
|
+
isKeyForKeyField,
|
|
31
|
+
} from "./permissions.js";
|
|
32
|
+
import { LocalNode } from "./node.js";
|
|
33
|
+
import { CoValueKnownState, NewContentMessage } from "./sync.js";
|
|
34
|
+
import { RawCoID, SessionID, TransactionID } from "./ids.js";
|
|
35
|
+
import { CoList } from "./contentTypes/coList.js";
|
|
36
|
+
import {
|
|
37
|
+
AccountID,
|
|
38
|
+
AccountIDOrAgentID,
|
|
39
|
+
GeneralizedControlledAccount,
|
|
40
|
+
} from "./account.js";
|
|
45
41
|
|
|
46
42
|
export type CoValueHeader = {
|
|
47
43
|
type: ContentType["type"];
|
|
48
44
|
ruleset: RulesetDef;
|
|
49
|
-
meta:
|
|
45
|
+
meta: JsonObject | null;
|
|
50
46
|
createdAt: `2${string}` | null;
|
|
51
47
|
uniqueness: `z${string}` | null;
|
|
52
|
-
publicNickname?: string;
|
|
53
48
|
};
|
|
54
49
|
|
|
55
|
-
function
|
|
50
|
+
export function idforHeader(header: CoValueHeader): RawCoID {
|
|
56
51
|
const hash = shortHash(header);
|
|
57
|
-
|
|
58
|
-
return `co_${header.publicNickname}_z${hash.slice(
|
|
59
|
-
"shortHash_z".length
|
|
60
|
-
)}`;
|
|
61
|
-
} else {
|
|
62
|
-
return `co_z${hash.slice("shortHash_z".length)}`;
|
|
63
|
-
}
|
|
52
|
+
return `co_z${hash.slice("shortHash_z".length)}`;
|
|
64
53
|
}
|
|
65
54
|
|
|
66
|
-
export function
|
|
67
|
-
|
|
55
|
+
export function accountOrAgentIDfromSessionID(
|
|
56
|
+
sessionID: SessionID
|
|
57
|
+
): AccountIDOrAgentID {
|
|
58
|
+
return sessionID.split("_session")[0] as AccountIDOrAgentID;
|
|
68
59
|
}
|
|
69
60
|
|
|
70
|
-
export function newRandomSessionID(
|
|
71
|
-
return `${
|
|
61
|
+
export function newRandomSessionID(accountID: AccountIDOrAgentID): SessionID {
|
|
62
|
+
return `${accountID}_session_z${base58.encode(randomBytes(8))}`;
|
|
72
63
|
}
|
|
73
64
|
|
|
74
65
|
type SessionLog = {
|
|
@@ -84,7 +75,7 @@ export type PrivateTransaction = {
|
|
|
84
75
|
keyUsed: KeyID;
|
|
85
76
|
encryptedChanges: Encrypted<
|
|
86
77
|
JsonValue[],
|
|
87
|
-
{ in:
|
|
78
|
+
{ in: RawCoID; tx: TransactionID }
|
|
88
79
|
>;
|
|
89
80
|
};
|
|
90
81
|
|
|
@@ -103,7 +94,7 @@ export type DecryptedTransaction = {
|
|
|
103
94
|
};
|
|
104
95
|
|
|
105
96
|
export class CoValue {
|
|
106
|
-
id:
|
|
97
|
+
id: RawCoID;
|
|
107
98
|
node: LocalNode;
|
|
108
99
|
header: CoValueHeader;
|
|
109
100
|
sessions: { [key: SessionID]: SessionLog };
|
|
@@ -111,18 +102,18 @@ export class CoValue {
|
|
|
111
102
|
listeners: Set<(content?: ContentType) => void> = new Set();
|
|
112
103
|
|
|
113
104
|
constructor(header: CoValueHeader, node: LocalNode) {
|
|
114
|
-
this.id =
|
|
105
|
+
this.id = idforHeader(header);
|
|
115
106
|
this.header = header;
|
|
116
107
|
this.sessions = {};
|
|
117
108
|
this.node = node;
|
|
118
109
|
}
|
|
119
110
|
|
|
120
|
-
|
|
121
|
-
|
|
111
|
+
testWithDifferentAccount(
|
|
112
|
+
account: GeneralizedControlledAccount,
|
|
122
113
|
ownSessionID: SessionID
|
|
123
114
|
): CoValue {
|
|
124
|
-
const newNode = this.node.
|
|
125
|
-
|
|
115
|
+
const newNode = this.node.testWithDifferentAccount(
|
|
116
|
+
account,
|
|
126
117
|
ownSessionID
|
|
127
118
|
);
|
|
128
119
|
|
|
@@ -131,7 +122,7 @@ export class CoValue {
|
|
|
131
122
|
|
|
132
123
|
knownState(): CoValueKnownState {
|
|
133
124
|
return {
|
|
134
|
-
|
|
125
|
+
id: this.id,
|
|
135
126
|
header: true,
|
|
136
127
|
sessions: Object.fromEntries(
|
|
137
128
|
Object.entries(this.sessions).map(([k, v]) => [
|
|
@@ -160,13 +151,18 @@ export class CoValue {
|
|
|
160
151
|
newHash: Hash,
|
|
161
152
|
newSignature: Signature
|
|
162
153
|
): boolean {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
154
|
+
const signerID = getAgentSignerID(
|
|
155
|
+
this.node.resolveAccountAgent(
|
|
156
|
+
accountOrAgentIDfromSessionID(sessionID),
|
|
157
|
+
"Expected to know signer of transaction"
|
|
158
|
+
)
|
|
159
|
+
);
|
|
167
160
|
|
|
168
|
-
if (!
|
|
169
|
-
console.warn(
|
|
161
|
+
if (!signerID) {
|
|
162
|
+
console.warn(
|
|
163
|
+
"Unknown agent",
|
|
164
|
+
accountOrAgentIDfromSessionID(sessionID)
|
|
165
|
+
);
|
|
170
166
|
return false;
|
|
171
167
|
}
|
|
172
168
|
|
|
@@ -180,12 +176,12 @@ export class CoValue {
|
|
|
180
176
|
return false;
|
|
181
177
|
}
|
|
182
178
|
|
|
183
|
-
if (!verify(newSignature, newHash,
|
|
179
|
+
if (!verify(newSignature, newHash, signerID)) {
|
|
184
180
|
console.warn(
|
|
185
181
|
"Invalid signature",
|
|
186
182
|
newSignature,
|
|
187
183
|
newHash,
|
|
188
|
-
|
|
184
|
+
signerID
|
|
189
185
|
);
|
|
190
186
|
return false;
|
|
191
187
|
}
|
|
@@ -281,7 +277,7 @@ export class CoValue {
|
|
|
281
277
|
]);
|
|
282
278
|
|
|
283
279
|
const signature = sign(
|
|
284
|
-
this.node.
|
|
280
|
+
this.node.account.currentSignerSecret(),
|
|
285
281
|
expectedNewHash
|
|
286
282
|
);
|
|
287
283
|
|
|
@@ -374,7 +370,7 @@ export class CoValue {
|
|
|
374
370
|
if (this.header.ruleset.type === "team") {
|
|
375
371
|
const content = expectTeamContent(this.getCurrentContent());
|
|
376
372
|
|
|
377
|
-
const currentKeyId = content.get("readKey")
|
|
373
|
+
const currentKeyId = content.get("readKey");
|
|
378
374
|
|
|
379
375
|
if (!currentKeyId) {
|
|
380
376
|
throw new Error("No readKey set");
|
|
@@ -401,61 +397,63 @@ export class CoValue {
|
|
|
401
397
|
if (this.header.ruleset.type === "team") {
|
|
402
398
|
const content = expectTeamContent(this.getCurrentContent());
|
|
403
399
|
|
|
404
|
-
|
|
400
|
+
// Try to find key revelation for us
|
|
405
401
|
|
|
406
|
-
|
|
402
|
+
const readKeyEntry = content.getLastEntry(`${keyID}_for_${this.node.account.id}`);
|
|
407
403
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
404
|
+
if (readKeyEntry) {
|
|
405
|
+
const revealer = accountOrAgentIDfromSessionID(
|
|
406
|
+
readKeyEntry.txID.sessionID
|
|
407
|
+
);
|
|
408
|
+
const revealerAgent = this.node.resolveAccountAgent(
|
|
409
|
+
revealer,
|
|
410
|
+
"Expected to know revealer"
|
|
411
|
+
);
|
|
415
412
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
413
|
+
const secret = unseal(
|
|
414
|
+
readKeyEntry.value,
|
|
415
|
+
this.node.account.currentSealerSecret(),
|
|
416
|
+
getAgentSealerID(revealerAgent),
|
|
417
|
+
{
|
|
418
|
+
in: this.id,
|
|
419
|
+
tx: readKeyEntry.txID,
|
|
420
|
+
}
|
|
421
|
+
);
|
|
425
422
|
|
|
426
|
-
|
|
427
|
-
}
|
|
423
|
+
if (secret) return secret as KeySecret;
|
|
428
424
|
}
|
|
429
425
|
|
|
430
426
|
// Try to find indirect revelation through previousKeys
|
|
431
427
|
|
|
432
|
-
for (const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const
|
|
436
|
-
const sealingKeySecret = this.getReadKey(sealingKeyID);
|
|
428
|
+
for (const field of content.keys()) {
|
|
429
|
+
if (isKeyForKeyField(field) && field.startsWith(keyID)) {
|
|
430
|
+
const encryptingKeyID = field.split("_for_")[1] as KeyID;
|
|
431
|
+
const encryptingKeySecret = this.getReadKey(encryptingKeyID);
|
|
437
432
|
|
|
438
|
-
if (!
|
|
433
|
+
if (!encryptingKeySecret) {
|
|
439
434
|
continue;
|
|
440
435
|
}
|
|
441
436
|
|
|
442
|
-
const
|
|
437
|
+
const encryptedPreviousKey = content.get(field)!;
|
|
438
|
+
|
|
439
|
+
const secret = decryptKeySecret(
|
|
443
440
|
{
|
|
444
|
-
|
|
445
|
-
|
|
441
|
+
encryptedID: keyID,
|
|
442
|
+
encryptingID: encryptingKeyID,
|
|
446
443
|
encrypted: encryptedPreviousKey,
|
|
447
444
|
},
|
|
448
|
-
|
|
445
|
+
encryptingKeySecret
|
|
449
446
|
);
|
|
450
447
|
|
|
451
448
|
if (secret) {
|
|
452
449
|
return secret;
|
|
453
450
|
} else {
|
|
454
451
|
console.error(
|
|
455
|
-
`
|
|
452
|
+
`Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`
|
|
456
453
|
);
|
|
457
454
|
}
|
|
458
455
|
}
|
|
456
|
+
|
|
459
457
|
}
|
|
460
458
|
|
|
461
459
|
return undefined;
|
|
@@ -493,10 +491,10 @@ export class CoValue {
|
|
|
493
491
|
knownState: CoValueKnownState | undefined
|
|
494
492
|
): NewContentMessage | undefined {
|
|
495
493
|
const newContent: NewContentMessage = {
|
|
496
|
-
action: "
|
|
497
|
-
|
|
494
|
+
action: "content",
|
|
495
|
+
id: this.id,
|
|
498
496
|
header: knownState?.header ? undefined : this.header,
|
|
499
|
-
|
|
497
|
+
new: Object.fromEntries(
|
|
500
498
|
Object.entries(this.sessions)
|
|
501
499
|
.map(([sessionID, log]) => {
|
|
502
500
|
const newTransactions = log.transactions.slice(
|
|
@@ -530,7 +528,7 @@ export class CoValue {
|
|
|
530
528
|
|
|
531
529
|
if (
|
|
532
530
|
!newContent.header &&
|
|
533
|
-
Object.keys(newContent.
|
|
531
|
+
Object.keys(newContent.new).length === 0
|
|
534
532
|
) {
|
|
535
533
|
return undefined;
|
|
536
534
|
}
|
|
@@ -538,97 +536,13 @@ export class CoValue {
|
|
|
538
536
|
return newContent;
|
|
539
537
|
}
|
|
540
538
|
|
|
541
|
-
getDependedOnCoValues():
|
|
539
|
+
getDependedOnCoValues(): RawCoID[] {
|
|
542
540
|
return this.header.ruleset.type === "team"
|
|
543
541
|
? expectTeamContent(this.getCurrentContent())
|
|
544
542
|
.keys()
|
|
545
|
-
.filter((k): k is
|
|
543
|
+
.filter((k): k is AccountID => k.startsWith("co_"))
|
|
546
544
|
: this.header.ruleset.type === "ownedByTeam"
|
|
547
545
|
? [this.header.ruleset.team]
|
|
548
546
|
: [];
|
|
549
547
|
}
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
export type Agent = {
|
|
553
|
-
signatoryID: SignatoryID;
|
|
554
|
-
recipientID: RecipientID;
|
|
555
|
-
publicNickname?: string;
|
|
556
|
-
};
|
|
557
|
-
|
|
558
|
-
export function getAgent(agentCredential: AgentCredential) {
|
|
559
|
-
return {
|
|
560
|
-
signatoryID: getSignatoryID(agentCredential.signatorySecret),
|
|
561
|
-
recipientID: getRecipientID(agentCredential.recipientSecret),
|
|
562
|
-
publicNickname: agentCredential.publicNickname,
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
export function getAgentCoValueHeader(agent: Agent): CoValueHeader {
|
|
567
|
-
return {
|
|
568
|
-
type: "comap",
|
|
569
|
-
ruleset: {
|
|
570
|
-
type: "agent",
|
|
571
|
-
initialSignatoryID: agent.signatoryID,
|
|
572
|
-
initialRecipientID: agent.recipientID,
|
|
573
|
-
},
|
|
574
|
-
meta: null,
|
|
575
|
-
createdAt: null,
|
|
576
|
-
uniqueness: null,
|
|
577
|
-
publicNickname:
|
|
578
|
-
"agent" + (agent.publicNickname ? `-${agent.publicNickname}` : ""),
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
export function getAgentID(agent: Agent): AgentID {
|
|
583
|
-
return coValueIDforHeader(getAgentCoValueHeader(agent)) as AgentID;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
export type AgentCredential = {
|
|
587
|
-
signatorySecret: SignatorySecret;
|
|
588
|
-
recipientSecret: RecipientSecret;
|
|
589
|
-
publicNickname?: string;
|
|
590
|
-
};
|
|
591
|
-
|
|
592
|
-
export function newRandomAgentCredential(
|
|
593
|
-
publicNickname?: string
|
|
594
|
-
): AgentCredential {
|
|
595
|
-
const signatorySecret = newRandomSignatory();
|
|
596
|
-
const recipientSecret = newRandomRecipient();
|
|
597
|
-
return { signatorySecret, recipientSecret, publicNickname };
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
export function agentCredentialToBytes(cred: AgentCredential): Uint8Array {
|
|
601
|
-
if (cred.publicNickname) {
|
|
602
|
-
throw new Error("Can't convert agent credential with publicNickname");
|
|
603
|
-
}
|
|
604
|
-
const bytes = new Uint8Array(64);
|
|
605
|
-
const signatorySecretBytes = signatorySecretToBytes(cred.signatorySecret);
|
|
606
|
-
if (signatorySecretBytes.length !== 32) {
|
|
607
|
-
throw new Error("Invalid signatorySecret length");
|
|
608
|
-
}
|
|
609
|
-
bytes.set(signatorySecretBytes);
|
|
610
|
-
const recipientSecretBytes = recipientSecretToBytes(cred.recipientSecret);
|
|
611
|
-
if (recipientSecretBytes.length !== 32) {
|
|
612
|
-
throw new Error("Invalid recipientSecret length");
|
|
613
|
-
}
|
|
614
|
-
bytes.set(recipientSecretBytes, 32);
|
|
615
|
-
|
|
616
|
-
return bytes;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
export function agentCredentialFromBytes(
|
|
620
|
-
bytes: Uint8Array
|
|
621
|
-
): AgentCredential | undefined {
|
|
622
|
-
if (bytes.length !== 64) {
|
|
623
|
-
return undefined;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
const signatorySecret = signatorySecretFromBytes(bytes.slice(0, 32));
|
|
627
|
-
const recipientSecret = recipientSecretFromBytes(bytes.slice(32));
|
|
628
|
-
|
|
629
|
-
return { signatorySecret, recipientSecret };
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// type Role = "admin" | "writer" | "reader";
|
|
633
|
-
|
|
634
|
-
// type PermissionsDef = CJMap<AgentID, Role, {[agent: AgentID]: Role}>;
|
|
548
|
+
}
|
package/src/contentType.test.ts
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
agentIDfromSessionID,
|
|
3
|
-
getAgent,
|
|
4
|
-
getAgentID,
|
|
5
|
-
newRandomAgentCredential,
|
|
6
|
-
newRandomSessionID,
|
|
7
|
-
} from './coValue.js';
|
|
1
|
+
import { accountOrAgentIDfromSessionID } from "./coValue.js";
|
|
8
2
|
import { createdNowUnique } from "./crypto.js";
|
|
9
3
|
import { LocalNode } from "./node.js";
|
|
4
|
+
import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
|
|
10
5
|
|
|
11
6
|
test("Empty COJSON Map works", () => {
|
|
12
|
-
const
|
|
13
|
-
const node = new LocalNode(
|
|
14
|
-
agentCredential,
|
|
15
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
16
|
-
);
|
|
7
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
17
8
|
|
|
18
9
|
const coValue = node.createCoValue({
|
|
19
10
|
type: "comap",
|
|
20
11
|
ruleset: { type: "unsafeAllowAll" },
|
|
21
12
|
meta: null,
|
|
22
|
-
...createdNowUnique()
|
|
13
|
+
...createdNowUnique(),
|
|
23
14
|
});
|
|
24
15
|
|
|
25
16
|
const content = coValue.getCurrentContent();
|
|
@@ -34,17 +25,13 @@ test("Empty COJSON Map works", () => {
|
|
|
34
25
|
});
|
|
35
26
|
|
|
36
27
|
test("Can insert and delete Map entries in edit()", () => {
|
|
37
|
-
const
|
|
38
|
-
const node = new LocalNode(
|
|
39
|
-
agentCredential,
|
|
40
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
41
|
-
);
|
|
28
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
42
29
|
|
|
43
30
|
const coValue = node.createCoValue({
|
|
44
31
|
type: "comap",
|
|
45
32
|
ruleset: { type: "unsafeAllowAll" },
|
|
46
33
|
meta: null,
|
|
47
|
-
...createdNowUnique()
|
|
34
|
+
...createdNowUnique(),
|
|
48
35
|
});
|
|
49
36
|
|
|
50
37
|
const content = coValue.getCurrentContent();
|
|
@@ -67,17 +54,13 @@ test("Can insert and delete Map entries in edit()", () => {
|
|
|
67
54
|
});
|
|
68
55
|
|
|
69
56
|
test("Can get map entry values at different points in time", () => {
|
|
70
|
-
const
|
|
71
|
-
const node = new LocalNode(
|
|
72
|
-
agentCredential,
|
|
73
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
74
|
-
);
|
|
57
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
75
58
|
|
|
76
59
|
const coValue = node.createCoValue({
|
|
77
60
|
type: "comap",
|
|
78
61
|
ruleset: { type: "unsafeAllowAll" },
|
|
79
62
|
meta: null,
|
|
80
|
-
...createdNowUnique()
|
|
63
|
+
...createdNowUnique(),
|
|
81
64
|
});
|
|
82
65
|
|
|
83
66
|
const content = coValue.getCurrentContent();
|
|
@@ -90,13 +73,13 @@ test("Can get map entry values at different points in time", () => {
|
|
|
90
73
|
|
|
91
74
|
content.edit((editable) => {
|
|
92
75
|
const beforeA = Date.now();
|
|
93
|
-
while(Date.now() < beforeA + 10){}
|
|
76
|
+
while (Date.now() < beforeA + 10) {}
|
|
94
77
|
editable.set("hello", "A", "trusting");
|
|
95
78
|
const beforeB = Date.now();
|
|
96
|
-
while(Date.now() < beforeB + 10){}
|
|
79
|
+
while (Date.now() < beforeB + 10) {}
|
|
97
80
|
editable.set("hello", "B", "trusting");
|
|
98
81
|
const beforeC = Date.now();
|
|
99
|
-
while(Date.now() < beforeC + 10){}
|
|
82
|
+
while (Date.now() < beforeC + 10) {}
|
|
100
83
|
editable.set("hello", "C", "trusting");
|
|
101
84
|
expect(editable.get("hello")).toEqual("C");
|
|
102
85
|
expect(editable.getAtTime("hello", Date.now())).toEqual("C");
|
|
@@ -107,17 +90,13 @@ test("Can get map entry values at different points in time", () => {
|
|
|
107
90
|
});
|
|
108
91
|
|
|
109
92
|
test("Can get all historic values of key", () => {
|
|
110
|
-
const
|
|
111
|
-
const node = new LocalNode(
|
|
112
|
-
agentCredential,
|
|
113
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
114
|
-
);
|
|
93
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
115
94
|
|
|
116
95
|
const coValue = node.createCoValue({
|
|
117
96
|
type: "comap",
|
|
118
97
|
ruleset: { type: "unsafeAllowAll" },
|
|
119
98
|
meta: null,
|
|
120
|
-
...createdNowUnique()
|
|
99
|
+
...createdNowUnique(),
|
|
121
100
|
});
|
|
122
101
|
|
|
123
102
|
const content = coValue.getCurrentContent();
|
|
@@ -137,9 +116,7 @@ test("Can get all historic values of key", () => {
|
|
|
137
116
|
const txDel = editable.getLastTxID("hello");
|
|
138
117
|
editable.set("hello", "C", "trusting");
|
|
139
118
|
const txC = editable.getLastTxID("hello");
|
|
140
|
-
expect(
|
|
141
|
-
editable.getHistory("hello")
|
|
142
|
-
).toEqual([
|
|
119
|
+
expect(editable.getHistory("hello")).toEqual([
|
|
143
120
|
{
|
|
144
121
|
txID: txA,
|
|
145
122
|
value: "A",
|
|
@@ -165,17 +142,13 @@ test("Can get all historic values of key", () => {
|
|
|
165
142
|
});
|
|
166
143
|
|
|
167
144
|
test("Can get last tx ID for a key", () => {
|
|
168
|
-
const
|
|
169
|
-
const node = new LocalNode(
|
|
170
|
-
agentCredential,
|
|
171
|
-
newRandomSessionID(getAgentID(getAgent(agentCredential)))
|
|
172
|
-
);
|
|
145
|
+
const node = new LocalNode(...randomAnonymousAccountAndSessionID());
|
|
173
146
|
|
|
174
147
|
const coValue = node.createCoValue({
|
|
175
148
|
type: "comap",
|
|
176
149
|
ruleset: { type: "unsafeAllowAll" },
|
|
177
150
|
meta: null,
|
|
178
|
-
...createdNowUnique()
|
|
151
|
+
...createdNowUnique(),
|
|
179
152
|
});
|
|
180
153
|
|
|
181
154
|
const content = coValue.getCurrentContent();
|
|
@@ -190,8 +163,8 @@ test("Can get last tx ID for a key", () => {
|
|
|
190
163
|
expect(editable.getLastTxID("hello")).toEqual(undefined);
|
|
191
164
|
editable.set("hello", "A", "trusting");
|
|
192
165
|
const sessionID = editable.getLastTxID("hello")?.sessionID;
|
|
193
|
-
expect(sessionID &&
|
|
194
|
-
|
|
166
|
+
expect(sessionID && accountOrAgentIDfromSessionID(sessionID)).toEqual(
|
|
167
|
+
node.account.id
|
|
195
168
|
);
|
|
196
169
|
expect(editable.getLastTxID("hello")?.txIndex).toEqual(0);
|
|
197
170
|
editable.set("hello", "B", "trusting");
|