cojson 0.16.4 → 0.16.5
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +13 -0
- package/dist/coValue.d.ts.map +1 -1
- package/dist/coValue.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +6 -10
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +15 -122
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValues/group.d.ts +18 -10
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +221 -59
- package/dist/coValues/group.js.map +1 -1
- package/dist/ids.d.ts +3 -3
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js.map +1 -1
- package/dist/localNode.d.ts +5 -5
- package/dist/localNode.d.ts.map +1 -1
- package/dist/tests/group.inheritance.test.js +195 -0
- package/dist/tests/group.inheritance.test.js.map +1 -1
- package/dist/tests/group.removeMember.test.js +152 -1
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/group.roleOf.test.js +2 -2
- package/dist/tests/group.roleOf.test.js.map +1 -1
- package/dist/tests/group.test.js +81 -3
- package/dist/tests/group.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +6 -3
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts +1 -0
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +5 -0
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
- package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.d.ts.map +1 -1
- package/dist/typeUtils/expectGroup.js +6 -5
- package/dist/typeUtils/expectGroup.js.map +1 -1
- package/package.json +1 -1
- package/src/coValue.ts +1 -4
- package/src/coValueCore/coValueCore.ts +23 -188
- package/src/coValues/group.ts +310 -91
- package/src/ids.ts +3 -3
- package/src/localNode.ts +7 -7
- package/src/tests/group.inheritance.test.ts +279 -0
- package/src/tests/group.removeMember.test.ts +244 -1
- package/src/tests/group.roleOf.test.ts +2 -2
- package/src/tests/group.test.ts +105 -5
- package/src/tests/sync.load.test.ts +6 -3
- package/src/tests/testUtils.ts +5 -0
- package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
- package/src/typeUtils/expectGroup.ts +8 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { UpDownCounter, ValueType, metrics } from "@opentelemetry/api";
|
|
2
2
|
import { Result, err } from "neverthrow";
|
|
3
|
-
import { PeerState } from "../PeerState.js";
|
|
4
|
-
import { RawCoValue } from "../coValue.js";
|
|
5
|
-
import { ControlledAccountOrAgent } from "../coValues/account.js";
|
|
6
|
-
import { RawGroup } from "../coValues/group.js";
|
|
3
|
+
import type { PeerState } from "../PeerState.js";
|
|
4
|
+
import type { RawCoValue } from "../coValue.js";
|
|
5
|
+
import type { ControlledAccountOrAgent } from "../coValues/account.js";
|
|
6
|
+
import type { RawGroup } from "../coValues/group.js";
|
|
7
7
|
import { CO_VALUE_LOADING_CONFIG } from "../config.js";
|
|
8
8
|
import { coreToCoValue } from "../coreToCoValue.js";
|
|
9
9
|
import {
|
|
@@ -16,25 +16,15 @@ import {
|
|
|
16
16
|
SignerID,
|
|
17
17
|
StreamingHash,
|
|
18
18
|
} from "../crypto/crypto.js";
|
|
19
|
-
import {
|
|
20
|
-
RawCoID,
|
|
21
|
-
SessionID,
|
|
22
|
-
TransactionID,
|
|
23
|
-
getParentGroupId,
|
|
24
|
-
isParentGroupReference,
|
|
25
|
-
} from "../ids.js";
|
|
19
|
+
import { RawCoID, SessionID, TransactionID } from "../ids.js";
|
|
26
20
|
import { parseJSON, stableStringify } from "../jsonStringify.js";
|
|
27
21
|
import { JsonValue } from "../jsonValue.js";
|
|
28
22
|
import { LocalNode, ResolveAccountAgentError } from "../localNode.js";
|
|
29
23
|
import { logger } from "../logger.js";
|
|
30
|
-
import {
|
|
31
|
-
determineValidTransactions,
|
|
32
|
-
isKeyForKeyField,
|
|
33
|
-
} from "../permissions.js";
|
|
24
|
+
import { determineValidTransactions } from "../permissions.js";
|
|
34
25
|
import { CoValueKnownState, PeerID, emptyKnownState } from "../sync.js";
|
|
35
26
|
import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
|
|
36
27
|
import { expectGroup } from "../typeUtils/expectGroup.js";
|
|
37
|
-
import { isAccountID } from "../typeUtils/isAccountID.js";
|
|
38
28
|
import { getDependedOnCoValuesFromRawData } from "./utils.js";
|
|
39
29
|
import { CoValueHeader, Transaction, VerifiedState } from "./verifiedState.js";
|
|
40
30
|
|
|
@@ -53,8 +43,6 @@ export type DecryptedTransaction = {
|
|
|
53
43
|
trusting?: boolean;
|
|
54
44
|
};
|
|
55
45
|
|
|
56
|
-
const readKeyCache = new WeakMap<CoValueCore, { [id: KeyID]: KeySecret }>();
|
|
57
|
-
|
|
58
46
|
export type AvailableCoValueCore = CoValueCore & { verified: VerifiedState };
|
|
59
47
|
|
|
60
48
|
export class CoValueCore {
|
|
@@ -768,20 +756,7 @@ export class CoValueCore {
|
|
|
768
756
|
}
|
|
769
757
|
|
|
770
758
|
if (this.verified.header.ruleset.type === "group") {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
const currentKeyId = content.getCurrentReadKeyId();
|
|
774
|
-
|
|
775
|
-
if (!currentKeyId) {
|
|
776
|
-
throw new Error("No readKey set");
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
const secret = this.getReadKey(currentKeyId);
|
|
780
|
-
|
|
781
|
-
return {
|
|
782
|
-
secret: secret,
|
|
783
|
-
id: currentKeyId,
|
|
784
|
-
};
|
|
759
|
+
return expectGroup(this.getCurrentContent()).getCurrentReadKey();
|
|
785
760
|
} else if (this.verified.header.ruleset.type === "ownedByGroup") {
|
|
786
761
|
return this.node
|
|
787
762
|
.expectCoValueLoaded(this.verified.header.ruleset.group)
|
|
@@ -793,154 +768,36 @@ export class CoValueCore {
|
|
|
793
768
|
}
|
|
794
769
|
}
|
|
795
770
|
|
|
771
|
+
readKeyCache = new Map<KeyID, KeySecret>();
|
|
796
772
|
getReadKey(keyID: KeyID): KeySecret | undefined {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
if (!cache) {
|
|
803
|
-
cache = {};
|
|
804
|
-
readKeyCache.set(this, cache);
|
|
805
|
-
}
|
|
806
|
-
cache[keyID] = key;
|
|
807
|
-
}
|
|
773
|
+
// We want to check the cache here, to skip re-computing the group content
|
|
774
|
+
const cachedSecret = this.readKeyCache.get(keyID);
|
|
775
|
+
|
|
776
|
+
if (cachedSecret) {
|
|
777
|
+
return cachedSecret;
|
|
808
778
|
}
|
|
809
|
-
return key;
|
|
810
|
-
}
|
|
811
779
|
|
|
812
|
-
getUncachedReadKey(keyID: KeyID): KeySecret | undefined {
|
|
813
780
|
if (!this.verified) {
|
|
814
781
|
throw new Error(
|
|
815
782
|
"CoValueCore: getUncachedReadKey called on coValue without verified state",
|
|
816
783
|
);
|
|
817
784
|
}
|
|
818
785
|
|
|
786
|
+
// Getting the readKey from accounts
|
|
819
787
|
if (this.verified.header.ruleset.type === "group") {
|
|
820
788
|
const content = expectGroup(
|
|
821
|
-
|
|
789
|
+
// load the account without private transactions, because we are here
|
|
790
|
+
// to be able to decrypt those
|
|
791
|
+
this.getCurrentContent({ ignorePrivateTransactions: true }),
|
|
822
792
|
);
|
|
823
|
-
const keyForEveryone = content.get(`${keyID}_for_everyone`);
|
|
824
|
-
if (keyForEveryone) {
|
|
825
|
-
return keyForEveryone;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
// Try to find key revelation for us
|
|
829
|
-
const currentAgentOrAccountID = accountOrAgentIDfromSessionID(
|
|
830
|
-
this.node.currentSessionID,
|
|
831
|
-
);
|
|
832
|
-
|
|
833
|
-
// being careful here to avoid recursion
|
|
834
|
-
const lookupAccountOrAgentID = isAccountID(currentAgentOrAccountID)
|
|
835
|
-
? this.id === currentAgentOrAccountID
|
|
836
|
-
? this.crypto.getAgentID(this.node.agentSecret) // in accounts, the read key is revealed for the primitive agent
|
|
837
|
-
: currentAgentOrAccountID // current account ID
|
|
838
|
-
: currentAgentOrAccountID; // current agent ID
|
|
839
|
-
|
|
840
|
-
const lastReadyKeyEdit = content.lastEditAt(
|
|
841
|
-
`${keyID}_for_${lookupAccountOrAgentID}`,
|
|
842
|
-
);
|
|
843
|
-
|
|
844
|
-
if (lastReadyKeyEdit?.value) {
|
|
845
|
-
const revealer = lastReadyKeyEdit.by;
|
|
846
|
-
const revealerAgent = this.node
|
|
847
|
-
.resolveAccountAgent(revealer, "Expected to know revealer")
|
|
848
|
-
._unsafeUnwrap({ withStackTrace: true });
|
|
849
|
-
|
|
850
|
-
const secret = this.crypto.unseal(
|
|
851
|
-
lastReadyKeyEdit.value,
|
|
852
|
-
this.crypto.getAgentSealerSecret(this.node.agentSecret), // being careful here to avoid recursion
|
|
853
|
-
this.crypto.getAgentSealerID(revealerAgent),
|
|
854
|
-
{
|
|
855
|
-
in: this.id,
|
|
856
|
-
tx: lastReadyKeyEdit.tx,
|
|
857
|
-
},
|
|
858
|
-
);
|
|
859
|
-
|
|
860
|
-
if (secret) {
|
|
861
|
-
return secret as KeySecret;
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
// Try to find indirect revelation through previousKeys
|
|
866
793
|
|
|
867
|
-
|
|
868
|
-
if (isKeyForKeyField(co) && co.startsWith(keyID)) {
|
|
869
|
-
const encryptingKeyID = co.split("_for_")[1] as KeyID;
|
|
870
|
-
const encryptingKeySecret = this.getReadKey(encryptingKeyID);
|
|
871
|
-
|
|
872
|
-
if (!encryptingKeySecret) {
|
|
873
|
-
continue;
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
const encryptedPreviousKey = content.get(co)!;
|
|
877
|
-
|
|
878
|
-
const secret = this.crypto.decryptKeySecret(
|
|
879
|
-
{
|
|
880
|
-
encryptedID: keyID,
|
|
881
|
-
encryptingID: encryptingKeyID,
|
|
882
|
-
encrypted: encryptedPreviousKey,
|
|
883
|
-
},
|
|
884
|
-
encryptingKeySecret,
|
|
885
|
-
);
|
|
886
|
-
|
|
887
|
-
if (secret) {
|
|
888
|
-
return secret as KeySecret;
|
|
889
|
-
} else {
|
|
890
|
-
logger.warn(
|
|
891
|
-
`Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`,
|
|
892
|
-
);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// try to find revelation to parent group read keys
|
|
898
|
-
for (const co of content.keys()) {
|
|
899
|
-
if (isParentGroupReference(co)) {
|
|
900
|
-
const parentGroupID = getParentGroupId(co);
|
|
901
|
-
const parentGroup = this.node.expectCoValueLoaded(
|
|
902
|
-
parentGroupID,
|
|
903
|
-
"Expected parent group to be loaded",
|
|
904
|
-
);
|
|
905
|
-
|
|
906
|
-
const parentKeys = this.findValidParentKeys(
|
|
907
|
-
keyID,
|
|
908
|
-
content,
|
|
909
|
-
parentGroup,
|
|
910
|
-
);
|
|
911
|
-
|
|
912
|
-
for (const parentKey of parentKeys) {
|
|
913
|
-
const revelationForParentKey = content.get(
|
|
914
|
-
`${keyID}_for_${parentKey.id}`,
|
|
915
|
-
);
|
|
916
|
-
|
|
917
|
-
if (revelationForParentKey) {
|
|
918
|
-
const secret = parentGroup.crypto.decryptKeySecret(
|
|
919
|
-
{
|
|
920
|
-
encryptedID: keyID,
|
|
921
|
-
encryptingID: parentKey.id,
|
|
922
|
-
encrypted: revelationForParentKey,
|
|
923
|
-
},
|
|
924
|
-
parentKey.secret,
|
|
925
|
-
);
|
|
926
|
-
|
|
927
|
-
if (secret) {
|
|
928
|
-
return secret as KeySecret;
|
|
929
|
-
} else {
|
|
930
|
-
logger.warn(
|
|
931
|
-
`Encrypting parent ${parentKey.id} key didn't decrypt ${keyID}`,
|
|
932
|
-
);
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
return undefined;
|
|
794
|
+
return content.getReadKey(keyID);
|
|
940
795
|
} else if (this.verified.header.ruleset.type === "ownedByGroup") {
|
|
941
|
-
return
|
|
942
|
-
|
|
943
|
-
|
|
796
|
+
return expectGroup(
|
|
797
|
+
this.node
|
|
798
|
+
.expectCoValueLoaded(this.verified.header.ruleset.group)
|
|
799
|
+
.getCurrentContent(),
|
|
800
|
+
).getReadKey(keyID);
|
|
944
801
|
} else {
|
|
945
802
|
throw new Error(
|
|
946
803
|
"Only groups or values owned by groups have read secrets",
|
|
@@ -948,28 +805,6 @@ export class CoValueCore {
|
|
|
948
805
|
}
|
|
949
806
|
}
|
|
950
807
|
|
|
951
|
-
findValidParentKeys(keyID: KeyID, group: RawGroup, parentGroup: CoValueCore) {
|
|
952
|
-
const validParentKeys: { id: KeyID; secret: KeySecret }[] = [];
|
|
953
|
-
|
|
954
|
-
for (const co of group.keys()) {
|
|
955
|
-
if (isKeyForKeyField(co) && co.startsWith(keyID)) {
|
|
956
|
-
const encryptingKeyID = co.split("_for_")[1] as KeyID;
|
|
957
|
-
const encryptingKeySecret = parentGroup.getReadKey(encryptingKeyID);
|
|
958
|
-
|
|
959
|
-
if (!encryptingKeySecret) {
|
|
960
|
-
continue;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
validParentKeys.push({
|
|
964
|
-
id: encryptingKeyID,
|
|
965
|
-
secret: encryptingKeySecret,
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
return validParentKeys;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
808
|
getGroup(): RawGroup {
|
|
974
809
|
if (!this.verified) {
|
|
975
810
|
throw new Error(
|