agent-comms 4.3.0 → 4.5.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +9 -2
- package/dist/bridges/user/web/dist/mesh-worker.js +1 -1
- package/dist/bridges/user/web/dist/sw.js +1 -1
- package/dist/core/agent-registry.d.ts.map +1 -1
- package/dist/core/agent-registry.js +2 -0
- package/dist/core/agent-registry.js.map +1 -1
- package/dist/core/bridge-mesh.d.ts.map +1 -1
- package/dist/core/bridge-mesh.js +1 -0
- package/dist/core/bridge-mesh.js.map +1 -1
- package/dist/core/bridge.d.ts.map +1 -1
- package/dist/core/bridge.js +6 -2
- package/dist/core/bridge.js.map +1 -1
- package/dist/core/device-membership-verification.d.ts +2 -1
- package/dist/core/device-membership-verification.d.ts.map +1 -1
- package/dist/core/device-membership-verification.js +1 -1
- package/dist/core/device-membership-verification.js.map +1 -1
- package/dist/core/device-membership.d.ts +2 -0
- package/dist/core/device-membership.d.ts.map +1 -1
- package/dist/core/device-membership.js +9 -5
- package/dist/core/device-membership.js.map +1 -1
- package/dist/core/directory-admission.d.ts +20 -0
- package/dist/core/directory-admission.d.ts.map +1 -0
- package/dist/core/directory-admission.js +88 -0
- package/dist/core/directory-admission.js.map +1 -0
- package/dist/core/dm-grant-actions.d.ts +2 -2
- package/dist/core/dm-grant-actions.d.ts.map +1 -1
- package/dist/core/dm-grant-actions.js +10 -5
- package/dist/core/dm-grant-actions.js.map +1 -1
- package/dist/core/gateway-trust-actions.d.ts +1 -1
- package/dist/core/gateway-trust-actions.d.ts.map +1 -1
- package/dist/core/gateway-trust-actions.js +5 -1
- package/dist/core/gateway-trust-actions.js.map +1 -1
- package/dist/core/gateway-trust.d.ts +14 -2
- package/dist/core/gateway-trust.d.ts.map +1 -1
- package/dist/core/gateway-trust.js +40 -2
- package/dist/core/gateway-trust.js.map +1 -1
- package/dist/core/gossip-directory.d.ts +2 -0
- package/dist/core/gossip-directory.d.ts.map +1 -1
- package/dist/core/gossip-directory.js +9 -0
- package/dist/core/gossip-directory.js.map +1 -1
- package/dist/core/gossip-extensions.d.ts +2 -0
- package/dist/core/gossip-extensions.d.ts.map +1 -1
- package/dist/core/hub-session.d.ts +3 -3
- package/dist/core/hub-session.d.ts.map +1 -1
- package/dist/core/hub-session.js +6 -4
- package/dist/core/hub-session.js.map +1 -1
- package/dist/core/membership-proof.d.ts +45 -0
- package/dist/core/membership-proof.d.ts.map +1 -0
- package/dist/core/membership-proof.js +59 -0
- package/dist/core/membership-proof.js.map +1 -0
- package/dist/core/membership-proofs.d.ts +34 -0
- package/dist/core/membership-proofs.d.ts.map +1 -0
- package/dist/core/membership-proofs.js +66 -0
- package/dist/core/membership-proofs.js.map +1 -0
- package/dist/core/mesh-store.d.ts +12 -0
- package/dist/core/mesh-store.d.ts.map +1 -1
- package/dist/core/mesh-store.js +26 -0
- package/dist/core/mesh-store.js.map +1 -1
- package/dist/core/room-lifecycle.d.ts +6 -0
- package/dist/core/room-lifecycle.d.ts.map +1 -1
- package/dist/core/room-lifecycle.js +52 -1
- package/dist/core/room-lifecycle.js.map +1 -1
- package/dist/core/tool.d.ts +10 -3
- package/dist/core/tool.d.ts.map +1 -1
- package/dist/core/tool.js +2 -0
- package/dist/core/tool.js.map +1 -1
- package/dist/core/types.d.ts +2 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +6 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/wire-mesh-transport-options.d.ts +12 -0
- package/dist/core/wire-mesh-transport-options.d.ts.map +1 -1
- package/dist/core/wire-mesh-transport.d.ts +1 -1
- package/dist/core/wire-mesh-transport.d.ts.map +1 -1
- package/dist/core/wire-mesh-transport.js +5 -5
- package/dist/core/wire-mesh-transport.js.map +1 -1
- package/dist/test/directory-admission.unit.test.d.ts +2 -0
- package/dist/test/directory-admission.unit.test.d.ts.map +1 -0
- package/dist/test/directory-admission.unit.test.js +182 -0
- package/dist/test/directory-admission.unit.test.js.map +1 -0
- package/dist/test/dm-grant-actions.unit.test.js +13 -7
- package/dist/test/dm-grant-actions.unit.test.js.map +1 -1
- package/dist/test/dm-grant-tool.integration.test.js +115 -2
- package/dist/test/dm-grant-tool.integration.test.js.map +1 -1
- package/dist/test/gateway-trust-tool.integration.test.js +22 -0
- package/dist/test/gateway-trust-tool.integration.test.js.map +1 -1
- package/dist/test/gateway-trust.unit.test.js +82 -1
- package/dist/test/gateway-trust.unit.test.js.map +1 -1
- package/dist/test/membership-proof.unit.test.d.ts +2 -0
- package/dist/test/membership-proof.unit.test.d.ts.map +1 -0
- package/dist/test/membership-proof.unit.test.js +148 -0
- package/dist/test/membership-proof.unit.test.js.map +1 -0
- package/dist/test/principal-membership-trust.integration.test.d.ts +5 -0
- package/dist/test/principal-membership-trust.integration.test.d.ts.map +1 -0
- package/dist/test/principal-membership-trust.integration.test.js +169 -0
- package/dist/test/principal-membership-trust.integration.test.js.map +1 -0
- package/dist/test/test-transport.d.ts.map +1 -1
- package/dist/test/test-transport.js +1 -0
- package/dist/test/test-transport.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,11 +9,9 @@ import { DEVICE_MEMBER_CAPABILITY, userGroupPath, } from "./device-membership-ve
|
|
|
9
9
|
import { deleteIssuedDeviceGrant, loadIssuedDeviceGrant, saveIssuedDeviceGrant, } from "./user-identity.js";
|
|
10
10
|
/** delegationsRemaining for every device-membership grant -- deliberately non-delegable: a device that could re-mint membership for another device would let any admitted device silently admit others, defeating the point of the principal being the one place admission is decided (the same reasoning room-lifecycle.ts's own mintOwnerRootGrant already documents for a room owner's self-grant). */
|
|
11
11
|
const NOT_DELEGABLE = 0;
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export async function admitDevice(options) {
|
|
16
|
-
const verdict = await mintCapabilityToken({
|
|
12
|
+
/** The group:member token itself, with no record kept of having issued it: a root-level, non-delegable grant bearing options.deviceId and scoped to the principal's own group (userGroupPath). admitDevice adds the issued-grant bookkeeping a later removeDevice needs; a caller that only needs a short-lived proof (membership-proof.ts) uses this directly, so the account's shared user-identity.json is not rewritten every time one of its many bridges refreshes its proof. */
|
|
13
|
+
export async function mintDeviceMembership(options) {
|
|
14
|
+
return mintCapabilityToken({
|
|
17
15
|
identity: options.userIdentity,
|
|
18
16
|
clock: options.clock,
|
|
19
17
|
tokenId: options.tokenId,
|
|
@@ -26,6 +24,12 @@ export async function admitDevice(options) {
|
|
|
26
24
|
expires: options.expires,
|
|
27
25
|
delegationsRemaining: NOT_DELEGABLE,
|
|
28
26
|
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Mints deviceId's own group:member grant from the user principal: a root-level, non-delegable token scoped to the principal's own group (userGroupPath). On success, records the grant's token-id under the principal's own issued-grant store so a later removeDevice call can find it to revoke -- an admission without this bookkeeping would leave removal permanently unable to find what to revoke, so this is not optional side-book-keeping, it is what makes revocation possible at all.
|
|
30
|
+
*/
|
|
31
|
+
export async function admitDevice(options) {
|
|
32
|
+
const verdict = await mintDeviceMembership(options);
|
|
29
33
|
if (!verdict.ok)
|
|
30
34
|
return verdict;
|
|
31
35
|
saveIssuedDeviceGrant(options.userIdentityOptions, deviceIdToHex(options.deviceId), options.tokenId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-membership.js","sourceRoot":"","sources":["../../src/core/device-membership.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GAEpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAQhE,OAAO,EACL,wBAAwB,EACxB,aAAa,GACd,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,GAEtB,MAAM,oBAAoB,CAAC;AAE5B,0YAA0Y;AAC1Y,MAAM,aAAa,GAAG,CAAC,CAAC;AAcxB
|
|
1
|
+
{"version":3,"file":"device-membership.js","sourceRoot":"","sources":["../../src/core/device-membership.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GAEpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAQhE,OAAO,EACL,wBAAwB,EACxB,aAAa,GACd,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,GAEtB,MAAM,oBAAoB,CAAC;AAE5B,0YAA0Y;AAC1Y,MAAM,aAAa,GAAG,CAAC,CAAC;AAcxB,udAAud;AACvd,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAKC;IAED,OAAO,mBAAmB,CAAC;QACzB,QAAQ,EAAE,OAAO,CAAC,YAAY;QAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,OAAO,CAAC,QAAQ;QACxB,UAAU,EAAE,wBAAwB;QACpC,KAAK,EAAE;YACL,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC;SACnD;QACD,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,oBAAoB,EAAE,aAAa;KACpC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAqC;IAErC,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC;IAEhC,qBAAqB,CACnB,OAAO,CAAC,mBAAmB,EAC3B,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,EAC/B,OAAO,CAAC,OAAO,CAChB,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC;AAYD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAsC;IAEtC,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;IAC9E,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE5C,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC;QACtC,QAAQ,EAAE,OAAO,CAAC,YAAY;QAC9B,OAAO;QACP,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE;KAC/B,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC3E,uBAAuB,CAAC,OAAO,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;IAChE,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which gossiped directory entries from the hub a gateway merges (agent-comms#156, widened by #187 and #266). Split out of WireMeshTransport, which hands it the two collaborators it needs.
|
|
3
|
+
*
|
|
4
|
+
* A membership proof shows that a trusted principal vouches for a device id. It does not show that whoever sent the advert is that device: the id and the proof both arrive in the same unauthenticated advert, and anyone who has read one can repeat it. So it earns only what GatewayTrust.isReachable grants (a directory entry and a route), never isTrusted, and everything a request to such a device carries is authenticated by the end-to-end session inside the relay. Verifying a proof is cryptography, so the work is bounded here: verdicts are remembered, a batch verifies only so many new proofs, and a verifier that throws refuses the entry rather than breaking the merge.
|
|
5
|
+
*/
|
|
6
|
+
import type { DirectoryEntry } from "wire-mesh-core/domain/mesh-session";
|
|
7
|
+
import type { GatewayTrustReader } from "./gateway-trust.js";
|
|
8
|
+
import type { WireMeshTransportOptions } from "./wire-mesh-transport-options.js";
|
|
9
|
+
/** How many new proofs one batch of entries may verify. Trusted devices and proofs already judged cost nothing against it, so a flood of fresh adverts costs a bounded amount of work per batch and the rest wait for the next. */
|
|
10
|
+
export declare const MAX_VERIFICATIONS_PER_BATCH = 8;
|
|
11
|
+
/** How long a refused proof is remembered before it is worth checking again: long enough that a repeated bad proof is not re-verified on every frame, short enough that a principal trusted a moment later takes effect promptly. */
|
|
12
|
+
export declare const NEGATIVE_VERDICT_TTL_MS: number;
|
|
13
|
+
export interface DirectoryAdmissionDeps {
|
|
14
|
+
gatewayTrust: Readonly<GatewayTrustReader>;
|
|
15
|
+
/** Absent when this side cannot verify proofs, in which case a proof is never enough. */
|
|
16
|
+
verifyMembership: WireMeshTransportOptions["verifyMembership"];
|
|
17
|
+
}
|
|
18
|
+
/** Builds the admission check for a transport's directory merge: given a batch of entries, the ones to merge. An entry is merged if its device is trusted by id, is itself a trusted principal's own device, or carries a proof that a trusted principal vouches for it; a verified device is recorded in gatewayTrust until the proof lapses or its principal stops being trusted. A device's newer proof is verified as it arrives, which is how its trust is renewed before the old one lapses. */
|
|
19
|
+
export declare function directoryAdmission(deps: Readonly<DirectoryAdmissionDeps>): (entries: readonly DirectoryEntry[]) => Promise<DirectoryEntry[]>;
|
|
20
|
+
//# sourceMappingURL=directory-admission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-admission.d.ts","sourceRoot":"","sources":["../../src/core/directory-admission.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAEjF,mOAAmO;AACnO,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAI7C,qOAAqO;AACrO,eAAO,MAAM,uBAAuB,QACU,CAAC;AAK/C,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC3C,yFAAyF;IACzF,gBAAgB,EAAE,wBAAwB,CAAC,kBAAkB,CAAC,CAAC;CAChE;AASD,seAAse;AACte,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,CAAC,sBAAsB,CAAC,GACrC,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,KAAK,OAAO,CAAC,cAAc,EAAE,CAAC,CA6EnE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which gossiped directory entries from the hub a gateway merges (agent-comms#156, widened by #187 and #266). Split out of WireMeshTransport, which hands it the two collaborators it needs.
|
|
3
|
+
*
|
|
4
|
+
* A membership proof shows that a trusted principal vouches for a device id. It does not show that whoever sent the advert is that device: the id and the proof both arrive in the same unauthenticated advert, and anyone who has read one can repeat it. So it earns only what GatewayTrust.isReachable grants (a directory entry and a route), never isTrusted, and everything a request to such a device carries is authenticated by the end-to-end session inside the relay. Verifying a proof is cryptography, so the work is bounded here: verdicts are remembered, a batch verifies only so many new proofs, and a verifier that throws refuses the entry rather than breaking the merge.
|
|
5
|
+
*/
|
|
6
|
+
import { deviceIdToHex } from "wire-mesh-core/domain/device-id";
|
|
7
|
+
import { readMembershipProof } from "./gossip-directory.js";
|
|
8
|
+
/** How many new proofs one batch of entries may verify. Trusted devices and proofs already judged cost nothing against it, so a flood of fresh adverts costs a bounded amount of work per batch and the rest wait for the next. */
|
|
9
|
+
export const MAX_VERIFICATIONS_PER_BATCH = 8;
|
|
10
|
+
const MS_PER_SECOND = 1000;
|
|
11
|
+
const NEGATIVE_VERDICT_TTL_SECONDS = 60;
|
|
12
|
+
/** How long a refused proof is remembered before it is worth checking again: long enough that a repeated bad proof is not re-verified on every frame, short enough that a principal trusted a moment later takes effect promptly. */
|
|
13
|
+
export const NEGATIVE_VERDICT_TTL_MS = NEGATIVE_VERDICT_TTL_SECONDS * MS_PER_SECOND;
|
|
14
|
+
/** The most devices whose last verdict is remembered. */
|
|
15
|
+
const VERDICT_CACHE_LIMIT = 1024;
|
|
16
|
+
/** Builds the admission check for a transport's directory merge: given a batch of entries, the ones to merge. An entry is merged if its device is trusted by id, is itself a trusted principal's own device, or carries a proof that a trusted principal vouches for it; a verified device is recorded in gatewayTrust until the proof lapses or its principal stops being trusted. A device's newer proof is verified as it arrives, which is how its trust is renewed before the old one lapses. */
|
|
17
|
+
export function directoryAdmission(deps) {
|
|
18
|
+
const { gatewayTrust, verifyMembership } = deps;
|
|
19
|
+
const verdicts = new Map();
|
|
20
|
+
const remember = (deviceHex, verdict) => {
|
|
21
|
+
verdicts.delete(deviceHex);
|
|
22
|
+
verdicts.set(deviceHex, verdict);
|
|
23
|
+
if (verdicts.size > VERDICT_CACHE_LIMIT) {
|
|
24
|
+
const oldest = verdicts.keys().next();
|
|
25
|
+
if (oldest.done !== true)
|
|
26
|
+
verdicts.delete(oldest.value);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
/** The expiry of the first trusted principal's verdict that vouches for the proof, or undefined. A principal the verifier throws on (a malformed id, or no identity attached yet) is skipped, so one bad principal never blocks the others. */
|
|
30
|
+
const vouchedFor = async (proof, deviceHex) => {
|
|
31
|
+
if (verifyMembership === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
for (const principal of gatewayTrust.listPrincipals()) {
|
|
34
|
+
try {
|
|
35
|
+
const verdict = await verifyMembership({
|
|
36
|
+
proof,
|
|
37
|
+
deviceHex,
|
|
38
|
+
principalHex: principal,
|
|
39
|
+
});
|
|
40
|
+
if (verdict.ok)
|
|
41
|
+
return { principal, expires: verdict.expires };
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
};
|
|
49
|
+
return async (entries) => {
|
|
50
|
+
const admitted = [];
|
|
51
|
+
let budget = MAX_VERIFICATIONS_PER_BATCH;
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
const deviceHex = deviceIdToHex(entry.device);
|
|
54
|
+
if (gatewayTrust.isTrusted(deviceHex) ||
|
|
55
|
+
gatewayTrust.isTrustedPrincipal(deviceHex)) {
|
|
56
|
+
admitted.push(entry);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const proof = readMembershipProof(entry.advert);
|
|
60
|
+
if (proof === undefined || verifyMembership === undefined)
|
|
61
|
+
continue;
|
|
62
|
+
const known = verdicts.get(deviceHex);
|
|
63
|
+
if (known?.proof === proof) {
|
|
64
|
+
if (known.ok && gatewayTrust.isReachable(deviceHex)) {
|
|
65
|
+
admitted.push(entry);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (!known.ok && known.until > Date.now())
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (budget === 0)
|
|
72
|
+
continue;
|
|
73
|
+
budget -= 1;
|
|
74
|
+
const vouch = await vouchedFor(proof, deviceHex);
|
|
75
|
+
remember(deviceHex, {
|
|
76
|
+
proof,
|
|
77
|
+
ok: vouch !== undefined,
|
|
78
|
+
until: Date.now() + NEGATIVE_VERDICT_TTL_MS,
|
|
79
|
+
});
|
|
80
|
+
if (vouch !== undefined) {
|
|
81
|
+
gatewayTrust.noteVerifiedMember(deviceHex, vouch.principal, vouch.expires);
|
|
82
|
+
admitted.push(entry);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return admitted;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=directory-admission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-admission.js","sourceRoot":"","sources":["../../src/core/directory-admission.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { CommsAction } from "./types.js";
|
|
7
7
|
import type { CommsResult, MeshOnlyFeatures } from "./tool.js";
|
|
8
|
-
/** Admits action.target to DM this user ahead of time. `receiverId` is this agent's own device-id, which the returned instructions name so the sender can quote them back verbatim. */
|
|
8
|
+
/** Admits action.target to DM this user ahead of time: that one device, or, with action.principal, every device of that user principal. `receiverId` is this agent's own device-id, which the returned instructions name so the sender can quote them back verbatim. */
|
|
9
9
|
export declare function dmAdmit(store: Readonly<Pick<MeshOnlyFeatures, "admitAgentForDm">>, action: CommsAction & {
|
|
10
10
|
action: "dm_admit";
|
|
11
11
|
}, receiverId: string): Promise<CommsResult>;
|
|
12
12
|
/** Presents action.grant to action.target so this device's DMs to it are admitted without a decision. Throws INVALID_TOKEN, before contacting anyone, when the grant text is not a token. */
|
|
13
|
-
export declare function dmUseGrant(store: Readonly<Pick<MeshOnlyFeatures, "
|
|
13
|
+
export declare function dmUseGrant(store: Readonly<Pick<MeshOnlyFeatures, "presentDmGrant">>, action: CommsAction & {
|
|
14
14
|
action: "dm_use_grant";
|
|
15
15
|
}): Promise<CommsResult>;
|
|
16
16
|
/** Withdraws the grant admitted for action.target, if one was ever issued. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dm-grant-actions.d.ts","sourceRoot":"","sources":["../../src/core/dm-grant-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"dm-grant-actions.d.ts","sourceRoot":"","sources":["../../src/core/dm-grant-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAc/D,wQAAwQ;AACxQ,wBAAsB,OAAO,CAC3B,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC,EAC1D,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,EAC5C,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC,CAkBtB;AAED,6LAA6L;AAC7L,wBAAsB,UAAU,CAC9B,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,EACzD,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,GAC/C,OAAO,CAAC,WAAW,CAAC,CAQtB;AAED,8EAA8E;AAC9E,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CAAC,EAC9D,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GAC5C,OAAO,CAAC,WAAW,CAAC,CAOtB"}
|
|
@@ -11,14 +11,19 @@ function grantsUnavailable() {
|
|
|
11
11
|
isError: true,
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
14
|
+
/** How many further hops a grant admitting a user principal permits: the principal delegating to one of its own devices. */
|
|
15
|
+
const PRINCIPAL_DELEGATION_DEPTH = 1;
|
|
16
|
+
/** Admits action.target to DM this user ahead of time: that one device, or, with action.principal, every device of that user principal. `receiverId` is this agent's own device-id, which the returned instructions name so the sender can quote them back verbatim. */
|
|
15
17
|
export async function dmAdmit(store, action, receiverId) {
|
|
16
18
|
if (!store.admitAgentForDm)
|
|
17
19
|
return grantsUnavailable();
|
|
18
|
-
const grant = await store.admitAgentForDm(action.target);
|
|
20
|
+
const grant = await store.admitAgentForDm(action.target, action.principal === true ? PRINCIPAL_DELEGATION_DEPTH : 0);
|
|
21
|
+
const who = action.principal === true
|
|
22
|
+
? `${action.target} and every device of that user`
|
|
23
|
+
: action.target;
|
|
19
24
|
return {
|
|
20
25
|
content: [
|
|
21
|
-
`Admitted ${
|
|
26
|
+
`Admitted ${who} to DM you without asking again.`,
|
|
22
27
|
`Give them this grant, and have them call dm_use_grant with target ${receiverId} and this grant:`,
|
|
23
28
|
encodeTokenText(grant),
|
|
24
29
|
].join("\n"),
|
|
@@ -27,10 +32,10 @@ export async function dmAdmit(store, action, receiverId) {
|
|
|
27
32
|
}
|
|
28
33
|
/** Presents action.grant to action.target so this device's DMs to it are admitted without a decision. Throws INVALID_TOKEN, before contacting anyone, when the grant text is not a token. */
|
|
29
34
|
export async function dmUseGrant(store, action) {
|
|
30
|
-
if (!store.
|
|
35
|
+
if (!store.presentDmGrant)
|
|
31
36
|
return grantsUnavailable();
|
|
32
37
|
const grant = decodeTokenText(action.grant);
|
|
33
|
-
await store.
|
|
38
|
+
await store.presentDmGrant(action.target, grant);
|
|
34
39
|
return {
|
|
35
40
|
content: `DM access to ${action.target} granted; you can now dm it.`,
|
|
36
41
|
isError: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dm-grant-actions.js","sourceRoot":"","sources":["../../src/core/dm-grant-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEnE,oHAAoH;AACpH,SAAS,iBAAiB;IACxB,OAAO;QACL,OAAO,EAAE,4CAA4C;QACrD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"dm-grant-actions.js","sourceRoot":"","sources":["../../src/core/dm-grant-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEnE,oHAAoH;AACpH,SAAS,iBAAiB;IACxB,OAAO;QACL,OAAO,EAAE,4CAA4C;QACrD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,4HAA4H;AAC5H,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAErC,wQAAwQ;AACxQ,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAA0D,EAC1D,MAA4C,EAC5C,UAAkB;IAElB,IAAI,CAAC,KAAK,CAAC,eAAe;QAAE,OAAO,iBAAiB,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,eAAe,CACvC,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAC3D,CAAC;IACF,MAAM,GAAG,GACP,MAAM,CAAC,SAAS,KAAK,IAAI;QACvB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,gCAAgC;QAClD,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;IACpB,OAAO;QACL,OAAO,EAAE;YACP,YAAY,GAAG,kCAAkC;YACjD,qEAAqE,UAAU,kBAAkB;YACjG,eAAe,CAAC,KAAK,CAAC;SACvB,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,KAAK;KACf,CAAC;AACJ,CAAC;AAED,6LAA6L;AAC7L,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAyD,EACzD,MAAgD;IAEhD,IAAI,CAAC,KAAK,CAAC,cAAc;QAAE,OAAO,iBAAiB,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACjD,OAAO;QACL,OAAO,EAAE,gBAAgB,MAAM,CAAC,MAAM,8BAA8B;QACpE,OAAO,EAAE,KAAK;KACf,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,KAA8D,EAC9D,MAA6C;IAE7C,IAAI,CAAC,KAAK,CAAC,mBAAmB;QAAE,OAAO,iBAAiB,EAAE,CAAC;IAC3D,MAAM,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/C,OAAO;QACL,OAAO,EAAE,WAAW,MAAM,CAAC,MAAM,cAAc;QAC/C,OAAO,EAAE,KAAK;KACf,CAAC;AACJ,CAAC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import type { CommsAction } from "./types.js";
|
|
5
5
|
import type { CommsResult, MeshOnlyFeatures } from "./tool.js";
|
|
6
6
|
/** The slice of MeshOnlyFeatures the three functions below actually need, named so this file doesn't repeat the same six-method Pick inline at every signature. */
|
|
7
|
-
export type GatewayTrustStore = Pick<MeshOnlyFeatures, "addTrustedGateway" | "removeTrustedGateway" | "listTrustedGateways" | "addTrustedGatewayPrincipal" | "removeTrustedGatewayPrincipal" | "listTrustedGatewayPrincipals">;
|
|
7
|
+
export type GatewayTrustStore = Pick<MeshOnlyFeatures, "addTrustedGateway" | "removeTrustedGateway" | "listTrustedGateways" | "addTrustedGatewayPrincipal" | "removeTrustedGatewayPrincipal" | "listTrustedGatewayPrincipals" | "listVerifiedMembers">;
|
|
8
8
|
/** Trusts action.device: as a user principal (GatewayTrust.addPrincipal, agent-comms#187) when action.principal is true, or as a bare remote device-id (the original agent-comms#156 behaviour) otherwise. */
|
|
9
9
|
export declare function gatewayTrust(store: Readonly<GatewayTrustStore>, action: CommsAction & {
|
|
10
10
|
action: "gateway_trust";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-trust-actions.d.ts","sourceRoot":"","sources":["../../src/core/gateway-trust-actions.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE/D,mKAAmK;AACnK,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,gBAAgB,EACd,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,4BAA4B,GAC5B,+BAA+B,GAC/B,8BAA8B,
|
|
1
|
+
{"version":3,"file":"gateway-trust-actions.d.ts","sourceRoot":"","sources":["../../src/core/gateway-trust-actions.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE/D,mKAAmK;AACnK,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,gBAAgB,EACd,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,4BAA4B,GAC5B,+BAA+B,GAC/B,8BAA8B,GAC9B,qBAAqB,CACxB,CAAC;AAUF,8MAA8M;AAC9M,wBAAgB,YAAY,CAC1B,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EAClC,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAChD,WAAW,CAeb;AAED,4OAA4O;AAC5O,wBAAgB,cAAc,CAC5B,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EAClC,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAClD,WAAW,CAeb;AAED,wRAAwR;AACxR,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACjC,WAAW,CA+Bb"}
|
|
@@ -49,7 +49,8 @@ export function gatewayListTrusted(store) {
|
|
|
49
49
|
return gatewayTrustUnavailable();
|
|
50
50
|
const devices = store.listTrustedGateways();
|
|
51
51
|
const principals = store.listTrustedGatewayPrincipals?.() ?? [];
|
|
52
|
-
|
|
52
|
+
const members = store.listVerifiedMembers?.() ?? [];
|
|
53
|
+
if (devices.length === 0 && principals.length === 0 && members.length === 0) {
|
|
53
54
|
return {
|
|
54
55
|
content: "No remote gateway devices or principals are trusted.",
|
|
55
56
|
isError: false,
|
|
@@ -62,6 +63,9 @@ export function gatewayListTrusted(store) {
|
|
|
62
63
|
if (principals.length > 0) {
|
|
63
64
|
sections.push(`Trusted remote gateway principals:\n${principals.map((principal) => ` ${principal}`).join("\n")}`);
|
|
64
65
|
}
|
|
66
|
+
if (members.length > 0) {
|
|
67
|
+
sections.push(`Devices trusted through a principal:\n${members.map((member) => ` ${member.device} (vouched for by ${member.principal})`).join("\n")}`);
|
|
68
|
+
}
|
|
65
69
|
return {
|
|
66
70
|
content: sections.join("\n"),
|
|
67
71
|
isError: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-trust-actions.js","sourceRoot":"","sources":["../../src/core/gateway-trust-actions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gateway-trust-actions.js","sourceRoot":"","sources":["../../src/core/gateway-trust-actions.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { IdentitySlot } from "./identity-store.js";
|
|
11
11
|
/** The read-only slice of GatewayTrust every consumer of the trust boundary actually needs (WireMeshTransport, HubSession, hub-forwarding.ts) -- named so call sites that only ever read trust decisions, never mutate them, don't repeat the same `Pick<GatewayTrust, "isTrusted" | "hasAny" | "isTrustedPrincipal" | "isTrustedFor">` inline at every field/parameter that takes one. */
|
|
12
|
-
export type GatewayTrustReader = Pick<GatewayTrust, "isTrusted" | "hasAny" | "isTrustedPrincipal" | "isTrustedFor">;
|
|
12
|
+
export type GatewayTrustReader = Pick<GatewayTrust, "isTrusted" | "isReachable" | "hasAny" | "isTrustedPrincipal" | "isTrustedFor" | "listPrincipals" | "noteVerifiedMember">;
|
|
13
13
|
export declare class GatewayTrust {
|
|
14
14
|
private readonly trusted;
|
|
15
15
|
private readonly trustedPrincipals;
|
|
16
|
+
/** Devices whose gossiped membership proof was verified against a trusted principal, with that principal and when the proof lapses. In memory only: a proof is short-lived and re-verified from the next advert, so nothing here is worth persisting. */
|
|
17
|
+
private readonly verifiedMembers;
|
|
16
18
|
private readonly slot;
|
|
17
19
|
/** Constructs the trust boundary, optionally bound to a bridge identity slot for persistence (agent-comms#186); see this class's own doc comment for what a slot does and doesn't change. Given a slot, immediately loads whatever devices and principals were trusted before the last restart into the initial in-memory sets. */
|
|
18
20
|
constructor(slot?: Readonly<IdentitySlot>);
|
|
@@ -24,8 +26,18 @@ export declare class GatewayTrust {
|
|
|
24
26
|
private persist;
|
|
25
27
|
/** Every currently trusted device-id, lowercase hex, in insertion order. */
|
|
26
28
|
list(): string[];
|
|
27
|
-
/** Whether the given device-id (hex, case-insensitive) is
|
|
29
|
+
/** Whether the given device-id (hex, case-insensitive) is trusted by id: on the bare-device allowlist. A device trusted only because a principal vouches for it (noteVerifiedMember) is not, on purpose: its proof is a claim that anyone who has read the device's gossiped advert can repeat, so it earns only what isReachable grants. */
|
|
28
30
|
isTrusted(deviceHex: string): boolean;
|
|
31
|
+
/** Whether this side may merge the device's gossiped directory entry and route requests to it: trusted by id, or a verified member of a trusted principal. Requests routed to a device are still authenticated end to end by the session inside the relay, so a false claim can misroute one (which then fails its handshake) but not read or forge one. */
|
|
32
|
+
isReachable(deviceHex: string): boolean;
|
|
33
|
+
/** Records that deviceHex presented a membership proof, valid until expiresAt (epoch ms), verified against principalHex (agent-comms#266). From then until the proof lapses, or principalHex stops being trusted, isReachable treats the device as reachable. A later proof never shortens an earlier one's window. The caller has already verified the proof: this class does no cryptography. */
|
|
34
|
+
noteVerifiedMember(deviceHex: string, principalHex: string, expiresAt: number): void;
|
|
35
|
+
/** Every device currently reachable only because a trusted principal vouches for it, with that principal. Excludes proofs that have lapsed and members whose principal is no longer trusted. */
|
|
36
|
+
listVerifiedMembers(): {
|
|
37
|
+
device: string;
|
|
38
|
+
principal: string;
|
|
39
|
+
}[];
|
|
40
|
+
private isVerifiedMember;
|
|
29
41
|
/** Marks a remote user-principal device-id (hex, case-insensitive; user-identity.ts) as trusted (agent-comms#187): a peer presenting a token whose delegation chain roots at this principal is trusted via `isTrustedFor` below, without that peer's own bare device-id ever needing individual trust. Idempotent, and entirely independent of the bare-device allowlist `add` manages. Persists the updated set when this instance was constructed with a slot. */
|
|
30
42
|
addPrincipal(deviceHex: string): void;
|
|
31
43
|
/** Withdraws a previously trusted principal (hex, case-insensitive). A no-op if it was never trusted. Governs future chain checks only, mirroring `remove`'s own already-merged-traffic-is-unaffected posture. Persists the updated set when this instance was constructed with a slot. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-trust.d.ts","sourceRoot":"","sources":["../../src/core/gateway-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,2XAA2X;AAC3X,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,YAAY,
|
|
1
|
+
{"version":3,"file":"gateway-trust.d.ts","sourceRoot":"","sources":["../../src/core/gateway-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,2XAA2X;AAC3X,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,YAAY,EACV,WAAW,GACX,aAAa,GACb,QAAQ,GACR,oBAAoB,GACpB,cAAc,GACd,gBAAgB,GAChB,oBAAoB,CACvB,CAAC;AAEF,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IACvD,yPAAyP;IACzP,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG5B;IACJ,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqC;IAE1D,mUAAmU;gBACvT,IAAI,CAAC,EAAE,QAAQ,CAAC,YAAY,CAAC;IAazC,mRAAmR;IACnR,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK5B,kWAAkW;IAClW,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK/B,qLAAqL;IACrL,OAAO,CAAC,OAAO;IAMf,4EAA4E;IAC5E,IAAI,IAAI,MAAM,EAAE;IAIhB,6UAA6U;IAC7U,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIrC,4VAA4V;IAC5V,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAKvC,mYAAmY;IACnY,kBAAkB,CAChB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,IAAI;IAaP,gMAAgM;IAChM,mBAAmB,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE;IAM9D,OAAO,CAAC,gBAAgB;IASxB,ocAAoc;IACpc,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKrC,2RAA2R;IAC3R,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IASxC,sFAAsF;IACtF,cAAc,IAAI,MAAM,EAAE;IAI1B,oGAAoG;IACpG,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI9C;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO;IAI/D;;OAEG;IACH,MAAM,IAAI,OAAO;CAGlB"}
|
|
@@ -2,6 +2,8 @@ import { loadGatewayTrust, saveGatewayTrust } from "./identity-store.js";
|
|
|
2
2
|
export class GatewayTrust {
|
|
3
3
|
trusted = new Set();
|
|
4
4
|
trustedPrincipals = new Set();
|
|
5
|
+
/** Devices whose gossiped membership proof was verified against a trusted principal, with that principal and when the proof lapses. In memory only: a proof is short-lived and re-verified from the next advert, so nothing here is worth persisting. */
|
|
6
|
+
verifiedMembers = new Map();
|
|
5
7
|
slot;
|
|
6
8
|
/** Constructs the trust boundary, optionally bound to a bridge identity slot for persistence (agent-comms#186); see this class's own doc comment for what a slot does and doesn't change. Given a slot, immediately loads whatever devices and principals were trusted before the last restart into the initial in-memory sets. */
|
|
7
9
|
constructor(slot) {
|
|
@@ -36,10 +38,41 @@ export class GatewayTrust {
|
|
|
36
38
|
list() {
|
|
37
39
|
return [...this.trusted];
|
|
38
40
|
}
|
|
39
|
-
/** Whether the given device-id (hex, case-insensitive) is
|
|
41
|
+
/** Whether the given device-id (hex, case-insensitive) is trusted by id: on the bare-device allowlist. A device trusted only because a principal vouches for it (noteVerifiedMember) is not, on purpose: its proof is a claim that anyone who has read the device's gossiped advert can repeat, so it earns only what isReachable grants. */
|
|
40
42
|
isTrusted(deviceHex) {
|
|
41
43
|
return this.trusted.has(deviceHex.toLowerCase());
|
|
42
44
|
}
|
|
45
|
+
/** Whether this side may merge the device's gossiped directory entry and route requests to it: trusted by id, or a verified member of a trusted principal. Requests routed to a device are still authenticated end to end by the session inside the relay, so a false claim can misroute one (which then fails its handshake) but not read or forge one. */
|
|
46
|
+
isReachable(deviceHex) {
|
|
47
|
+
const key = deviceHex.toLowerCase();
|
|
48
|
+
return this.trusted.has(key) || this.isVerifiedMember(key);
|
|
49
|
+
}
|
|
50
|
+
/** Records that deviceHex presented a membership proof, valid until expiresAt (epoch ms), verified against principalHex (agent-comms#266). From then until the proof lapses, or principalHex stops being trusted, isReachable treats the device as reachable. A later proof never shortens an earlier one's window. The caller has already verified the proof: this class does no cryptography. */
|
|
51
|
+
noteVerifiedMember(deviceHex, principalHex, expiresAt) {
|
|
52
|
+
const key = deviceHex.toLowerCase();
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
for (const [device, member] of this.verifiedMembers) {
|
|
55
|
+
if (member.expiresAt <= now)
|
|
56
|
+
this.verifiedMembers.delete(device);
|
|
57
|
+
}
|
|
58
|
+
const existing = this.verifiedMembers.get(key);
|
|
59
|
+
this.verifiedMembers.set(key, {
|
|
60
|
+
principal: principalHex.toLowerCase(),
|
|
61
|
+
expiresAt: Math.max(expiresAt, existing?.expiresAt ?? 0),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** Every device currently reachable only because a trusted principal vouches for it, with that principal. Excludes proofs that have lapsed and members whose principal is no longer trusted. */
|
|
65
|
+
listVerifiedMembers() {
|
|
66
|
+
return [...this.verifiedMembers]
|
|
67
|
+
.filter(([device]) => this.isVerifiedMember(device))
|
|
68
|
+
.map(([device, member]) => ({ device, principal: member.principal }));
|
|
69
|
+
}
|
|
70
|
+
isVerifiedMember(deviceKey) {
|
|
71
|
+
const member = this.verifiedMembers.get(deviceKey);
|
|
72
|
+
return (member !== undefined &&
|
|
73
|
+
member.expiresAt > Date.now() &&
|
|
74
|
+
this.trustedPrincipals.has(member.principal));
|
|
75
|
+
}
|
|
43
76
|
/** Marks a remote user-principal device-id (hex, case-insensitive; user-identity.ts) as trusted (agent-comms#187): a peer presenting a token whose delegation chain roots at this principal is trusted via `isTrustedFor` below, without that peer's own bare device-id ever needing individual trust. Idempotent, and entirely independent of the bare-device allowlist `add` manages. Persists the updated set when this instance was constructed with a slot. */
|
|
44
77
|
addPrincipal(deviceHex) {
|
|
45
78
|
this.trustedPrincipals.add(deviceHex.toLowerCase());
|
|
@@ -47,7 +80,12 @@ export class GatewayTrust {
|
|
|
47
80
|
}
|
|
48
81
|
/** Withdraws a previously trusted principal (hex, case-insensitive). A no-op if it was never trusted. Governs future chain checks only, mirroring `remove`'s own already-merged-traffic-is-unaffected posture. Persists the updated set when this instance was constructed with a slot. */
|
|
49
82
|
removePrincipal(deviceHex) {
|
|
50
|
-
|
|
83
|
+
const key = deviceHex.toLowerCase();
|
|
84
|
+
this.trustedPrincipals.delete(key);
|
|
85
|
+
for (const [device, member] of this.verifiedMembers) {
|
|
86
|
+
if (member.principal === key)
|
|
87
|
+
this.verifiedMembers.delete(device);
|
|
88
|
+
}
|
|
51
89
|
this.persist();
|
|
52
90
|
}
|
|
53
91
|
/** Every currently trusted principal device-id, lowercase hex, in insertion order. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-trust.js","sourceRoot":"","sources":["../../src/core/gateway-trust.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"gateway-trust.js","sourceRoot":"","sources":["../../src/core/gateway-trust.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,8 @@ export declare function listKnownDevicesEntries(knownDevices: ReadonlyMap<string
|
|
|
15
15
|
}[];
|
|
16
16
|
/** Reads a presence extension from one specific device's own gossiped self-advert, if this event's directory carries a fresh one for exactly that device-id -- never for any other device-id a multi-hop directory might mention, since only the session's own authenticated peer's advert is that session's business to report. Returns undefined for a missing presence/status key, or a value that isn't a recognised AgentStatus -- an advert simply not participating in this convention, not an error (the same verifier obligation peer-advert's own open extension tail is documented under). */
|
|
17
17
|
export declare function findPresenceAdvert(deviceIdHex: string, directory: readonly DirectoryEntry[]): AgentStatus | undefined;
|
|
18
|
+
/** The membership proof a peer gossiped in its agent/self advert, or undefined when it carries none. The advert is self-asserted by whichever peer sent it, so this only reads it; nothing about the proof is believed until it is verified. */
|
|
19
|
+
export declare function readMembershipProof(advert: Readonly<PeerAdvert>): string | undefined;
|
|
18
20
|
/** Re-sends this side's own current presence status, currently-hosted rooms, self-agent identity, and package versions, together, onto every live session's gossip self-advert -- one gossip frame per tick carrying whichever facts are actually known, rather than a separate frame per fact. Split out of wire-mesh-transport.ts's own WireMeshTransport class purely to keep that file under the repo's max-lines cap, the same reason mergeKnownDevices/findPresenceAdvert above already live here rather than there. A session that fails to send (mid-disconnect, most likely -- watchForDisconnect will independently notice and clean it up) is reported via onError and skipped, not allowed to stop the tick from reaching the rest of allSessions: a periodic broadcast to N peers is N independent operations, not one atomic unit. Unlike presence/hostedRooms/selfAgentAdvert, the versions extension is never actually absent (this side's own agent-comms package version is always known), so every tick this function is called for sends at least that one fact -- there is no "nothing to report" case left to short-circuit on. The hub's own session (agent-comms#156) is gated separately from every ordinary local-peer session in allSessions: local mesh trust is a different layer (connect_request/introduce approval already gated it before it ever joined allSessions), but the hub session is a broadcast to every connected hub peer, trusted or not, and would otherwise leak this side's own presence/hosted-rooms/self-agent/versions advert onto the hub regardless of GatewayTrust -- forwardAdvertsToHub/pushHubCatchUp's own hasAny gate exists to prevent exactly this for OTHER local peers' adverts, and this side's own self-advert deserves the identical gate, not a bypass. */
|
|
19
21
|
export declare function readvertiseGossip(options: {
|
|
20
22
|
allSessions: ReadonlySet<AcceptedMeshSession>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gossip-directory.d.ts","sourceRoot":"","sources":["../../src/core/gossip-directory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,mBAAmB,EACnB,cAAc,EACf,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAKhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,2OAA2O;AAC3O,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACrC,SAAS,EAAE,SAAS,cAAc,EAAE,GACnC,IAAI,CAWN;AAED,idAAid;AACjd,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,GACtD,SAAS;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAA;CAAE,EAAE,CAK/D;AAED,ykBAAykB;AACzkB,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,SAAS,cAAc,EAAE,GACnC,WAAW,GAAG,SAAS,CAOzB;AAED,+tDAA+tD;AAC/tD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,WAAW,EAAE,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC9C,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;IAC/C,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC9C,kBAAkB,EAAE,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IAChE,cAAc,EAAE,CAAC,MAAM,SAAS,gBAAgB,EAAE,CAAC,GAAG,SAAS,CAAC;IAChE,kBAAkB,EAAE,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACpE,mkBAAmkB;IACnkB,gBAAgB,EAAE,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CAC1D,GAAG,IAAI,CAgCP;AAED,0yBAA0yB;AAC1yB,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,WAAW,EAAE,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC9C,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;IAC/C,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC9C,kBAAkB,EAAE,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IAChE,cAAc,EAAE,CAAC,MAAM,SAAS,gBAAgB,EAAE,CAAC,GAAG,SAAS,CAAC;IAChE,kBAAkB,EAAE,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACpE,gBAAgB,EAAE,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACzD,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,SAAS,CAiC7C"}
|
|
1
|
+
{"version":3,"file":"gossip-directory.d.ts","sourceRoot":"","sources":["../../src/core/gossip-directory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,mBAAmB,EACnB,cAAc,EACf,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAKhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,2OAA2O;AAC3O,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACrC,SAAS,EAAE,SAAS,cAAc,EAAE,GACnC,IAAI,CAWN;AAED,idAAid;AACjd,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,GACtD,SAAS;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAA;CAAE,EAAE,CAK/D;AAED,ykBAAykB;AACzkB,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,SAAS,cAAc,EAAE,GACnC,WAAW,GAAG,SAAS,CAOzB;AAED,gPAAgP;AAChP,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC3B,MAAM,GAAG,SAAS,CAKpB;AAED,+tDAA+tD;AAC/tD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,WAAW,EAAE,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC9C,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;IAC/C,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC9C,kBAAkB,EAAE,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IAChE,cAAc,EAAE,CAAC,MAAM,SAAS,gBAAgB,EAAE,CAAC,GAAG,SAAS,CAAC;IAChE,kBAAkB,EAAE,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACpE,mkBAAmkB;IACnkB,gBAAgB,EAAE,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CAC1D,GAAG,IAAI,CAgCP;AAED,0yBAA0yB;AAC1yB,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,WAAW,EAAE,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC9C,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;IAC/C,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC9C,kBAAkB,EAAE,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IAChE,cAAc,EAAE,CAAC,MAAM,SAAS,gBAAgB,EAAE,CAAC,GAAG,SAAS,CAAC;IAChE,kBAAkB,EAAE,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACpE,gBAAgB,EAAE,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACzD,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,SAAS,CAiC7C"}
|
|
@@ -32,6 +32,15 @@ export function findPresenceAdvert(deviceIdHex, directory) {
|
|
|
32
32
|
const status = entry.advert[PRESENCE_GOSSIP_KEY];
|
|
33
33
|
return AgentStatus.is(status) ? status : undefined;
|
|
34
34
|
}
|
|
35
|
+
/** The membership proof a peer gossiped in its agent/self advert, or undefined when it carries none. The advert is self-asserted by whichever peer sent it, so this only reads it; nothing about the proof is believed until it is verified. */
|
|
36
|
+
export function readMembershipProof(advert) {
|
|
37
|
+
const self = advert[AGENT_SELF_GOSSIP_KEY];
|
|
38
|
+
if (typeof self !== "object" || self === null)
|
|
39
|
+
return undefined;
|
|
40
|
+
if (!("membership" in self))
|
|
41
|
+
return undefined;
|
|
42
|
+
return typeof self.membership === "string" ? self.membership : undefined;
|
|
43
|
+
}
|
|
35
44
|
/** Re-sends this side's own current presence status, currently-hosted rooms, self-agent identity, and package versions, together, onto every live session's gossip self-advert -- one gossip frame per tick carrying whichever facts are actually known, rather than a separate frame per fact. Split out of wire-mesh-transport.ts's own WireMeshTransport class purely to keep that file under the repo's max-lines cap, the same reason mergeKnownDevices/findPresenceAdvert above already live here rather than there. A session that fails to send (mid-disconnect, most likely -- watchForDisconnect will independently notice and clean it up) is reported via onError and skipped, not allowed to stop the tick from reaching the rest of allSessions: a periodic broadcast to N peers is N independent operations, not one atomic unit. Unlike presence/hostedRooms/selfAgentAdvert, the versions extension is never actually absent (this side's own agent-comms package version is always known), so every tick this function is called for sends at least that one fact -- there is no "nothing to report" case left to short-circuit on. The hub's own session (agent-comms#156) is gated separately from every ordinary local-peer session in allSessions: local mesh trust is a different layer (connect_request/introduce approval already gated it before it ever joined allSessions), but the hub session is a broadcast to every connected hub peer, trusted or not, and would otherwise leak this side's own presence/hosted-rooms/self-agent/versions advert onto the hub regardless of GatewayTrust -- forwardAdvertsToHub/pushHubCatchUp's own hasAny gate exists to prevent exactly this for OTHER local peers' adverts, and this side's own self-advert deserves the identical gate, not a bypass. */
|
|
36
45
|
export function readvertiseGossip(options) {
|
|
37
46
|
const { allSessions, hub, hasAnyTrustedGateway, onError, getCurrentPresence, getHostedRooms, getSelfAgentAdvert, getCcPeerVersion, } = options;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gossip-directory.js","sourceRoot":"","sources":["../../src/core/gossip-directory.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gossip-directory.js","sourceRoot":"","sources":["../../src/core/gossip-directory.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,5 +23,7 @@ export interface AgentSelfAdvert {
|
|
|
23
23
|
startedAt: string;
|
|
24
24
|
tags: string[];
|
|
25
25
|
subscribedRooms: string[];
|
|
26
|
+
/** A proof that this device's user principal vouches for it (membership-proof.ts), so a peer that trusts that principal trusts this device without it being listed individually. Absent until the first proof has been minted. */
|
|
27
|
+
membership?: string;
|
|
26
28
|
}
|
|
27
29
|
//# sourceMappingURL=gossip-extensions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gossip-extensions.d.ts","sourceRoot":"","sources":["../../src/core/gossip-extensions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8QAA8Q;AAC9Q,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,mSAAmS;AACnS,eAAO,MAAM,uBAAuB,gBAAgB,CAAC;AAErD,+cAA+c;AAC/c,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,6RAA6R;AAC7R,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD,gkBAAgkB;AAChkB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,eAAe,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"gossip-extensions.d.ts","sourceRoot":"","sources":["../../src/core/gossip-extensions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8QAA8Q;AAC9Q,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,mSAAmS;AACnS,eAAO,MAAM,uBAAuB,gBAAgB,CAAC;AAErD,+cAA+c;AAC/c,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,6RAA6R;AAC7R,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD,gkBAAgkB;AAChkB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,kOAAkO;IAClO,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -27,10 +27,10 @@ export interface HubSessionDeps {
|
|
|
27
27
|
onDirectory: (entries: readonly DirectoryEntry[]) => void;
|
|
28
28
|
/** Dispatches an already-received, non-legacy-frame request (a real core/room verb: room.send, room.notify, room.join, ...) to WireMeshTransport's own roomRouter, the identical dispatch a local peer session's own drainSession already uses -- the outbound half of agent-comms#155's "remote to local" routing leg. Deferred the same lazy-`this`-capture way DeliveryEngine's own sendRoomRequestToMember closure is, since roomRouter is constructed after this class's own instance in WireMeshTransport's constructor. Declared with the identical (request, handle, origin?) shape RoomRouter.handleRequest itself has (agent-comms#216) so WireMeshTransport can keep wiring this dep as a direct method reference rather than a wrapper -- dispatchHubRequest below is what actually supplies a non-empty origin, carrying this side's own dialled hub address. */
|
|
29
29
|
handleRoomRequest: (request: IncomingManageRequest, handle: Readonly<ConnectionHandle>, origin?: Readonly<RoomRequestOrigin>) => Promise<void>;
|
|
30
|
-
/** The gateway trust boundary (agent-comms#156): whether the given device-id (hex) is currently trusted as a bare device. Since agent-comms#192, this gates only the traffic that carries no independent per-message security of its own: the legacy FRAME_VERB path (consume()'s own doc explains why) and dispatchHubRequest's own hubPeersKnown bookkeeping for a room-domain sender. A real room-domain verb's own dispatch is never gated on this at all; see dispatchHubRequest's own doc for why that is sound. connect()'s own directory-merge filter uses
|
|
30
|
+
/** The gateway trust boundary (agent-comms#156): whether the given device-id (hex) is currently trusted as a bare device. Since agent-comms#192, this gates only the traffic that carries no independent per-message security of its own: the legacy FRAME_VERB path (consume()'s own doc explains why) and dispatchHubRequest's own hubPeersKnown bookkeeping for a room-domain sender. A real room-domain verb's own dispatch is never gated on this at all; see dispatchHubRequest's own doc for why that is sound. connect()'s own directory-merge filter uses admitEntries below instead, not this. */
|
|
31
31
|
isTrusted: (deviceHex: string) => boolean;
|
|
32
|
-
/** Whether
|
|
33
|
-
|
|
32
|
+
/** Whether a gossiped directory entry may be merged (agent-comms#156, widened by #187 and #266): its device is trusted by id, or is itself a trusted principal's own device (agent-comms#192), or carries a membership proof a trusted principal vouches for. A gossiped advert is self-asserted, so the proof is what makes trusting a principal cover its devices; verifying one is cryptography, hence asynchronous. */
|
|
33
|
+
admitEntries: (entries: readonly DirectoryEntry[]) => Promise<DirectoryEntry[]>;
|
|
34
34
|
/** Forwards a room-domain manage-request on to a specific LOCAL peer session (one this gateway is directly connected to over the ordinary local mesh, keyed by device-id hex) rather than dispatching it against this gateway's own local state -- consume()'s own toDevice disambiguation (agent-comms#184, wire-mesh-core 1.48.1's IncomingManageRequest.toDevice). Returns undefined when no local session exists for that device-id, in which case consume() falls back to handleRoomRequest exactly as it always has. */
|
|
35
35
|
forwardToLocalPeer: (deviceHex: string, command: ManageCommand, scope: Readonly<CapabilityScope>, token?: CapabilityToken) => Promise<ManageOutcome> | undefined;
|
|
36
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hub-session.d.ts","sourceRoot":"","sources":["../../src/core/hub-session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EACnB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,KAAK,EACL,aAAa,EACd,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EAChB,MAAM,gBAAgB,CAAC;AAKxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAS1D,2fAA2f;AAE3f,MAAM,WAAW,cAAc;IAC7B,oIAAoI;IACpI,yBAAyB,EAAE,MAAM,CAAC;IAClC,yDAAyD;IACzD,aAAa,EAAE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/C,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IAClC,yHAAyH;IACzH,cAAc,EAAE,MAAM,OAAO,CAAC;IAC9B,wEAAwE;IACxE,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,sIAAsI;IACtI,OAAO,EAAE,CACP,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,EAChC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,KACnB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,2FAA2F;IAC3F,gBAAgB,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD,uZAAuZ;IACvZ,WAAW,EAAE,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,KAAK,IAAI,CAAC;IAC1D,80BAA80B;IAC90B,iBAAiB,EAAE,CACjB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAClC,MAAM,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,KACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,
|
|
1
|
+
{"version":3,"file":"hub-session.d.ts","sourceRoot":"","sources":["../../src/core/hub-session.ts"],"names":[],"mappings":"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"}
|
package/dist/core/hub-session.js
CHANGED
|
@@ -66,14 +66,13 @@ export class HubSession {
|
|
|
66
66
|
this.connection = connection;
|
|
67
67
|
this.url = url;
|
|
68
68
|
this.deps.trackForShutdown(session);
|
|
69
|
-
// Merge the hub's directory (its catch-up arrives as the first session events) and keep refreshing it on every subsequent one. Every trusted remote entry is also surfaced via onDirectory, so the transport can merge it into its own mesh-wide knownDevices (agent-comms#155's remote-directory-merge leg). Filtered to
|
|
69
|
+
// Merge the hub's directory (its catch-up arrives as the first session events) and keep refreshing it on every subsequent one. Every trusted remote entry is also surfaced via onDirectory, so the transport can merge it into its own mesh-wide knownDevices (agent-comms#155's remote-directory-merge leg). Filtered to admitEntries (agent-comms#156, widened by agent-comms#187's principal allowlist per agent-comms#192 and by #266's membership proofs) before either hubPeersKnown tracking or onDirectory sees it: an untrusted device's gossiped presence is not merely withheld from listAgents, it is never even recorded as "known" here, so nothing downstream can act on it via any path this class exposes.
|
|
70
70
|
void (async () => {
|
|
71
71
|
const ownHex = deviceIdToHex(identity.deviceId);
|
|
72
72
|
for await (const event of session.events) {
|
|
73
73
|
if (this.deps.isShuttingDown())
|
|
74
74
|
break;
|
|
75
|
-
const remoteEntries = event.directory.filter((entry) => deviceIdToHex(entry.device) !== ownHex
|
|
76
|
-
this.deps.isTrustedForDirectory(deviceIdToHex(entry.device)));
|
|
75
|
+
const remoteEntries = await this.deps.admitEntries(event.directory.filter((entry) => deviceIdToHex(entry.device) !== ownHex));
|
|
77
76
|
for (const entry of remoteEntries) {
|
|
78
77
|
this.hubPeersKnown.add(deviceIdToHex(entry.device));
|
|
79
78
|
}
|
|
@@ -82,7 +81,10 @@ export class HubSession {
|
|
|
82
81
|
if (event.state.status === "closed")
|
|
83
82
|
break;
|
|
84
83
|
}
|
|
85
|
-
})()
|
|
84
|
+
})().catch((error) => {
|
|
85
|
+
// The merge loop must not die silently: a failure here would stop this side learning of every remote device until the hub is redialled.
|
|
86
|
+
this.deps.events.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
87
|
+
});
|
|
86
88
|
this.consume(session, deviceIdToHex(identity.deviceId));
|
|
87
89
|
void (async () => {
|
|
88
90
|
await this.watchDisconnect(session);
|