@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
|
@@ -35,6 +35,8 @@ export declare const inviteIdentitySchema: z.ZodObject<{
|
|
|
35
35
|
type: "peers-services" | "https";
|
|
36
36
|
url: string;
|
|
37
37
|
}>, "many">>;
|
|
38
|
+
/** The owner's signature over that first anchor list (see `signUserObject`). */
|
|
39
|
+
anchorsSignature: z.ZodOptional<z.ZodString>;
|
|
38
40
|
}, "strict", z.ZodTypeAny, {
|
|
39
41
|
publicKey: string;
|
|
40
42
|
userId: string;
|
|
@@ -43,6 +45,7 @@ export declare const inviteIdentitySchema: z.ZodObject<{
|
|
|
43
45
|
type: "peers-services" | "https";
|
|
44
46
|
url: string;
|
|
45
47
|
}[] | undefined;
|
|
48
|
+
anchorsSignature?: string | undefined;
|
|
46
49
|
displayName?: string | undefined;
|
|
47
50
|
}, {
|
|
48
51
|
publicKey: string;
|
|
@@ -52,6 +55,7 @@ export declare const inviteIdentitySchema: z.ZodObject<{
|
|
|
52
55
|
type: "peers-services" | "https";
|
|
53
56
|
url: string;
|
|
54
57
|
}[] | undefined;
|
|
58
|
+
anchorsSignature?: string | undefined;
|
|
55
59
|
displayName?: string | undefined;
|
|
56
60
|
}>;
|
|
57
61
|
/** Public identity of a party to an invite. */
|
|
@@ -110,6 +114,8 @@ export declare const peersInviteContentsSchema: z.ZodEffects<z.ZodObject<{
|
|
|
110
114
|
type: "peers-services" | "https";
|
|
111
115
|
url: string;
|
|
112
116
|
}>, "many">>;
|
|
117
|
+
/** The owner's signature over that first anchor list (see `signUserObject`). */
|
|
118
|
+
anchorsSignature: z.ZodOptional<z.ZodString>;
|
|
113
119
|
}, "strict", z.ZodTypeAny, {
|
|
114
120
|
publicKey: string;
|
|
115
121
|
userId: string;
|
|
@@ -118,6 +124,7 @@ export declare const peersInviteContentsSchema: z.ZodEffects<z.ZodObject<{
|
|
|
118
124
|
type: "peers-services" | "https";
|
|
119
125
|
url: string;
|
|
120
126
|
}[] | undefined;
|
|
127
|
+
anchorsSignature?: string | undefined;
|
|
121
128
|
displayName?: string | undefined;
|
|
122
129
|
}, {
|
|
123
130
|
publicKey: string;
|
|
@@ -127,6 +134,7 @@ export declare const peersInviteContentsSchema: z.ZodEffects<z.ZodObject<{
|
|
|
127
134
|
type: "peers-services" | "https";
|
|
128
135
|
url: string;
|
|
129
136
|
}[] | undefined;
|
|
137
|
+
anchorsSignature?: string | undefined;
|
|
130
138
|
displayName?: string | undefined;
|
|
131
139
|
}>;
|
|
132
140
|
/** ISO 8601 instant after which the token is invalid. */
|
|
@@ -171,6 +179,7 @@ export declare const peersInviteContentsSchema: z.ZodEffects<z.ZodObject<{
|
|
|
171
179
|
type: "peers-services" | "https";
|
|
172
180
|
url: string;
|
|
173
181
|
}[] | undefined;
|
|
182
|
+
anchorsSignature?: string | undefined;
|
|
174
183
|
displayName?: string | undefined;
|
|
175
184
|
};
|
|
176
185
|
epoch: number;
|
|
@@ -196,6 +205,7 @@ export declare const peersInviteContentsSchema: z.ZodEffects<z.ZodObject<{
|
|
|
196
205
|
type: "peers-services" | "https";
|
|
197
206
|
url: string;
|
|
198
207
|
}[] | undefined;
|
|
208
|
+
anchorsSignature?: string | undefined;
|
|
199
209
|
displayName?: string | undefined;
|
|
200
210
|
};
|
|
201
211
|
epoch: number;
|
|
@@ -221,6 +231,7 @@ export declare const peersInviteContentsSchema: z.ZodEffects<z.ZodObject<{
|
|
|
221
231
|
type: "peers-services" | "https";
|
|
222
232
|
url: string;
|
|
223
233
|
}[] | undefined;
|
|
234
|
+
anchorsSignature?: string | undefined;
|
|
224
235
|
displayName?: string | undefined;
|
|
225
236
|
};
|
|
226
237
|
epoch: number;
|
|
@@ -246,6 +257,7 @@ export declare const peersInviteContentsSchema: z.ZodEffects<z.ZodObject<{
|
|
|
246
257
|
type: "peers-services" | "https";
|
|
247
258
|
url: string;
|
|
248
259
|
}[] | undefined;
|
|
260
|
+
anchorsSignature?: string | undefined;
|
|
249
261
|
displayName?: string | undefined;
|
|
250
262
|
};
|
|
251
263
|
epoch: number;
|
|
@@ -284,6 +296,8 @@ export declare const peersInviteSchema: z.ZodObject<{
|
|
|
284
296
|
type: "peers-services" | "https";
|
|
285
297
|
url: string;
|
|
286
298
|
}>, "many">>;
|
|
299
|
+
/** The owner's signature over that first anchor list (see `signUserObject`). */
|
|
300
|
+
anchorsSignature: z.ZodOptional<z.ZodString>;
|
|
287
301
|
}, "strict", z.ZodTypeAny, {
|
|
288
302
|
publicKey: string;
|
|
289
303
|
userId: string;
|
|
@@ -292,6 +306,7 @@ export declare const peersInviteSchema: z.ZodObject<{
|
|
|
292
306
|
type: "peers-services" | "https";
|
|
293
307
|
url: string;
|
|
294
308
|
}[] | undefined;
|
|
309
|
+
anchorsSignature?: string | undefined;
|
|
295
310
|
displayName?: string | undefined;
|
|
296
311
|
}, {
|
|
297
312
|
publicKey: string;
|
|
@@ -301,6 +316,7 @@ export declare const peersInviteSchema: z.ZodObject<{
|
|
|
301
316
|
type: "peers-services" | "https";
|
|
302
317
|
url: string;
|
|
303
318
|
}[] | undefined;
|
|
319
|
+
anchorsSignature?: string | undefined;
|
|
304
320
|
displayName?: string | undefined;
|
|
305
321
|
}>;
|
|
306
322
|
expiresAt: z.ZodString;
|
|
@@ -344,6 +360,7 @@ export declare const peersInviteSchema: z.ZodObject<{
|
|
|
344
360
|
type: "peers-services" | "https";
|
|
345
361
|
url: string;
|
|
346
362
|
}[] | undefined;
|
|
363
|
+
anchorsSignature?: string | undefined;
|
|
347
364
|
displayName?: string | undefined;
|
|
348
365
|
};
|
|
349
366
|
epoch: number;
|
|
@@ -370,6 +387,7 @@ export declare const peersInviteSchema: z.ZodObject<{
|
|
|
370
387
|
type: "peers-services" | "https";
|
|
371
388
|
url: string;
|
|
372
389
|
}[] | undefined;
|
|
390
|
+
anchorsSignature?: string | undefined;
|
|
373
391
|
displayName?: string | undefined;
|
|
374
392
|
};
|
|
375
393
|
epoch: number;
|
|
@@ -44,6 +44,8 @@ exports.inviteIdentitySchema = zod_1.z
|
|
|
44
44
|
* keeps it; this is only the bootstrap that arrives with the invitation.
|
|
45
45
|
*/
|
|
46
46
|
anchors: zod_1.z.array(anchor_document_1.anchorRefSchema).max(8).optional(),
|
|
47
|
+
/** The owner's signature over that first anchor list (see `signUserObject`). */
|
|
48
|
+
anchorsSignature: zod_1.z.string().max(200).optional(),
|
|
47
49
|
})
|
|
48
50
|
.strict();
|
|
49
51
|
/** How joiners are admitted by a group token. */
|
package/dist/keys.d.ts
CHANGED
|
@@ -138,6 +138,13 @@ export declare function addSignatureToObject<T extends Record<string, any>>(obj:
|
|
|
138
138
|
export declare function verifyObjectSignature<T extends IMaybeSignature>(objectWithSignature: T): void;
|
|
139
139
|
/** True if {@link verifyObjectSignature} would succeed. */
|
|
140
140
|
export declare function isObjectSignatureValid<T extends IMaybeSignature>(objectWithSignature: T): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* The key that validly signed `row` ({@link addSignatureToObject}'s `publicKey:signature`), or
|
|
143
|
+
* `undefined` when the row is unsigned or its signature doesn't verify. Memoized.
|
|
144
|
+
*
|
|
145
|
+
* @param row - A row with an optional `signature`.
|
|
146
|
+
*/
|
|
147
|
+
export declare function signedByKey(row: IMaybeSignature): string | undefined;
|
|
141
148
|
/**
|
|
142
149
|
* Parses the Ed25519 public key prefix from a `publicKey:signature` field, or `undefined` if malformed.
|
|
143
150
|
*/
|
package/dist/keys.js
CHANGED
|
@@ -27,6 +27,7 @@ exports.decryptData = decryptData;
|
|
|
27
27
|
exports.addSignatureToObject = addSignatureToObject;
|
|
28
28
|
exports.verifyObjectSignature = verifyObjectSignature;
|
|
29
29
|
exports.isObjectSignatureValid = isObjectSignatureValid;
|
|
30
|
+
exports.signedByKey = signedByKey;
|
|
30
31
|
exports.getPublicKeyFromObjectSignature = getPublicKeyFromObjectSignature;
|
|
31
32
|
const sha2_1 = require("@noble/hashes/sha2");
|
|
32
33
|
const buffer_1 = require("buffer");
|
|
@@ -391,6 +392,32 @@ function isObjectSignatureValid(objectWithSignature) {
|
|
|
391
392
|
}
|
|
392
393
|
return true;
|
|
393
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Signature checks already made, by the hash of the signed row (signature included). A group's
|
|
397
|
+
* authority is rebuilt after any change to its rows and re-checks every one, and an Ed25519
|
|
398
|
+
* check costs milliseconds, so without this a rebuild would take seconds in a large group.
|
|
399
|
+
*/
|
|
400
|
+
const signatureChecks = new Map();
|
|
401
|
+
const SIGNATURE_CHECKS_MAX = 10_000;
|
|
402
|
+
/**
|
|
403
|
+
* The key that validly signed `row` ({@link addSignatureToObject}'s `publicKey:signature`), or
|
|
404
|
+
* `undefined` when the row is unsigned or its signature doesn't verify. Memoized.
|
|
405
|
+
*
|
|
406
|
+
* @param row - A row with an optional `signature`.
|
|
407
|
+
*/
|
|
408
|
+
function signedByKey(row) {
|
|
409
|
+
if (!row.signature)
|
|
410
|
+
return undefined;
|
|
411
|
+
const key = hashValue(canonicalJSONString(row));
|
|
412
|
+
let valid = signatureChecks.get(key);
|
|
413
|
+
if (valid === undefined) {
|
|
414
|
+
valid = isObjectSignatureValid(row);
|
|
415
|
+
if (signatureChecks.size >= SIGNATURE_CHECKS_MAX)
|
|
416
|
+
signatureChecks.clear();
|
|
417
|
+
signatureChecks.set(key, valid);
|
|
418
|
+
}
|
|
419
|
+
return valid ? getPublicKeyFromObjectSignature(row) : undefined;
|
|
420
|
+
}
|
|
394
421
|
/**
|
|
395
422
|
* Parses the Ed25519 public key prefix from a `publicKey:signature` field, or `undefined` if malformed.
|
|
396
423
|
*/
|
|
@@ -10,7 +10,7 @@ import type { IInstallOpts, IInstallResult, IPackageInfo, IPackageInstallerDeps
|
|
|
10
10
|
* triggers the package loader and device version resolution.
|
|
11
11
|
*
|
|
12
12
|
* When the bundle hash matches the existing PackageVersion, no files or PV are
|
|
13
|
-
* rewritten.
|
|
13
|
+
* rewritten. An Admin's Packages row still gets a missing `activePackageVersionId`
|
|
14
14
|
* (and description), and when the id was missing the version is activated on
|
|
15
15
|
* this device unless `skipResolve`.
|
|
16
16
|
*/
|
|
@@ -8,6 +8,8 @@ exports.getPackageInfo = getPackageInfo;
|
|
|
8
8
|
exports.getPackageLocalPath = getPackageLocalPath;
|
|
9
9
|
const file_types_1 = require("../data/files/file.types");
|
|
10
10
|
const files_1 = require("../data/files/files");
|
|
11
|
+
const group_member_roles_1 = require("../data/group-member-roles");
|
|
12
|
+
const group_permissions_1 = require("../data/group-permissions");
|
|
11
13
|
const package_version_resolver_1 = require("../data/package-version-resolver");
|
|
12
14
|
const package_versions_1 = require("../data/package-versions");
|
|
13
15
|
const packages_1 = require("../data/packages");
|
|
@@ -23,7 +25,7 @@ const package_author_signer_1 = require("./package-author-signer");
|
|
|
23
25
|
* triggers the package loader and device version resolution.
|
|
24
26
|
*
|
|
25
27
|
* When the bundle hash matches the existing PackageVersion, no files or PV are
|
|
26
|
-
* rewritten.
|
|
28
|
+
* rewritten. An Admin's Packages row still gets a missing `activePackageVersionId`
|
|
27
29
|
* (and description), and when the id was missing the version is activated on
|
|
28
30
|
* this device unless `skipResolve`.
|
|
29
31
|
*/
|
|
@@ -127,7 +129,8 @@ async function installPackageFromBundles(dataContext, deps, packageId, opts) {
|
|
|
127
129
|
* this device.
|
|
128
130
|
*
|
|
129
131
|
* Updates the description when it differs, and sets `activePackageVersionId`
|
|
130
|
-
* when it is empty
|
|
132
|
+
* when it is empty and the current user may select for the group (first install, or
|
|
133
|
+
* reimport after the row was deleted). Writers activate dev builds on their own device.
|
|
131
134
|
* Unless `skipResolve`, writes device prefs and force-resolves the version.
|
|
132
135
|
* With `resolveOnlyWhenActivated`, the device step runs only when this call
|
|
133
136
|
* filled an empty `activePackageVersionId`.
|
|
@@ -143,7 +146,9 @@ async function activateInstalledPackageVersion(dataContext, packageId, packageVe
|
|
|
143
146
|
needsSave = true;
|
|
144
147
|
}
|
|
145
148
|
const activated = !pkg.activePackageVersionId;
|
|
146
|
-
|
|
149
|
+
const canSelectForGroup = !dataContext.groupId ||
|
|
150
|
+
(await (0, group_permissions_1.getUserRole)(dataContext.groupId, dataContext.userContext.userId, dataContext.userContext)) >= group_member_roles_1.GroupMemberRole.Admin;
|
|
151
|
+
if (activated && canSelectForGroup) {
|
|
147
152
|
pkg.activePackageVersionId = packageVersion.packageVersionId;
|
|
148
153
|
needsSave = true;
|
|
149
154
|
}
|
|
@@ -22,8 +22,10 @@ export declare function propagatePvOnChanged(userContext?: UserContext): Promise
|
|
|
22
22
|
* any that are missing from admin groups. Useful for manual repair.
|
|
23
23
|
*/
|
|
24
24
|
export declare function discoverAndPropagateVersions(userContext: UserContext): Promise<IPropagationResult[]>;
|
|
25
|
+
/** Whether automatic follow policy selected a group release. */
|
|
25
26
|
export interface IActivationResult {
|
|
26
27
|
activated: boolean;
|
|
27
28
|
activePackageVersionId?: string;
|
|
28
29
|
}
|
|
30
|
+
/** Select the best publisher-signed release under an Admin-approved package's follow policy. */
|
|
29
31
|
export declare function activateBestEligibleVersion(dataContext: DataContext, pkg: IPackage): Promise<IActivationResult>;
|
|
@@ -4,6 +4,7 @@ exports.propagatePvOnChanged = propagatePvOnChanged;
|
|
|
4
4
|
exports.discoverAndPropagateVersions = discoverAndPropagateVersions;
|
|
5
5
|
exports.activateBestEligibleVersion = activateBestEligibleVersion;
|
|
6
6
|
const context_1 = require("../context");
|
|
7
|
+
const authority_write_checks_1 = require("../data/authority-write-checks");
|
|
7
8
|
const files_1 = require("../data/files/files");
|
|
8
9
|
const group_member_roles_1 = require("../data/group-member-roles");
|
|
9
10
|
const group_permissions_1 = require("../data/group-permissions");
|
|
@@ -113,12 +114,12 @@ async function propagatePvToAdminGroups(userContext, sourceContext, pv) {
|
|
|
113
114
|
*/
|
|
114
115
|
async function installPvInGroupNoActivate(source, dest, pv) {
|
|
115
116
|
const pkg = await (0, packages_1.Packages)(dest).get(pv.packageId);
|
|
116
|
-
if (!pkg || pkg.disabled)
|
|
117
|
+
if (!pkg || pkg.disabled || !(await (0, authority_write_checks_1.isPackageRowAdminSigned)(pkg, dest)))
|
|
117
118
|
return false;
|
|
118
119
|
const existingPv = await (0, package_versions_1.PackageVersions)(dest).get(pv.packageVersionId);
|
|
119
120
|
if (existingPv)
|
|
120
121
|
return false;
|
|
121
|
-
if (!(await
|
|
122
|
+
if (!(await verifyPinnedPublisher(dest, pkg, pv)))
|
|
122
123
|
return false;
|
|
123
124
|
const files = await copyBundleFiles(source, pv);
|
|
124
125
|
if (!files)
|
|
@@ -143,7 +144,8 @@ async function installPvInGroup(source, dest, pv, retryCnt = 0) {
|
|
|
143
144
|
await (0, utils_1.sleep)(delayMs);
|
|
144
145
|
}
|
|
145
146
|
const pkg = await (0, packages_1.Packages)(dest).get(pv.packageId);
|
|
146
|
-
|
|
147
|
+
// Copying signs the release with this device's key: only into a package an Admin added.
|
|
148
|
+
if (!pkg || pkg.disabled || !(await (0, authority_write_checks_1.isPackageRowAdminSigned)(pkg, dest)))
|
|
147
149
|
return undefined;
|
|
148
150
|
const existingPv = await (0, package_versions_1.PackageVersions)(dest).get(pv.packageVersionId);
|
|
149
151
|
if (existingPv) {
|
|
@@ -153,10 +155,8 @@ async function installPvInGroup(source, dest, pv, retryCnt = 0) {
|
|
|
153
155
|
? makeResult(dest, pv, activation.activePackageVersionId === pv.packageVersionId)
|
|
154
156
|
: undefined;
|
|
155
157
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return await retryOrFail(source, dest, pv, retryCnt, "TOFU");
|
|
159
|
-
}
|
|
158
|
+
if (!(await verifyPinnedPublisher(dest, pkg, pv)))
|
|
159
|
+
return undefined;
|
|
160
160
|
// Copy bundle files
|
|
161
161
|
const files = await copyBundleFiles(source, pv);
|
|
162
162
|
if (!files) {
|
|
@@ -184,45 +184,19 @@ async function retryOrFail(source, dest, pv, retryCnt, reason) {
|
|
|
184
184
|
console.error(`[propagation] ${reason} for ${pv.packageVersionId}, giving up`);
|
|
185
185
|
return undefined;
|
|
186
186
|
}
|
|
187
|
-
// --- TOFU ---
|
|
188
187
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* transient failures (missing source key).
|
|
188
|
+
* Another context can supply bytes, never a new trust root. The destination must already
|
|
189
|
+
* pin the publisher (or use the host's peers-core anchor) before this device endorses a release.
|
|
192
190
|
*/
|
|
193
|
-
async function
|
|
191
|
+
async function verifyPinnedPublisher(targetContext, targetPkg, pv) {
|
|
194
192
|
// peers-core pinned to a revoked key: move the pin to the host's current key first so a
|
|
195
193
|
// version signed by the replacement key can be accepted.
|
|
196
194
|
const repinned = await (0, peers_core_trust_anchor_1.repinPeersCoreIfRevoked)(targetContext, targetPkg);
|
|
197
195
|
if (repinned !== targetPkg) {
|
|
198
196
|
targetPkg.publishPublicKey = repinned.publishPublicKey;
|
|
199
197
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
console.error(`[propagation] Invalid signature for ${pv.packageVersionId}`);
|
|
203
|
-
return false;
|
|
204
|
-
}
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
|
-
// TOFU: get key from source
|
|
208
|
-
const sourcePkg = await (0, packages_1.Packages)(sourceContext).get(targetPkg.packageId);
|
|
209
|
-
if (!sourcePkg?.publishPublicKey)
|
|
210
|
-
return false;
|
|
211
|
-
// Never adopt a revoked key as a trust anchor, however it reached the source group.
|
|
212
|
-
if ((0, package_author_signing_1.isRevokedPublisherKey)(sourcePkg.publishPublicKey)) {
|
|
213
|
-
console.error(`[propagation] Refusing revoked publisher key for ${targetPkg.packageId} from ${sourceContext.dataContextId}`);
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
|
-
if (!(0, package_author_signing_1.verifyPackageAuthorSignature)(pv, sourcePkg.publishPublicKey).valid) {
|
|
217
|
-
console.error(`[propagation] Invalid signature for ${pv.packageVersionId} (TOFU)`);
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
await (0, packages_1.Packages)(targetContext).signAndSave({
|
|
221
|
-
...targetPkg,
|
|
222
|
-
publishPublicKey: sourcePkg.publishPublicKey,
|
|
223
|
-
});
|
|
224
|
-
targetPkg.publishPublicKey = sourcePkg.publishPublicKey;
|
|
225
|
-
return true;
|
|
198
|
+
return (!!targetPkg.publishPublicKey &&
|
|
199
|
+
(0, package_author_signing_1.verifyPackageAuthorSignature)(pv, targetPkg.publishPublicKey).valid);
|
|
226
200
|
}
|
|
227
201
|
/**
|
|
228
202
|
* Loads and verifies all bundle file records from source. Returns null if
|
|
@@ -272,7 +246,15 @@ async function saveFileAndIndexTree(sourceFiles, destFiles, file, copiedIds) {
|
|
|
272
246
|
}
|
|
273
247
|
await destFiles.saveFileRecord(file);
|
|
274
248
|
}
|
|
249
|
+
/** Select the best publisher-signed release under an Admin-approved package's follow policy. */
|
|
275
250
|
async function activateBestEligibleVersion(dataContext, pkg) {
|
|
251
|
+
// Callers may have copied files or waited for an activation lock since reading the row.
|
|
252
|
+
// Always decide from current, approved settings before signing a group selection.
|
|
253
|
+
const current = await (0, packages_1.Packages)(dataContext).get(pkg.packageId);
|
|
254
|
+
if (!current || current.disabled || !(await (0, authority_write_checks_1.isPackageRowAdminSigned)(current, dataContext))) {
|
|
255
|
+
return { activated: false };
|
|
256
|
+
}
|
|
257
|
+
pkg = current;
|
|
276
258
|
const range = pkg.versionFollowRange ?? "pinned";
|
|
277
259
|
if (range === "pinned")
|
|
278
260
|
return { activated: false };
|
|
@@ -10,6 +10,7 @@ exports.checkPackageRemoteForNewVersion = checkPackageRemoteForNewVersion;
|
|
|
10
10
|
exports.checkAndInstallPackageRemoteVersion = checkAndInstallPackageRemoteVersion;
|
|
11
11
|
exports.installRemotePackageVersion = installRemotePackageVersion;
|
|
12
12
|
exports.clearRemoteCheckCache = clearRemoteCheckCache;
|
|
13
|
+
const authority_write_checks_1 = require("../data/authority-write-checks");
|
|
13
14
|
const file_types_1 = require("../data/files/file.types");
|
|
14
15
|
const package_version_resolver_1 = require("../data/package-version-resolver");
|
|
15
16
|
const package_versions_1 = require("../data/package-versions");
|
|
@@ -45,12 +46,18 @@ function checkPackageRemoteForNewVersion(packageId, updateUrl, tag, http) {
|
|
|
45
46
|
* group does not already have the remote PackageVersion.
|
|
46
47
|
*/
|
|
47
48
|
async function checkAndInstallPackageRemoteVersion(dataContext, pkg, tag, http) {
|
|
48
|
-
|
|
49
|
-
if (!
|
|
49
|
+
let current = await (0, packages_1.Packages)(dataContext).get(pkg.packageId);
|
|
50
|
+
if (!current || current.disabled)
|
|
50
51
|
return null;
|
|
51
52
|
// A peers-core row pinned to a revoked publisher key would reject every new release; move
|
|
52
53
|
// it to the host's current anchor before looking at the remote.
|
|
53
|
-
await (0, peers_core_trust_anchor_1.repinPeersCoreIfRevoked)(dataContext,
|
|
54
|
+
current = await (0, peers_core_trust_anchor_1.repinPeersCoreIfRevoked)(dataContext, current);
|
|
55
|
+
// The release would be signed with this device's key: only for a package an Admin added.
|
|
56
|
+
if (!(await (0, authority_write_checks_1.isPackageRowAdminSigned)(current, dataContext)))
|
|
57
|
+
return null;
|
|
58
|
+
const updateUrl = current.updateUrl;
|
|
59
|
+
if (!updateUrl)
|
|
60
|
+
return null;
|
|
54
61
|
const result = await checkPackageRemoteForNewVersion(pkg.packageId, updateUrl, tag, http);
|
|
55
62
|
if (!result)
|
|
56
63
|
return null;
|
|
@@ -139,6 +146,11 @@ async function installRemotePackageVersion(dataContext, result) {
|
|
|
139
146
|
if (!pkg) {
|
|
140
147
|
throw new Error(`Cannot install remote package version: package ${packageId} is not installed`);
|
|
141
148
|
}
|
|
149
|
+
// The fetch may have outlived a delete/reinsert of the package. Never sign a release or
|
|
150
|
+
// establish a publisher pin on behalf of a newly added, unapproved row.
|
|
151
|
+
if (!(await (0, authority_write_checks_1.isPackageRowAdminSigned)(pkg, dataContext))) {
|
|
152
|
+
throw new Error("Cannot install remote package version: package settings need an Admin signature");
|
|
153
|
+
}
|
|
142
154
|
if (!unpacked.payload.publicKey) {
|
|
143
155
|
throw new Error("Cannot install remote package version: payload publicKey is missing");
|
|
144
156
|
}
|
|
@@ -783,8 +783,6 @@ function validateIsolatedPackageArtifact(artifact, options = {}) {
|
|
|
783
783
|
"tables",
|
|
784
784
|
"network",
|
|
785
785
|
"appNavs",
|
|
786
|
-
// Voice Skill v1's retired action aliases: an older manifest may carry them; ignored.
|
|
787
|
-
"actionAliases",
|
|
788
786
|
"executionMode",
|
|
789
787
|
"guestApi",
|
|
790
788
|
], "manifest");
|
|
@@ -751,9 +751,15 @@ class PackageLoader {
|
|
|
751
751
|
/* no version record */
|
|
752
752
|
}
|
|
753
753
|
}
|
|
754
|
+
if (packageVersion) {
|
|
755
|
+
await (0, package_version_resolver_1.assertPackageVersionRunnable)(pkg, packageVersion, this.dataContext, !!opts?.localPath);
|
|
756
|
+
}
|
|
754
757
|
if (bundleFileId) {
|
|
755
758
|
const bundleBuffer = await (0, files_1.Files)(this.dataContext).getFileContents(bundleFileId);
|
|
756
759
|
if (bundleBuffer) {
|
|
760
|
+
if (this.dataContext.groupId && packageVersion) {
|
|
761
|
+
(0, package_version_resolver_1.assertPackageBundleIntegrity)(packageVersion, "package", bundleBuffer);
|
|
762
|
+
}
|
|
757
763
|
bundleCode = Buffer.from(bundleBuffer).toString("utf8");
|
|
758
764
|
}
|
|
759
765
|
else if (warn) {
|
|
@@ -7,6 +7,8 @@ export interface IPeerDevice {
|
|
|
7
7
|
deviceId: string;
|
|
8
8
|
/** User identity that owns this device. */
|
|
9
9
|
userId: string;
|
|
10
|
+
/** Signing key the device authenticated with, for a remote device: roles are checked against it. */
|
|
11
|
+
publicKey?: string;
|
|
10
12
|
/** Role used when this device participates in a shared group. */
|
|
11
13
|
role: GroupMemberRole;
|
|
12
14
|
/** Lists change records available from this device. */
|
package/dist/types/workflow.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ export declare const workflowSchema: z.ZodObject<{
|
|
|
45
45
|
name: string;
|
|
46
46
|
description: string;
|
|
47
47
|
updatedAt: Date;
|
|
48
|
+
createdBy: string;
|
|
48
49
|
createdAt: Date;
|
|
49
50
|
workflowId: string;
|
|
50
51
|
defaultAssistantId: string;
|
|
@@ -54,14 +55,13 @@ export declare const workflowSchema: z.ZodObject<{
|
|
|
54
55
|
directCallToolId?: string | undefined;
|
|
55
56
|
subWorkflowId?: string | undefined;
|
|
56
57
|
}[];
|
|
57
|
-
createdBy: string;
|
|
58
58
|
packageId?: string | undefined;
|
|
59
59
|
}, {
|
|
60
60
|
name: string;
|
|
61
61
|
description: string;
|
|
62
|
+
createdBy: string;
|
|
62
63
|
workflowId: string;
|
|
63
64
|
defaultAssistantId: string;
|
|
64
|
-
createdBy: string;
|
|
65
65
|
updatedAt?: Date | undefined;
|
|
66
66
|
packageId?: string | undefined;
|
|
67
67
|
createdAt?: Date | undefined;
|
package/package.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { IPackage } from "./packages";
|
|
2
|
-
/**
|
|
3
|
-
* Verifies that a package update signature is valid.
|
|
4
|
-
*
|
|
5
|
-
* Writers can create or update packages that have a dev active version.
|
|
6
|
-
* Admins are required for packages with beta or stable active versions.
|
|
7
|
-
*
|
|
8
|
-
* @param packageObj The package record to verify
|
|
9
|
-
* @param opts.isDevVersion When true, allows Writer role (for dev version operations)
|
|
10
|
-
* @throws Error if signature is invalid or unauthorized
|
|
11
|
-
*/
|
|
12
|
-
export declare function verifyPackageSignature(packageObj: IPackage, groupId: string, opts?: {
|
|
13
|
-
isDevVersion?: boolean;
|
|
14
|
-
}): Promise<void>;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.verifyPackageSignature = verifyPackageSignature;
|
|
4
|
-
const keys_1 = require("../keys");
|
|
5
|
-
const group_permissions_1 = require("./group-permissions");
|
|
6
|
-
/**
|
|
7
|
-
* Verifies that a package update signature is valid.
|
|
8
|
-
*
|
|
9
|
-
* Writers can create or update packages that have a dev active version.
|
|
10
|
-
* Admins are required for packages with beta or stable active versions.
|
|
11
|
-
*
|
|
12
|
-
* @param packageObj The package record to verify
|
|
13
|
-
* @param opts.isDevVersion When true, allows Writer role (for dev version operations)
|
|
14
|
-
* @throws Error if signature is invalid or unauthorized
|
|
15
|
-
*/
|
|
16
|
-
async function verifyPackageSignature(packageObj, groupId, opts) {
|
|
17
|
-
(0, keys_1.verifyObjectSignature)(packageObj);
|
|
18
|
-
const signerPublicKey = (0, keys_1.getPublicKeyFromObjectSignature)(packageObj) ?? "";
|
|
19
|
-
const signerRole = await (0, group_permissions_1.getUserRoleFromPublicKey)(groupId, signerPublicKey);
|
|
20
|
-
const requiredRole = opts?.isDevVersion ? group_permissions_1.GroupMemberRole.Writer : group_permissions_1.GroupMemberRole.Admin;
|
|
21
|
-
if (signerRole < requiredRole) {
|
|
22
|
-
throw new Error(opts?.isDevVersion
|
|
23
|
-
? "Only group writers or above can create or update dev packages"
|
|
24
|
-
: "Only group admins can create or update packages");
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { GroupMemberRole } from "./group-permissions";
|
|
2
|
-
import type { IPackageVersion } from "./package-versions";
|
|
3
|
-
/**
|
|
4
|
-
* Verifies that a package version update signature is valid.
|
|
5
|
-
*
|
|
6
|
-
* Dev versions (`versionTag === "dev"`) require Writer role.
|
|
7
|
-
* Beta and stable versions require Admin role.
|
|
8
|
-
*
|
|
9
|
-
* @param packageVersion The package version record to verify
|
|
10
|
-
* @param groupId The group context to check roles against
|
|
11
|
-
* @param signerRole Optional pre-resolved role (skips `getUserRoleFromPublicKey` lookup; useful in tests)
|
|
12
|
-
* @throws Error if signature is invalid or unauthorized
|
|
13
|
-
*/
|
|
14
|
-
export declare function verifyPackageVersionSignature(packageVersion: IPackageVersion, groupId: string, signerRole?: GroupMemberRole): Promise<void>;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.verifyPackageVersionSignature = verifyPackageVersionSignature;
|
|
4
|
-
const keys_1 = require("../keys");
|
|
5
|
-
const group_permissions_1 = require("./group-permissions");
|
|
6
|
-
/**
|
|
7
|
-
* Verifies that a package version update signature is valid.
|
|
8
|
-
*
|
|
9
|
-
* Dev versions (`versionTag === "dev"`) require Writer role.
|
|
10
|
-
* Beta and stable versions require Admin role.
|
|
11
|
-
*
|
|
12
|
-
* @param packageVersion The package version record to verify
|
|
13
|
-
* @param groupId The group context to check roles against
|
|
14
|
-
* @param signerRole Optional pre-resolved role (skips `getUserRoleFromPublicKey` lookup; useful in tests)
|
|
15
|
-
* @throws Error if signature is invalid or unauthorized
|
|
16
|
-
*/
|
|
17
|
-
async function verifyPackageVersionSignature(packageVersion, groupId, signerRole) {
|
|
18
|
-
(0, keys_1.verifyObjectSignature)(packageVersion);
|
|
19
|
-
if (signerRole === undefined) {
|
|
20
|
-
const signerPublicKey = (0, keys_1.getPublicKeyFromObjectSignature)(packageVersion) ?? "";
|
|
21
|
-
signerRole = await (0, group_permissions_1.getUserRoleFromPublicKey)(groupId, signerPublicKey);
|
|
22
|
-
}
|
|
23
|
-
const isDevVersion = packageVersion.versionTag === "dev";
|
|
24
|
-
const requiredRole = isDevVersion ? group_permissions_1.GroupMemberRole.Writer : group_permissions_1.GroupMemberRole.Admin;
|
|
25
|
-
if (signerRole < requiredRole) {
|
|
26
|
-
throw new Error(isDevVersion
|
|
27
|
-
? "Only group writers or above can create dev package versions"
|
|
28
|
-
: "Only group admins can create or update beta/stable package versions");
|
|
29
|
-
}
|
|
30
|
-
}
|