Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: quality

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:18
env:
POSTGRES_USER: captcha
POSTGRES_PASSWORD: replace-me
POSTGRES_DB: captcha
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U captcha -d captcha"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
CAPTCHA_BOT_CONFIG: config.example.toml
TEST_DATABASE_URL: postgresql+psycopg://captcha:replace-me@127.0.0.1:5432/captcha

steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v8
with:
enable-cache: true
python-version: "3.14"
- run: uv sync --locked --all-groups
- run: uv run ruff format --check .
- run: uv run ruff check .
- run: uv run ty check src main.py tests
- run: uv run pytest
- run: uv run alembic upgrade head
- run: uv run alembic current
- run: uv run alembic check
- run: uv run pip-audit
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# config files
config.json
config.ini
config.toml

# Byte-compiled / optimized / DLL files
__pycache__/
Expand All @@ -18,4 +19,11 @@ __pycache__/
data.sqlite

#venv
venv
venv
.venv

# Tool caches
.pytest_cache/
.ruff_cache/
.coverage
htmlcov/
13 changes: 0 additions & 13 deletions Dockerfile

This file was deleted.

165 changes: 111 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,86 +1,143 @@
# Telegram-CAPTCHA-bot
# Telegram CAPTCHA Bot

一个用于验证新成员是不是真人的bot
基于 Kurigram、FastAPI 和 PostgreSQL 的异步 Telegram 入群验证机器人。支持普通入群与申请入群、数学题与 Cloudflare Turnstile、人工通过/拒绝、超时处理、全局黑名单及验证日志/IP 管理

[![GNU Public License Affero 3.0](https://img.shields.io/badge/license-AGPL3.0-%23373737.svg)](https://www.gnu.org/licenses/agpl-3.0.en.html) [![Python 3.11](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org) [![Pyrogram](https://img.shields.io/badge/Pyrogram-asyncio-green.svg)](https://github.com/pyrogram/pyrogram/)
本版本固定使用 **Python 3.14**,依赖只由 `pyproject.toml` 与 `uv.lock` 管理。配置只读取 TOML;旧 INI/JSON 配置需要先通过迁移命令转换。

A bot running on Telegram which will send CAPTCHA to verify if the new member is a human.
## 准备

基于[原始项目](https://github.com/Tooruchan/Telegram-CAPTCHA-bot-pyrogram)修改
需要:

Forked based on [Original Repository](https://github.com/TooruchanTelegram-CAPTCHA-bot-pyrogram)
- Python 3.14
- [uv](https://docs.astral.sh/uv/)
- PostgreSQL
- Telegram Bot Token、API ID 与 API Hash
- Cloudflare Turnstile site key 与 secret key

修改者:[@kkren](https://www.kkren.me/)(新 API 支持)
安装锁定依赖:

Bot实例: [@FubukiAntiSpamBot](https://t.me/FubukiAntiSpamBot)
日志频道:[@FAS_bot_log](https://t.me/FAS_bot_log)
```bash
uv sync --locked
cp config.example.toml config.toml
chmod 600 config.toml
```

## 一些简单的Q&A
编辑 `config.toml` 中的 `[bot]`、`[database]`、`[web]`、`[proxy]`、`[turnstile]`、`[defaults]` 和 `[messages]`。数据库 URL 必须使用 PostgreSQL,例如:

```toml
[database]
url = "postgresql+psycopg://captcha:password@127.0.0.1/captcha"
```

Q: 被误加入黑名单了,怎么解除?
配置会在启动前严格校验:ID 和端口类型、正数范围、动作/验证类型枚举、HTTP URL、可信代理 CIDR 及消息占位符均不合法时拒绝启动。Token、API Hash、数据库 URL 和 Turnstile secret 在模型日志中会被隐藏。

A: 当前此 bot 实例只会进行踢出群操作,只需要再次加入你想加入的群,如果被自动踢出,在1分钟之后10分钟之内再次加入即可进入。
## 原理
## 从旧配置迁移

本 Bot 通过读取 Telegram API 中返回的入群消息来识别新用户入群,并生成一道随机问题对用户进行验证,非严格模式只要有回答问题就通过;严格模式下回答错误将会被移除或者封禁,这个验证的效果目前无法绕过具有人工操作的广告机器人,但是可以对外语(如阿拉伯语和波斯语)类骚扰用户起到一定的拦截作用。再此基础上增加了全局黑名单功能,只有验证超时的广告机器人会自动加入到[黑名单](https://ca.oracle.db.nimaqu.com/view/phpliteadmin.php?database=.%2Fdb%2Fdata.sqlite&table=user&fulltexts=0&numRows=30&action=row_view),之后在任意有此 bot 的群组加群将会被自动踢出,对误封禁的影响造成最低。
```bash
uv run captcha-bot migrate-config \
--ini config.ini \
--json config.json \
--output config.toml
```

Telegram Bot API 使用了基于 MTProto 框架的 pyrogram,多线程使用了 asyncio
迁移命令不会覆盖已有输出文件,不会输出秘密,并会报告已删除的遗留字段。POSIX 系统上的新文件权限会设置为 `0600`。运行时不再读取 INI 或 JSON

## 安装与使用
## 数据库升级与启动

此仓库仅为遵守 AGPL 协议进行代码展示,并未对用户部署使用进行优化,普通用户建议直接使用[原始项目](https://github.com/Tooruchan/Telegram-CAPTCHA-bot-pyrogram) 如果你仍想使用此 Bot,请参照下面说明进行部署。
首次部署或每次更新代码后,必须先显式升级数据库;应用不会自动修改生产库:

Python 要求: **最低 python 版本 3.9 ,建议 python 版本: 3.11**
1. 请先向 [@BotFather](https://t.me/botfather) 申请一个 Bot API Token
> 你申请到的机器人会在你的 Telegram 账号所在数据中心上运行(即申请机器人的账号A位于 DC 5 (新加坡),则 A 申请到的机器人也将会在 DC5 上运行)
2. 在 [Obtaining Telegram API ID](https://core.telegram.org/api/obtaining_api_id) 申请 API ID 与 API Hash
3. 使用 Python Virtual Environment 部署:
```bash
CAPTCHA_BOT_CONFIG=config.toml uv run alembic upgrade head
CAPTCHA_BOT_CONFIG=config.toml uv run alembic current
uv run captcha-bot run --config config.toml
```
# 若未安装pip3,请先安装 python3-pip
apt update && apt install -y python3-pip python3
git clone https://github.com/NimaQu/Telegram-CAPTCHA-bot-pyrogram.git
cd Telegram-CAPTCHA-bot-pyrogram
python3 -m venv venv
venv/bin/pip install wheel
venv/bin/pip install -r requirements.txt

兼容入口仍然可用:

```bash
uv run python main.py
```

Web 服务保留以下接口:

- `GET /`:状态页,缓存五分钟
- `GET|POST /recaptcha?challenge=...`:Turnstile 验证页,禁止缓存
- `GET /healthz`:数据库和 Telegram client 健康状态

只有直接连接来源属于 `[web].trusted_proxy_cidrs` 时,服务才接受 `CF-Connecting-IP`。默认只信任本机反向代理;直接暴露 Uvicorn 时应按实际网络结构调整,不要信任任意公网 CIDR。

## 配置热重载

Telegram 中的 `/reload` 会先完整校验 TOML。仅 `[defaults]` 与 `[messages]` 可以热更新;Bot 身份、数据库、Web、代理或 Turnstile 等启动级配置变化时会拒绝重载并提示重启,旧配置继续生效。

群管理员可继续使用原语法设置群策略:

```text
/faset challenge_timeout 120
/faset challenge_type recaptcha
/faset challenge_failed_action kick
/faset challenge_timeout_action ban
/faset enable_global_blacklist true
```

4. 将项目文件夹中 auth.ini 里的 token 字段(与等号间存在一个空格)修改为你在 [@BotFather](https://t.me/botfather) 获取到的 API Token,api_hash 和 api_id 修改为你在步骤2中获得的两串内容,其中 API ID 为数字,而 API Hash 为一组字符,你也可以对 config.json 里的内容酌情修改。
首次设置由 PostgreSQL upsert 原子写入并立即生效。

## 旧 CSV 导入

有关填写字段说明:
目标库必须已经升级到当前 Alembic head:

`channel`: Bot 日志记录频道 Chat ID (-100 开头),未填写将会导致无法正常工作(这是一个 bug,等待修复)。
```bash
uv run captcha-bot import-csv group_config.csv --table group-config --config config.toml
uv run captcha-bot import-csv blacklist_user.csv --table blacklist-user --config config.toml
```

`admin`: 管理用户 User ID,不填写则`/leave`和`/reload`指令无效。
## systemd

5. 使用 `venv/bin/python` 直接运行这个 bot,或者在 `/etc/systemd/system/ `下新建一个 .service 文件,使用 systemd 控制这个bot的运行,配置文件示例请参考本项目目录下的 `example.service` 文件进行修改。
复制并修改仓库中的 `example.service`

```bash
cp example.service /etc/systemd/system/captchabot.service
nano captchabot.service
#编辑参数
systemctl start captchabot
#启动
systemctl enable captchabot
#开机自启
sudo cp example.service /etc/systemd/system/captchabot.service
sudo systemctl daemon-reload
sudo systemctl enable --now captchabot.service
sudo journalctl -f -u captchabot.service
```

6. 将本 bot 加入一个群组,并给予封禁用户的权限,即可开始使用
服务使用 `Restart=on-failure`。正常停止时,应用依次取消 challenge timeout、停止 Telegram client、关闭 HTTP client 并释放数据库连接池。

## 在多个群组(10个以上等)部署本Bot的提示
## 开发与质量门禁

~~由于一个已知无解的严重 Bug, Bot 在运行一周至13天左右的时间可能会由于线程冲突导致整个 Bot 死掉,如果需要在多个(10个以上)的群组内部署本 Bot 请考虑在crontab等地方设置定期重启。~~
```bash
uv sync --locked --all-groups
uv run ruff format --check .
uv run ruff check .
uv run ty check src main.py tests
uv run pytest
uv run pip-audit
```

现在的分支加入了一遇到异常就会自动重启的设定,Bot 在正常运行情况下应该是不会卡死了。
PostgreSQL 集成测试只对显式指定的一次性测试库运行,测试过程会清空并重建该数据库:

## 日志
在安装了 systemd ,且已经在 /etc/systemd/system 下部署了服务的 Linux 操作系统环境下,请使用命令:
```bash
journalctl -u captchabot.service
#查看从启动时的日志
journalctl -f -u captchabot.service
#查看实时日志
# 这里的 captchabot.service 请自行更名为你在服务器上部署的服务名
TEST_DATABASE_URL=postgresql+psycopg://captcha:password@127.0.0.1/captcha_test uv run pytest -m integration
```
## 开源协议
本项目使用 GNU Affero 通用公共许可证 3.0 开源

不要把生产数据库 URL 传给 `TEST_DATABASE_URL`。GitHub Actions 使用 Python 3.14 与独立 PostgreSQL service 执行格式、静态检查、类型检查、测试、覆盖率、Alembic check 和依赖审计。

## 项目结构

```text
src/captcha_bot/
├── app.py # FastAPI lifespan 与资源所有权
├── challenges.py # 验证状态及并发安全 Registry
├── config.py # TOML 模型、热重载及旧配置迁移
├── handlers/ # Telegram 管理、入群、回调处理
├── db/ # SQLAlchemy 2.0 async repository 与导入
├── services.py # 群策略和 Turnstile 服务
└── web.py # Web/健康检查路由
```

`main.py` 只保留兼容启动包装。未完成的 `/report`、OpenAI、第三方黑名单、`mute` 和无效消息项已移除。

## 许可证

[GNU Affero General Public License v3.0](LICENSE)
26 changes: 0 additions & 26 deletions Timer/__init__.py

This file was deleted.

91 changes: 0 additions & 91 deletions ai.py

This file was deleted.

Loading
Loading