Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ await channels.resolveApproval({ id: 'the-approval-id', approved: true });
| Channel | Request | Response |
| ------- | ------- | -------- |
| `httpChannel({ name?, verify? })` | JSON `{ sessionKey, input }` (`input` a string or content parts); anything else is a 400. Without `verify`, a body sent without `Content-Type: application/json` is a `415` (`LOUSHO_UNSUPPORTED_MEDIA_TYPE`), so a web page cannot post a form to it | `200 { sessionId, text, finishReason }`; when paused, `approval` too and `text` is the prompt |
| `webhookChannel({ secret?, auth?, name?, principal? })` | The JSON body's `input` string, or the whole body; a one-shot session unless the body has a `sessionKey` | `200` with the turn's `ExecutionResult` |
| `webhookChannel({ secret?, auth?, name?, principal?, fullResult? })` | The JSON body's `input` string, or the whole body; a one-shot session unless the body has a `sessionKey` | `200` with `{ sessionId, text, finishReason, approval? }` (the full `ExecutionResult` with `fullResult: true`) |
| `slackChannel({ signingSecret, botToken, name?, fetch?, approvers?, onError? })` | Slack Events API and interactivity requests (see [Slack](#slack)) | `200` at once; replies are posted in the Slack thread |
| `discordChannel({ publicKey, applicationId, botToken?, name?, fetch?, approvers?, onError? })` | Discord slash-command and button interactions (see [Discord](#discord)) | Deferred ack at once; the reply edits the original response |
| `telegramChannel({ botToken, secretToken, botUsername?, name?, fetch?, approvers?, onError? })` | Telegram bot webhook updates: messages and inline-keyboard taps (see [Telegram](#telegram)) | `200` at once; replies are sent with `sendMessage` as plain text |
Expand Down
2 changes: 1 addition & 1 deletion llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4231,7 +4231,7 @@ await channels.resolveApproval({ id: 'the-approval-id', approved: true });
| Channel | Request | Response |
| ------- | ------- | -------- |
| `httpChannel({ name?, verify? })` | JSON `{ sessionKey, input }` (`input` a string or content parts); anything else is a 400. Without `verify`, a body sent without `Content-Type: application/json` is a `415` (`LOUSHO_UNSUPPORTED_MEDIA_TYPE`), so a web page cannot post a form to it | `200 { sessionId, text, finishReason }`; when paused, `approval` too and `text` is the prompt |
| `webhookChannel({ secret?, auth?, name?, principal? })` | The JSON body's `input` string, or the whole body; a one-shot session unless the body has a `sessionKey` | `200` with the turn's `ExecutionResult` |
| `webhookChannel({ secret?, auth?, name?, principal?, fullResult? })` | The JSON body's `input` string, or the whole body; a one-shot session unless the body has a `sessionKey` | `200` with `{ sessionId, text, finishReason, approval? }` (the full `ExecutionResult` with `fullResult: true`) |
| `slackChannel({ signingSecret, botToken, name?, fetch?, approvers?, onError? })` | Slack Events API and interactivity requests (see [Slack](#slack)) | `200` at once; replies are posted in the Slack thread |
| `discordChannel({ publicKey, applicationId, botToken?, name?, fetch?, approvers?, onError? })` | Discord slash-command and button interactions (see [Discord](#discord)) | Deferred ack at once; the reply edits the original response |
| `telegramChannel({ botToken, secretToken, botUsername?, name?, fetch?, approvers?, onError? })` | Telegram bot webhook updates: messages and inline-keyboard taps (see [Telegram](#telegram)) | `200` at once; replies are sent with `sendMessage` as plain text |
Expand Down
4 changes: 3 additions & 1 deletion src/channels/httpChannel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ describe('httpChannel verify warning', () => {
expect(warn).toHaveBeenCalledTimes(1);
const message = String(warn.mock.calls[0]?.[0]);
expect(message).toContain('[lousho]');
expect(message).toMatch(/unauthenticated/);
expect(message).toMatch(/unless the server in front of it checks auth/);
expect(message).toMatch(/LOUSHO_API_TOKEN/);
expect(message).not.toMatch(/is unauthenticated/);
expect(message).toMatch(/sessionKey/);
expect(message).toMatch(/verify/);
});
Expand Down
8 changes: 4 additions & 4 deletions src/channels/httpChannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface HttpChannelOptions {
* JSON `Content-Type` (else `415`), so a web page cannot post to it with a
* form; under `lousho dev` its `Host` is checked like the dev routes'.
* Omitting it logs a one-time warning: sessions are keyed by the
* caller-chosen `sessionKey`, so an unauthenticated channel exposes them.
* caller-chosen `sessionKey`, so without a `verify` (or auth in the host in front of it) anyone who can reach it can guess them.
*/
verify?: (req: ChannelRequest) => Promise<boolean>;
}
Expand All @@ -38,9 +38,9 @@ export interface HttpChannelOptions {
export function httpChannel(options: HttpChannelOptions = {}): Channel {
if (!options.verify) {
console.warn(
'[lousho] httpChannel() has no `verify`: the channel is unauthenticated, and sessions are keyed by the caller-chosen `sessionKey`, ' +
"so anyone who can reach it can read or continue another user's conversation by guessing a key. " +
'Pass `verify: async (req) => req.headers.authorization === `Bearer ${token}`` (see docs/channels.md#securing-the-http-channel).'
'[lousho] httpChannel() has no `verify`: unless the server in front of it checks auth (the built node-server does when LOUSHO_API_TOKEN or auth.ts is set), ' +
'anyone who can reach it can use the agent and guess `sessionKey` values to read or continue other conversations. ' +
'Pass `verify: async (req) => req.headers.authorization === `Bearer ${token}`` to authenticate requests yourself (see docs/channels.md#securing-the-http-channel).'
);
}
return defineChannel({
Expand Down
Loading