Skip to content

Commit 33defda

Browse files
authored
Merge pull request #260 from sanil-23/fix/agent-send-requires-encryption
fix(sdk): fail fast when agent messaging has no encryption
2 parents f464f32 + 1561dc6 commit 33defda

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

sdk/typescript/src/agent/messaging.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,34 @@ export interface SendMessageResult {
8989
}
9090

9191
/**
92-
* Sends a message to `recipient` (a @handle, cryptoId, or base64 key). The body
93-
* is Signal-encrypted by the client before it leaves the process when encryption
94-
* is configured (the recommended setup); otherwise it is sent as plaintext.
92+
* The E2E facade REQUIRES a client with encryption configured (`encryption: { store }`
93+
* + a signer). A client without it would relay the body as plaintext, which the backend
94+
* rejects — a plaintext JSON body trips its `looksLikeJSON` guard with `HTTP 400: body
95+
* must be encrypted ciphertext`, surfacing far from the misconfiguration (a client built
96+
* without a signer/store, e.g. an under-provisioned daemon). Fail fast with a clear cause
97+
* instead of leaking plaintext. Callers that want plain transport use `client.messages.send`.
98+
*/
99+
function assertEncryptionEnabled(client: TinyPlaceClient): void {
100+
if (client.encryptionEnabled) return;
101+
throw new Error(
102+
"agent messaging requires encryption: construct the client with " +
103+
"`encryption: { store }` and a signer. Sending a plaintext body over the " +
104+
'E2E channel is rejected by the relay ("body must be encrypted ciphertext").',
105+
);
106+
}
107+
108+
/**
109+
* Sends a message to `recipient` (a @handle, cryptoId, or base64 key). The body is
110+
* Signal-encrypted by the client before it leaves the process; encryption must be
111+
* configured (see {@link assertEncryptionEnabled}).
95112
*/
96113
export async function sendMessage(
97114
client: TinyPlaceClient,
98115
signer: AgentSigner,
99116
recipient: string,
100117
text: string,
101118
): Promise<SendMessageResult> {
119+
assertEncryptionEnabled(client);
102120
const to = await resolveRecipientKey(client, recipient);
103121
const envelope: MessageEnvelope = {
104122
id: messageId(),

sdk/typescript/tests/agent-messaging.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,16 @@ describe("sendMessage / readMessages round-trip", () => {
162162
// Consumed on read.
163163
expect(await readMessages(bob.client, bob.signer)).toHaveLength(0);
164164
});
165+
166+
it("refuses to send when the client has no encryption configured", async () => {
167+
// A client built without `encryption: { store }` would relay the body as
168+
// plaintext, which the backend rejects with `400: body must be encrypted
169+
// ciphertext`. The facade must fail fast at the misconfiguration instead.
170+
const signer = await LocalSigner.generate();
171+
const plain = new TinyPlaceClient({ baseUrl: "https://relay.test", signer });
172+
expect(plain.encryptionEnabled).toBe(false);
173+
await expect(
174+
sendMessage(plain, signer, signer.agentId, "hi"),
175+
).rejects.toThrow(/requires encryption/);
176+
});
165177
});

0 commit comments

Comments
 (0)