- Go 99.6%
- Dockerfile 0.4%
| internal | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| bot.go | ||
| BRIEF.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| README.md | ||
lainrocks Telegram Bot
A Telegram bot that ties a Telegram user_id to a lain.rocks account (LLDAP uid) and exposes:
- New email notifications — watch Maildir dirs for new mail, DM the user.
- lainboard new-post notifications — poll
/var/www/boards/<board>/threads.json, DM on new threads/replies. - Account access from Telegram — link/unlink Telegram ↔ LLDAP, view profile, change password, register.
Link methods
- LDAP bind —
/link <uid> <password>: bot attemptsldap://10.0.0.1:3890bind asuid=<uid>,ou=people,dc=lain,dc=rocks. - Authelia OIDC (variant A) —
/link oidc: bot returns an Authelia authorization URL; user logs in a browser, pastes the code back to/link oidc <code>; bot exchanges code → token →/api/oidc/userinfo→preferred_username. - Claim token —
/link claim <token>: user generates a claim token on the web account page and pastes it.
Commands
| Command | Auth | Behavior |
|---|---|---|
/start |
none | welcome + link options |
/help |
none | command list |
/link <uid> <password> |
none | LDAP bind link |
/link oidc [<code>] |
none | OIDC authorize / paste code |
/link claim <token> |
none | claim token link |
/unlink |
linked | remove mapping |
/whoami |
linked | uid + profile via LLDAP GraphQL |
/passwd <new> |
linked | verify current, then change via admin ldap_modify |
/register <uid> <email> <password> |
none | create LLDAP account (rate-limited) |
/subscribe <board> |
linked | subscribe to board alerts |
/unsubscribe <board> |
linked | unsubscribe |
/subscribed |
linked | list subscriptions |
/stats |
admin | bot statistics |
Gated commands reply Please link your account first when unlinked.
User interface
The bot registers a command menu so users see a /commands button in the chat attachment menu. In addition to typing commands, most actions are available via clickable inline keyboards:
- Linking —
/startor/linkshows buttons for LDAP bind, Authelia OAuth2, and claim token. - Main menu — every reply attaches a menu with Whoami, Subscribe, and Help buttons.
- Board subscriptions — tap a board to toggle subscription on/off.
- Unlink — confirmed via Yes/Cancel buttons.
All user-facing messages are HTML-formatted (bold labels, code spans for commands/credentials).
Admin permission system
Set ADMIN_USER_IDS in .env to a comma-separated list of Telegram user IDs (e.g. ADMIN_USER_IDS=12345678,87654321). Only listed IDs can run admin commands:
/stats— linked accounts, total board subscriptions, admin count.
Stack
- Language: Go 1.26 (stdlib
net/httpfor Telegram Bot API; no external bot framework) - LDAP:
github.com/go-ldap/ldap/v3 - SQLite:
modernc.org/sqlite(pure Go, no CGO) - Env:
github.com/joho/godotenv
Deployment
cp .env.example .env
# edit .env with real secrets (BOT_TOKEN, LDAP_ADMIN_PW, AUTHELIA_CLIENT_SECRET)
go build -o bot .
sudo systemctl edit --force --full telegram-bot
Systemd unit (/etc/systemd/system/telegram-bot.service):
[Unit]
Description=lainrocks Telegram Bot
After=network.target
[Service]
Type=simple
WorkingDir=/root/stacks/telegram-bot
EnvironmentFile=/root/stacks/telegram-bot/.env
ExecStart=/root/stacks/telegram-bot/bot
Restart=unless-stopped
User=root
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now telegram-bot
sudo journalctl -u telegram-bot -f
Docker
Build and run with compose:
cp .env.example .env
# edit .env with real secrets
docker compose up -d --build
docker compose logs -f telegram-bot
The container joins the existing ldap_net Docker network (external) so it can reach LLDAP at ldap://10.0.0.1:3890 and the LLDAP HTTP API at http://10.0.0.1:17170. It persists state in the telegram-bot-data volume mounted at /app/data.
No ports are published — the bot polls Telegram via getUpdates long-poll.
Files created at runtime
data/links.db— SQLite:links(tg_id, uid UNIQUE, linked_at, tg_username),subs(tg_id, board),state(key, value)state.json— poll state (mail seen files by inode+mtime; per-board last_no/last_modified)
Secrets
.env is gitignored. Never commit real tokens or passwords.