cojson 0.18.29 → 0.18.31
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 +17 -0
- package/dist/PeerState.d.ts +23 -14
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +74 -23
- package/dist/PeerState.js.map +1 -1
- package/dist/SyncStateManager.d.ts +3 -3
- package/dist/SyncStateManager.d.ts.map +1 -1
- package/dist/SyncStateManager.js +18 -44
- package/dist/SyncStateManager.js.map +1 -1
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +2 -1
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/PeerKnownState.d.ts +21 -0
- package/dist/coValueCore/PeerKnownState.d.ts.map +1 -0
- package/dist/coValueCore/PeerKnownState.js +52 -0
- package/dist/coValueCore/PeerKnownState.js.map +1 -0
- package/dist/coValueCore/coValueCore.d.ts +39 -8
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +139 -40
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/decryptTransactionChangesAndMeta.d.ts.map +1 -1
- package/dist/coValueCore/decryptTransactionChangesAndMeta.js +0 -5
- package/dist/coValueCore/decryptTransactionChangesAndMeta.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +0 -14
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +2 -32
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coList.d.ts +3 -4
- package/dist/coValues/coList.d.ts.map +1 -1
- package/dist/coValues/coList.js +4 -4
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.d.ts +3 -4
- package/dist/coValues/coMap.d.ts.map +1 -1
- package/dist/coValues/coMap.js +5 -4
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.d.ts +3 -3
- package/dist/coValues/coStream.d.ts.map +1 -1
- package/dist/coValues/coStream.js +3 -4
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/coValues/group.d.ts +3 -3
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +74 -52
- package/dist/coValues/group.js.map +1 -1
- package/dist/exports.d.ts +2 -2
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +2 -2
- package/dist/exports.js.map +1 -1
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +7 -5
- package/dist/localNode.js.map +1 -1
- package/dist/permissions.d.ts +5 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +173 -109
- package/dist/permissions.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +33 -44
- package/dist/sync.js.map +1 -1
- package/dist/tests/PeerKnownState.test.d.ts +2 -0
- package/dist/tests/PeerKnownState.test.d.ts.map +1 -0
- package/dist/tests/PeerKnownState.test.js +342 -0
- package/dist/tests/PeerKnownState.test.js.map +1 -0
- package/dist/tests/PeerState.test.js +17 -16
- package/dist/tests/PeerState.test.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.js +12 -12
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +11 -11
- package/dist/tests/StorageApiSync.test.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +16 -21
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/coValueCore.dependencies.test.js +59 -0
- package/dist/tests/coValueCore.dependencies.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +41 -21
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/group.addMember.test.js +266 -219
- package/dist/tests/group.addMember.test.js.map +1 -1
- package/dist/tests/group.inheritance.test.js +12 -0
- package/dist/tests/group.inheritance.test.js.map +1 -1
- package/dist/tests/group.invite.test.js +77 -0
- package/dist/tests/group.invite.test.js.map +1 -1
- package/dist/tests/group.removeMember.test.js +65 -8
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/group.roleOf.test.js +14 -4
- package/dist/tests/group.roleOf.test.js.map +1 -1
- package/dist/tests/permissions.test.js +51 -202
- package/dist/tests/permissions.test.js.map +1 -1
- package/dist/tests/sync.content.test.js +2 -2
- package/dist/tests/sync.content.test.js.map +1 -1
- package/dist/tests/sync.invite.test.js +6 -6
- package/dist/tests/sync.load.test.js +22 -22
- package/dist/tests/sync.mesh.test.js +9 -9
- package/dist/tests/sync.storage.test.js +13 -7
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +3 -3
- package/dist/tests/sync.test.js +13 -33
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +2 -2
- package/package.json +3 -3
- package/src/PeerState.ts +86 -34
- package/src/SyncStateManager.ts +25 -60
- package/src/coValueContentMessage.ts +3 -1
- package/src/coValueCore/PeerKnownState.ts +74 -0
- package/src/coValueCore/coValueCore.ts +180 -49
- package/src/coValueCore/decryptTransactionChangesAndMeta.ts +0 -6
- package/src/coValueCore/verifiedState.ts +2 -37
- package/src/coValues/coList.ts +7 -7
- package/src/coValues/coMap.ts +9 -7
- package/src/coValues/coStream.ts +6 -5
- package/src/coValues/group.ts +99 -60
- package/src/exports.ts +2 -1
- package/src/localNode.ts +7 -5
- package/src/permissions.ts +204 -123
- package/src/sync.ts +37 -53
- package/src/tests/PeerKnownState.test.ts +426 -0
- package/src/tests/PeerState.test.ts +24 -24
- package/src/tests/StorageApiAsync.test.ts +12 -12
- package/src/tests/StorageApiSync.test.ts +11 -11
- package/src/tests/SyncStateManager.test.ts +23 -53
- package/src/tests/coValueCore.dependencies.test.ts +87 -0
- package/src/tests/coValueCore.test.ts +64 -22
- package/src/tests/group.addMember.test.ts +384 -345
- package/src/tests/group.inheritance.test.ts +33 -0
- package/src/tests/group.invite.test.ts +117 -0
- package/src/tests/group.removeMember.test.ts +96 -10
- package/src/tests/group.roleOf.test.ts +16 -4
- package/src/tests/permissions.test.ts +56 -295
- package/src/tests/sync.content.test.ts +2 -2
- package/src/tests/sync.invite.test.ts +6 -6
- package/src/tests/sync.load.test.ts +22 -22
- package/src/tests/sync.mesh.test.ts +9 -9
- package/src/tests/sync.storage.test.ts +13 -8
- package/src/tests/sync.storageAsync.test.ts +3 -3
- package/src/tests/sync.test.ts +21 -50
- package/src/tests/sync.upload.test.ts +2 -2
- package/dist/PeerKnownStates.d.ts +0 -19
- package/dist/PeerKnownStates.d.ts.map +0 -1
- package/dist/PeerKnownStates.js +0 -64
- package/dist/PeerKnownStates.js.map +0 -1
- package/dist/tests/PeerKnownStates.test.d.ts +0 -2
- package/dist/tests/PeerKnownStates.test.d.ts.map +0 -1
- package/dist/tests/PeerKnownStates.test.js +0 -77
- package/dist/tests/PeerKnownStates.test.js.map +0 -1
- package/src/PeerKnownStates.ts +0 -93
- package/src/tests/PeerKnownStates.test.ts +0 -99
package/src/permissions.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { CoID } from "./coValue.js";
|
|
2
2
|
import { CoValueCore } from "./coValueCore/coValueCore.js";
|
|
3
|
-
import { Transaction } from "./coValueCore/verifiedState.js";
|
|
4
3
|
import { RawAccount, RawAccountID, RawProfile } from "./coValues/account.js";
|
|
5
4
|
import { MapOpPayload, RawCoMap } from "./coValues/coMap.js";
|
|
6
5
|
import {
|
|
@@ -15,10 +14,8 @@ import {
|
|
|
15
14
|
AgentID,
|
|
16
15
|
ParentGroupReference,
|
|
17
16
|
RawCoID,
|
|
18
|
-
TransactionID,
|
|
19
17
|
getParentGroupId,
|
|
20
18
|
} from "./ids.js";
|
|
21
|
-
import { parseJSON } from "./jsonStringify.js";
|
|
22
19
|
import { JsonValue } from "./jsonValue.js";
|
|
23
20
|
import { logger } from "./logger.js";
|
|
24
21
|
import { expectGroup } from "./typeUtils/expectGroup.js";
|
|
@@ -41,6 +38,10 @@ export type AccountRole =
|
|
|
41
38
|
* Can read and write to the group, and change group member roles
|
|
42
39
|
*/
|
|
43
40
|
| "admin"
|
|
41
|
+
/**
|
|
42
|
+
* Can read and write, invite and revoke members except admin
|
|
43
|
+
*/
|
|
44
|
+
| "manager"
|
|
44
45
|
/**
|
|
45
46
|
* Can only write to the group's CoValues and read their own changes
|
|
46
47
|
*/
|
|
@@ -49,6 +50,7 @@ export type AccountRole =
|
|
|
49
50
|
export type Role =
|
|
50
51
|
| AccountRole
|
|
51
52
|
| "revoked"
|
|
53
|
+
| "managerInvite"
|
|
52
54
|
| "adminInvite"
|
|
53
55
|
| "writerInvite"
|
|
54
56
|
| "readerInvite"
|
|
@@ -56,6 +58,7 @@ export type Role =
|
|
|
56
58
|
|
|
57
59
|
export function isAccountRole(role?: Role): role is AccountRole {
|
|
58
60
|
return (
|
|
61
|
+
role === "manager" ||
|
|
59
62
|
role === "admin" ||
|
|
60
63
|
role === "writer" ||
|
|
61
64
|
role === "reader" ||
|
|
@@ -63,7 +66,10 @@ export function isAccountRole(role?: Role): role is AccountRole {
|
|
|
63
66
|
);
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
|
|
69
|
+
function canAdmin(role: Role | undefined): boolean {
|
|
70
|
+
return role === "admin" || role === "manager";
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
type MemberState = { [agent: RawAccountID | AgentID]: Role; [EVERYONE]?: Role };
|
|
68
74
|
|
|
69
75
|
let logPermissionErrors = true;
|
|
@@ -83,11 +89,12 @@ function logPermissionError(
|
|
|
83
89
|
logger.debug("Permission error: " + message, attributes);
|
|
84
90
|
}
|
|
85
91
|
|
|
86
|
-
export function determineValidTransactions(coValue: CoValueCore) {
|
|
92
|
+
export function determineValidTransactions(coValue: CoValueCore): void {
|
|
87
93
|
if (!coValue.isAvailable()) {
|
|
88
94
|
throw new Error("determineValidTransactions CoValue is not available");
|
|
89
95
|
}
|
|
90
96
|
|
|
97
|
+
// The CoValue is a group
|
|
91
98
|
if (coValue.verified.header.ruleset.type === "group") {
|
|
92
99
|
const initialAdmin = coValue.verified.header.ruleset.initialAdmin;
|
|
93
100
|
if (!initialAdmin) {
|
|
@@ -95,7 +102,11 @@ export function determineValidTransactions(coValue: CoValueCore) {
|
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
determineValidTransactionsForGroup(coValue, initialAdmin);
|
|
98
|
-
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// The CoValue is owned by a group
|
|
109
|
+
if (coValue.verified.header.ruleset.type === "ownedByGroup") {
|
|
99
110
|
const groupContent = expectGroup(
|
|
100
111
|
coValue.node
|
|
101
112
|
.expectCoValueLoaded(
|
|
@@ -109,12 +120,7 @@ export function determineValidTransactions(coValue: CoValueCore) {
|
|
|
109
120
|
throw new Error("Group must be a map");
|
|
110
121
|
}
|
|
111
122
|
|
|
112
|
-
for (const tx of coValue.
|
|
113
|
-
if (tx.isValidated) {
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
tx.isValidated = true;
|
|
123
|
+
for (const tx of coValue.toValidateTransactions) {
|
|
118
124
|
// We use the original made at to get the group at the original time when the transaction was made
|
|
119
125
|
// madeAt might be changed by the meta field (e.g. merged transactions), and so can't be used for permissions checks
|
|
120
126
|
const groupAtTime = groupContent.atTime(tx.currentMadeAt);
|
|
@@ -124,7 +130,7 @@ export function determineValidTransactions(coValue: CoValueCore) {
|
|
|
124
130
|
);
|
|
125
131
|
|
|
126
132
|
if (!effectiveTransactor) {
|
|
127
|
-
tx.
|
|
133
|
+
tx.markInvalid();
|
|
128
134
|
continue;
|
|
129
135
|
}
|
|
130
136
|
|
|
@@ -142,32 +148,37 @@ export function determineValidTransactions(coValue: CoValueCore) {
|
|
|
142
148
|
ownerId: tx.meta.ownerId,
|
|
143
149
|
};
|
|
144
150
|
tx.changes = [];
|
|
145
|
-
tx.
|
|
151
|
+
tx.markValid();
|
|
146
152
|
continue;
|
|
147
153
|
}
|
|
148
154
|
|
|
149
155
|
if (
|
|
150
156
|
transactorRoleAtTxTime !== "admin" &&
|
|
157
|
+
transactorRoleAtTxTime !== "manager" &&
|
|
151
158
|
transactorRoleAtTxTime !== "writer" &&
|
|
152
159
|
transactorRoleAtTxTime !== "writeOnly"
|
|
153
160
|
) {
|
|
154
|
-
tx.
|
|
161
|
+
tx.markInvalid();
|
|
155
162
|
continue;
|
|
156
163
|
}
|
|
157
164
|
|
|
158
|
-
tx.
|
|
165
|
+
tx.markValid();
|
|
159
166
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// The CoValue has unsafeAllowAll ruleset
|
|
171
|
+
if (coValue.verified.header.ruleset.type === "unsafeAllowAll") {
|
|
172
|
+
for (const tx of coValue.toValidateTransactions) {
|
|
173
|
+
tx.markValid();
|
|
164
174
|
}
|
|
165
|
-
|
|
166
|
-
throw new Error(
|
|
167
|
-
"Unknown ruleset type " +
|
|
168
|
-
(coValue.verified.header.ruleset as { type: string }).type,
|
|
169
|
-
);
|
|
175
|
+
return;
|
|
170
176
|
}
|
|
177
|
+
|
|
178
|
+
throw new Error(
|
|
179
|
+
"Unknown ruleset type " +
|
|
180
|
+
(coValue.verified.header.ruleset as { type: string }).type,
|
|
181
|
+
);
|
|
171
182
|
}
|
|
172
183
|
|
|
173
184
|
function isHigherRole(a: Role, b: Role | undefined) {
|
|
@@ -176,6 +187,9 @@ function isHigherRole(a: Role, b: Role | undefined) {
|
|
|
176
187
|
if (b === "admin") return false;
|
|
177
188
|
if (a === "admin") return true;
|
|
178
189
|
|
|
190
|
+
if (b === "manager") return false;
|
|
191
|
+
if (a === "manager") return true;
|
|
192
|
+
|
|
179
193
|
return a === "writer" && b === "reader";
|
|
180
194
|
}
|
|
181
195
|
|
|
@@ -236,19 +250,17 @@ function determineValidTransactionsForGroup(
|
|
|
236
250
|
|
|
237
251
|
const memberState: MemberState = {};
|
|
238
252
|
const writeOnlyKeys: Record<RawAccountID | AgentID, KeyID> = {};
|
|
239
|
-
|
|
240
253
|
const writeKeys = new Set<string>();
|
|
241
254
|
|
|
242
255
|
for (const transaction of coValue.verifiedTransactions) {
|
|
243
256
|
const transactor = transaction.author;
|
|
244
|
-
|
|
245
|
-
transaction.isValidated = true;
|
|
257
|
+
const transactorRole = memberState[transactor];
|
|
246
258
|
|
|
247
259
|
const tx = transaction.tx;
|
|
248
260
|
|
|
249
261
|
if (tx.privacy === "private") {
|
|
250
262
|
if (memberState[transactor] === "admin") {
|
|
251
|
-
transaction.
|
|
263
|
+
transaction.markValid();
|
|
252
264
|
continue;
|
|
253
265
|
} else {
|
|
254
266
|
logPermissionError(
|
|
@@ -274,66 +286,70 @@ function determineValidTransactionsForGroup(
|
|
|
274
286
|
|
|
275
287
|
if (changes.length !== 1) {
|
|
276
288
|
logPermissionError("Group transaction must have exactly one change");
|
|
277
|
-
transaction.
|
|
289
|
+
transaction.markInvalid();
|
|
278
290
|
continue;
|
|
279
291
|
}
|
|
280
292
|
|
|
281
293
|
if (change.op !== "set") {
|
|
282
294
|
logPermissionError("Group transaction must set a role or readKey");
|
|
283
|
-
transaction.
|
|
295
|
+
transaction.markInvalid();
|
|
284
296
|
continue;
|
|
285
297
|
}
|
|
286
298
|
|
|
287
299
|
if (change.key === "readKey") {
|
|
288
|
-
if (
|
|
300
|
+
if (!canAdmin(transactorRole)) {
|
|
289
301
|
logPermissionError("Only admins can set readKeys");
|
|
290
|
-
transaction.
|
|
302
|
+
transaction.markInvalid();
|
|
291
303
|
continue;
|
|
292
304
|
}
|
|
293
305
|
|
|
294
|
-
transaction.
|
|
306
|
+
transaction.markValid();
|
|
295
307
|
continue;
|
|
296
308
|
} else if (change.key === "profile") {
|
|
297
|
-
if (
|
|
309
|
+
if (!canAdmin(transactorRole)) {
|
|
298
310
|
logPermissionError("Only admins can set profile");
|
|
299
|
-
transaction.
|
|
311
|
+
transaction.markInvalid();
|
|
300
312
|
continue;
|
|
301
313
|
}
|
|
302
314
|
|
|
303
|
-
transaction.
|
|
315
|
+
transaction.markValid();
|
|
304
316
|
continue;
|
|
305
317
|
} else if (change.key === "root") {
|
|
306
|
-
if (
|
|
318
|
+
if (!canAdmin(transactorRole)) {
|
|
307
319
|
logPermissionError("Only admins can set root");
|
|
308
320
|
continue;
|
|
309
321
|
}
|
|
310
322
|
|
|
311
|
-
transaction.
|
|
323
|
+
transaction.markValid();
|
|
312
324
|
continue;
|
|
313
325
|
} else if (
|
|
314
326
|
isKeyForKeyField(change.key) ||
|
|
315
327
|
isKeyForAccountField(change.key)
|
|
316
328
|
) {
|
|
317
329
|
if (
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
330
|
+
transactorRole !== "admin" &&
|
|
331
|
+
transactorRole !== "adminInvite" &&
|
|
332
|
+
transactorRole !== "manager" &&
|
|
333
|
+
transactorRole !== "managerInvite" &&
|
|
334
|
+
transactorRole !== "writerInvite" &&
|
|
335
|
+
transactorRole !== "readerInvite" &&
|
|
336
|
+
transactorRole !== "writeOnlyInvite" &&
|
|
323
337
|
!isOwnWriteKeyRevelation(change.key, transactor, writeOnlyKeys)
|
|
324
338
|
) {
|
|
325
|
-
logPermissionError("Only admins can reveal keys");
|
|
326
|
-
transaction.
|
|
339
|
+
logPermissionError("Only admins and managers can reveal keys");
|
|
340
|
+
transaction.markInvalid();
|
|
327
341
|
continue;
|
|
328
342
|
}
|
|
329
343
|
|
|
330
344
|
// TODO: check validity of agents who the key is revealed to?
|
|
331
|
-
transaction.
|
|
345
|
+
transaction.markValid();
|
|
332
346
|
continue;
|
|
333
347
|
} else if (isParentExtension(change.key)) {
|
|
334
|
-
if (
|
|
335
|
-
logPermissionError(
|
|
336
|
-
|
|
348
|
+
if (!canAdmin(transactorRole)) {
|
|
349
|
+
logPermissionError(
|
|
350
|
+
"Only admins and managers can set parent extensions",
|
|
351
|
+
);
|
|
352
|
+
transaction.markInvalid();
|
|
337
353
|
continue;
|
|
338
354
|
}
|
|
339
355
|
|
|
@@ -352,25 +368,27 @@ function determineValidTransactionsForGroup(
|
|
|
352
368
|
logPermissionError(
|
|
353
369
|
"Circular extend detected, dropping the transaction",
|
|
354
370
|
);
|
|
355
|
-
transaction.
|
|
371
|
+
transaction.markInvalid();
|
|
356
372
|
continue;
|
|
357
373
|
}
|
|
358
374
|
|
|
359
|
-
transaction.
|
|
375
|
+
transaction.markValid();
|
|
360
376
|
continue;
|
|
361
377
|
} else if (isChildExtension(change.key)) {
|
|
362
|
-
|
|
378
|
+
logPermissionError("Child extensions are not allowed anymore");
|
|
379
|
+
transaction.markInvalid();
|
|
363
380
|
continue;
|
|
364
381
|
} else if (isWriteKeyForMember(change.key)) {
|
|
365
382
|
const memberKey = getAccountOrAgentFromWriteKeyForMember(change.key);
|
|
366
383
|
|
|
367
384
|
if (
|
|
368
|
-
|
|
369
|
-
|
|
385
|
+
transactorRole !== "admin" &&
|
|
386
|
+
transactorRole !== "manager" &&
|
|
387
|
+
transactorRole !== "writeOnlyInvite" &&
|
|
370
388
|
memberKey !== transactor
|
|
371
389
|
) {
|
|
372
|
-
logPermissionError("Only admins can set writeKeys");
|
|
373
|
-
transaction.
|
|
390
|
+
logPermissionError("Only admins and managers can set writeKeys");
|
|
391
|
+
transaction.markInvalid();
|
|
374
392
|
continue;
|
|
375
393
|
}
|
|
376
394
|
|
|
@@ -384,17 +402,17 @@ function determineValidTransactionsForGroup(
|
|
|
384
402
|
* write keys, otherwise they could hide a write key to other writeOnly users
|
|
385
403
|
* blocking them from accessing the group.ß
|
|
386
404
|
*/
|
|
387
|
-
if (writeKeys.has(change.key) &&
|
|
405
|
+
if (writeKeys.has(change.key) && !canAdmin(transactorRole)) {
|
|
388
406
|
logPermissionError(
|
|
389
407
|
"Write key already exists and can't be overridden by invite",
|
|
390
408
|
);
|
|
391
|
-
transaction.
|
|
409
|
+
transaction.markInvalid();
|
|
392
410
|
continue;
|
|
393
411
|
}
|
|
394
412
|
|
|
395
413
|
writeKeys.add(change.key);
|
|
396
414
|
|
|
397
|
-
transaction.
|
|
415
|
+
transaction.markValid();
|
|
398
416
|
continue;
|
|
399
417
|
}
|
|
400
418
|
|
|
@@ -402,93 +420,156 @@ function determineValidTransactionsForGroup(
|
|
|
402
420
|
const assignedRole = change.value;
|
|
403
421
|
|
|
404
422
|
if (
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
423
|
+
assignedRole !== "admin" &&
|
|
424
|
+
assignedRole !== "manager" &&
|
|
425
|
+
assignedRole !== "writer" &&
|
|
426
|
+
assignedRole !== "reader" &&
|
|
427
|
+
assignedRole !== "writeOnly" &&
|
|
428
|
+
assignedRole !== "revoked" &&
|
|
429
|
+
assignedRole !== "managerInvite" &&
|
|
430
|
+
assignedRole !== "adminInvite" &&
|
|
431
|
+
assignedRole !== "writerInvite" &&
|
|
432
|
+
assignedRole !== "readerInvite" &&
|
|
433
|
+
assignedRole !== "writeOnlyInvite"
|
|
414
434
|
) {
|
|
415
435
|
logPermissionError("Group transaction must set a valid role");
|
|
416
|
-
transaction.
|
|
436
|
+
transaction.markInvalid();
|
|
417
437
|
continue;
|
|
418
438
|
}
|
|
419
439
|
|
|
420
440
|
if (
|
|
421
441
|
affectedMember === EVERYONE &&
|
|
422
442
|
!(
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
443
|
+
assignedRole === "reader" ||
|
|
444
|
+
assignedRole === "writer" ||
|
|
445
|
+
assignedRole === "writeOnly" ||
|
|
446
|
+
assignedRole === "revoked"
|
|
427
447
|
)
|
|
428
448
|
) {
|
|
429
449
|
logPermissionError(
|
|
430
450
|
"Everyone can only be set to reader, writer, writeOnly or revoked",
|
|
431
451
|
);
|
|
432
|
-
transaction.
|
|
452
|
+
transaction.markInvalid();
|
|
433
453
|
continue;
|
|
434
454
|
}
|
|
435
455
|
|
|
436
|
-
|
|
437
|
-
|
|
456
|
+
function markTransactionSetRoleAsValid(
|
|
457
|
+
change: MapOpPayload<RawAccountID | AgentID | Everyone, Role>,
|
|
458
|
+
) {
|
|
459
|
+
if (change.op !== "set") {
|
|
460
|
+
throw new Error("Expected set operation");
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
memberState[change.key] = change.value;
|
|
464
|
+
transaction.markValid();
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function markTransactionAsInvalid(message: string) {
|
|
468
|
+
logPermissionError(message);
|
|
469
|
+
transaction.markInvalid();
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// is first self promotion to admin
|
|
473
|
+
if (
|
|
474
|
+
transactorRole === undefined &&
|
|
438
475
|
transactor === initialAdmin &&
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
476
|
+
affectedMember === transactor &&
|
|
477
|
+
assignedRole === "admin"
|
|
478
|
+
) {
|
|
479
|
+
markTransactionSetRoleAsValid(change);
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
442
482
|
|
|
443
|
-
|
|
444
|
-
|
|
483
|
+
// if I'm self revoking, it is always valid
|
|
484
|
+
if (transactor === change.key && change.value === "revoked") {
|
|
485
|
+
markTransactionSetRoleAsValid(change);
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
445
488
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
continue;
|
|
480
|
-
}
|
|
481
|
-
} else {
|
|
482
|
-
logPermissionError(
|
|
483
|
-
"Group transaction must be made by current admin or invite",
|
|
484
|
-
);
|
|
485
|
-
transaction.isValid = false;
|
|
489
|
+
const affectedMemberRole = memberState[affectedMember];
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Admins can't:
|
|
493
|
+
* - demote other admins
|
|
494
|
+
*/
|
|
495
|
+
if (transactorRole === "admin") {
|
|
496
|
+
if (
|
|
497
|
+
affectedMemberRole === "admin" &&
|
|
498
|
+
assignedRole !== "admin" &&
|
|
499
|
+
affectedMember !== transactor
|
|
500
|
+
) {
|
|
501
|
+
markTransactionAsInvalid("Admins can't demote admins.");
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
markTransactionSetRoleAsValid(change);
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Managers can't:
|
|
511
|
+
* - demote other admins
|
|
512
|
+
* - invite new admins
|
|
513
|
+
* - promote to admin
|
|
514
|
+
*/
|
|
515
|
+
if (transactorRole === "manager") {
|
|
516
|
+
if (affectedMemberRole === "admin") {
|
|
517
|
+
markTransactionAsInvalid("Managers can't demote admins.");
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (change.value === "admin") {
|
|
521
|
+
markTransactionAsInvalid("Managers can't promote to admin.");
|
|
486
522
|
continue;
|
|
487
523
|
}
|
|
524
|
+
|
|
525
|
+
if (change.value === "adminInvite") {
|
|
526
|
+
markTransactionAsInvalid("Managers can't invite admins.");
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
if (change.value === "managerInvite") {
|
|
530
|
+
markTransactionAsInvalid("Managers can't invite managers.");
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
markTransactionSetRoleAsValid(change);
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (transactorRole === "adminInvite") {
|
|
539
|
+
if (change.value !== "admin") {
|
|
540
|
+
logPermissionError("AdminInvites can only create admins.");
|
|
541
|
+
transaction.markInvalid();
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
} else if (transactorRole === "managerInvite") {
|
|
545
|
+
if (change.value !== "manager") {
|
|
546
|
+
markTransactionAsInvalid("managerInvite can only create managers.");
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
} else if (transactorRole === "writerInvite") {
|
|
550
|
+
if (change.value !== "writer") {
|
|
551
|
+
markTransactionAsInvalid("WriterInvites can only create writers.");
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
} else if (transactorRole === "readerInvite") {
|
|
555
|
+
if (change.value !== "reader") {
|
|
556
|
+
markTransactionAsInvalid("ReaderInvites can only create reader.");
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
} else if (transactorRole === "writeOnlyInvite") {
|
|
560
|
+
if (change.value !== "writeOnly") {
|
|
561
|
+
markTransactionAsInvalid("WriteOnlyInvites can only create writeOnly.");
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
565
|
+
markTransactionAsInvalid(
|
|
566
|
+
"Group transaction must be made by current admin, manager, or invite",
|
|
567
|
+
);
|
|
568
|
+
continue;
|
|
488
569
|
}
|
|
489
570
|
|
|
490
571
|
memberState[affectedMember] = change.value;
|
|
491
|
-
transaction.
|
|
572
|
+
transaction.markValid();
|
|
492
573
|
}
|
|
493
574
|
|
|
494
575
|
return { memberState };
|