@peers-app/peers-sdk 0.27.5 → 0.28.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.
- package/dist/context/user-context.d.ts +7 -1
- package/dist/context/user-context.js +4 -9
- package/dist/contracts/contract-proxy.d.ts +5 -0
- package/dist/contracts/contract-proxy.js +2 -2
- package/dist/contracts/contract-resolvers.d.ts +2 -2
- package/dist/contracts/contract-resolvers.js +14 -15
- package/dist/contracts/system/network-contracts.d.ts +1 -1
- package/dist/contracts/tool-catalog-service.js +1 -1
- package/dist/data/assistants.d.ts +3 -3
- package/dist/data/authority-write-checks.d.ts +42 -0
- package/dist/data/authority-write-checks.js +324 -0
- package/dist/data/change-tracking.d.ts +4 -4
- package/dist/data/create-group.js +1 -0
- package/dist/data/devices.d.ts +27 -4
- package/dist/data/devices.js +31 -0
- package/dist/data/group-authority.d.ts +111 -0
- package/dist/data/group-authority.js +281 -0
- package/dist/data/group-members.d.ts +8 -2
- package/dist/data/group-members.js +41 -18
- package/dist/data/group-permissions.d.ts +15 -31
- package/dist/data/group-permissions.js +25 -95
- package/dist/data/group-resign.d.ts +38 -0
- package/dist/data/group-resign.js +71 -0
- package/dist/data/groups.d.ts +11 -0
- package/dist/data/groups.js +31 -13
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.js +3 -0
- package/dist/data/invites.d.ts +14 -0
- package/dist/data/orm/index.d.ts +1 -0
- package/dist/data/orm/index.js +1 -0
- package/dist/data/orm/sql.data-source.d.ts +2 -2
- package/dist/data/orm/sql.data-source.js +8 -9
- package/dist/data/orm/table-container.js +14 -8
- package/dist/data/orm/write-checks.d.ts +89 -0
- package/dist/data/orm/write-checks.js +115 -0
- package/dist/data/package-table-identity.d.ts +6 -0
- package/dist/data/package-table-identity.js +51 -0
- package/dist/data/package-version-resolver.d.ts +15 -0
- package/dist/data/package-version-resolver.js +58 -3
- package/dist/data/package-versions.d.ts +20 -14
- package/dist/data/package-versions.js +15 -9
- package/dist/data/packages.d.ts +6 -1
- package/dist/data/packages.js +15 -20
- package/dist/data/persistent-vars.js +2 -39
- package/dist/data/sync-recovery-queue.d.ts +4 -4
- package/dist/data/sync-recovery-queue.js +7 -1
- package/dist/data/tool-access-approvals.d.ts +3 -3
- package/dist/data/user-permissions.d.ts +33 -2
- package/dist/data/user-permissions.js +87 -10
- package/dist/data/users.d.ts +49 -12
- package/dist/data/users.js +21 -1
- package/dist/data/workflows.d.ts +1 -1
- package/dist/device/binary-peer-connection-v2.d.ts +1 -1
- package/dist/device/binary-peer-connection-v2.js +1 -1
- package/dist/device/connection.d.ts +1 -1
- package/dist/device/frame-cipher.d.ts +1 -1
- package/dist/device/frame-cipher.js +1 -1
- package/dist/device/get-trust-level-fn.js +3 -6
- package/dist/device-pairing/types.d.ts +26 -26
- package/dist/identity/user-row-change.d.ts +3 -1
- package/dist/identity/user-row-change.js +33 -18
- package/dist/invites/group-approval.js +23 -24
- package/dist/invites/invite-messages.d.ts +250 -28
- package/dist/invites/invite-token.d.ts +18 -0
- package/dist/invites/invite-token.js +2 -0
- package/dist/keys.d.ts +7 -0
- package/dist/keys.js +27 -0
- package/dist/package-installer/package-installer.d.ts +1 -1
- package/dist/package-installer/package-installer.js +8 -3
- package/dist/package-installer/package-propagation.d.ts +2 -0
- package/dist/package-installer/package-propagation.js +20 -38
- package/dist/package-installer/package-remote-checker.js +15 -3
- package/dist/package-loader/isolated-artifact.js +0 -2
- package/dist/package-loader/package-loader.js +6 -0
- package/dist/types/peer-device.d.ts +2 -0
- package/dist/types/workflow.d.ts +2 -2
- package/package.json +1 -1
- package/dist/data/package-permissions.d.ts +0 -14
- package/dist/data/package-permissions.js +0 -26
- package/dist/data/package-version-permissions.d.ts +0 -14
- package/dist/data/package-version-permissions.js +0 -30
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveUserRowChange = resolveUserRowChange;
|
|
4
|
+
const user_permissions_1 = require("../data/user-permissions");
|
|
4
5
|
const users_1 = require("../data/users");
|
|
5
6
|
const anchor_resolution_1 = require("./anchor-resolution");
|
|
6
7
|
const key_change_1 = require("./key-change");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return
|
|
8
|
+
/** `row` carrying `source`'s anchor list and the owner's signature over it, or no list. */
|
|
9
|
+
function withListOf(row, source) {
|
|
10
|
+
const { anchors: _anchors, anchorsSignature: _signature, ...profile } = row;
|
|
11
|
+
return { ...profile, ...(0, user_permissions_1.anchorFields)(source) };
|
|
12
|
+
}
|
|
13
|
+
/** `row` as a first record: its list only when the owner signed it, else no list. */
|
|
14
|
+
function bootstrap(row) {
|
|
15
|
+
return (0, user_permissions_1.hasSignedUserAnchors)(row) ? row : withListOf(row, {});
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* The one decision for every path that writes another user's `Users` row: a direct save, a
|
|
@@ -20,9 +21,11 @@ function withAnchors(row, anchors) {
|
|
|
20
21
|
* The record is the personal `Users` row when it exists, else the row already stored in the
|
|
21
22
|
* table being written. The rule:
|
|
22
23
|
*
|
|
23
|
-
* - Nothing stored yet: the
|
|
24
|
+
* - Nothing stored yet: bootstrap the identity; its initial anchors need an owner signature.
|
|
24
25
|
* - A different key: the anchors on record decide ({@link evaluatePresentedKey}). The
|
|
25
26
|
* presented anchor list is ignored; the applied row keeps the list on record.
|
|
27
|
+
* - The user's own row with their current keys: takes the anchor list from their personal row.
|
|
28
|
+
* - A row with no list keeps the list on record.
|
|
26
29
|
* - The same key and a different list: when nothing is on record the list is accepted as the
|
|
27
30
|
* bootstrap (an upgraded contact announcing its first anchors); when the personal record
|
|
28
31
|
* already holds the list it is accepted; otherwise the anchors on record must publish it
|
|
@@ -31,12 +34,19 @@ function withAnchors(row, anchors) {
|
|
|
31
34
|
*/
|
|
32
35
|
async function resolveUserRowChange(params) {
|
|
33
36
|
const { existing, incoming, personalContext } = params;
|
|
34
|
-
if (!existing?.publicKey)
|
|
35
|
-
return { action: "apply", row: incoming };
|
|
36
37
|
const personal = await (0, users_1.Users)(personalContext).get(incoming.userId);
|
|
37
38
|
const record = personal?.publicKey ? personal : existing;
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
if (!record?.publicKey)
|
|
40
|
+
return { action: "apply", row: bootstrap(incoming) };
|
|
41
|
+
const recordAnchors = record.anchors ?? [];
|
|
42
|
+
// My own row with my current keys: my personal copy is the record of my anchors, so a copy
|
|
43
|
+
// anywhere else carries that list (a stale or replayed copy can't move it either way).
|
|
44
|
+
if (incoming.userId === personalContext.userContext.userId &&
|
|
45
|
+
personal?.publicKey === incoming.publicKey &&
|
|
46
|
+
personal.publicBoxKey === incoming.publicBoxKey) {
|
|
47
|
+
return { action: "apply", row: withListOf(incoming, personal) };
|
|
48
|
+
}
|
|
49
|
+
if (incoming.publicKey !== record.publicKey || incoming.publicBoxKey !== record.publicBoxKey) {
|
|
40
50
|
const decision = await (0, key_change_1.evaluatePresentedKey)({
|
|
41
51
|
dataContext: personalContext,
|
|
42
52
|
userId: incoming.userId,
|
|
@@ -47,18 +57,23 @@ async function resolveUserRowChange(params) {
|
|
|
47
57
|
if (decision.accepted) {
|
|
48
58
|
// The resolver may have just stored a confirmed list on the personal row.
|
|
49
59
|
const confirmed = await (0, users_1.Users)(personalContext).get(incoming.userId);
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
return {
|
|
61
|
+
action: "apply",
|
|
62
|
+
row: withListOf(incoming, confirmed?.anchors?.length ? confirmed : record),
|
|
63
|
+
};
|
|
52
64
|
}
|
|
53
65
|
if (decision.state === "pending" || decision.state === "recovery-pending") {
|
|
54
66
|
return { action: "defer", reason: "Key change is not confirmed by the anchors on record" };
|
|
55
67
|
}
|
|
56
68
|
return { action: "refuse", reason: "Key change is not confirmed by the anchors on record" };
|
|
57
69
|
}
|
|
58
|
-
if ((0, anchor_resolution_1.sameAnchorList)(
|
|
70
|
+
if ((0, anchor_resolution_1.sameAnchorList)(record.anchors, incoming.anchors))
|
|
59
71
|
return { action: "apply", row: incoming };
|
|
72
|
+
// A row with no list (a stub, a copy that dropped it) proposes no change: keep the record's.
|
|
73
|
+
if (!incoming.anchors?.length)
|
|
74
|
+
return { action: "apply", row: withListOf(incoming, record) };
|
|
60
75
|
if (recordAnchors.length === 0)
|
|
61
|
-
return { action: "apply", row: incoming };
|
|
76
|
+
return { action: "apply", row: bootstrap(incoming) };
|
|
62
77
|
if ((0, anchor_resolution_1.sameAnchorList)(personal?.anchors, incoming.anchors)) {
|
|
63
78
|
return { action: "apply", row: incoming };
|
|
64
79
|
}
|
|
@@ -76,6 +91,6 @@ async function resolveUserRowChange(params) {
|
|
|
76
91
|
reason: "Anchor list change is not confirmed by the anchors on record",
|
|
77
92
|
};
|
|
78
93
|
}
|
|
79
|
-
return { action: "apply", row:
|
|
94
|
+
return { action: "apply", row: withListOf(incoming, record) };
|
|
80
95
|
}
|
|
81
96
|
(0, users_1.setUserRowChangeGuard)((personalContext, incoming, existing) => resolveUserRowChange({ personalContext, incoming, existing }));
|
|
@@ -35,13 +35,15 @@ async function buildGroupApproval(userContext, input) {
|
|
|
35
35
|
groupId: input.groupId,
|
|
36
36
|
userId: userContext.userId,
|
|
37
37
|
role: data_1.GroupMemberRole.Founder,
|
|
38
|
+
publicKey: input.approverKeys.publicKey,
|
|
38
39
|
signature: "",
|
|
39
40
|
});
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
+
const approvingRole = await (0, data_1.getUserRole)(input.groupId, userContext.userId, userContext);
|
|
43
|
+
if (!approvingMember || approvingRole < data_1.GroupMemberRole.Admin) {
|
|
42
44
|
throw new Error("Only Admin or higher members can approve group joins");
|
|
43
45
|
}
|
|
44
|
-
if (input.role >
|
|
46
|
+
if (input.role > approvingRole) {
|
|
45
47
|
throw new Error("Cannot grant a role higher than your own");
|
|
46
48
|
}
|
|
47
49
|
const groupSecretKey = await (0, data_1.readGroupSecretKey)(userContext, input.groupId, input.approverKeys.secretKey);
|
|
@@ -58,27 +60,24 @@ async function buildGroupApproval(userContext, input) {
|
|
|
58
60
|
groupId: input.groupId,
|
|
59
61
|
userId: input.joiner.userId,
|
|
60
62
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (!adminMembers.some((member) => member.groupMemberId === approvingMember.groupMemberId)) {
|
|
80
|
-
adminMembers = [approvingMember, ...adminMembers];
|
|
81
|
-
}
|
|
63
|
+
// The same id on each approving device, while preserving an existing row's identity.
|
|
64
|
+
const membership = await groupMembersTable.signAndSave({
|
|
65
|
+
groupMemberId: (0, utils_1.deterministicGroupMemberId)(input.groupId, input.joiner.userId),
|
|
66
|
+
signature: "",
|
|
67
|
+
...existingMember,
|
|
68
|
+
groupId: input.groupId,
|
|
69
|
+
userId: input.joiner.userId,
|
|
70
|
+
role: input.role,
|
|
71
|
+
publicKey: input.joiner.publicKey,
|
|
72
|
+
deleted: undefined,
|
|
73
|
+
});
|
|
74
|
+
const authority = await (0, data_1.getGroupAuthority)(userContext, input.groupId);
|
|
75
|
+
const adminMembers = (await groupMembersTable.list({ groupId: input.groupId })).filter((member) => !member.deleted &&
|
|
76
|
+
member.role >= data_1.GroupMemberRole.Admin &&
|
|
77
|
+
authority.roles.get(member.userId) === member.role);
|
|
78
|
+
// A joiner must verify the complete grant chain before it can admit its first peer: the
|
|
79
|
+
// verified profile of each member whose key counts, and no other contact of the approver's.
|
|
80
|
+
const seedUsers = [...authority.keys.keys()].flatMap((userId) => authority.users.get(userId) ?? []);
|
|
82
81
|
const me = await (0, data_1.Users)(userContext.userDataContext).get(userContext.userId);
|
|
83
82
|
if (!me) {
|
|
84
83
|
throw new Error("My user object was not found in the DB. Is the user setup?");
|
|
@@ -100,7 +99,7 @@ async function buildGroupApproval(userContext, input) {
|
|
|
100
99
|
membership,
|
|
101
100
|
seed: {
|
|
102
101
|
groupMembers: adminMembers,
|
|
103
|
-
users:
|
|
102
|
+
users: seedUsers,
|
|
104
103
|
devices: seedDevices,
|
|
105
104
|
},
|
|
106
105
|
approver: {
|