@agentvault/agentvault 0.17.5 → 0.19.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/README.md +10 -11
- package/dist/__tests__/crypto-helpers.test.d.ts +2 -0
- package/dist/__tests__/crypto-helpers.test.d.ts.map +1 -0
- package/dist/__tests__/functional.test.d.ts +21 -0
- package/dist/__tests__/functional.test.d.ts.map +1 -0
- package/dist/__tests__/multi-session.test.d.ts +2 -0
- package/dist/__tests__/multi-session.test.d.ts.map +1 -0
- package/dist/__tests__/state.test.d.ts +2 -0
- package/dist/__tests__/state.test.d.ts.map +1 -0
- package/dist/__tests__/transport.test.d.ts +2 -0
- package/dist/__tests__/transport.test.d.ts.map +1 -0
- package/dist/_cp.d.ts +10 -0
- package/dist/_cp.d.ts.map +1 -0
- package/dist/account-config.d.ts +20 -0
- package/dist/account-config.d.ts.map +1 -0
- package/dist/channel.d.ts +393 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +2257 -0
- package/dist/channel.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +344 -2
- package/dist/cli.js.map +4 -4
- package/dist/create-agent.d.ts +28 -0
- package/dist/create-agent.d.ts.map +1 -0
- package/dist/credential-store.d.ts +62 -0
- package/dist/credential-store.d.ts.map +1 -0
- package/dist/crypto-helpers.d.ts +2 -0
- package/dist/crypto-helpers.d.ts.map +1 -0
- package/dist/crypto-helpers.js +4 -0
- package/dist/crypto-helpers.js.map +1 -0
- package/dist/doctor.d.ts +41 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/fetch-interceptor.d.ts +32 -0
- package/dist/fetch-interceptor.d.ts.map +1 -0
- package/dist/gateway-send.d.ts +98 -0
- package/dist/gateway-send.d.ts.map +1 -0
- package/dist/http-handlers.d.ts +53 -0
- package/dist/http-handlers.d.ts.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +359 -11
- package/dist/index.js.map +4 -4
- package/dist/mcp-handlers.d.ts +26 -0
- package/dist/mcp-handlers.d.ts.map +1 -0
- package/dist/mcp-proxy-helpers.d.ts +9 -0
- package/dist/mcp-proxy-helpers.d.ts.map +1 -0
- package/dist/mcp-server.d.ts +90 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/openclaw-compat.d.ts +33 -0
- package/dist/openclaw-compat.d.ts.map +1 -0
- package/dist/openclaw-entry.d.ts +27 -0
- package/dist/openclaw-entry.d.ts.map +1 -0
- package/dist/openclaw-entry.js +45184 -195
- package/dist/openclaw-entry.js.map +4 -4
- package/dist/openclaw-plugin.d.ts +102 -0
- package/dist/openclaw-plugin.d.ts.map +1 -0
- package/dist/openclaw-plugin.js +222 -0
- package/dist/openclaw-plugin.js.map +1 -0
- package/dist/openclaw-types.d.ts +155 -0
- package/dist/openclaw-types.d.ts.map +1 -0
- package/dist/policy-enforcer.d.ts +78 -0
- package/dist/policy-enforcer.d.ts.map +1 -0
- package/dist/setup.d.ts +27 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +329 -0
- package/dist/setup.js.map +1 -0
- package/dist/skill-invoker.d.ts +30 -0
- package/dist/skill-invoker.d.ts.map +1 -0
- package/dist/skill-manifest.d.ts +30 -0
- package/dist/skill-manifest.d.ts.map +1 -0
- package/dist/skill-telemetry.d.ts +36 -0
- package/dist/skill-telemetry.d.ts.map +1 -0
- package/dist/skills-publish.d.ts +8 -0
- package/dist/skills-publish.d.ts.map +1 -0
- package/dist/state.d.ts +32 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +61 -0
- package/dist/state.js.map +1 -0
- package/dist/transport.d.ts +24 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +43 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +417 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/workspace-handlers.d.ts +62 -0
- package/dist/workspace-handlers.d.ts.map +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -46265,6 +46265,123 @@ var init_dist = __esm({
|
|
|
46265
46265
|
}
|
|
46266
46266
|
});
|
|
46267
46267
|
|
|
46268
|
+
// src/credential-store.ts
|
|
46269
|
+
var CredentialStore;
|
|
46270
|
+
var init_credential_store = __esm({
|
|
46271
|
+
"src/credential-store.ts"() {
|
|
46272
|
+
"use strict";
|
|
46273
|
+
CredentialStore = class _CredentialStore {
|
|
46274
|
+
/** Map<roomId, Map<credentialKey, RenterCredential>> */
|
|
46275
|
+
_store = /* @__PURE__ */ new Map();
|
|
46276
|
+
/** Seen nonces for replay prevention — bounded per room */
|
|
46277
|
+
_seenNonces = /* @__PURE__ */ new Map();
|
|
46278
|
+
static MAX_NONCES_PER_ROOM = 1e3;
|
|
46279
|
+
constructor() {
|
|
46280
|
+
const purge = () => this.purgeAll();
|
|
46281
|
+
process.on("exit", purge);
|
|
46282
|
+
process.on("SIGINT", () => {
|
|
46283
|
+
purge();
|
|
46284
|
+
process.exit(0);
|
|
46285
|
+
});
|
|
46286
|
+
process.on("SIGTERM", () => {
|
|
46287
|
+
purge();
|
|
46288
|
+
process.exit(0);
|
|
46289
|
+
});
|
|
46290
|
+
}
|
|
46291
|
+
/**
|
|
46292
|
+
* Check if a nonce has been seen (replay prevention).
|
|
46293
|
+
* Returns true if the nonce is new (not a replay), false if seen before.
|
|
46294
|
+
*/
|
|
46295
|
+
checkNonce(roomId, nonce) {
|
|
46296
|
+
if (!nonce) return true;
|
|
46297
|
+
let nonces = this._seenNonces.get(roomId);
|
|
46298
|
+
if (!nonces) {
|
|
46299
|
+
nonces = /* @__PURE__ */ new Set();
|
|
46300
|
+
this._seenNonces.set(roomId, nonces);
|
|
46301
|
+
}
|
|
46302
|
+
if (nonces.has(nonce)) return false;
|
|
46303
|
+
nonces.add(nonce);
|
|
46304
|
+
if (nonces.size > _CredentialStore.MAX_NONCES_PER_ROOM) {
|
|
46305
|
+
const iter = nonces.values();
|
|
46306
|
+
for (let i2 = 0; i2 < 100; i2++) {
|
|
46307
|
+
const val = iter.next().value;
|
|
46308
|
+
if (val !== void 0) nonces.delete(val);
|
|
46309
|
+
}
|
|
46310
|
+
}
|
|
46311
|
+
return true;
|
|
46312
|
+
}
|
|
46313
|
+
/** Store a credential for a room. */
|
|
46314
|
+
grant(roomId, credential) {
|
|
46315
|
+
let room = this._store.get(roomId);
|
|
46316
|
+
if (!room) {
|
|
46317
|
+
room = /* @__PURE__ */ new Map();
|
|
46318
|
+
this._store.set(roomId, room);
|
|
46319
|
+
}
|
|
46320
|
+
room.set(credential.key, credential);
|
|
46321
|
+
}
|
|
46322
|
+
/** Revoke a specific credential. */
|
|
46323
|
+
revoke(roomId, key) {
|
|
46324
|
+
const room = this._store.get(roomId);
|
|
46325
|
+
if (!room) return false;
|
|
46326
|
+
return room.delete(key);
|
|
46327
|
+
}
|
|
46328
|
+
/** Revoke all credentials for a room. */
|
|
46329
|
+
revokeAll(roomId) {
|
|
46330
|
+
this._store.delete(roomId);
|
|
46331
|
+
}
|
|
46332
|
+
/** Get a credential value. */
|
|
46333
|
+
get(roomId, key) {
|
|
46334
|
+
return this._store.get(roomId)?.get(key);
|
|
46335
|
+
}
|
|
46336
|
+
/** Get all credentials for a room (values included — only for agent context injection). */
|
|
46337
|
+
getAll(roomId) {
|
|
46338
|
+
const room = this._store.get(roomId);
|
|
46339
|
+
if (!room) return [];
|
|
46340
|
+
return Array.from(room.values());
|
|
46341
|
+
}
|
|
46342
|
+
/** Get credential info without values (safe for logging). */
|
|
46343
|
+
getInfo(roomId) {
|
|
46344
|
+
const room = this._store.get(roomId);
|
|
46345
|
+
if (!room) return [];
|
|
46346
|
+
return Array.from(room.values()).map((c2) => ({
|
|
46347
|
+
key: c2.key,
|
|
46348
|
+
type: c2.type,
|
|
46349
|
+
scope: c2.scope,
|
|
46350
|
+
grantedAt: c2.grantedAt
|
|
46351
|
+
}));
|
|
46352
|
+
}
|
|
46353
|
+
/** Check if a specific credential exists. */
|
|
46354
|
+
has(roomId, key) {
|
|
46355
|
+
return this._store.get(roomId)?.has(key) ?? false;
|
|
46356
|
+
}
|
|
46357
|
+
/** Get credential count for a room. */
|
|
46358
|
+
count(roomId) {
|
|
46359
|
+
return this._store.get(roomId)?.size ?? 0;
|
|
46360
|
+
}
|
|
46361
|
+
/** Purge all credentials for a room (rental end). */
|
|
46362
|
+
purgeForRoom(roomId) {
|
|
46363
|
+
this._store.delete(roomId);
|
|
46364
|
+
this._seenNonces.delete(roomId);
|
|
46365
|
+
}
|
|
46366
|
+
/** Purge everything (process exit). */
|
|
46367
|
+
purgeAll() {
|
|
46368
|
+
this._store.clear();
|
|
46369
|
+
this._seenNonces.clear();
|
|
46370
|
+
}
|
|
46371
|
+
/** Get a map of credential key → value for context injection. */
|
|
46372
|
+
getCredentialMap(roomId) {
|
|
46373
|
+
const room = this._store.get(roomId);
|
|
46374
|
+
if (!room) return {};
|
|
46375
|
+
const result = {};
|
|
46376
|
+
for (const [key, cred] of room) {
|
|
46377
|
+
result[key] = cred.value;
|
|
46378
|
+
}
|
|
46379
|
+
return result;
|
|
46380
|
+
}
|
|
46381
|
+
};
|
|
46382
|
+
}
|
|
46383
|
+
});
|
|
46384
|
+
|
|
46268
46385
|
// src/crypto-helpers.ts
|
|
46269
46386
|
var init_crypto_helpers = __esm({
|
|
46270
46387
|
async "src/crypto-helpers.ts"() {
|
|
@@ -46541,7 +46658,8 @@ __export(http_handlers_exports, {
|
|
|
46541
46658
|
handleMcpConfigRequest: () => handleMcpConfigRequest,
|
|
46542
46659
|
handleSendRequest: () => handleSendRequest,
|
|
46543
46660
|
handleStatusRequest: () => handleStatusRequest,
|
|
46544
|
-
handleTargetsRequest: () => handleTargetsRequest
|
|
46661
|
+
handleTargetsRequest: () => handleTargetsRequest,
|
|
46662
|
+
handleTrustRequest: () => handleTrustRequest
|
|
46545
46663
|
});
|
|
46546
46664
|
async function handleSendRequest(parsed, channel) {
|
|
46547
46665
|
const text = parsed.text;
|
|
@@ -46680,6 +46798,24 @@ function handleTargetsRequest(channel) {
|
|
|
46680
46798
|
}
|
|
46681
46799
|
};
|
|
46682
46800
|
}
|
|
46801
|
+
function handleTrustRequest(channel) {
|
|
46802
|
+
const token = channel.trustToken;
|
|
46803
|
+
if (!token) {
|
|
46804
|
+
return {
|
|
46805
|
+
status: 503,
|
|
46806
|
+
body: { ok: false, error: "token_unavailable" }
|
|
46807
|
+
};
|
|
46808
|
+
}
|
|
46809
|
+
return {
|
|
46810
|
+
status: 200,
|
|
46811
|
+
body: {
|
|
46812
|
+
ok: true,
|
|
46813
|
+
tier: channel.trustTier,
|
|
46814
|
+
composite: null,
|
|
46815
|
+
token_expires_at: channel.trustTokenExpiresAt
|
|
46816
|
+
}
|
|
46817
|
+
};
|
|
46818
|
+
}
|
|
46683
46819
|
function handleMcpConfigRequest(agentName, port, mcpSkillCount) {
|
|
46684
46820
|
return {
|
|
46685
46821
|
status: 200,
|
|
@@ -46934,12 +47070,13 @@ function migratePersistedState(raw) {
|
|
|
46934
47070
|
messageHistory: []
|
|
46935
47071
|
};
|
|
46936
47072
|
}
|
|
46937
|
-
var ROOM_AGENT_TYPES, POLL_INTERVAL_MS, RECONNECT_BASE_MS, RECONNECT_MAX_MS, PENDING_POLL_INTERVAL_MS, SecureChannel;
|
|
47073
|
+
var ROOM_AGENT_TYPES, CREDENTIAL_MESSAGE_TYPES, POLL_INTERVAL_MS, RECONNECT_BASE_MS, RECONNECT_MAX_MS, PENDING_POLL_INTERVAL_MS, SecureChannel;
|
|
46938
47074
|
var init_channel = __esm({
|
|
46939
47075
|
async "src/channel.ts"() {
|
|
46940
47076
|
"use strict";
|
|
46941
47077
|
await init_libsodium_wrappers();
|
|
46942
47078
|
await init_dist();
|
|
47079
|
+
init_credential_store();
|
|
46943
47080
|
await init_crypto_helpers();
|
|
46944
47081
|
await init_state();
|
|
46945
47082
|
init_transport2();
|
|
@@ -46950,6 +47087,11 @@ var init_channel = __esm({
|
|
|
46950
47087
|
"decision_response",
|
|
46951
47088
|
"artifact_share"
|
|
46952
47089
|
]);
|
|
47090
|
+
CREDENTIAL_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
47091
|
+
"credential_grant",
|
|
47092
|
+
"credential_revoke",
|
|
47093
|
+
"credential_request"
|
|
47094
|
+
]);
|
|
46953
47095
|
POLL_INTERVAL_MS = 6e3;
|
|
46954
47096
|
RECONNECT_BASE_MS = 1e3;
|
|
46955
47097
|
RECONNECT_MAX_MS = 3e4;
|
|
@@ -46986,17 +47128,26 @@ var init_channel = __esm({
|
|
|
46986
47128
|
_heartbeatIntervalSeconds = 0;
|
|
46987
47129
|
_wakeDetectorTimer = null;
|
|
46988
47130
|
_lastWakeTick = Date.now();
|
|
47131
|
+
_trustToken = null;
|
|
47132
|
+
_trustTier = null;
|
|
47133
|
+
_trustTokenExpiresAt = null;
|
|
47134
|
+
_trustTokenInterval = null;
|
|
46989
47135
|
_pendingPollTimer = null;
|
|
46990
47136
|
_syncMessageIds = null;
|
|
46991
47137
|
/** Sender Key chains — own chain per room for O(1) encryption */
|
|
46992
47138
|
_senderKeyChains = /* @__PURE__ */ new Map();
|
|
46993
47139
|
/** Sender Key peer state — peer chains per room for decryption */
|
|
46994
47140
|
_senderKeyStates = /* @__PURE__ */ new Map();
|
|
47141
|
+
/** In-memory credential store for renter-provided credentials (never persisted). */
|
|
47142
|
+
_credentialStore = new CredentialStore();
|
|
46995
47143
|
/** Queued A2A messages for responder channels not yet activated (no first initiator message received). */
|
|
46996
47144
|
_a2aPendingQueue = {};
|
|
46997
47145
|
/** Dedup buffer for A2A message IDs (prevents double-delivery via direct + Redis) */
|
|
46998
47146
|
_a2aSeenMessageIds = /* @__PURE__ */ new Set();
|
|
46999
47147
|
static A2A_SEEN_MAX = 500;
|
|
47148
|
+
/** Dedup buffer for regular message IDs (prevents double-decrypt via direct WS + Redis pub/sub) */
|
|
47149
|
+
_seenMessageIds = /* @__PURE__ */ new Set();
|
|
47150
|
+
static SEEN_MSG_MAX = 500;
|
|
47000
47151
|
_scanEngine = null;
|
|
47001
47152
|
_scanRuleSetVersion = 0;
|
|
47002
47153
|
_telemetryReporter = null;
|
|
@@ -47926,9 +48077,56 @@ var init_channel = __esm({
|
|
|
47926
48077
|
this.emit("error", new Error(`Heartbeat send failed: ${err}`));
|
|
47927
48078
|
});
|
|
47928
48079
|
}
|
|
48080
|
+
// --- Trust Gate token management ---
|
|
48081
|
+
getTrustHeaders() {
|
|
48082
|
+
if (!this._trustToken) return {};
|
|
48083
|
+
return { "AgentVault-Trust": this._trustToken };
|
|
48084
|
+
}
|
|
48085
|
+
get trustToken() {
|
|
48086
|
+
return this._trustToken;
|
|
48087
|
+
}
|
|
48088
|
+
get trustTier() {
|
|
48089
|
+
return this._trustTier;
|
|
48090
|
+
}
|
|
48091
|
+
get trustTokenExpiresAt() {
|
|
48092
|
+
return this._trustTokenExpiresAt;
|
|
48093
|
+
}
|
|
48094
|
+
async refreshTrustToken() {
|
|
48095
|
+
try {
|
|
48096
|
+
const res = await fetch(`${this.config.apiUrl}/api/v1/gate/token`, {
|
|
48097
|
+
method: "POST",
|
|
48098
|
+
headers: {
|
|
48099
|
+
Authorization: `Bearer ${this._deviceJwt}`,
|
|
48100
|
+
"Content-Type": "application/json"
|
|
48101
|
+
}
|
|
48102
|
+
});
|
|
48103
|
+
if (res.ok) {
|
|
48104
|
+
const data = await res.json();
|
|
48105
|
+
this._trustToken = data.token;
|
|
48106
|
+
this._trustTier = data.tier;
|
|
48107
|
+
this._trustTokenExpiresAt = data.expires_at;
|
|
48108
|
+
}
|
|
48109
|
+
} catch (err) {
|
|
48110
|
+
console.warn("[AgentVault] Trust token refresh failed:", err);
|
|
48111
|
+
}
|
|
48112
|
+
}
|
|
48113
|
+
startTrustTokenRefresh() {
|
|
48114
|
+
this.refreshTrustToken();
|
|
48115
|
+
this._trustTokenInterval = setInterval(
|
|
48116
|
+
() => this.refreshTrustToken(),
|
|
48117
|
+
12 * 60 * 1e3
|
|
48118
|
+
);
|
|
48119
|
+
}
|
|
48120
|
+
stopTrustTokenRefresh() {
|
|
48121
|
+
if (this._trustTokenInterval) {
|
|
48122
|
+
clearInterval(this._trustTokenInterval);
|
|
48123
|
+
this._trustTokenInterval = null;
|
|
48124
|
+
}
|
|
48125
|
+
}
|
|
47929
48126
|
async stop() {
|
|
47930
48127
|
this._stopped = true;
|
|
47931
48128
|
await this.stopHeartbeat();
|
|
48129
|
+
this.stopTrustTokenRefresh();
|
|
47932
48130
|
this._flushAcks();
|
|
47933
48131
|
this._stopPing();
|
|
47934
48132
|
this._stopWakeDetector();
|
|
@@ -48044,6 +48242,10 @@ var init_channel = __esm({
|
|
|
48044
48242
|
res.end(JSON.stringify({ ok: false, error: "Internal MCP error" }));
|
|
48045
48243
|
}
|
|
48046
48244
|
});
|
|
48245
|
+
} else if (req.method === "GET" && req.url === "/trust") {
|
|
48246
|
+
const result = handlers.handleTrustRequest(this);
|
|
48247
|
+
res.writeHead(result.status, { "Content-Type": "application/json" });
|
|
48248
|
+
res.end(JSON.stringify(result.body));
|
|
48047
48249
|
} else if (req.method === "GET" && req.url === "/mcp-config") {
|
|
48048
48250
|
const agentName = this.config.agentName ?? "agent";
|
|
48049
48251
|
const mcpSkillCount = this._mcpServer?.skillCount ?? 0;
|
|
@@ -48550,6 +48752,7 @@ var init_channel = __esm({
|
|
|
48550
48752
|
});
|
|
48551
48753
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
48552
48754
|
}
|
|
48755
|
+
this.startTrustTokenRefresh();
|
|
48553
48756
|
this.emit("ready");
|
|
48554
48757
|
} catch (openErr) {
|
|
48555
48758
|
console.error("[SecureChannel] Error in WS open handler:", openErr);
|
|
@@ -48582,6 +48785,17 @@ var init_channel = __esm({
|
|
|
48582
48785
|
return;
|
|
48583
48786
|
}
|
|
48584
48787
|
if (data.event === "message") {
|
|
48788
|
+
const inMsgId = data.data?.message_id;
|
|
48789
|
+
if (inMsgId && this._seenMessageIds.has(inMsgId)) {
|
|
48790
|
+
return;
|
|
48791
|
+
}
|
|
48792
|
+
if (inMsgId) {
|
|
48793
|
+
this._seenMessageIds.add(inMsgId);
|
|
48794
|
+
if (this._seenMessageIds.size > _SecureChannel.SEEN_MSG_MAX) {
|
|
48795
|
+
const first = this._seenMessageIds.values().next().value;
|
|
48796
|
+
if (first) this._seenMessageIds.delete(first);
|
|
48797
|
+
}
|
|
48798
|
+
}
|
|
48585
48799
|
try {
|
|
48586
48800
|
await this._handleIncomingMessage(data.data);
|
|
48587
48801
|
} catch (msgErr) {
|
|
@@ -48612,6 +48826,17 @@ var init_channel = __esm({
|
|
|
48612
48826
|
}).catch((err) => this.emit("error", err));
|
|
48613
48827
|
}
|
|
48614
48828
|
if (data.event === "room_message") {
|
|
48829
|
+
const rmMsgId = data.data?.message_id;
|
|
48830
|
+
if (rmMsgId && this._seenMessageIds.has(rmMsgId)) {
|
|
48831
|
+
return;
|
|
48832
|
+
}
|
|
48833
|
+
if (rmMsgId) {
|
|
48834
|
+
this._seenMessageIds.add(rmMsgId);
|
|
48835
|
+
if (this._seenMessageIds.size > _SecureChannel.SEEN_MSG_MAX) {
|
|
48836
|
+
const first = this._seenMessageIds.values().next().value;
|
|
48837
|
+
if (first) this._seenMessageIds.delete(first);
|
|
48838
|
+
}
|
|
48839
|
+
}
|
|
48615
48840
|
try {
|
|
48616
48841
|
await this._handleRoomMessage(data.data);
|
|
48617
48842
|
} catch (rmErr) {
|
|
@@ -49146,6 +49371,10 @@ var init_channel = __esm({
|
|
|
49146
49371
|
if (!session.activated) {
|
|
49147
49372
|
session.activated = true;
|
|
49148
49373
|
console.log(`[SecureChannel] Session ${convId.slice(0, 8)}... activated by first owner message`);
|
|
49374
|
+
if (this._persisted?.sessions[convId]) {
|
|
49375
|
+
this._persisted.sessions[convId].activated = true;
|
|
49376
|
+
}
|
|
49377
|
+
await this._persistState();
|
|
49149
49378
|
}
|
|
49150
49379
|
let messageText;
|
|
49151
49380
|
let messageType;
|
|
@@ -49760,6 +49989,14 @@ ${messageText}`;
|
|
|
49760
49989
|
`[SecureChannel] Room ratchet re-initialized for conv ${convId.slice(0, 8)}...`
|
|
49761
49990
|
);
|
|
49762
49991
|
plaintext = session.ratchet.decrypt(encrypted);
|
|
49992
|
+
session.activated = true;
|
|
49993
|
+
if (this._persisted.sessions[convId]) {
|
|
49994
|
+
this._persisted.sessions[convId].activated = true;
|
|
49995
|
+
}
|
|
49996
|
+
await this._persistState();
|
|
49997
|
+
console.log(
|
|
49998
|
+
`[SecureChannel] Room session ${convId.slice(0, 8)}... re-activated after ratchet re-init`
|
|
49999
|
+
);
|
|
49763
50000
|
} catch (reinitErr) {
|
|
49764
50001
|
console.error(
|
|
49765
50002
|
`[SecureChannel] Room ratchet re-init failed for conv ${convId.slice(0, 8)}...:`,
|
|
@@ -49778,6 +50015,14 @@ ${messageText}`;
|
|
|
49778
50015
|
messageType = "message";
|
|
49779
50016
|
messageText = plaintext;
|
|
49780
50017
|
}
|
|
50018
|
+
if (CREDENTIAL_MESSAGE_TYPES.has(messageType)) {
|
|
50019
|
+
this._handleCredentialMessage(msgData.room_id, messageType, messageText, msgData.message_id);
|
|
50020
|
+
if (msgData.created_at && this._persisted) {
|
|
50021
|
+
this._persisted.lastMessageTimestamp = msgData.created_at;
|
|
50022
|
+
}
|
|
50023
|
+
await this._persistState();
|
|
50024
|
+
return;
|
|
50025
|
+
}
|
|
49781
50026
|
if (!ROOM_AGENT_TYPES.has(messageType)) {
|
|
49782
50027
|
return;
|
|
49783
50028
|
}
|
|
@@ -49814,6 +50059,94 @@ ${messageText}`;
|
|
|
49814
50059
|
console.error("[SecureChannel] onMessage callback error:", err);
|
|
49815
50060
|
});
|
|
49816
50061
|
}
|
|
50062
|
+
/**
|
|
50063
|
+
* Handle credential protocol messages (grant, revoke, request).
|
|
50064
|
+
* These are intercepted before reaching the agent's onMessage callback.
|
|
50065
|
+
*/
|
|
50066
|
+
_handleCredentialMessage(roomId, messageType, plaintext, messageId) {
|
|
50067
|
+
try {
|
|
50068
|
+
const payload = JSON.parse(plaintext);
|
|
50069
|
+
if (messageType === "credential_grant") {
|
|
50070
|
+
const grant = payload;
|
|
50071
|
+
if (grant.nonce && !this._credentialStore.checkNonce(roomId, grant.nonce)) {
|
|
50072
|
+
console.warn(`[SecureChannel] Credential grant replay detected for room ${roomId.slice(0, 8)}..., ignoring`);
|
|
50073
|
+
return;
|
|
50074
|
+
}
|
|
50075
|
+
const keys = [];
|
|
50076
|
+
for (const cred of grant.credentials || []) {
|
|
50077
|
+
this._credentialStore.grant(roomId, {
|
|
50078
|
+
key: cred.key,
|
|
50079
|
+
value: cred.value,
|
|
50080
|
+
type: cred.type,
|
|
50081
|
+
scope: cred.scope,
|
|
50082
|
+
grantedAt: grant.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
50083
|
+
agreementId: grant.agreement_id,
|
|
50084
|
+
roomId
|
|
50085
|
+
});
|
|
50086
|
+
keys.push(cred.key);
|
|
50087
|
+
}
|
|
50088
|
+
console.log(
|
|
50089
|
+
`[SecureChannel] Credentials granted for room ${roomId.slice(0, 8)}...: ${keys.join(", ")} (${keys.length} keys)`
|
|
50090
|
+
);
|
|
50091
|
+
this._sendCredentialAck(roomId, grant.agreement_id, keys, "stored");
|
|
50092
|
+
this.emit("credentials_granted", { roomId, keys, agreementId: grant.agreement_id });
|
|
50093
|
+
} else if (messageType === "credential_revoke") {
|
|
50094
|
+
const revoke = payload;
|
|
50095
|
+
const revoked = [];
|
|
50096
|
+
for (const key of revoke.credential_keys || []) {
|
|
50097
|
+
if (this._credentialStore.revoke(roomId, key)) {
|
|
50098
|
+
revoked.push(key);
|
|
50099
|
+
}
|
|
50100
|
+
}
|
|
50101
|
+
console.log(
|
|
50102
|
+
`[SecureChannel] Credentials revoked for room ${roomId.slice(0, 8)}...: ${revoked.join(", ")} (reason: ${revoke.reason || "none"})`
|
|
50103
|
+
);
|
|
50104
|
+
this._sendCredentialAck(roomId, revoke.agreement_id, revoked, "revoked");
|
|
50105
|
+
this.emit("credentials_revoked", { roomId, keys: revoked, agreementId: revoke.agreement_id });
|
|
50106
|
+
}
|
|
50107
|
+
} catch (err) {
|
|
50108
|
+
console.error("[SecureChannel] Error handling credential message:", err);
|
|
50109
|
+
}
|
|
50110
|
+
if (messageId) {
|
|
50111
|
+
this._sendAck(messageId);
|
|
50112
|
+
}
|
|
50113
|
+
}
|
|
50114
|
+
/**
|
|
50115
|
+
* Send a credential_ack back to a room.
|
|
50116
|
+
*/
|
|
50117
|
+
_sendCredentialAck(roomId, agreementId, keys, ackStatus) {
|
|
50118
|
+
const ack = JSON.stringify({
|
|
50119
|
+
type: "credential_ack",
|
|
50120
|
+
agreement_id: agreementId,
|
|
50121
|
+
acknowledged_keys: keys,
|
|
50122
|
+
status: ackStatus,
|
|
50123
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
50124
|
+
});
|
|
50125
|
+
this.sendToRoom(roomId, ack, { messageType: "credential_ack" }).catch((err) => {
|
|
50126
|
+
console.warn("[SecureChannel] Failed to send credential ACK:", err);
|
|
50127
|
+
});
|
|
50128
|
+
}
|
|
50129
|
+
// --- Public credential accessors ---
|
|
50130
|
+
/** Get a specific renter credential for a room. */
|
|
50131
|
+
getCredential(roomId, key) {
|
|
50132
|
+
return this._credentialStore.get(roomId, key);
|
|
50133
|
+
}
|
|
50134
|
+
/** Get all renter credentials for a room (includes values — for agent context). */
|
|
50135
|
+
getCredentials(roomId) {
|
|
50136
|
+
return this._credentialStore.getAll(roomId);
|
|
50137
|
+
}
|
|
50138
|
+
/** Get credential key→value map for a room (for context injection). */
|
|
50139
|
+
getCredentialMap(roomId) {
|
|
50140
|
+
return this._credentialStore.getCredentialMap(roomId);
|
|
50141
|
+
}
|
|
50142
|
+
/** Check if a specific credential exists for a room. */
|
|
50143
|
+
hasCredential(roomId, key) {
|
|
50144
|
+
return this._credentialStore.has(roomId, key);
|
|
50145
|
+
}
|
|
50146
|
+
/** Purge all credentials for a room (call on rental end). */
|
|
50147
|
+
purgeRoomCredentials(roomId) {
|
|
50148
|
+
this._credentialStore.purgeForRoom(roomId);
|
|
50149
|
+
}
|
|
49817
50150
|
/**
|
|
49818
50151
|
* Find the pairwise conversation ID for a given sender in a room.
|
|
49819
50152
|
*/
|
|
@@ -49976,6 +50309,14 @@ ${messageText}`;
|
|
|
49976
50309
|
messageType = "message";
|
|
49977
50310
|
messageText = plaintext;
|
|
49978
50311
|
}
|
|
50312
|
+
if (CREDENTIAL_MESSAGE_TYPES.has(messageType)) {
|
|
50313
|
+
this._handleCredentialMessage(msgData.room_id, messageType, messageText, msgData.message_id);
|
|
50314
|
+
if (msgData.created_at && this._persisted) {
|
|
50315
|
+
this._persisted.lastMessageTimestamp = msgData.created_at;
|
|
50316
|
+
}
|
|
50317
|
+
await this._persistState();
|
|
50318
|
+
return;
|
|
50319
|
+
}
|
|
49979
50320
|
if (!ROOM_AGENT_TYPES.has(messageType)) {
|
|
49980
50321
|
return;
|
|
49981
50322
|
}
|
|
@@ -76664,21 +77005,26 @@ function loadSkillsFromDirectory(dir) {
|
|
|
76664
77005
|
const skills = [];
|
|
76665
77006
|
const absDir = resolve2(dir);
|
|
76666
77007
|
if (!existsSync(absDir)) return skills;
|
|
76667
|
-
const
|
|
76668
|
-
|
|
76669
|
-
|
|
76670
|
-
|
|
76671
|
-
|
|
77008
|
+
const seen = /* @__PURE__ */ new Set();
|
|
77009
|
+
function tryLoad(filePath) {
|
|
77010
|
+
if (seen.has(filePath)) return;
|
|
77011
|
+
seen.add(filePath);
|
|
77012
|
+
try {
|
|
77013
|
+
const content = readFileSync(filePath, "utf-8");
|
|
77014
|
+
const skill = parseSkillMd(content);
|
|
77015
|
+
if (skill) skills.push(skill);
|
|
77016
|
+
} catch {
|
|
77017
|
+
}
|
|
76672
77018
|
}
|
|
76673
77019
|
try {
|
|
76674
77020
|
const entries = readdirSync(absDir, { withFileTypes: true });
|
|
76675
77021
|
for (const entry of entries) {
|
|
76676
|
-
if (entry.
|
|
77022
|
+
if (entry.isFile() && entry.name.endsWith("SKILL.md")) {
|
|
77023
|
+
tryLoad(join4(absDir, entry.name));
|
|
77024
|
+
} else if (entry.isDirectory()) {
|
|
76677
77025
|
const subSkill = join4(absDir, entry.name, "SKILL.md");
|
|
76678
77026
|
if (existsSync(subSkill)) {
|
|
76679
|
-
|
|
76680
|
-
const skill = parseSkillMd(content);
|
|
76681
|
-
if (skill) skills.push(skill);
|
|
77027
|
+
tryLoad(subSkill);
|
|
76682
77028
|
}
|
|
76683
77029
|
}
|
|
76684
77030
|
}
|
|
@@ -77079,6 +77425,7 @@ var init_index = __esm({
|
|
|
77079
77425
|
async "src/index.ts"() {
|
|
77080
77426
|
await init_channel();
|
|
77081
77427
|
init_types();
|
|
77428
|
+
init_credential_store();
|
|
77082
77429
|
init_account_config();
|
|
77083
77430
|
await init_openclaw_plugin();
|
|
77084
77431
|
init_gateway_send();
|
|
@@ -77097,6 +77444,7 @@ var init_index = __esm({
|
|
|
77097
77444
|
await init_index();
|
|
77098
77445
|
export {
|
|
77099
77446
|
AgentVaultMcpServer,
|
|
77447
|
+
CredentialStore,
|
|
77100
77448
|
PolicyEnforcer,
|
|
77101
77449
|
SecureChannel,
|
|
77102
77450
|
VERSION,
|