cojson 0.8.18 → 0.8.19-group-inheritance.0

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.
@@ -1708,3 +1708,751 @@ test("Can give write permissions to 'everyone' (high-level)", async () => {
1708
1708
  childContent2.set("foo", "bar2", "private");
1709
1709
  expect(childContent2.get("foo")).toEqual("bar2");
1710
1710
  });
1711
+
1712
+ test("Admins can set parent extensions", () => {
1713
+ const { group, node } = newGroupHighLevel();
1714
+ const parentGroup = node.createGroup();
1715
+
1716
+ group.set(`parent_${parentGroup.id}`, "extend", "trusting");
1717
+ expect(group.get(`parent_${parentGroup.id}`)).toEqual("extend");
1718
+ });
1719
+
1720
+ test("Writers, readers and invitees can not set parent extensions", () => {
1721
+ const { group, node } = newGroupHighLevel();
1722
+ const parentGroup = node.createGroup();
1723
+
1724
+ const writer = node.createAccount();
1725
+ const reader = node.createAccount();
1726
+ const adminInvite = node.createAccount();
1727
+ const writerInvite = node.createAccount();
1728
+ const readerInvite = node.createAccount();
1729
+
1730
+ group.addMember(writer, "writer");
1731
+ group.addMember(reader, "reader");
1732
+ group.addMember(adminInvite, "adminInvite");
1733
+ group.addMember(writerInvite, "writerInvite");
1734
+ group.addMember(readerInvite, "readerInvite");
1735
+
1736
+ const groupAsWriter = expectGroup(
1737
+ group.core
1738
+ .testWithDifferentAccount(writer, Crypto.newRandomSessionID(writer.id))
1739
+ .getCurrentContent(),
1740
+ );
1741
+
1742
+ groupAsWriter.set(`parent_${parentGroup.id}`, "extend", "trusting");
1743
+ expect(groupAsWriter.get(`parent_${parentGroup.id}`)).toBeUndefined();
1744
+
1745
+ const groupAsReader = expectGroup(
1746
+ group.core
1747
+ .testWithDifferentAccount(reader, Crypto.newRandomSessionID(reader.id))
1748
+ .getCurrentContent(),
1749
+ );
1750
+
1751
+ groupAsReader.set(`parent_${parentGroup.id}`, "extend", "trusting");
1752
+ expect(groupAsReader.get(`parent_${parentGroup.id}`)).toBeUndefined();
1753
+
1754
+ const groupAsAdminInvite = expectGroup(
1755
+ group.core
1756
+ .testWithDifferentAccount(
1757
+ adminInvite,
1758
+ Crypto.newRandomSessionID(adminInvite.currentAgentID()._unsafeUnwrap()),
1759
+ )
1760
+ .getCurrentContent(),
1761
+ );
1762
+
1763
+ groupAsAdminInvite.set(`parent_${parentGroup.id}`, "extend", "trusting");
1764
+ expect(groupAsAdminInvite.get(`parent_${parentGroup.id}`)).toBeUndefined();
1765
+
1766
+ const groupAsWriterInvite = expectGroup(
1767
+ group.core
1768
+ .testWithDifferentAccount(
1769
+ writerInvite,
1770
+ Crypto.newRandomSessionID(
1771
+ writerInvite.currentAgentID()._unsafeUnwrap(),
1772
+ ),
1773
+ )
1774
+ .getCurrentContent(),
1775
+ );
1776
+
1777
+ groupAsWriterInvite.set(`parent_${parentGroup.id}`, "extend", "trusting");
1778
+ expect(groupAsWriterInvite.get(`parent_${parentGroup.id}`)).toBeUndefined();
1779
+
1780
+ const groupAsReaderInvite = expectGroup(
1781
+ group.core
1782
+ .testWithDifferentAccount(
1783
+ readerInvite,
1784
+ Crypto.newRandomSessionID(
1785
+ readerInvite.currentAgentID()._unsafeUnwrap(),
1786
+ ),
1787
+ )
1788
+ .getCurrentContent(),
1789
+ );
1790
+
1791
+ groupAsReaderInvite.set(`parent_${parentGroup.id}`, "extend", "trusting");
1792
+ expect(groupAsReaderInvite.get(`parent_${parentGroup.id}`)).toBeUndefined();
1793
+ });
1794
+
1795
+ test("Admins can set child extensions", () => {
1796
+ const { group, node } = newGroupHighLevel();
1797
+ const childGroup = node.createGroup();
1798
+
1799
+ group.set(`child_${childGroup.id}`, "extend", "trusting");
1800
+ expect(group.get(`child_${childGroup.id}`)).toEqual("extend");
1801
+ });
1802
+
1803
+ test("Writers, readers and invitees can not set child extensions", () => {
1804
+ const { group, node } = newGroupHighLevel();
1805
+ const childGroup = node.createGroup();
1806
+
1807
+ const writer = node.createAccount();
1808
+ const reader = node.createAccount();
1809
+ const adminInvite = node.createAccount();
1810
+ const writerInvite = node.createAccount();
1811
+ const readerInvite = node.createAccount();
1812
+
1813
+ group.addMember(writer, "writer");
1814
+ group.addMember(reader, "reader");
1815
+ group.addMember(adminInvite, "adminInvite");
1816
+ group.addMember(writerInvite, "writerInvite");
1817
+ group.addMember(readerInvite, "readerInvite");
1818
+
1819
+ const groupAsWriter = expectGroup(
1820
+ group.core
1821
+ .testWithDifferentAccount(writer, Crypto.newRandomSessionID(writer.id))
1822
+ .getCurrentContent(),
1823
+ );
1824
+
1825
+ groupAsWriter.set(`child_${childGroup.id}`, "extend", "trusting");
1826
+ expect(groupAsWriter.get(`child_${childGroup.id}`)).toBeUndefined();
1827
+
1828
+ const groupAsReader = expectGroup(
1829
+ group.core
1830
+ .testWithDifferentAccount(reader, Crypto.newRandomSessionID(reader.id))
1831
+ .getCurrentContent(),
1832
+ );
1833
+
1834
+ groupAsReader.set(`child_${childGroup.id}`, "extend", "trusting");
1835
+ expect(groupAsReader.get(`child_${childGroup.id}`)).toBeUndefined();
1836
+
1837
+ const groupAsAdminInvite = expectGroup(
1838
+ group.core
1839
+ .testWithDifferentAccount(
1840
+ adminInvite,
1841
+ Crypto.newRandomSessionID(adminInvite.currentAgentID()._unsafeUnwrap()),
1842
+ )
1843
+ .getCurrentContent(),
1844
+ );
1845
+
1846
+ groupAsAdminInvite.set(`child_${childGroup.id}`, "extend", "trusting");
1847
+ expect(groupAsAdminInvite.get(`child_${childGroup.id}`)).toBeUndefined();
1848
+
1849
+ const groupAsWriterInvite = expectGroup(
1850
+ group.core
1851
+ .testWithDifferentAccount(
1852
+ writerInvite,
1853
+ Crypto.newRandomSessionID(
1854
+ writerInvite.currentAgentID()._unsafeUnwrap(),
1855
+ ),
1856
+ )
1857
+ .getCurrentContent(),
1858
+ );
1859
+
1860
+ groupAsWriterInvite.set(`child_${childGroup.id}`, "extend", "trusting");
1861
+ expect(groupAsWriterInvite.get(`child_${childGroup.id}`)).toBeUndefined();
1862
+
1863
+ const groupAsReaderInvite = expectGroup(
1864
+ group.core
1865
+ .testWithDifferentAccount(
1866
+ readerInvite,
1867
+ Crypto.newRandomSessionID(
1868
+ readerInvite.currentAgentID()._unsafeUnwrap(),
1869
+ ),
1870
+ )
1871
+ .getCurrentContent(),
1872
+ );
1873
+
1874
+ groupAsReaderInvite.set(`child_${childGroup.id}`, "extend", "trusting");
1875
+ expect(groupAsReaderInvite.get(`child_${childGroup.id}`)).toBeUndefined();
1876
+ });
1877
+
1878
+ test("Member roles are inherited by child groups (except invites)", () => {
1879
+ const { group, node, admin } = newGroupHighLevel();
1880
+ const parentGroup = node.createGroup();
1881
+
1882
+ group.set(`parent_${parentGroup.id}`, "extend", "trusting");
1883
+
1884
+ const writer = node.createAccount();
1885
+ const reader = node.createAccount();
1886
+ const adminInvite = node.createAccount();
1887
+ const writerInvite = node.createAccount();
1888
+ const readerInvite = node.createAccount();
1889
+
1890
+ parentGroup.addMember(writer, "writer");
1891
+ parentGroup.addMember(reader, "reader");
1892
+ parentGroup.addMember(adminInvite, "adminInvite");
1893
+ parentGroup.addMember(writerInvite, "writerInvite");
1894
+ parentGroup.addMember(readerInvite, "readerInvite");
1895
+
1896
+ expect(group.roleOfInternal(admin.id)).toEqual({
1897
+ role: "admin",
1898
+ via: undefined,
1899
+ });
1900
+
1901
+ expect(group.roleOfInternal(writer.id)).toEqual({
1902
+ role: "writer",
1903
+ via: parentGroup.id,
1904
+ });
1905
+ expect(group.roleOf(writer.id)).toEqual("writer");
1906
+
1907
+ expect(group.roleOfInternal(reader.id)).toEqual({
1908
+ role: "reader",
1909
+ via: parentGroup.id,
1910
+ });
1911
+ expect(group.roleOf(reader.id)).toEqual("reader");
1912
+
1913
+ expect(group.roleOfInternal(adminInvite.id)).toEqual(undefined);
1914
+ expect(group.roleOf(adminInvite.id)).toEqual(undefined);
1915
+
1916
+ expect(group.roleOfInternal(writerInvite.id)).toEqual(undefined);
1917
+ expect(group.roleOf(writerInvite.id)).toEqual(undefined);
1918
+
1919
+ expect(group.roleOfInternal(readerInvite.id)).toEqual(undefined);
1920
+ expect(group.roleOf(readerInvite.id)).toEqual(undefined);
1921
+ });
1922
+
1923
+ test("Member roles are inherited by grand-children groups (except invites)", () => {
1924
+ const { group, node, admin } = newGroupHighLevel();
1925
+ const parentGroup = node.createGroup();
1926
+ const grandParentGroup = node.createGroup();
1927
+
1928
+ group.set(`parent_${parentGroup.id}`, "extend", "trusting");
1929
+ parentGroup.set(`parent_${grandParentGroup.id}`, "extend", "trusting");
1930
+
1931
+ const writer = node.createAccount();
1932
+ const reader = node.createAccount();
1933
+ const adminInvite = node.createAccount();
1934
+ const writerInvite = node.createAccount();
1935
+ const readerInvite = node.createAccount();
1936
+
1937
+ grandParentGroup.addMember(writer, "writer");
1938
+ grandParentGroup.addMember(reader, "reader");
1939
+ grandParentGroup.addMember(adminInvite, "adminInvite");
1940
+ grandParentGroup.addMember(writerInvite, "writerInvite");
1941
+ grandParentGroup.addMember(readerInvite, "readerInvite");
1942
+
1943
+ expect(group.roleOfInternal(admin.id)).toEqual({
1944
+ role: "admin",
1945
+ via: undefined,
1946
+ });
1947
+
1948
+ expect(group.roleOfInternal(writer.id)).toEqual({
1949
+ role: "writer",
1950
+ via: parentGroup.id,
1951
+ });
1952
+ expect(group.roleOf(writer.id)).toEqual("writer");
1953
+
1954
+ expect(group.roleOfInternal(reader.id)).toEqual({
1955
+ role: "reader",
1956
+ via: parentGroup.id,
1957
+ });
1958
+ expect(group.roleOf(reader.id)).toEqual("reader");
1959
+
1960
+ expect(group.roleOfInternal(adminInvite.id)).toEqual(undefined);
1961
+ expect(group.roleOf(adminInvite.id)).toEqual(undefined);
1962
+
1963
+ expect(group.roleOfInternal(writerInvite.id)).toEqual(undefined);
1964
+ expect(group.roleOf(writerInvite.id)).toEqual(undefined);
1965
+
1966
+ expect(group.roleOfInternal(readerInvite.id)).toEqual(undefined);
1967
+ expect(group.roleOf(readerInvite.id)).toEqual(undefined);
1968
+ });
1969
+
1970
+ test("Admins can reveal parent read keys to child groups", () => {
1971
+ const { group, node } = newGroupHighLevel();
1972
+ const parentGroup = node.createGroup();
1973
+
1974
+ const parentReadKeyID = parentGroup.get("readKey");
1975
+ if (!parentReadKeyID) {
1976
+ throw new Error("Can't get parent group read key");
1977
+ }
1978
+
1979
+ const readKeyID = group.get("readKey");
1980
+ if (!readKeyID) {
1981
+ throw new Error("Can't get group read key");
1982
+ }
1983
+
1984
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1985
+ const encrypted = "fake_encrypted_key_secret" as any;
1986
+
1987
+ group.set(`${readKeyID}_for_${parentReadKeyID}`, encrypted, "trusting");
1988
+ expect(group.get(`${readKeyID}_for_${parentReadKeyID}`)).toEqual(encrypted);
1989
+ });
1990
+
1991
+ test("Writers, readers and invites can't reveal parent read keys to child groups", () => {
1992
+ const { group, node } = newGroupHighLevel();
1993
+ const parentGroup = node.createGroup();
1994
+
1995
+ const parentReadKeyID = parentGroup.get("readKey");
1996
+ if (!parentReadKeyID) {
1997
+ throw new Error("Can't get parent group read key");
1998
+ }
1999
+
2000
+ const readKeyID = group.get("readKey");
2001
+ if (!readKeyID) {
2002
+ throw new Error("Can't get group read key");
2003
+ }
2004
+
2005
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2006
+ const encrypted = "fake_encrypted_key_secret" as any;
2007
+
2008
+ const writer = node.createAccount();
2009
+ const reader = node.createAccount();
2010
+ const adminInvite = node.createAccount();
2011
+ const writerInvite = node.createAccount();
2012
+ const readerInvite = node.createAccount();
2013
+
2014
+ group.addMember(writer, "writer");
2015
+ group.addMember(reader, "reader");
2016
+ group.addMember(adminInvite, "adminInvite");
2017
+ group.addMember(writerInvite, "writerInvite");
2018
+ group.addMember(readerInvite, "readerInvite");
2019
+
2020
+ const groupAsWriter = expectGroup(
2021
+ group.core
2022
+ .testWithDifferentAccount(writer, Crypto.newRandomSessionID(writer.id))
2023
+ .getCurrentContent(),
2024
+ );
2025
+
2026
+ groupAsWriter.set(
2027
+ `${readKeyID}_for_${parentReadKeyID}`,
2028
+ encrypted,
2029
+ "trusting",
2030
+ );
2031
+ expect(
2032
+ groupAsWriter.get(`${readKeyID}_for_${parentReadKeyID}`),
2033
+ ).toBeUndefined();
2034
+
2035
+ const groupAsReader = expectGroup(
2036
+ group.core
2037
+ .testWithDifferentAccount(reader, Crypto.newRandomSessionID(reader.id))
2038
+ .getCurrentContent(),
2039
+ );
2040
+
2041
+ groupAsReader.set(
2042
+ `${readKeyID}_for_${parentReadKeyID}`,
2043
+ encrypted,
2044
+ "trusting",
2045
+ );
2046
+ expect(
2047
+ groupAsReader.get(`${readKeyID}_for_${parentReadKeyID}`),
2048
+ ).toBeUndefined();
2049
+
2050
+ const groupAsAdminInvite = expectGroup(
2051
+ group.core
2052
+ .testWithDifferentAccount(
2053
+ adminInvite,
2054
+ Crypto.newRandomSessionID(adminInvite.currentAgentID()._unsafeUnwrap()),
2055
+ )
2056
+ .getCurrentContent(),
2057
+ );
2058
+
2059
+ groupAsAdminInvite.set(
2060
+ `${readKeyID}_for_${parentReadKeyID}`,
2061
+ encrypted,
2062
+ "trusting",
2063
+ );
2064
+ expect(
2065
+ groupAsAdminInvite.get(`${readKeyID}_for_${parentReadKeyID}`),
2066
+ ).toBeUndefined();
2067
+
2068
+ const groupAsWriterInvite = expectGroup(
2069
+ group.core
2070
+ .testWithDifferentAccount(
2071
+ writerInvite,
2072
+ Crypto.newRandomSessionID(
2073
+ writerInvite.currentAgentID()._unsafeUnwrap(),
2074
+ ),
2075
+ )
2076
+ .getCurrentContent(),
2077
+ );
2078
+
2079
+ groupAsWriterInvite.set(
2080
+ `${readKeyID}_for_${parentReadKeyID}`,
2081
+ encrypted,
2082
+ "trusting",
2083
+ );
2084
+ expect(
2085
+ groupAsWriterInvite.get(`${readKeyID}_for_${parentReadKeyID}`),
2086
+ ).toBeUndefined();
2087
+
2088
+ const groupAsReaderInvite = expectGroup(
2089
+ group.core
2090
+ .testWithDifferentAccount(
2091
+ readerInvite,
2092
+ Crypto.newRandomSessionID(
2093
+ readerInvite.currentAgentID()._unsafeUnwrap(),
2094
+ ),
2095
+ )
2096
+ .getCurrentContent(),
2097
+ );
2098
+
2099
+ groupAsReaderInvite.set(
2100
+ `${readKeyID}_for_${parentReadKeyID}`,
2101
+ encrypted,
2102
+ "trusting",
2103
+ );
2104
+ expect(
2105
+ groupAsReaderInvite.get(`${readKeyID}_for_${parentReadKeyID}`),
2106
+ ).toBeUndefined();
2107
+ });
2108
+
2109
+ test("Writers and readers in a parent group can read from an object owned by a child group", () => {
2110
+ const { group, node } = newGroupHighLevel();
2111
+ const parentGroup = node.createGroup();
2112
+
2113
+ group.set(`parent_${parentGroup.id}`, "extend", "trusting");
2114
+
2115
+ const parentReadKeyID = parentGroup.get("readKey");
2116
+ const parentKey =
2117
+ parentReadKeyID && parentGroup.core.getReadKey(parentReadKeyID);
2118
+ if (!parentReadKeyID || !parentKey) {
2119
+ throw new Error("Can't get parent group read key");
2120
+ }
2121
+
2122
+ const readKeyID = group.get("readKey");
2123
+ const readKey = readKeyID && group.core.getReadKey(readKeyID);
2124
+ if (!readKeyID || !readKey) {
2125
+ throw new Error("Can't get group read key");
2126
+ }
2127
+
2128
+ const encrypted = node.crypto.encryptKeySecret({
2129
+ toEncrypt: {
2130
+ id: readKeyID,
2131
+ secret: readKey,
2132
+ },
2133
+ encrypting: {
2134
+ id: parentReadKeyID,
2135
+ secret: parentKey,
2136
+ },
2137
+ }).encrypted;
2138
+
2139
+ group.set(`${readKeyID}_for_${parentReadKeyID}`, encrypted, "trusting");
2140
+
2141
+ const writer = node.createAccount();
2142
+ const reader = node.createAccount();
2143
+ parentGroup.addMember(writer, "writer");
2144
+ parentGroup.addMember(reader, "reader");
2145
+
2146
+ const childObject = node.createCoValue({
2147
+ type: "comap",
2148
+ ruleset: { type: "ownedByGroup", group: group.id },
2149
+ meta: null,
2150
+ ...Crypto.createdNowUnique(),
2151
+ });
2152
+
2153
+ const childContent = expectMap(childObject.getCurrentContent());
2154
+
2155
+ childContent.set("foo", "bar", "private");
2156
+ expect(childContent.get("foo")).toEqual("bar");
2157
+
2158
+ const childContentAsWriter = expectMap(
2159
+ childObject
2160
+ .testWithDifferentAccount(writer, Crypto.newRandomSessionID(writer.id))
2161
+ .getCurrentContent(),
2162
+ );
2163
+
2164
+ expect(childContentAsWriter.get("foo")).toEqual("bar");
2165
+
2166
+ const childContentAsReader = expectMap(
2167
+ childObject
2168
+ .testWithDifferentAccount(reader, Crypto.newRandomSessionID(reader.id))
2169
+ .getCurrentContent(),
2170
+ );
2171
+
2172
+ expect(childContentAsReader.get("foo")).toEqual("bar");
2173
+ });
2174
+
2175
+ test("Writers in a parent group can write to an object owned by a child group", () => {
2176
+ const { group, node } = newGroupHighLevel();
2177
+ const parentGroup = node.createGroup();
2178
+
2179
+ group.set(`parent_${parentGroup.id}`, "extend", "trusting");
2180
+
2181
+ const parentReadKeyID = parentGroup.get("readKey");
2182
+ const parentKey =
2183
+ parentReadKeyID && parentGroup.core.getReadKey(parentReadKeyID);
2184
+ if (!parentReadKeyID || !parentKey) {
2185
+ throw new Error("Can't get parent group read key");
2186
+ }
2187
+
2188
+ const readKeyID = group.get("readKey");
2189
+ const readKey = readKeyID && group.core.getReadKey(readKeyID);
2190
+ if (!readKeyID || !readKey) {
2191
+ throw new Error("Can't get group read key");
2192
+ }
2193
+
2194
+ const encrypted = node.crypto.encryptKeySecret({
2195
+ toEncrypt: {
2196
+ id: readKeyID,
2197
+ secret: readKey,
2198
+ },
2199
+ encrypting: {
2200
+ id: parentReadKeyID,
2201
+ secret: parentKey,
2202
+ },
2203
+ }).encrypted;
2204
+
2205
+ group.set(`${readKeyID}_for_${parentReadKeyID}`, encrypted, "trusting");
2206
+
2207
+ const writer = node.createAccount();
2208
+ parentGroup.addMember(writer, "writer");
2209
+
2210
+ const childObject = node.createCoValue({
2211
+ type: "comap",
2212
+ ruleset: { type: "ownedByGroup", group: group.id },
2213
+ meta: null,
2214
+ ...Crypto.createdNowUnique(),
2215
+ });
2216
+
2217
+ const childContentAsWriter = expectMap(
2218
+ childObject
2219
+ .testWithDifferentAccount(writer, Crypto.newRandomSessionID(writer.id))
2220
+ .getCurrentContent(),
2221
+ );
2222
+
2223
+ childContentAsWriter.set("foo", "bar", "private");
2224
+ expect(childContentAsWriter.get("foo")).toEqual("bar");
2225
+ });
2226
+
2227
+ test("When rotating the key of a child group, the new child key is exposed to the parent group", () => {
2228
+ const { group, node } = newGroupHighLevel();
2229
+ const parentGroup = node.createGroup();
2230
+
2231
+ group.set(`parent_${parentGroup.id}`, "extend", "trusting");
2232
+
2233
+ const currentReadKeyID = group.get("readKey");
2234
+ if (!currentReadKeyID) {
2235
+ throw new Error("Can't get group read key");
2236
+ }
2237
+
2238
+ group.rotateReadKey();
2239
+
2240
+ const newReadKeyID = group.get("readKey");
2241
+ if (!newReadKeyID) {
2242
+ throw new Error("Can't get new group read key");
2243
+ }
2244
+ expect(newReadKeyID).not.toEqual(currentReadKeyID);
2245
+
2246
+ const parentReadKeyID = parentGroup.get("readKey");
2247
+ if (!parentReadKeyID) {
2248
+ throw new Error("Can't get parent group read key");
2249
+ }
2250
+
2251
+ console.log("Checking", `${newReadKeyID}_for_${parentReadKeyID}`);
2252
+
2253
+ expect(group.get(`${newReadKeyID}_for_${parentReadKeyID}`)).toBeDefined();
2254
+ });
2255
+
2256
+ test("When rotating the key of a parent group, the keys of all child groups are also rotated", () => {
2257
+ const { group, node } = newGroupHighLevel();
2258
+ const parentGroup = node.createGroup();
2259
+
2260
+ parentGroup.set(`child_${group.id}`, "extend", "trusting");
2261
+ group.set(`parent_${parentGroup.id}`, "extend", "trusting");
2262
+
2263
+ group.rotateReadKey();
2264
+
2265
+ const currentChildReadKeyID = group.get("readKey");
2266
+ if (!currentChildReadKeyID) {
2267
+ throw new Error("Can't get group read key");
2268
+ }
2269
+
2270
+ console.log("child id", group.id);
2271
+ parentGroup.rotateReadKey();
2272
+
2273
+ const newChildReadKeyID = expectGroup(group.core.getCurrentContent()).get(
2274
+ "readKey",
2275
+ );
2276
+ if (!newChildReadKeyID) {
2277
+ throw new Error("Can't get new group read key");
2278
+ }
2279
+
2280
+ expect(newChildReadKeyID).not.toEqual(currentChildReadKeyID);
2281
+ });
2282
+
2283
+ test("When rotating the key of a grand-parent group, the keys of all child and grand-child groups are also rotated", () => {
2284
+ const { group, node } = newGroupHighLevel();
2285
+ const grandParentGroup = node.createGroup();
2286
+ const parentGroup = node.createGroup();
2287
+
2288
+ grandParentGroup.set(`child_${parentGroup.id}`, "extend", "trusting");
2289
+ parentGroup.set(`child_${group.id}`, "extend", "trusting");
2290
+ parentGroup.set(`parent_${grandParentGroup.id}`, "extend", "trusting");
2291
+ group.set(`parent_${grandParentGroup.id}`, "extend", "trusting");
2292
+
2293
+ const currentGrandParentReadKeyID = grandParentGroup.get("readKey");
2294
+ if (!currentGrandParentReadKeyID) {
2295
+ throw new Error("Can't get grand-parent group read key");
2296
+ }
2297
+
2298
+ const currentParentReadKeyID = parentGroup.get("readKey");
2299
+ if (!currentParentReadKeyID) {
2300
+ throw new Error("Can't get parent group read key");
2301
+ }
2302
+
2303
+ const currentChildReadKeyID = group.get("readKey");
2304
+ if (!currentChildReadKeyID) {
2305
+ throw new Error("Can't get group read key");
2306
+ }
2307
+
2308
+ grandParentGroup.rotateReadKey();
2309
+
2310
+ const newGrandParentReadKeyID = grandParentGroup.get("readKey");
2311
+ if (!newGrandParentReadKeyID) {
2312
+ throw new Error("Can't get new grand-parent group read key");
2313
+ }
2314
+
2315
+ expect(newGrandParentReadKeyID).not.toEqual(currentGrandParentReadKeyID);
2316
+
2317
+ const newParentReadKeyID = expectGroup(
2318
+ parentGroup.core.getCurrentContent(),
2319
+ ).get("readKey");
2320
+ if (!newParentReadKeyID) {
2321
+ throw new Error("Can't get new parent group read key");
2322
+ }
2323
+
2324
+ expect(newParentReadKeyID).not.toEqual(currentParentReadKeyID);
2325
+
2326
+ const newChildReadKeyID = expectGroup(group.core.getCurrentContent()).get(
2327
+ "readKey",
2328
+ );
2329
+ if (!newChildReadKeyID) {
2330
+ throw new Error("Can't get new group read key");
2331
+ }
2332
+
2333
+ expect(newChildReadKeyID).not.toEqual(currentChildReadKeyID);
2334
+ });
2335
+
2336
+ test("Calling extend on group sets up parent and child references and reveals child key to parent", () => {
2337
+ const { group, node } = newGroupHighLevel();
2338
+ const parentGroup = node.createGroup();
2339
+
2340
+ group.extend(parentGroup);
2341
+
2342
+ expect(group.get(`parent_${parentGroup.id}`)).toEqual("extend");
2343
+ expect(parentGroup.get(`child_${group.id}`)).toEqual("extend");
2344
+
2345
+ const parentReadKeyID = parentGroup.get("readKey");
2346
+ if (!parentReadKeyID) {
2347
+ throw new Error("Can't get parent group read key");
2348
+ }
2349
+
2350
+ const childReadKeyID = group.get("readKey");
2351
+ if (!childReadKeyID) {
2352
+ throw new Error("Can't get group read key");
2353
+ }
2354
+
2355
+ expect(group.get(`${childReadKeyID}_for_${parentReadKeyID}`)).toBeDefined();
2356
+
2357
+ const reader = node.createAccount();
2358
+ parentGroup.addMember(reader, "reader");
2359
+
2360
+ const childObject = node.createCoValue({
2361
+ type: "comap",
2362
+ ruleset: { type: "ownedByGroup", group: group.id },
2363
+ meta: null,
2364
+ ...Crypto.createdNowUnique(),
2365
+ });
2366
+ const childMap = expectMap(childObject.getCurrentContent());
2367
+
2368
+ childMap.set("foo", "bar", "private");
2369
+
2370
+ const childContentAsReader = expectMap(
2371
+ childObject
2372
+ .testWithDifferentAccount(reader, Crypto.newRandomSessionID(reader.id))
2373
+ .getCurrentContent(),
2374
+ );
2375
+
2376
+ expect(childContentAsReader.get("foo")).toEqual("bar");
2377
+ });
2378
+
2379
+ test("Calling extend to create grand-child groups parent and child references and reveals child key to parent(s)", () => {
2380
+ const { group, node } = newGroupHighLevel();
2381
+ const parentGroup = node.createGroup();
2382
+ const grandParentGroup = node.createGroup();
2383
+
2384
+ group.extend(parentGroup);
2385
+ parentGroup.extend(grandParentGroup);
2386
+
2387
+ expect(group.get(`parent_${parentGroup.id}`)).toEqual("extend");
2388
+ expect(parentGroup.get(`parent_${grandParentGroup.id}`)).toEqual("extend");
2389
+ expect(parentGroup.get(`child_${group.id}`)).toEqual("extend");
2390
+ expect(grandParentGroup.get(`child_${parentGroup.id}`)).toEqual("extend");
2391
+
2392
+ const reader = node.createAccount();
2393
+ grandParentGroup.addMember(reader, "reader");
2394
+
2395
+ const childObject = node.createCoValue({
2396
+ type: "comap",
2397
+ ruleset: { type: "ownedByGroup", group: group.id },
2398
+ meta: null,
2399
+ ...Crypto.createdNowUnique(),
2400
+ });
2401
+ const childMap = expectMap(childObject.getCurrentContent());
2402
+
2403
+ childMap.set("foo", "bar", "private");
2404
+
2405
+ const childContentAsReader = expectMap(
2406
+ childObject
2407
+ .testWithDifferentAccount(reader, Crypto.newRandomSessionID(reader.id))
2408
+ .getCurrentContent(),
2409
+ );
2410
+
2411
+ expect(childContentAsReader.get("foo")).toEqual("bar");
2412
+ });
2413
+
2414
+ test("High-level permissions work correctly when a group is extended", () => {
2415
+ const { group, node } = newGroupHighLevel();
2416
+ const parentGroup = node.createGroup();
2417
+
2418
+ group.extend(parentGroup);
2419
+
2420
+ const reader = node.createAccount();
2421
+ parentGroup.addMember(reader, "reader");
2422
+
2423
+ const mapCore = node.createCoValue({
2424
+ type: "comap",
2425
+ ruleset: { type: "ownedByGroup", group: group.id },
2426
+ meta: null,
2427
+ ...Crypto.createdNowUnique(),
2428
+ });
2429
+
2430
+ const map = expectMap(mapCore.getCurrentContent());
2431
+
2432
+ map.set("foo", "bar", "private");
2433
+
2434
+ const mapAsReader = expectMap(
2435
+ mapCore
2436
+ .testWithDifferentAccount(reader, Crypto.newRandomSessionID(reader.id))
2437
+ .getCurrentContent(),
2438
+ );
2439
+
2440
+ expect(mapAsReader.get("foo")).toEqual("bar");
2441
+
2442
+ const groupKeyBeforeRemove = group.core.getCurrentReadKey().id;
2443
+
2444
+ parentGroup.removeMember(reader);
2445
+
2446
+ const groupKeyAfterRemove = group.core.getCurrentReadKey().id;
2447
+ expect(groupKeyAfterRemove).not.toEqual(groupKeyBeforeRemove);
2448
+
2449
+ map.set("foo", "baz", "private");
2450
+
2451
+ const mapAsReaderAfterRemove = expectMap(
2452
+ mapCore
2453
+ .testWithDifferentAccount(reader, Crypto.newRandomSessionID(reader.id))
2454
+ .getCurrentContent(),
2455
+ );
2456
+
2457
+ expect(mapAsReaderAfterRemove.get("foo")).not.toEqual("baz");
2458
+ });