UNPKG

@essentialai/cogent-bridge

Version:

Cogent Bridge — cross-agent comms for Claude Code, OpenAI Codex and Slack. Codex users: install with `curl -fsSL https://cogent.tools/install.sh | sh`, then start with `cogent-codex` for real-time peer wake.

83 lines • 5.01 kB
import { successResult, errorResult, BridgeError, BridgeErrorCode } from "../errors.js"; import { loadCredentials } from "../cloud/credential-store.js"; import { loadMailCredentials, saveMailCredentials, MAIL_DEFAULT_HOST, } from "../cloud/mail-credential-store.js"; /** Total budget for the relay round-trip. */ const ROTATE_TIMEOUT_MS = 8000; /** * cogent_rotate_mail_creds — self-service mailbox password rotation (Cogent Mail M2.4). * * Re-keys THIS agent's Team mailbox: the bridge asks the relay (authenticated by the per-cwd cloud * session token) to rotate on the mail server; the relay derives orgScope + channel label from the * session (never client input) so the box is targeted deterministically. On success the fresh * password is returned ONCE and written to the per-cwd 0600 mail-credential store, so subsequent * cogent_send_mail / cogent_fetch_mail keep working. Use it if a mailbox password may be compromised. * * Cloud + Team only: it needs cloud credentials (endpoint/session/token/peerId) and a CP-provisioned * mailbox. A free/local session gets a clear "rotation isn't available for this channel" error. */ export function registerRotateMailCredsTool(server) { server.registerTool("cogent_rotate_mail_creds", { title: "Rotate this agent's mailbox password", description: "Rotate (re-key) this agent's Team mailbox password on the mail server and update the local " + "credential store, so cogent_send_mail / cogent_fetch_mail keep working with the fresh secret. " + "Use it if the mailbox password may be compromised. Team channels only.", inputSchema: {}, annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, }, async () => { try { const creds = await loadCredentials(); if (!creds || !creds.endpoint || !creds.sessionId || !creds.token) { throw new BridgeError(BridgeErrorCode.INVALID_INPUT, "Not registered in cloud mode", "Rotation applies to a cloud Team channel — register the peer first"); } if (!creds.peerId) { throw new BridgeError(BridgeErrorCode.INVALID_INPUT, "Cannot identify this peer", "Re-register the peer so its peerId is stored, then rotate"); } const url = `${creds.endpoint.replace(/\/+$/, "")}/api/sessions/${encodeURIComponent(creds.sessionId)}` + `/peers/${encodeURIComponent(creds.peerId)}/mail/rotate`; let res; try { res = await fetch(url, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${creds.token}` }, body: "{}", signal: AbortSignal.timeout(ROTATE_TIMEOUT_MS), }); } catch { throw new BridgeError(BridgeErrorCode.NETWORK_TIMEOUT, "Could not reach the relay to rotate the mailbox", "Check connectivity and try again"); } if (!res.ok) { // The relay maps a non-Team / no-rotator channel to a 400 with a clear message. const detail = await res.text().catch(() => ""); throw new BridgeError(BridgeErrorCode.INVALID_INPUT, `Mailbox rotation was rejected (HTTP ${res.status})`, detail.slice(0, 200) || "Rotation applies to Team channels with a provisioned mailbox"); } const data = (await res.json().catch(() => null)); if (!data || data.success !== true) { throw new BridgeError(BridgeErrorCode.NETWORK_TIMEOUT, "Mailbox rotation failed", "The relay returned an unexpected response"); } if (!data.rotated) { // Clean "nothing to rotate" (no mailbox) — do NOT touch the local creds. return successResult({ rotated: false, reason: data.reason ?? "no_mailbox" }); } if (!data.address || !data.password) { throw new BridgeError(BridgeErrorCode.NETWORK_TIMEOUT, "Rotation returned no new password", "Try again; the mailbox password was not updated locally"); } // Persist the fresh secret, preserving the existing host/port config where present. const existing = await loadMailCredentials(); await saveMailCredentials({ address: data.address, password: data.password, imapHost: existing?.imapHost ?? MAIL_DEFAULT_HOST, imapPort: existing?.imapPort ?? 993, smtpHost: existing?.smtpHost ?? MAIL_DEFAULT_HOST, smtpPort: existing?.smtpPort ?? 465, savedAt: new Date().toISOString(), }); return successResult({ rotated: true, address: data.address }); } catch (err) { return errorResult(err); } }); } //# sourceMappingURL=rotate-mail-creds.js.map