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.
Files changed (50) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +13 -0
  3. package/dist/coValue.d.ts.map +1 -1
  4. package/dist/coValue.js.map +1 -1
  5. package/dist/coValueCore/coValueCore.d.ts +6 -10
  6. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  7. package/dist/coValueCore/coValueCore.js +15 -122
  8. package/dist/coValueCore/coValueCore.js.map +1 -1
  9. package/dist/coValues/group.d.ts +18 -10
  10. package/dist/coValues/group.d.ts.map +1 -1
  11. package/dist/coValues/group.js +221 -59
  12. package/dist/coValues/group.js.map +1 -1
  13. package/dist/ids.d.ts +3 -3
  14. package/dist/ids.d.ts.map +1 -1
  15. package/dist/ids.js.map +1 -1
  16. package/dist/localNode.d.ts +5 -5
  17. package/dist/localNode.d.ts.map +1 -1
  18. package/dist/tests/group.inheritance.test.js +195 -0
  19. package/dist/tests/group.inheritance.test.js.map +1 -1
  20. package/dist/tests/group.removeMember.test.js +152 -1
  21. package/dist/tests/group.removeMember.test.js.map +1 -1
  22. package/dist/tests/group.roleOf.test.js +2 -2
  23. package/dist/tests/group.roleOf.test.js.map +1 -1
  24. package/dist/tests/group.test.js +81 -3
  25. package/dist/tests/group.test.js.map +1 -1
  26. package/dist/tests/sync.load.test.js +6 -3
  27. package/dist/tests/sync.load.test.js.map +1 -1
  28. package/dist/tests/testUtils.d.ts +1 -0
  29. package/dist/tests/testUtils.d.ts.map +1 -1
  30. package/dist/tests/testUtils.js +5 -0
  31. package/dist/tests/testUtils.js.map +1 -1
  32. package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
  33. package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
  34. package/dist/typeUtils/expectGroup.d.ts.map +1 -1
  35. package/dist/typeUtils/expectGroup.js +6 -5
  36. package/dist/typeUtils/expectGroup.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/coValue.ts +1 -4
  39. package/src/coValueCore/coValueCore.ts +23 -188
  40. package/src/coValues/group.ts +310 -91
  41. package/src/ids.ts +3 -3
  42. package/src/localNode.ts +7 -7
  43. package/src/tests/group.inheritance.test.ts +279 -0
  44. package/src/tests/group.removeMember.test.ts +244 -1
  45. package/src/tests/group.roleOf.test.ts +2 -2
  46. package/src/tests/group.test.ts +105 -5
  47. package/src/tests/sync.load.test.ts +6 -3
  48. package/src/tests/testUtils.ts +5 -0
  49. package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
  50. 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
- const content = expectGroup(this.getCurrentContent());
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
- let key = readKeyCache.get(this)?.[keyID];
798
- if (!key) {
799
- key = this.getUncachedReadKey(keyID);
800
- if (key) {
801
- let cache = readKeyCache.get(this);
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
- this.getCurrentContent({ ignorePrivateTransactions: true }), // to prevent recursion
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
- for (const co of content.keys()) {
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 this.node
942
- .expectCoValueLoaded(this.verified.header.ruleset.group)
943
- .getReadKey(keyID);
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(