manual improvement 2 & add telegram bot
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# balinyaar-telegram-otp-bot
|
||||
|
||||
A **standalone, dev-only** Telegram relay. It is not part of `client/` or `server/` — it is its own
|
||||
tiny Node project with **zero dependencies** (Node 18+ built-ins only: `node:http` + global `fetch`).
|
||||
|
||||
Its whole job: expose an HTTP endpoint that the .NET API calls, and forward the message to a fixed
|
||||
list of Telegram chat ids. That replaces "read the OTP out of the server log" during manual testing —
|
||||
you get the code on your phone instead, without paying an Iranian SMS gateway.
|
||||
|
||||
> **Development only.** There is no per-user routing: *every* configured recipient receives *every*
|
||||
> OTP, regardless of which phone number requested it. That is fine for a test group; it is not an SMS
|
||||
> gateway. Do not point a real environment at this.
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Create the bot.** Message [@BotFather](https://t.me/BotFather) → `/newbot` → follow the prompts →
|
||||
copy the token (`1234567890:AAH...`).
|
||||
|
||||
2. **Configure.**
|
||||
```bash
|
||||
cd telegram-otp-bot
|
||||
cp .env.example .env # PowerShell: Copy-Item .env.example .env
|
||||
node -e "console.log(require('crypto').randomBytes(24).toString('hex'))"
|
||||
```
|
||||
Paste the token into `TELEGRAM_BOT_TOKEN` and the generated secret into `API_KEY`
|
||||
(**required** — the process refuses to start without it). Leave `TELEGRAM_CHAT_IDS` empty for now.
|
||||
|
||||
3. **Run it.**
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
No `npm install` needed — there are no dependencies. On boot it prints the bot's `@username`, which
|
||||
confirms the token works.
|
||||
|
||||
4. **Discover the chat ids.** Each recipient opens the bot in Telegram and presses **Start** (a bot
|
||||
cannot open a conversation — the user must message it first). Then:
|
||||
```bash
|
||||
curl -H "X-Api-Key: $API_KEY" http://localhost:5010/chat_ids
|
||||
```
|
||||
Copy the returned `chat_id` values into `TELEGRAM_CHAT_IDS` (comma-separated) and restart.
|
||||
|
||||
5. **Test it.**
|
||||
```bash
|
||||
curl -X POST http://localhost:5010/send_otp \
|
||||
-H "X-Api-Key: $API_KEY" \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"phone":"09120000001","code":"123456"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## HTTP API
|
||||
|
||||
Base URL: `http://127.0.0.1:5010` (configurable via `HOST`/`PORT`).
|
||||
|
||||
**Every route except `GET /health` requires the `X-Api-Key` header**, compared against `API_KEY` in
|
||||
constant time. There is no way to disable it: `API_KEY` is mandatory (min 16 chars) and the process
|
||||
exits at boot without one, so the relay is never reachable unauthenticated. A rejected request is
|
||||
logged with the caller's address.
|
||||
|
||||
| Route | Auth | Body | Purpose |
|
||||
| --- | --- | --- | --- |
|
||||
| `GET /health` | — | — | Liveness only; echoes no configuration. |
|
||||
| `GET /chat_ids` | `X-Api-Key` | — | Chat ids that recently messaged the bot (setup helper). |
|
||||
| `POST /send_otp` | `X-Api-Key` | `{ "phone": "...", "code": "..." }` | Broadcast a login code. |
|
||||
| `POST /send` | `X-Api-Key` | `{ "phone": "...", "message": "..." }` | Broadcast a free-form transactional message. |
|
||||
|
||||
The two POST routes mirror the server's `ISmsSender` (`SendOtpAsync` / `SendAsync`) one-for-one, so a
|
||||
`TelegramSmsSender` adapter is a thin HTTP call per method.
|
||||
|
||||
**Response**
|
||||
|
||||
```json
|
||||
{ "ok": true, "delivered": ["11111111"], "failed": [{ "chatId": "22222222", "error": "chat not found" }] }
|
||||
```
|
||||
|
||||
- `200` — at least one recipient received it (partial delivery still counts; one reachable reader is
|
||||
enough to complete a login).
|
||||
- `502` — **no** recipient received it. The caller should treat this as a delivery failure so the OTP
|
||||
command fails loudly rather than pretending an undeliverable code was sent.
|
||||
- `503` — `TELEGRAM_CHAT_IDS` is empty.
|
||||
- `400` / `401` — bad body / missing-or-wrong `X-Api-Key`.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `TELEGRAM_BOT_TOKEN` | — | **Required.** From @BotFather. Process exits without it. |
|
||||
| `API_KEY` | — | **Required**, min 16 chars. Shared secret expected in `X-Api-Key`. Process exits without it. |
|
||||
| `TELEGRAM_CHAT_IDS` | — | Comma-separated recipient chat ids. Empty ⇒ every send returns `503`. |
|
||||
| `PORT` | `5010` | HTTP port. |
|
||||
| `HOST` | `127.0.0.1` | Bind address. Keep it loopback unless the API runs on another machine. |
|
||||
| `REDACT_CODE_IN_LOGS` | `false` | Keep the code out of *this process's* stdout (still delivered). |
|
||||
|
||||
The API key is the only access control — there is no IP allow-list and no TLS. Keep `HOST` on
|
||||
loopback when the API runs on the same machine; if you must expose it, put it behind something that
|
||||
terminates TLS, or the key travels in clear text.
|
||||
|
||||
Values come from `.env` (git-ignored) or from real environment variables, which take precedence.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Cause |
|
||||
| --- | --- |
|
||||
| `chat not found` in `failed[]` | That user never messaged the bot. Press **Start** in Telegram. |
|
||||
| `GET /chat_ids` returns nothing | No message in the last 24h, or a webhook is set on the bot (`getUpdates` returns nothing while a webhook is registered — call `deleteWebhook`). |
|
||||
| `token check FAILED` / `fetch failed` | Wrong/revoked token, or no outbound access to `api.telegram.org` — see below. |
|
||||
| `401` on every call | The caller isn't sending `X-Api-Key`, or its value differs from `API_KEY`. |
|
||||
|
||||
### Reaching Telegram from Iran
|
||||
|
||||
`api.telegram.org` is filtered, so the machine running this needs a proxy. On **Node 24+** the built-in
|
||||
`fetch` honours the standard proxy variables once opted in — uncomment these in `.env`:
|
||||
|
||||
```
|
||||
NODE_USE_ENV_PROXY=1
|
||||
HTTPS_PROXY=http://127.0.0.1:10809
|
||||
```
|
||||
|
||||
pointing `HTTPS_PROXY` at whatever your VPN/proxy client listens on. On older Node, run the process
|
||||
under a system-wide/TUN-mode proxy instead — `fetch` there ignores the env vars.
|
||||
Reference in New Issue
Block a user