remote/api
The Remote API is the Signal service. It verifies remote tickets, issues resume tokens and TURN
credentials, and relays WebRTC signalling between peers. It does not carry team chats, files, or
commands. The exceptions are Slack, Discord, Telegram and GitHub. POST /v1/slack/events checks the OpenBot Slack
app's signature, reads only the app ID (api_app_id), the workspace ID (team_id), the
url_verification challenge, and the event's type, channel_type, thread_ts, bot_id and
subtype (to know whether it addresses OpenBot, never the text), and passes the body to the ingress
socket of the workspace's host in transit. POST /v1/telegram/updates/<bot ID> checks the bot's secret header, reads only the chat ID,
the callback query ID, a /start <code> link code, and the chat type, the entity types and whether the
message replies, is in a thread, or renames or leaves the chat (to know whether it can address
OpenBot, never the text), and passes the body to the ingress socket of
the chat's host in the same way. POST /v1/github/events checks the OpenBot GitHub App's signature,
reads only the installation ID and the repository ID, and passes the body to the ingress socket of
every host whose GitHub route names the repository. Do not log these bodies, and do not read more of them. The one store
is src/ingress-queue.ts: for a hosted server that sleeps, and for the /start update of a Telegram
chat that was just linked to a host, it keeps an event in memory only, sealed to the host's queue key
before it is queued, for at most 10 minutes. Never keep a body that is not
sealed, and never write the queue to disk. Hosts
trust a delivery because Signal checked the signature or the secret; never remove those checks.
Signal holds the Telegram bot tokens: a host that had one could read and post in every chat. Never
put a bot token in a frame, a log, an error message or a result. A host calls the Bot API only
through telegram-call, and src/protocol.ts accepts only the methods and the parameters of
TelegramCallParams, with strict objects. Do not add a method or a key there without the same
change in the contract. src/signal-service.ts allows a call only into a chat routed to that socket,
and an answer only to a callback query delivered to it. A result has only the reduced fields of
TelegramCallResult. Files go through short signed tokens (TelegramFileTokens); an upload token
works once.
Signal also holds the OpenBot Discord bot. src/discord-gateway.ts holds the bot token and the
Gateway connection; src/discord-events.ts turns a Gateway event into a delivery for the ingress
socket of the guild's host; src/discord-api.ts makes the typed Discord calls of POST /v1/discord/api for a host, only in the guilds routed to its socket. Never log the bot token, a
discord-session token, an interaction token, a message's content or Discord's error text. Never
let a host call Discord in a guild or channel that is not routed to its socket.
- The message shapes come from
@openbot/contracts/signal-protocol.src/protocol.tsonly re-exports them for the server. Change them there, and keep released messages compatible. src/tokens.tsholds the secrets. Compare secrets in constant time (timingSafeEqual), and keep the TTL limits. Never log a ticket, a token, a Slack, Discord, Telegram or GitHub route ticket, a request or update body, a bot token, a file or upload token, a TURN credential, or a secret fromsrc/config.ts. Log only the error message, assrc/app.tsdoes.- This project uses Bun types. Keep them inside
remote/api; rootscripts/**and Electron main use Node types. See check design notes. remote/scripts/update.tsrecreates the live coturn container. Do not run it as a check.bun run test:signalstarts this service with throwaway secrets and checks the secret and authentication rules above over real HTTP and WebSocket. CI runs it whenremote/changes.