@peers-app/peers-sdk 0.27.4 → 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/contract-transport.d.ts +2 -1
- package/dist/contracts/contract-transport.js +24 -2
- package/dist/contracts/system/network-contracts.d.ts +1 -1
- package/dist/contracts/tool-catalog-service.js +1 -1
- package/dist/contracts/tool-catalog.js +6 -2
- 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 +8 -16
- package/dist/device/binary-peer-connection-v2.js +15 -31
- package/dist/device/connection.d.ts +35 -44
- package/dist/device/connection.js +188 -186
- package/dist/device/device.d.ts +1 -8
- package/dist/device/device.js +1 -30
- 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/socket.type.d.ts +6 -12
- 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
- package/dist/device/binary-peer-connection.d.ts +0 -58
- package/dist/device/binary-peer-connection.js +0 -516
- package/dist/device/streamed-socket.d.ts +0 -23
- package/dist/device/streamed-socket.js +0 -255
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { DataContext } from "../context/data-context";
|
|
2
|
+
/** What {@link resignGroupAuthority} did, per table. */
|
|
3
|
+
export interface IResignGroupAuthorityResult {
|
|
4
|
+
/** Rows re-signed. */
|
|
5
|
+
resigned: Record<"Groups" | "GroupMembers" | "Packages" | "PackageVersions", number>;
|
|
6
|
+
/** Rows left as they were because their table refused this user's signature, with why. */
|
|
7
|
+
refused: {
|
|
8
|
+
table: string;
|
|
9
|
+
recordId: string;
|
|
10
|
+
error: string;
|
|
11
|
+
}[];
|
|
12
|
+
}
|
|
13
|
+
/** Which rows {@link resignGroupAuthority} re-signs. */
|
|
14
|
+
export interface IResignGroupAuthorityOptions {
|
|
15
|
+
/** Only rows validly signed with this public key (a key the user just rotated away from). */
|
|
16
|
+
signedByKey?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Sign with this secret key instead of the tables' registered signer. Key rotation passes the
|
|
19
|
+
* new key, since the running host still signs with the old one until it restarts. Host code
|
|
20
|
+
* only; never accepted from a client.
|
|
21
|
+
*/
|
|
22
|
+
secretKey?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Re-sign the rows that carry a group's authority (the group row, memberships, packages and
|
|
26
|
+
* package versions) with this device's current key, so they count under the group's verified
|
|
27
|
+
* authority again: after the hard cutover that started checking synced rows, and after a key
|
|
28
|
+
* rotation (`signedByKey`), since roles are traced through signatures by current keys.
|
|
29
|
+
*
|
|
30
|
+
* Each row goes through its table's `signAndSave`, so its table's rules still apply: the founder
|
|
31
|
+
* can re-sign everything; an Admin only what an Admin may sign. Rows a table refuses are left
|
|
32
|
+
* as they were and reported. Re-signing vouches for each row as it is now, so only run it on a
|
|
33
|
+
* group whose current rows you trust.
|
|
34
|
+
*
|
|
35
|
+
* @param dataContext - The group's context (not the personal context).
|
|
36
|
+
* @param opts - Limit to rows signed by one key.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resignGroupAuthority(dataContext: DataContext, opts?: IResignGroupAuthorityOptions): Promise<IResignGroupAuthorityResult>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resignGroupAuthority = resignGroupAuthority;
|
|
4
|
+
const keys_1 = require("../keys");
|
|
5
|
+
const write_checks_1 = require("./orm/write-checks");
|
|
6
|
+
/**
|
|
7
|
+
* Re-sign the rows that carry a group's authority (the group row, memberships, packages and
|
|
8
|
+
* package versions) with this device's current key, so they count under the group's verified
|
|
9
|
+
* authority again: after the hard cutover that started checking synced rows, and after a key
|
|
10
|
+
* rotation (`signedByKey`), since roles are traced through signatures by current keys.
|
|
11
|
+
*
|
|
12
|
+
* Each row goes through its table's `signAndSave`, so its table's rules still apply: the founder
|
|
13
|
+
* can re-sign everything; an Admin only what an Admin may sign. Rows a table refuses are left
|
|
14
|
+
* as they were and reported. Re-signing vouches for each row as it is now, so only run it on a
|
|
15
|
+
* group whose current rows you trust.
|
|
16
|
+
*
|
|
17
|
+
* @param dataContext - The group's context (not the personal context).
|
|
18
|
+
* @param opts - Limit to rows signed by one key.
|
|
19
|
+
*/
|
|
20
|
+
async function resignGroupAuthority(dataContext, opts = {}) {
|
|
21
|
+
const groupId = dataContext.groupId;
|
|
22
|
+
if (!groupId) {
|
|
23
|
+
throw new Error("resignGroupAuthority needs a group context");
|
|
24
|
+
}
|
|
25
|
+
const { Groups } = await Promise.resolve().then(() => require("./groups"));
|
|
26
|
+
const { GroupMembers } = await Promise.resolve().then(() => require("./group-members"));
|
|
27
|
+
const { Packages } = await Promise.resolve().then(() => require("./packages"));
|
|
28
|
+
const { PackageVersions } = await Promise.resolve().then(() => require("./package-versions"));
|
|
29
|
+
const result = {
|
|
30
|
+
resigned: { Groups: 0, GroupMembers: 0, Packages: 0, PackageVersions: 0 },
|
|
31
|
+
refused: [],
|
|
32
|
+
};
|
|
33
|
+
const snapshot = { saveAsSnapshot: true, restoreIfDeleted: true };
|
|
34
|
+
// Through each table's own save, so its rules still apply to the new signature.
|
|
35
|
+
const resign = async (table, rows, prepare = (row) => row) => {
|
|
36
|
+
const tableName = table.tableName;
|
|
37
|
+
// Only rows that key really signed: a row can name any key in its signature field.
|
|
38
|
+
for (const row of rows.filter((row) => !opts.signedByKey || (0, keys_1.signedByKey)(row) === opts.signedByKey)) {
|
|
39
|
+
try {
|
|
40
|
+
if (opts.secretKey) {
|
|
41
|
+
const stamp = await (0, write_checks_1.signingStamp)(table, row, row);
|
|
42
|
+
await table.save((0, keys_1.addSignatureToObject)({ ...row, ...stamp }, opts.secretKey), snapshot);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
await table.signAndSave(prepare(row), snapshot);
|
|
46
|
+
}
|
|
47
|
+
result.resigned[tableName]++;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
result.refused.push({
|
|
51
|
+
table: tableName,
|
|
52
|
+
recordId: row[table.primaryKeyName],
|
|
53
|
+
error: String(error),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const groups = Groups(dataContext);
|
|
59
|
+
const group = await groups.get(groupId);
|
|
60
|
+
await resign(groups, group ? [group] : []);
|
|
61
|
+
const members = GroupMembers(dataContext);
|
|
62
|
+
await resign(members, await members.list({ groupId }),
|
|
63
|
+
// A rotation re-signs the grant as it is; otherwise bind it to the member's key as this
|
|
64
|
+
// device knows it (a grant from before keys were named, or to a key since replaced).
|
|
65
|
+
({ publicKey: _named, ...rest }) => rest);
|
|
66
|
+
const packages = Packages(dataContext);
|
|
67
|
+
await resign(packages, await packages.list());
|
|
68
|
+
const versions = PackageVersions(dataContext);
|
|
69
|
+
await resign(versions, await versions.list());
|
|
70
|
+
return result;
|
|
71
|
+
}
|
package/dist/data/groups.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { DataContext } from "../context/data-context";
|
|
3
3
|
import { GroupMemberRole } from "./group-member-roles";
|
|
4
|
+
import type { IResignGroupAuthorityOptions, IResignGroupAuthorityResult } from "./group-resign";
|
|
4
5
|
import type { ISaveOptions } from "./orm/data-query";
|
|
5
6
|
import { Table } from "./orm/table";
|
|
6
7
|
/** Schema for a signed group record, including membership policy and group public keys. */
|
|
@@ -13,6 +14,7 @@ export declare const groupSchema: z.ZodObject<{
|
|
|
13
14
|
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
14
15
|
founderUserId: z.ZodEffects<z.ZodString, string, string>;
|
|
15
16
|
signature: z.ZodString;
|
|
17
|
+
signedAt: z.ZodOptional<z.ZodNumber>;
|
|
16
18
|
publicKey: z.ZodString;
|
|
17
19
|
publicBoxKey: z.ZodString;
|
|
18
20
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -25,6 +27,7 @@ export declare const groupSchema: z.ZodObject<{
|
|
|
25
27
|
founderUserId: string;
|
|
26
28
|
disabled?: boolean | undefined;
|
|
27
29
|
iconClassName?: string | undefined;
|
|
30
|
+
signedAt?: number | undefined;
|
|
28
31
|
publicRole?: GroupMemberRole | undefined;
|
|
29
32
|
}, {
|
|
30
33
|
name: string;
|
|
@@ -36,6 +39,7 @@ export declare const groupSchema: z.ZodObject<{
|
|
|
36
39
|
founderUserId: string;
|
|
37
40
|
disabled?: boolean | undefined;
|
|
38
41
|
iconClassName?: string | undefined;
|
|
42
|
+
signedAt?: number | undefined;
|
|
39
43
|
publicRole?: GroupMemberRole | undefined;
|
|
40
44
|
}>;
|
|
41
45
|
/** A signed group record shared between personal and group contexts. */
|
|
@@ -47,6 +51,13 @@ export declare class GroupsTable extends Table<IGroup> {
|
|
|
47
51
|
static isPassthrough: boolean;
|
|
48
52
|
save(group: IGroup, opts?: ISaveOptions): Promise<IGroup>;
|
|
49
53
|
signAndSave(group: IGroup, opts?: ISaveOptions): Promise<IGroup>;
|
|
54
|
+
/**
|
|
55
|
+
* Re-sign this group's authority rows (group row, memberships, packages, package versions)
|
|
56
|
+
* with this device's key. See {@link resignGroupAuthority}. Only on a group context's table.
|
|
57
|
+
*
|
|
58
|
+
* @param opts - Limit to rows signed by one key.
|
|
59
|
+
*/
|
|
60
|
+
resignAuthority(opts?: IResignGroupAuthorityOptions): Promise<IResignGroupAuthorityResult>;
|
|
50
61
|
delete(groupId: string): Promise<void>;
|
|
51
62
|
/** Registers the signer for all SDK copies in this JavaScript realm. Replaces any prior signer. */
|
|
52
63
|
static enableGroupSigning(fn: (group: IGroup) => IGroup): void;
|
package/dist/data/groups.js
CHANGED
|
@@ -39,12 +39,13 @@ exports.Groups = Groups;
|
|
|
39
39
|
const zod_1 = require("zod");
|
|
40
40
|
const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
41
41
|
const zod_types_1 = require("../types/zod-types");
|
|
42
|
+
const authority_write_checks_1 = require("./authority-write-checks");
|
|
42
43
|
const group_member_roles_1 = require("./group-member-roles");
|
|
43
|
-
const group_permissions_1 = require("./group-permissions");
|
|
44
44
|
const decorators_1 = require("./orm/decorators");
|
|
45
45
|
const table_1 = require("./orm/table");
|
|
46
46
|
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
47
47
|
const types_1 = require("./orm/types");
|
|
48
|
+
const write_checks_1 = require("./orm/write-checks");
|
|
48
49
|
/** Schema for a signed group record, including membership policy and group public keys. */
|
|
49
50
|
exports.groupSchema = zod_1.z.object({
|
|
50
51
|
groupId: zod_types_1.zodPeerId,
|
|
@@ -61,6 +62,10 @@ exports.groupSchema = zod_1.z.object({
|
|
|
61
62
|
disabled: zod_1.z.boolean().optional().describe("Whether the group is currently disabled"),
|
|
62
63
|
founderUserId: zod_types_1.zodPeerId.describe("The user ID of the group founder"),
|
|
63
64
|
signature: zod_1.z.string().describe("The signed hash of this data excluding the signature itself"),
|
|
65
|
+
signedAt: zod_1.z
|
|
66
|
+
.number()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe("When the signer signed this row (ms since epoch), under the signature: a copy of an earlier row can't replace a later one"),
|
|
64
69
|
publicKey: zod_1.z
|
|
65
70
|
.string()
|
|
66
71
|
.describe("The public key of the group used to verify a data has come from a group member with write permissions or higher"),
|
|
@@ -86,26 +91,20 @@ let GroupsTable = (() => {
|
|
|
86
91
|
let _classSuper = table_1.Table;
|
|
87
92
|
let _instanceExtraInitializers = [];
|
|
88
93
|
let _signAndSave_decorators;
|
|
94
|
+
let _resignAuthority_decorators;
|
|
89
95
|
return class GroupsTable extends _classSuper {
|
|
90
96
|
static {
|
|
91
97
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
92
98
|
_signAndSave_decorators = [(0, decorators_1.ProxyClientTableMethodCalls)()];
|
|
99
|
+
_resignAuthority_decorators = [(0, decorators_1.ProxyClientTableMethodCalls)()];
|
|
93
100
|
__esDecorate(this, null, _signAndSave_decorators, { kind: "method", name: "signAndSave", static: false, private: false, access: { has: obj => "signAndSave" in obj, get: obj => obj.signAndSave }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
101
|
+
__esDecorate(this, null, _resignAuthority_decorators, { kind: "method", name: "resignAuthority", static: false, private: false, access: { has: obj => "resignAuthority" in obj, get: obj => obj.resignAuthority }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
94
102
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
95
103
|
}
|
|
96
104
|
static isPassthrough = false;
|
|
97
105
|
async save(group, opts) {
|
|
98
|
-
if (GroupsTable.isPassthrough)
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
const userContext = await (0, user_context_singleton_1.getUserContext)();
|
|
102
|
-
const userContextGroups = Groups(userContext.userDataContext);
|
|
103
|
-
if (userContextGroups === this) {
|
|
104
|
-
// users can do whatever they want to groups in their personal space
|
|
105
|
-
return super.save(group, opts);
|
|
106
|
-
}
|
|
107
|
-
const oldGroup = await this.get(group.groupId);
|
|
108
|
-
await (0, group_permissions_1.verifyGroupSignature)(group, oldGroup);
|
|
106
|
+
if (!GroupsTable.isPassthrough)
|
|
107
|
+
await (0, write_checks_1.checkLocalSave)(this, group, authority_write_checks_1.checkGroup);
|
|
109
108
|
return super.save(group, opts);
|
|
110
109
|
}
|
|
111
110
|
async signAndSave(group, opts) {
|
|
@@ -113,9 +112,28 @@ let GroupsTable = (() => {
|
|
|
113
112
|
if (!sign) {
|
|
114
113
|
throw new Error("Group signing must be enabled to sign and save groups. Call GroupsTable.enableGroupSigning(fn) to enable it.");
|
|
115
114
|
}
|
|
116
|
-
group = sign.call(GroupsTable,
|
|
115
|
+
group = sign.call(GroupsTable, {
|
|
116
|
+
...group,
|
|
117
|
+
...(await (0, write_checks_1.signingStamp)(this, group)),
|
|
118
|
+
});
|
|
117
119
|
return this.save(group, opts);
|
|
118
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Re-sign this group's authority rows (group row, memberships, packages, package versions)
|
|
123
|
+
* with this device's key. See {@link resignGroupAuthority}. Only on a group context's table.
|
|
124
|
+
*
|
|
125
|
+
* @param opts - Limit to rows signed by one key.
|
|
126
|
+
*/
|
|
127
|
+
async resignAuthority(opts) {
|
|
128
|
+
const { resignGroupAuthority } = await Promise.resolve().then(() => require("./group-resign"));
|
|
129
|
+
if (!this.groupId) {
|
|
130
|
+
throw new Error("Re-sign a group from its own context, not the personal context");
|
|
131
|
+
}
|
|
132
|
+
// Signs with the registered signer only: a client never supplies a key.
|
|
133
|
+
return resignGroupAuthority((await (0, user_context_singleton_1.getUserContext)()).getDataContext(this.groupId), {
|
|
134
|
+
signedByKey: opts?.signedByKey,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
119
137
|
async delete(groupId) {
|
|
120
138
|
const userContext = await (0, user_context_singleton_1.getUserContext)();
|
|
121
139
|
const userContextGroups = Groups(userContext.userDataContext);
|
package/dist/data/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./access-level";
|
|
2
2
|
export * from "./assistants";
|
|
3
|
+
export * from "./authority-write-checks";
|
|
3
4
|
export * from "./change-tracking";
|
|
4
5
|
export * from "./channels";
|
|
5
6
|
export * from "./create-group";
|
|
@@ -7,9 +8,11 @@ export * from "./device-sync-info";
|
|
|
7
8
|
export * from "./devices";
|
|
8
9
|
export * from "./embeddings";
|
|
9
10
|
export * from "./files";
|
|
11
|
+
export * from "./group-authority";
|
|
10
12
|
export * from "./group-member-roles";
|
|
11
13
|
export * from "./group-members";
|
|
12
14
|
export * from "./group-permissions";
|
|
15
|
+
export * from "./group-resign";
|
|
13
16
|
export * from "./group-secret";
|
|
14
17
|
export * from "./group-share";
|
|
15
18
|
export * from "./groups";
|
package/dist/data/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./access-level"), exports);
|
|
18
18
|
__exportStar(require("./assistants"), exports);
|
|
19
|
+
__exportStar(require("./authority-write-checks"), exports);
|
|
19
20
|
__exportStar(require("./change-tracking"), exports);
|
|
20
21
|
__exportStar(require("./channels"), exports);
|
|
21
22
|
__exportStar(require("./create-group"), exports);
|
|
@@ -23,9 +24,11 @@ __exportStar(require("./device-sync-info"), exports);
|
|
|
23
24
|
__exportStar(require("./devices"), exports);
|
|
24
25
|
__exportStar(require("./embeddings"), exports);
|
|
25
26
|
__exportStar(require("./files"), exports);
|
|
27
|
+
__exportStar(require("./group-authority"), exports);
|
|
26
28
|
__exportStar(require("./group-member-roles"), exports);
|
|
27
29
|
__exportStar(require("./group-members"), exports);
|
|
28
30
|
__exportStar(require("./group-permissions"), exports);
|
|
31
|
+
__exportStar(require("./group-resign"), exports);
|
|
29
32
|
__exportStar(require("./group-secret"), exports);
|
|
30
33
|
__exportStar(require("./group-share"), exports);
|
|
31
34
|
__exportStar(require("./groups"), exports);
|
package/dist/data/invites.d.ts
CHANGED
|
@@ -47,6 +47,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
47
47
|
type: "peers-services" | "https";
|
|
48
48
|
url: string;
|
|
49
49
|
}>, "many">>;
|
|
50
|
+
anchorsSignature: z.ZodOptional<z.ZodString>;
|
|
50
51
|
}, "strict", z.ZodTypeAny, {
|
|
51
52
|
publicKey: string;
|
|
52
53
|
userId: string;
|
|
@@ -55,6 +56,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
55
56
|
type: "peers-services" | "https";
|
|
56
57
|
url: string;
|
|
57
58
|
}[] | undefined;
|
|
59
|
+
anchorsSignature?: string | undefined;
|
|
58
60
|
displayName?: string | undefined;
|
|
59
61
|
}, {
|
|
60
62
|
publicKey: string;
|
|
@@ -64,6 +66,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
64
66
|
type: "peers-services" | "https";
|
|
65
67
|
url: string;
|
|
66
68
|
}[] | undefined;
|
|
69
|
+
anchorsSignature?: string | undefined;
|
|
67
70
|
displayName?: string | undefined;
|
|
68
71
|
}>>;
|
|
69
72
|
/** Device the counterpart used, when they told us; lets the network layer connect early. */
|
|
@@ -95,6 +98,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
95
98
|
type: "peers-services" | "https";
|
|
96
99
|
url: string;
|
|
97
100
|
}>, "many">>;
|
|
101
|
+
anchorsSignature: z.ZodOptional<z.ZodString>;
|
|
98
102
|
}, "strict", z.ZodTypeAny, {
|
|
99
103
|
publicKey: string;
|
|
100
104
|
userId: string;
|
|
@@ -103,6 +107,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
103
107
|
type: "peers-services" | "https";
|
|
104
108
|
url: string;
|
|
105
109
|
}[] | undefined;
|
|
110
|
+
anchorsSignature?: string | undefined;
|
|
106
111
|
displayName?: string | undefined;
|
|
107
112
|
}, {
|
|
108
113
|
publicKey: string;
|
|
@@ -112,6 +117,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
112
117
|
type: "peers-services" | "https";
|
|
113
118
|
url: string;
|
|
114
119
|
}[] | undefined;
|
|
120
|
+
anchorsSignature?: string | undefined;
|
|
115
121
|
displayName?: string | undefined;
|
|
116
122
|
}>;
|
|
117
123
|
expiresAt: z.ZodString;
|
|
@@ -155,6 +161,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
155
161
|
type: "peers-services" | "https";
|
|
156
162
|
url: string;
|
|
157
163
|
}[] | undefined;
|
|
164
|
+
anchorsSignature?: string | undefined;
|
|
158
165
|
displayName?: string | undefined;
|
|
159
166
|
};
|
|
160
167
|
epoch: number;
|
|
@@ -181,6 +188,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
181
188
|
type: "peers-services" | "https";
|
|
182
189
|
url: string;
|
|
183
190
|
}[] | undefined;
|
|
191
|
+
anchorsSignature?: string | undefined;
|
|
184
192
|
displayName?: string | undefined;
|
|
185
193
|
};
|
|
186
194
|
epoch: number;
|
|
@@ -253,6 +261,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
253
261
|
type: "peers-services" | "https";
|
|
254
262
|
url: string;
|
|
255
263
|
}[] | undefined;
|
|
264
|
+
anchorsSignature?: string | undefined;
|
|
256
265
|
displayName?: string | undefined;
|
|
257
266
|
};
|
|
258
267
|
epoch: number;
|
|
@@ -274,6 +283,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
274
283
|
type: "peers-services" | "https";
|
|
275
284
|
url: string;
|
|
276
285
|
}[] | undefined;
|
|
286
|
+
anchorsSignature?: string | undefined;
|
|
277
287
|
displayName?: string | undefined;
|
|
278
288
|
} | undefined;
|
|
279
289
|
counterpartDeviceId?: string | undefined;
|
|
@@ -314,6 +324,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
314
324
|
type: "peers-services" | "https";
|
|
315
325
|
url: string;
|
|
316
326
|
}[] | undefined;
|
|
327
|
+
anchorsSignature?: string | undefined;
|
|
317
328
|
displayName?: string | undefined;
|
|
318
329
|
};
|
|
319
330
|
epoch: number;
|
|
@@ -335,6 +346,7 @@ export declare const inviteSchema: z.ZodObject<{
|
|
|
335
346
|
type: "peers-services" | "https";
|
|
336
347
|
url: string;
|
|
337
348
|
}[] | undefined;
|
|
349
|
+
anchorsSignature?: string | undefined;
|
|
338
350
|
displayName?: string | undefined;
|
|
339
351
|
} | undefined;
|
|
340
352
|
counterpartDeviceId?: string | undefined;
|
|
@@ -383,6 +395,7 @@ export declare function Invites(dataContext?: DataContext): import("..").Table<{
|
|
|
383
395
|
type: "peers-services" | "https";
|
|
384
396
|
url: string;
|
|
385
397
|
}[] | undefined;
|
|
398
|
+
anchorsSignature?: string | undefined;
|
|
386
399
|
displayName?: string | undefined;
|
|
387
400
|
};
|
|
388
401
|
epoch: number;
|
|
@@ -404,6 +417,7 @@ export declare function Invites(dataContext?: DataContext): import("..").Table<{
|
|
|
404
417
|
type: "peers-services" | "https";
|
|
405
418
|
url: string;
|
|
406
419
|
}[] | undefined;
|
|
420
|
+
anchorsSignature?: string | undefined;
|
|
407
421
|
displayName?: string | undefined;
|
|
408
422
|
} | undefined;
|
|
409
423
|
counterpartDeviceId?: string | undefined;
|
package/dist/data/orm/index.d.ts
CHANGED
package/dist/data/orm/index.js
CHANGED
|
@@ -30,3 +30,4 @@ __exportStar(require("./table-container"), exports);
|
|
|
30
30
|
__exportStar(require("./table-definitions.type"), exports);
|
|
31
31
|
__exportStar(require("./table-dependencies"), exports);
|
|
32
32
|
__exportStar(require("./types"), exports);
|
|
33
|
+
__exportStar(require("./write-checks"), exports);
|
|
@@ -96,8 +96,8 @@ export declare class SQLDataSource<T extends {
|
|
|
96
96
|
*/
|
|
97
97
|
bulkSave(records: T[]): Promise<T[]>;
|
|
98
98
|
}
|
|
99
|
-
/** Encode a JavaScript field for SQLite parameters
|
|
100
|
-
export declare function jsValueToSqlValue(value: any
|
|
99
|
+
/** Encode a JavaScript field for SQLite parameters. */
|
|
100
|
+
export declare function jsValueToSqlValue(value: any): any;
|
|
101
101
|
/** Restore a SQLite field according to its declared Peers type. */
|
|
102
102
|
export declare function sqlValueToJsValue(value: any, fieldType: FieldType, isArray: boolean): any;
|
|
103
103
|
/** Default value used when adding a required field to an existing table. */
|
|
@@ -136,6 +136,7 @@ class SQLDataSource {
|
|
|
136
136
|
// sql query to copy existing data and set new required fields to default values
|
|
137
137
|
const defaults = this.initRecord();
|
|
138
138
|
const fieldsInsert = this.metaData.fields.map((f) => `"${f.name}"`).join(", ");
|
|
139
|
+
const params = [];
|
|
139
140
|
const fieldsSelect = this.metaData.fields
|
|
140
141
|
.map((f) => {
|
|
141
142
|
const existingField = existingTableDef.includes(`"${f.name}"`);
|
|
@@ -146,18 +147,19 @@ class SQLDataSource {
|
|
|
146
147
|
if (defaultValue === undefined) {
|
|
147
148
|
defaultValue = globalDefaultValues(f);
|
|
148
149
|
}
|
|
149
|
-
|
|
150
|
+
if (!f.optional)
|
|
151
|
+
params.push(jsValueToSqlValue(defaultValue));
|
|
150
152
|
if (existingField && !f.optional) {
|
|
151
|
-
return `
|
|
153
|
+
return `COALESCE("${f.name}", ?) as "${f.name}"`;
|
|
152
154
|
}
|
|
153
155
|
if (!existingField && !f.optional) {
|
|
154
|
-
return
|
|
156
|
+
return `? as "${f.name}"`;
|
|
155
157
|
}
|
|
156
158
|
return `NULL as "${f.name}"`;
|
|
157
159
|
})
|
|
158
160
|
.join(", ");
|
|
159
161
|
const insertSql = `INSERT INTO "${this.tableName}"(${fieldsInsert}) SELECT ${fieldsSelect} FROM "${tempTableName}"`;
|
|
160
|
-
await this.db.exec(insertSql,
|
|
162
|
+
await this.db.exec(insertSql, params);
|
|
161
163
|
// drop old table
|
|
162
164
|
const dropSql = `DROP TABLE IF EXISTS "${tempTableName}"`;
|
|
163
165
|
await this.db.exec(dropSql, []);
|
|
@@ -536,8 +538,8 @@ class SQLDataSource {
|
|
|
536
538
|
}
|
|
537
539
|
}
|
|
538
540
|
exports.SQLDataSource = SQLDataSource;
|
|
539
|
-
/** Encode a JavaScript field for SQLite parameters
|
|
540
|
-
function jsValueToSqlValue(value
|
|
541
|
+
/** Encode a JavaScript field for SQLite parameters. */
|
|
542
|
+
function jsValueToSqlValue(value) {
|
|
541
543
|
if (value === undefined)
|
|
542
544
|
return null;
|
|
543
545
|
if (value instanceof Date) {
|
|
@@ -549,9 +551,6 @@ function jsValueToSqlValue(value, escapeQuote = false) {
|
|
|
549
551
|
if (typeof value === "boolean") {
|
|
550
552
|
return value ? 1 : 0;
|
|
551
553
|
}
|
|
552
|
-
if (typeof value === "string" && escapeQuote) {
|
|
553
|
-
return value.replace(/'/g, "''");
|
|
554
|
-
}
|
|
555
554
|
return value;
|
|
556
555
|
}
|
|
557
556
|
/** Restore a SQLite field according to its declared Peers type. */
|
|
@@ -4,6 +4,7 @@ exports.TableContainer = void 0;
|
|
|
4
4
|
exports.checkVersionedUpdate = checkVersionedUpdate;
|
|
5
5
|
const rpc_types_1 = require("../../rpc-types");
|
|
6
6
|
const utils_1 = require("../../utils");
|
|
7
|
+
const package_table_identity_1 = require("../package-table-identity");
|
|
7
8
|
const table_1 = require("./table");
|
|
8
9
|
const table_definitions_system_1 = require("./table-definitions.system");
|
|
9
10
|
const types_1 = require("./types");
|
|
@@ -266,7 +267,8 @@ class TableContainer {
|
|
|
266
267
|
const record = await tableDefsTable.findOne({ name: tableName });
|
|
267
268
|
if (!record || record.deleted)
|
|
268
269
|
return null;
|
|
269
|
-
this.registerFromTableDefinitionRecord(record)
|
|
270
|
+
if (!this.registerFromTableDefinitionRecord(record))
|
|
271
|
+
return null;
|
|
270
272
|
// Now instantiate via getTableByName which checks fallbackDefinitions
|
|
271
273
|
return this.getTableByName(tableName);
|
|
272
274
|
}
|
|
@@ -334,22 +336,25 @@ class TableContainer {
|
|
|
334
336
|
* External code should not need to call this directly.
|
|
335
337
|
*/
|
|
336
338
|
registerFromTableDefinitionRecord(record) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
console.warn(`Invalid table definition record, skipping:`, record);
|
|
340
|
-
return;
|
|
339
|
+
try {
|
|
340
|
+
(0, package_table_identity_1.validateTableDefinitionRecord)(record);
|
|
341
341
|
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
console.warn("Refusing invalid synced table definition", error);
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
const metaData = record.metaData;
|
|
342
347
|
const tableName = (0, utils_1.getFullTableName)(metaData);
|
|
343
348
|
// Deleted tables should not be registered as fallbacks
|
|
344
349
|
if (record.deleted) {
|
|
345
350
|
delete this.fallbackDefinitions[tableName];
|
|
346
351
|
delete this.fallbackInstances[tableName];
|
|
347
|
-
return;
|
|
352
|
+
return false;
|
|
348
353
|
}
|
|
349
354
|
// Don't overwrite a full (code-registered) definition -- that always takes precedence
|
|
350
355
|
const fullDef = this.tableDefinitions[tableName] || table_definitions_system_1.systemTableDefinitions[tableName];
|
|
351
356
|
if (fullDef) {
|
|
352
|
-
return; // full definition exists, no need for a fallback
|
|
357
|
+
return true; // full definition exists, no need for a fallback
|
|
353
358
|
}
|
|
354
359
|
const existing = this.fallbackDefinitions[tableName];
|
|
355
360
|
if (existing) {
|
|
@@ -357,13 +362,14 @@ class TableContainer {
|
|
|
357
362
|
const incomingVersion = record.versionNumber ?? 0;
|
|
358
363
|
const result = checkVersionedUpdate(existingVersion, incomingVersion, existing.metaData, metaData);
|
|
359
364
|
if (result === "skip") {
|
|
360
|
-
return;
|
|
365
|
+
return true;
|
|
361
366
|
}
|
|
362
367
|
// Remove old fallback instance so it gets re-created with the new schema
|
|
363
368
|
delete this.fallbackInstances[tableName];
|
|
364
369
|
}
|
|
365
370
|
const schema = (0, types_1.fieldsToSchema)(metaData.fields);
|
|
366
371
|
this.fallbackDefinitions[tableName] = { metaData, schema };
|
|
372
|
+
return true;
|
|
367
373
|
}
|
|
368
374
|
/**
|
|
369
375
|
* This ensures all tables have been new'ed up and then returns the entire list of them.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { DataContext } from "../../context/data-context";
|
|
2
|
+
import type { Table } from "./table";
|
|
3
|
+
/**
|
|
4
|
+
* Prefix of every refusal from a {@link TableWriteCheck}. Sync recovery parks a change refused
|
|
5
|
+
* with it, and checks it again only from local history, when the group's authority changes.
|
|
6
|
+
*/
|
|
7
|
+
export declare const WRITE_NOT_AUTHORIZED = "Write not authorized";
|
|
8
|
+
/** Where a checked write lands. */
|
|
9
|
+
export interface ITableWriteCheckContext {
|
|
10
|
+
/** The context the row belongs to. */
|
|
11
|
+
dataContext: DataContext;
|
|
12
|
+
/** The row's primary key, also given for a delete. */
|
|
13
|
+
recordId: string;
|
|
14
|
+
/** Checked snapshots retained by the same atomic recovery transaction. */
|
|
15
|
+
retainedRows?: readonly unknown[];
|
|
16
|
+
/** Records removed by the same atomic recovery transaction. */
|
|
17
|
+
deletedRecordIds?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A rule a row must meet before it's written, run by the host on every synced change (sync
|
|
21
|
+
* writes rows without going through the table class). Throw an error from
|
|
22
|
+
* {@link writeNotAuthorized} to refuse it.
|
|
23
|
+
*
|
|
24
|
+
* @param existing - The row as stored now, if any.
|
|
25
|
+
* @param candidate - The row about to be stored, or undefined for a delete.
|
|
26
|
+
*/
|
|
27
|
+
export type TableWriteCheck<T = any> = (existing: T | undefined, candidate: T | undefined, context: ITableWriteCheckContext) => Promise<void> | void;
|
|
28
|
+
/**
|
|
29
|
+
* Register the {@link TableWriteCheck} for a table name. One per table; a second registration
|
|
30
|
+
* replaces the first.
|
|
31
|
+
*
|
|
32
|
+
* @param tableName - Table the check guards.
|
|
33
|
+
* @param check - The rule.
|
|
34
|
+
*/
|
|
35
|
+
export declare function registerTableWriteCheck<T>(tableName: string, check: TableWriteCheck<T>): void;
|
|
36
|
+
/**
|
|
37
|
+
* The {@link TableWriteCheck} registered for a table, if any.
|
|
38
|
+
*
|
|
39
|
+
* @param tableName - Table name.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getTableWriteCheck(tableName: string): TableWriteCheck | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Run `check` on a local save to `table`, as the host runs it on every synced row, so a local
|
|
44
|
+
* write and a synced write are judged by the same code. Nothing is checked in the personal
|
|
45
|
+
* context: only the user's own devices write it.
|
|
46
|
+
*
|
|
47
|
+
* @param table - The table being saved to.
|
|
48
|
+
* @param row - The row about to be stored.
|
|
49
|
+
* @param check - The table's rule.
|
|
50
|
+
*/
|
|
51
|
+
export declare function checkLocalSave<T extends {
|
|
52
|
+
[key: string]: any;
|
|
53
|
+
}>(table: Table<T>, row: T, check: TableWriteCheck<T>): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Tables whose approvals are bound to a context (`signedContextId`) and whose deletes are open,
|
|
56
|
+
* so a deleted row's signing time is retained ({@link deletedSignedAt}).
|
|
57
|
+
*/
|
|
58
|
+
export declare const packageApprovalTables: ReadonlySet<string>;
|
|
59
|
+
/**
|
|
60
|
+
* What a table's `signAndSave` (and a re-sign) puts under the signature: `signedAt`, now or
|
|
61
|
+
* just after the row on record when that was signed by a clock running ahead, so the new
|
|
62
|
+
* signature counts as the later one (and, for a package table, after the deleted row's
|
|
63
|
+
* retained stamp); for a package table also the context the approval is for.
|
|
64
|
+
*
|
|
65
|
+
* @param table - The table being signed for.
|
|
66
|
+
* @param row - The row being signed.
|
|
67
|
+
* @param current - A row already read from storage; membership repair may supply another id's row.
|
|
68
|
+
*/
|
|
69
|
+
export declare function signingStamp<T extends Record<string, any>>(table: Table<T>, row: T, current?: {
|
|
70
|
+
signedAt?: number;
|
|
71
|
+
}): Promise<{
|
|
72
|
+
signedAt: number;
|
|
73
|
+
signedContextId?: string;
|
|
74
|
+
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Read a deleted authority row's last signing time, optionally retaining the stored row's
|
|
77
|
+
* stamp before deletion. Device-local personal storage survives deletion and log compaction.
|
|
78
|
+
* Only pass `existing` from storage, never an unverified incoming candidate.
|
|
79
|
+
*/
|
|
80
|
+
export declare function deletedSignedAt(tableName: string, context: ITableWriteCheckContext, existing?: {
|
|
81
|
+
signedAt?: number;
|
|
82
|
+
}): Promise<number>;
|
|
83
|
+
/**
|
|
84
|
+
* An error refusing a write, carrying the {@link WRITE_NOT_AUTHORIZED} prefix.
|
|
85
|
+
*
|
|
86
|
+
* @param tableName - Table the write was for.
|
|
87
|
+
* @param reason - Why, for logs and the sync recovery queue.
|
|
88
|
+
*/
|
|
89
|
+
export declare function writeNotAuthorized(tableName: string, reason: string): Error;
|