79785768

Date: 2025-10-08 18:42:50
Score: 0.5
Natty:
Report link

# code/python (save as bot.py)

"""

Secure minimal Telegram bot using python-telegram-bot (v20+)

Features:

- Token loaded from env var

- Admin-only commands (by telegram user_id)

- Safe DB access (sqlite + parameterized queries)

- Graceful error handling & rate limiting (simple)

- Example of using webhook (recommended) or polling fallback

"""

import os

import logging

import sqlite3

import time

from functools import wraps

from http import HTTPStatus

from telegram import Update, Bot

from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, MessageHandler, filters

# --- Configuration (from environment) ---

BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")

if not BOT_TOKEN:

raise SystemExit("TELEGRAM_BOT_TOKEN env var required")

ALLOWED_ADMINS = {int(x) for x in os.getenv("BOT_ADMINS", "").split(",") if x.strip()} # comma-separated IDs

WEBHOOK_URL = os.getenv("WEBHOOK_URL") # e.g. https://your.domain/path

DATABASE_PATH = os.getenv("BOT_DB_PATH", "bot_data.sqlite")

# --- Logging ---

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")

logger = logging.getLogger("secure_bot")

# --- DB helpers (safe parameterized queries) ---

def init_db():

conn = sqlite3.connect(DATABASE_PATH, check_same_thread=False)

c = conn.cursor()

c.execute("""CREATE TABLE IF NOT EXISTS messages (

              id INTEGER PRIMARY KEY AUTOINCREMENT,

              user_id INTEGER,

              username TEXT,

              text TEXT,

              ts INTEGER

            )""")

conn.commit()

return conn

db = init_db()

# --- admin check decorator ---

def admin_only(func):

@wraps(func)

async def wrapper(update: Update, context: ContextTypes.DEFAULT_TYPE):

    user = update.effective_user

    if not user or user.id not in ALLOWED_ADMINS:

        logger.warning("Unauthorized access attempt by %s (%s)", user.id if user else "unknown", user.username if user else "")

        if update.effective_chat:

            await update.effective_chat.send_message("Unauthorized.")

        return

    return await func(update, context)

return wrapper

# --- Handlers ---

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):

await update.message.reply_text("Hello. This bot is configured securely. Use /help for commands.")

async def help_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):

await update.message.reply_text("/status - admin only\\n/echo \<text\> - echo back\\n/help - this message")

@admin_only

async def status(update: Update, context: ContextTypes.DEFAULT_TYPE):

await update.message.reply_text("OK — bot is running.")

async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):

\# store incoming message safely

try:

    msg = update.effective_message

    with db:

        db.execute("INSERT INTO messages (user_id, username, text, ts) VALUES (?, ?, ?, ?)",

                   (msg.from_user.id, msg.from_user.username or "", msg.text or "", int(time.time())))

    \# simple rate-limit: disallow messages \> 400 chars

    if msg.text and len(msg.text) \> 400:

        await msg.reply_text("Message too long.")

        return

    await msg.reply_text(msg.text or "Empty message.")

except Exception as e:

    logger.exception("Error in echo handler: %s", e)

    await update.effective_chat.send_message("Internal error.")

# --- basic command to rotate token reminder (admin only) ---

@admin_only

async def rotate_reminder(update: Update, context: ContextTypes.DEFAULT_TYPE):

await update.message.reply_text("Reminder: rotate token and update TELEGRAM_BOT_TOKEN env var on server.")

# --- Build application ---

async def main():

app = ApplicationBuilder().token(BOT_TOKEN).concurrent_updates(8).build()

app.add_handler(CommandHandler("start", start))

app.add_handler(CommandHandler("help", help_cmd))

app.add_handler(CommandHandler("status", status))

app.add_handler(CommandHandler("rotate", rotate_reminder))

app.add_handler(CommandHandler("echo", echo))

app.add_handler(MessageHandler(filters.TEXT & \~filters.COMMAND, echo))

\# Webhook preferred (more secure than polling) if WEBHOOK_URL provided

if WEBHOOK_URL:

    \# set webhook (TLS must be handled by your web server/reverse-proxy)

    bot = Bot(token=BOT_TOKEN)

    await bot.set_webhook(WEBHOOK_URL)

    logger.info("Webhook set to %s", WEBHOOK_URL)

    \# start the app (it will use long polling by default in local runner;

    \# for production you should run an ASGI server with endpoints calling app.update_queue)

    await app.initialize()

    await app.start()

    logger.info("Bot started with webhook mode (app running).")

    \# keep running until terminated

    await app.updater.stop()  # placeholder to keep structure consistent

else:

    \# fallback to polling (useful for dev only)

    logger.info("Starting in polling mode (development only).")

    await app.run_polling()

if _name_ == "_main_":

import asyncio

asyncio.run(main())
Reasons:
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @admin_only
  • Low reputation (1):
Posted by: dot