fix(cli): e2e encrypt vault entries with libsodium
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claudemesh-cli",
|
"name": "claudemesh-cli",
|
||||||
"version": "0.8.3",
|
"version": "0.8.4",
|
||||||
"description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
"description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"claude-code",
|
"claude-code",
|
||||||
|
|||||||
@@ -1354,16 +1354,30 @@ Your message mode is "${messageMode}".
|
|||||||
const client = allClients()[0];
|
const client = allClients()[0];
|
||||||
if (!client) return text("vault_set: not connected", true);
|
if (!client) return text("vault_set: not connected", true);
|
||||||
const entryType = vType ?? "env";
|
const entryType = vType ?? "env";
|
||||||
let plaintext = value;
|
|
||||||
|
// Read plaintext
|
||||||
|
let plaintextBytes: Uint8Array;
|
||||||
if (entryType === "file") {
|
if (entryType === "file") {
|
||||||
const { existsSync, readFileSync } = await import("node:fs");
|
const { existsSync, readFileSync } = await import("node:fs");
|
||||||
if (!existsSync(value)) return text(`vault_set: file not found: ${value}`, true);
|
if (!existsSync(value)) return text(`vault_set: file not found: ${value}`, true);
|
||||||
plaintext = readFileSync(value, "base64");
|
plaintextBytes = new Uint8Array(readFileSync(value));
|
||||||
|
} else {
|
||||||
|
plaintextBytes = new TextEncoder().encode(value);
|
||||||
}
|
}
|
||||||
const encoded = Buffer.from(plaintext).toString("base64");
|
|
||||||
const ok = await client.vaultSet(key, encoded, "placeholder-nonce", "placeholder-sealed", entryType, mount_path, description);
|
// E2E encrypt: crypto_secretbox with random Kf, then seal Kf with mesh pubkey
|
||||||
|
const { encryptFile, sealKeyForPeer } = await import("../crypto/file-crypto");
|
||||||
|
const { ciphertext, nonce, key: kf } = await encryptFile(plaintextBytes);
|
||||||
|
const sealedKey = await sealKeyForPeer(kf, client.getMeshPubkey());
|
||||||
|
|
||||||
|
// Convert ciphertext to base64 for storage
|
||||||
|
const { ensureSodium } = await import("../crypto/keypair");
|
||||||
|
const sodium = await ensureSodium();
|
||||||
|
const ciphertextB64 = sodium.to_base64(ciphertext, sodium.base64_variants.ORIGINAL);
|
||||||
|
|
||||||
|
const ok = await client.vaultSet(key, ciphertextB64, nonce, sealedKey, entryType, mount_path, description);
|
||||||
if (!ok) return text("vault_set: broker did not acknowledge", true);
|
if (!ok) return text("vault_set: broker did not acknowledge", true);
|
||||||
return text(`Vault entry "${key}" stored (${entryType}).`);
|
return text(`Vault entry "${key}" stored (${entryType}, E2E encrypted).`);
|
||||||
}
|
}
|
||||||
case "vault_list": {
|
case "vault_list": {
|
||||||
const client = allClients()[0];
|
const client = allClients()[0];
|
||||||
|
|||||||
@@ -194,6 +194,10 @@ export class BrokerClient {
|
|||||||
getSessionPubkey(): string | null { return this.sessionPubkey; }
|
getSessionPubkey(): string | null { return this.sessionPubkey; }
|
||||||
/** Session secret key hex (null before first connection). */
|
/** Session secret key hex (null before first connection). */
|
||||||
getSessionSecretKey(): string | null { return this.sessionSecretKey; }
|
getSessionSecretKey(): string | null { return this.sessionSecretKey; }
|
||||||
|
/** Mesh member public key hex (stable across sessions). */
|
||||||
|
getMeshPubkey(): string { return this.mesh.pubkey; }
|
||||||
|
/** Mesh member secret key hex (stable across sessions). */
|
||||||
|
getMeshSecretKey(): string { return this.mesh.secretKey; }
|
||||||
|
|
||||||
private makeReqId(): string {
|
private makeReqId(): string {
|
||||||
return Math.random().toString(36).slice(2) + Date.now().toString(36);
|
return Math.random().toString(36).slice(2) + Date.now().toString(36);
|
||||||
|
|||||||
Reference in New Issue
Block a user