Skip to content

Latest commit

 

History

History
735 lines (526 loc) · 23.1 KB

File metadata and controls

735 lines (526 loc) · 23.1 KB

🤖 Telegram ChatBot

Telegram two-way chat bot · Web admin panel · Multi-storage backend · Multiple verification methods

Vue 3 Cloudflare Pages Docker PostgreSQL MIT License

中文文档


Users DM the bot → auto-creates a forum topic → admin replies → message forwarded back to user.

Deploy via Cloudflare Pages or Docker. Storage supports KV / D1 / Hyperdrive (PostgreSQL & MySQL) with seamless switching.


Features · Quick Start · Deployment · Configuration · Verification · Message Filtering · Storage · Security · Local Dev · Troubleshooting


✨ Features

📨 Messaging
  • Two-way message forwarding (user ↔ admin forum topics)
  • Per-user forum topics
  • Message edit sync
  • Message deduplication (prevents duplicate forwarding)
  • Supports all message types (text/photo/video/audio/file/sticker/location/poll etc.)
  • Admin replies auto-forwarded back to user
🔐 Verification System (8 verification methods)
Type Key Required Site URL Required Description
Math Random arithmetic, button selection
Image Numeric 4-digit image captcha
Image Alphanumeric 5-digit alphanumeric image captcha
Cloudflare Turnstile Cloudflare invisible verification
Google reCAPTCHA v2 "I'm not a robot" checkbox
Google reCAPTCHA v3 Invisible score-based verification
hCaptcha hCaptcha verification widget

All verification methods support:

  • Auto-timeout with notification and cleanup
  • Max attempts limit
  • Whitelist bypass
🛡️ Moderation
  • Ban / unban / permanent ban
  • User appeal flow (admin approval)
  • Slash command filter (/xxx commands not forwarded to admin)
  • Zalgo abnormal text filter
  • Keyword filtering (text and regex rules, ReDoS protection)
🖥️ Web Admin Panel
  • Dashboard (total users, message statistics, bot info)
  • Conversation history
  • User management (ban/unblock/whitelist/delete)
  • Whitelist management
  • Full settings page (Bot/Webhook/Verification/Features/Filters/Welcome/Storage)
  • Profile (change password/username/2FA)
🗄️ Storage System
  • KV — Zero config, suitable for small-medium scale
  • D1 — SQLite, supports SQL queries
  • Hyperdrive — PostgreSQL / MySQL, suitable for production
  • One-click switching with automatic data sync
  • SQL import/export (plain / Base64 / AES-256-GCM encryption)
🌍 Internationalization
  • Simplified Chinese / Traditional Chinese / English
  • Bot message language and WebUI language configured independently
  • Switch bot language via settings page

🚀 Quick Start

Fastest: Docker Compose

git clone https://github.com/milangree/Telegram_ChatBot.git
cd Telegram_ChatBot
docker compose up -d

Visit http://localhost:3000. On first boot a temporary admin admin is created; the random password is printed in the server logs (log in immediately and complete first-time registration to disable the default account).

To set a specific admin password on first boot (avoid checking logs), add ADMIN_USERNAME and ADMIN_PASSWORD environment variables in docker-compose.yml — see the "Environment Variables" table below for details.

Setup Order

  1. Login to WebUI → Change password → Enable 2FA
  2. Set Bot Token (from @BotFather)
  3. Set Forum Group ID (supergroup with topics enabled, system provides chat resolver)
  4. Set Admin Telegram IDs
  5. Set Webhook URL: https://your-domain/webhook
  6. Choose and configure verification method
  7. Test: user sends message → topic created → admin replies → user receives

📦 Deployment Guide

☁️ Cloudflare Pages Deployment

1. Create Storage Resources

Required — KV namespace: Cloudflare Dashboard → Workers & Pages → KV → Create a namespace

Optional — D1 database:

npx wrangler d1 create tg-chatbot-d1

Optional — Hyperdrive: Dashboard → Hyperdrive → Create connection (postgres:// / mysql://)

2. Create Pages Project

Fork this repo → Workers & Pages → Create → Pages → Connect GitHub repo

Setting Value
Framework preset Vue
Build command npm run build
Output directory dist

3. Add Bindings

Settings → Bindings → Add binding:

Variable Binding type Required
KV KV namespace
D1 D1 database
HYPERDRIVE Hyperdrive

For Hyperdrive: run npm install pg mysql2 and add nodejs_compat in Settings → Compatibility flags.

4. Deploy

Push code to trigger auto-deploy. You'll get https://your-project.pages.dev.

5. How to look up / recover admin accounts on Cloudflare

Passwords are stored as hashes only. Plaintext passwords cannot be recovered; you can only reset them.

Find usernames (Dashboard):

  1. Cloudflare Dashboard → Workers & Pages → KV
  2. Open the KV namespace bound to this project
  3. Search these prefixes:
    • webuser: → key suffix is the username (e.g. webuser:ops)
    • webuser_id: → full account JSON (username / id / totp_enabled)
    • auth:bootstrap:v2 → bootstrap admin state (defaultAdminUsername / state)

If D1 is bound:

npx wrangler d1 execute <your-d1-name> --remote --command "SELECT id, username, is_admin, totp_enabled, created_at FROM web_users;"

Reset password (manual Cloudflare steps):

  1. Generate a new password hash locally:
npm run admin -- hash-password 'NewPassw0rd!'
# Example output: pbkdf2:100000:<salt>:<hash>
  1. Update the target account:
    • KV: edit password_hash in both webuser_id:<id> and webuser:<username>
    • D1:
npx wrangler d1 execute <your-d1-name> --remote --command "UPDATE web_users SET password_hash='pbkdf2:...' WHERE username='ops';"
  1. Revoke existing sessions (strongly recommended):

    • Put/overwrite KV key auth:session_epoch:<userId> with any random string
    • Optionally delete sess_user:<userId>: keys and matching sess: keys
  2. If 2FA is also lost, set totp_enabled to 0 and clear totp_secret.

🐳 Docker Deployment

Docker Compose (Recommended)

git clone https://github.com/milangree/Telegram_ChatBot.git
cd Telegram_ChatBot
docker compose up -d

Docker Run

docker pull kakuwari/tg-chatbot:latest
docker run -d \
  -p 3000:3000 \
  -v telegram-data:/app/data \
  --name telegram-chatbot \
  kakuwari/tg-chatbot:latest

Build Locally

docker build -t telegram-chatbot .
docker run -d -p 3000:3000 -v data:/app/data telegram-chatbot

Environment Variables

Variable Default Description
PORT 3000 Server port
KV_FILE /app/data/kv-store.db KV storage SQLite path
D1_FILE /app/data/d1-store.db D1 storage SQLite path
DATABASE_URL PostgreSQL / MySQL connection string
ACTIVE_DB kv Storage backend: kv / d1 / hyperdrive
COOKIE_SECURE false Set to true behind HTTPS reverse proxy
KV_PERSIST true KV persistence (recommended for Docker)
ADMIN_USERNAME admin Initial admin username (Docker/VPS, effective on first boot)
ADMIN_PASSWORD Initial admin password (not printed in logs when set, supports password sync on restart)

See .env.example for the full list of environment variables.

Using PostgreSQL

Edit docker-compose.yml, uncomment the PostgreSQL service:

services:
  telegram-chatbot:
    environment:
      - DATABASE_URL=postgresql://telegram:password@postgres:5432/telegram_bot
      - ACTIVE_DB=hyperdrive

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: telegram_bot
      POSTGRES_USER: telegram
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-telegram_password}
    volumes:
      - postgres-data:/var/lib/postgresql/data

HTTPS Configuration

Docker has no built-in HTTPS. Use a reverse proxy:

Cloudflare Tunnel (Recommended):

cloudflared tunnel --url http://localhost:3000

Nginx Reverse Proxy:

server {
    listen 443 ssl;
    server_name bot.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Admin recovery CLI (local / Docker)

If the permanent admin username / password / 2FA are all lost, Web recovery is not enough. Use the ops CLI:

# Local
npm run admin -- list
npm run admin -- show <username|id>
npm run admin -- bootstrap
npm run admin -- reset-password <username|id> --yes
npm run admin -- reset-password <username|id> --password 'NewPassw0rd!' --yes
npm run admin -- disable-2fa <username|id> --yes
npm run admin -- create newadmin --password 'NewPassw0rd!' --yes

# Docker
docker exec -it telegram-chatbot node scripts/admin-recovery.js list
docker exec -it telegram-chatbot node scripts/admin-recovery.js reset-password ops --yes
docker exec -it telegram-chatbot node scripts/admin-recovery.js disable-2fa ops --yes

Notes:

  • list shows username, id, 2FA status, whether login is blocked, and whether it is the bootstrap account
  • reset-password resets the password and revokes all sessions for that user
  • If --password is omitted, a random password is generated and printed once
  • Plaintext passwords cannot be recovered from hashes
  • A retired bootstrap account (login=blocked) is usually not the permanent login account — reset the real admin, or create a new one

⚙️ Configuration

🤖 Bot Settings
Setting Description Required
BOT_TOKEN Telegram Bot Token (from @BotFather)
FORUM_GROUP_ID Forum supergroup ID (starts with -100)
ADMIN_IDS Admin Telegram IDs (comma-separated)
BOT_LOCALE Bot language: zh-hans / zh-hant / en

Getting Group ID: Use the "Query Chat ID" helper in WebUI settings — enter group username or link to resolve.

🔗 Webhook Settings
Setting Description
WEBHOOK_URL Webhook URL, format: https://domain/webhook

After setting the webhook, WEBHOOK_SECRET is auto-generated for request verification. On Cloudflare Pages, CAPTCHA_SITE_URL is auto-filled from the Webhook URL origin.

🔐 Verification Settings
Setting Default Description
VERIFICATION_ENABLED true Verification toggle
CAPTCHA_TYPE math Verification type (see table below)
VERIFICATION_TIMEOUT 300 Timeout in seconds (60-3600)
MAX_VERIFICATION_ATTEMPTS 3 Max retry attempts (1-10)
CAPTCHA_SITE_URL Verification page site URL

Per-type settings:

Setting Used by
TURNSTILE_SITE_KEY / TURNSTILE_SECRET_KEY Cloudflare Turnstile
RECAPTCHA_SITE_KEY / RECAPTCHA_SECRET_KEY Google reCAPTCHA v2
RECAPTCHA_V3_SITE_KEY / RECAPTCHA_V3_SECRET_KEY Google reCAPTCHA v3
RECAPTCHA_V3_SCORE_THRESHOLD reCAPTCHA v3 min score (default 0.5)
HCAPTCHA_SITE_KEY / HCAPTCHA_SECRET_KEY hCaptcha
🛡️ Moderation Settings
Setting Default Description
AUTO_UNBLOCK_ENABLED true Allow banned users to appeal
WHITELIST_ENABLED false Whitelist feature (skip verification)
BOT_COMMAND_FILTER true Filter /xxx commands from forwarding
ADMIN_NOTIFY_ENABLED false Admin DM notifications
ZALGO_FILTER_ENABLED true Filter Zalgo abnormal text
MESSAGE_FILTER_RULES [] Keyword filter rules (JSON array)
⏰ Message Management Settings
Setting Default Description
USER_MSG_DELETE_SECONDS 30 Auto-delete user messages (0=disabled)
INLINE_KB_MSG_DELETE_ENABLED true Auto-delete button messages toggle
INLINE_KB_MSG_DELETE_SECONDS 30 Auto-delete button messages timeout
WELCOME_ENABLED true Welcome message toggle
WELCOME_MESSAGE Welcome message content (HTML supported)
🔒 Security Settings
Setting Default Description
LOGIN_SESSION_TTL 86400 WebUI login expiration (seconds)

Passwords stored with PBKDF2 (100,000 iterations SHA-256). TOTP two-factor authentication supported. If username/password/2FA are all lost, use the ops CLI or Cloudflare manual recovery (see Deployment). Plaintext passwords cannot be recovered from hashes.


🔐 Verification System

Flow

User sends first message
    ↓
Bot sends verification message (buttons/image/link, depending on type)
    ↓
User completes verification
    ↓
Bot marks user as verified → forwards pending message to admin
    ↓
Subsequent messages forwarded directly, no re-verification needed

Timeout Handling

  • After timeout, bot auto-edits verification message to "⏳ Verification timed out"
  • Cleans up all verification data (verify record, pending message, webverify KV)
  • User can re-trigger verification by sending a new message

Whitelist

Whitelisted users skip verification. Add via WebUI or bot command /wl <userID>.


📝 Message Filtering (Regex)

Two filter rule types supported:

Type Description Example
text Plain text match (case-insensitive) spam, advertisement
regex Regular expression match /https?:\/\/t\.me\/\w+/i

Adding Rules

WebUI: Settings → Message Filter → Select type → Enter content → Add

Bot commands:

/addfilter text keyword
/addfilter regex /https?:\/\/t\.me\/\w+/i
/delfilter 1
/filters

Regex Tutorial

Regex Basic Syntax
Syntax Description Example
. Any single character a.c matches abc, a1c
* Previous char 0+ times ab*c matches ac, abc, abbc
+ Previous char 1+ times ab+c matches abc, abbc
? Previous char optional ab?c matches ac, abc
\d Digit [0-9] \d+ matches one or more digits
\w Word char [a-zA-Z0-9_] \w+ matches a word
\s Whitespace \s+ matches one or more spaces
[abc] Character set [aeiou] matches any vowel
[^abc] Negated set [^0-9] matches non-digit
(abc) Group (ab)+ matches ab, abab
a|b Or cat|dog matches cat or dog
^ Start of line ^Hello matches Hello at start
$ End of line end$ matches end at end
Common Filter Regex Examples
# Match Telegram invite links
/addfilter regex /t\.me\/(joinchat\/|\+)\w+/i

# Match all external links
/addfilter regex /https?:\/\/[^\s]+/i

# Match phone numbers
/addfilter regex /\b1[3-9]\d{9}\b/

# Match specific keywords (Chinese)
/addfilter regex /加群|进群|入群/

# Match pure emoji messages (5+ consecutive)
/addfilter regex /^[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]{5,}$/u
Regex Testing & Debugging

Online Testing Tools

Before adding complex regex rules, test them with online tools:

  • regex101.com — Most popular regex tester with syntax highlighting and explanation
  • regexr.com — Visual regex matching
  • debuggex.com — Regex visualization (state machine diagrams)

Testing Steps

  1. Open regex101.com
  2. Paste your test message text in "Test String"
  3. Enter your regex in "Regular Expression" (without leading/trailing / and flags)
  4. Select flags on the right: g (global), i (case-insensitive), m (multiline)
  5. Confirm the match results are correct, then add in bot: /addfilter regex /your-regex/flags

Notes

  • Regex matching targets extracted plain text from message content (not raw JSON), including text, usernames, titles, etc.
  • Avoid nested quantifiers like (a+)+ — these cause ReDoS (Regex Denial of Service)
  • The system auto-detects and rejects regex patterns with ReDoS risk at creation time
  • Match target string is limited to 4096 characters to prevent performance issues with long messages
  • Regex match failures (syntax errors etc.) silently return no-match without affecting message processing
ReDoS Protection

Built-in ReDoS (Regular Expression Denial of Service) protection:

  1. Creation-time detection: Nested quantifier patterns (e.g., (a+)+, (a|a)+) are automatically detected and rejected
  2. Match-time protection: Regex matching is wrapped in try-catch, target string limited to 4096 characters
  3. Silent errors: Match failures don't affect normal message processing

If your regex is rejected, it contains patterns that may cause catastrophic backtracking. Simplify the regex or use more specific character classes.


🗄️ Storage System

Backend Use Case Features
KV Small-medium Zero config, key-value storage
D1 Medium-large SQLite, SQL queries, transactions
Hyperdrive Production PostgreSQL / MySQL, external database

Switching Storage

One-click switch in WebUI Settings → Storage Management. System auto-syncs data.

⚠️ Stop bot message processing before switching to avoid data inconsistency during sync.

SQL Import/Export

Three modes supported:

  • Plain — Direct SQL text export
  • Base64 — Base64 encoded
  • AES-256-GCM — Encrypted export, requires password

🛡️ Security

Mechanism Description
Password Hashing PBKDF2 (100,000 iterations SHA-256), backward-compatible with legacy salt:sha256
Two-Factor Auth TOTP (RFC 6238), login page recovery supported
Webhook Verification Secret Token header validation
SQL Injection Prevention All queries use parameterized bindings
Default Admin Random password on first boot (printed in logs); auto-disabled after real registration
ReDoS Protection Regex creation-time detection, match-time protection
Regex Error Handling Match exceptions handled silently, no message flow disruption

🛠️ Local Development

# Install dependencies (frontend + backend)
npm install
cd server && npm install && cd ..

# Build frontend
npm run build

# Start full stack (static UI + API + Webhook)
npm run preview
# equivalent to: node server/index.js
# open http://localhost:3000

# Stop local server
npm run stop
# or press Ctrl+C in the start terminal

# Static-only preview (no API — not for local integration)
npm run preview:static

How to stop the local server:

Method Command / Action Notes
Recommended npm run stop Stops by PID file / listening port
Foreground Ctrl+C in the start terminal Graceful shutdown
Alias npm run server:stop Same as npm run stop

npm run preview starts server/index.js, serving the UI together with /api and /webhook.
Running plain vite preview (preview:static) alone will make /api/* requests fail with empty/non-JSON responses.
If better-sqlite3 cannot be installed (missing Python / build tools), the server falls back to in-memory KV (data is lost on restart), which is fine for local integration.


🩺 Troubleshooting

WebUI 500 / Blank Page

Check that KV is bound with variable name KV (uppercase). Redeploy after binding.

In Docker mode, check KV_FILE path has write permissions.

Webhook Setup Fails
  • Bot Token is correct (format: 123456:ABC-DEF...)
  • URL must be public HTTPS: https://domain/webhook
  • Docker users need a reverse proxy for HTTPS
Messages Not Forwarding
  • Group has topics enabled (supergroup → Settings → Topics)
  • Bot is a group admin (needs manage topics permission)
  • FORUM_GROUP_ID is correct (starts with -100)
  • User has passed verification
Forgot Password
  • With 2FA enabled: Use the login page "Recover" flow with TOTP code
  • Without 2FA: Manually edit storage (delete web_users records in KV/D1/database, restart to rebuild default admin)
Docker Has No HTTPS

Use one of:

  • Cloudflare Tunnel (recommended): cloudflared tunnel --url http://localhost:3000
  • Nginx reverse proxy (see deployment guide)
  • Caddy: Auto-HTTPS, simplest configuration
Verification Timeout No Response
  • Check VERIFICATION_TIMEOUT setting (default 300 seconds)
  • Turnstile/reCAPTCHA requires correct CAPTCHA_SITE_URL configuration
  • Unconfigured secret keys auto-fallback to math captcha
  • Check container logs: docker compose logs -f telegram-chatbot
Viewing Container Logs
# Real-time logs
docker compose logs -f telegram-chatbot

# Last 100 lines
docker compose logs --tail 100 telegram-chatbot

# Key log keywords
# [web_app_verify] — Web verification callbacks
# [verify_timeout] — Verification timeout cleanup
# [api/verify] — Verification API operations

📄 License

See the LICENSE file in the repository root.