Features: - Receive SMS from TranspondSms Android APP - HMAC-SHA256 signature verification (optional) - SQLite database storage - Web UI with login authentication - Multiple API tokens support - Timezone conversion (Asia/Shanghai) - Search, filter, and statistics - Auto refresh and session management Tech Stack: - Flask 3.0 - SQLite database - HTML5/CSS3 responsive design
962 lines
21 KiB
Markdown
962 lines
21 KiB
Markdown
# 短信转发接收端 - 开发文档
|
||
|
||
## 目录
|
||
|
||
- [项目概述](#项目概述)
|
||
- [实现逻辑](#实现逻辑)
|
||
- [使用指南](#使用指南)
|
||
- [部署指南](#部署指南)
|
||
- [API 文档](#api-文档)
|
||
- [配置说明](#配置说明)
|
||
- [常见问题](#常见问题)
|
||
- [开发规范](#开发规范)
|
||
|
||
---
|
||
|
||
## 项目概述
|
||
|
||
### 技术架构
|
||
|
||
```
|
||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||
│ Android APP │ │ Flask Web │ │ SQLite DB │
|
||
│ TranspondSms │────────▶│ Server │────────▶│ sms_receiver │
|
||
│ │ POST │ │ Store │ .db │
|
||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────┐
|
||
│ Web UI │
|
||
│ (登录认证) │
|
||
└─────────────────┘
|
||
```
|
||
|
||
### 核心功能
|
||
|
||
1. **短信接收**:接收 TranspondSms Android APP 转发的短信
|
||
2. **签名验证**:HMAC-SHA256 签名验证,防止伪造请求
|
||
3. **数据存储**:SQLite 数据库存储短信和日志
|
||
4. **Web 管理**:登录验证 + 短信列表、详情、日志、统计
|
||
5. **时区转换**:UTC 存储时区转换显示
|
||
6. **Token 配置**:支持多设备、多 Token 配置
|
||
|
||
---
|
||
|
||
## 实现逻辑
|
||
|
||
### 1. 整体数据流
|
||
|
||
```
|
||
Android APP 接收短信
|
||
│
|
||
├─ 解析短信内容(支持多PDU)
|
||
├─ 提取发送方、内容、时间戳
|
||
├─ 可选:生成签名(HMAC-SHA256)
|
||
│
|
||
▼
|
||
POST 请求发送到 /api/receive
|
||
│
|
||
├─ 解析 multipart/form-data
|
||
├─ 验证必填参数(from, content)
|
||
├─ 可选:验证签名
|
||
│ ├─ 检查时间戳是否过期
|
||
│ ├─ 生成期望的签名
|
||
│ └─ 比较签名是否匹配
|
||
│
|
||
├─ 保存到数据库
|
||
│ ├─ 存储为 UTC 时间
|
||
│ ├─ 关联 Token 和 Secret
|
||
│ └─ 记录接收日志
|
||
│
|
||
▼
|
||
返回成功响应
|
||
```
|
||
|
||
### 2. 签名验证逻辑
|
||
|
||
TranspondSms 的签名规则:
|
||
|
||
```python
|
||
# 1. 拼接待签名字符串
|
||
string_to_sign = timestamp + "\n" + secret
|
||
|
||
# 2. HMAC-SHA256 计算
|
||
hmac_code = hmac.new(
|
||
secret.encode('utf-8'),
|
||
string_to_sign.encode('utf-8'),
|
||
digestmod=hashlib.sha256
|
||
).digest()
|
||
|
||
# 3. Base64 编码
|
||
sign_bytes = base64.b64encode(hmac_code)
|
||
|
||
# 4. URL 编码
|
||
sign = urllib.parse.quote(sign_bytes.decode())
|
||
```
|
||
|
||
**防重放攻击**:
|
||
- 检查时间戳是否在允许范围内(默认1小时)
|
||
- 超出范围的请求拒绝
|
||
|
||
### 3. 时区转换逻辑
|
||
|
||
```
|
||
数据库存储(UTC)
|
||
│
|
||
├─ created_at: 2024-02-06 14:30:00 (UTC)
|
||
└─ timestamp: 1707223800000 (毫秒时间戳)
|
||
│
|
||
▼
|
||
读取时转换
|
||
│
|
||
├─ UTC 时间 + 时区偏移(8小时)
|
||
└─ datetime.fromtimestamp(timestamp / 1000)
|
||
│
|
||
▼
|
||
显示(本地时间)
|
||
│
|
||
└─ created_at: 2024-02-06 22:30:00 (Asia/Shanghai)
|
||
```
|
||
|
||
### 4. 登录验证流程
|
||
|
||
```
|
||
用户访问页面
|
||
│
|
||
▼
|
||
检查 session['logged_in']
|
||
│
|
||
├─ 已登录 ──▶ 更新 last_activity ──▶ 允许访问
|
||
│
|
||
└─ 未登录 ──▶ 跳转到 /login
|
||
│
|
||
▼
|
||
提交表单
|
||
│
|
||
├─ 验证用户名和密码
|
||
│
|
||
├─ 成功:
|
||
│ ├─ session['logged_in'] = True
|
||
│ ├─ session['username'] = username
|
||
│ ├─ session['login_time'] = now
|
||
│ └─ 跳转到原页面或首页
|
||
│
|
||
└─ 失败:显示错误消息
|
||
```
|
||
|
||
**会话超时检查**:
|
||
```python
|
||
last_activity = session.get('last_activity')
|
||
if now - last_activity > SESSION_LIFETIME:
|
||
# 清空会话,重定向到登录页
|
||
session.clear()
|
||
return redirect('/login')
|
||
```
|
||
|
||
### 5. Token 匹配逻辑
|
||
|
||
```python
|
||
# 接收请求时
|
||
token = request.form.get('token') # 从参数获取
|
||
|
||
# 在配置中查找对应的 secret
|
||
for token_config in API_TOKENS:
|
||
if token_config['token'] == token and token_config['enabled']:
|
||
secret = token_config['secret']
|
||
break
|
||
|
||
# 使用找到的 secret 进行签名验证
|
||
if secret and SIGN_VERIFY:
|
||
verify_sign(secret, sign, timestamp)
|
||
```
|
||
|
||
### 6. 数据库设计
|
||
|
||
#### sms_messages 表
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | INTEGER | 主键,自增 |
|
||
| from_number | TEXT | 发送方手机号 |
|
||
| content | TEXT | 短信内容 |
|
||
| timestamp | INTEGER | 原始时间戳(毫秒) |
|
||
| device_info | TEXT | 设备信息(可选) |
|
||
| sim_info | TEXT | SIM 卡信息(可选) |
|
||
| sign_verified | INTEGER | 是否通过签名验证(0/1) |
|
||
| ip_address | TEXT | 来源 IP 地址 |
|
||
| created_at | TIMESTAMP | 创建时间(UTC) |
|
||
|
||
#### receive_logs 表
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | INTEGER | 主键,自增 |
|
||
| from_number | TEXT | 发送方手机号 |
|
||
| content | TEXT | 短信内容 |
|
||
| timestamp | INTEGER | 时间戳 |
|
||
| sign | TEXT | 签名 |
|
||
| sign_valid | INTEGER | 签名是否有效(0/1/null) |
|
||
| ip_address | TEXT | IP 地址 |
|
||
| status | TEXT | 处理状态(success/error) |
|
||
| error_message | TEXT | 错误消息 |
|
||
| created_at | TIMESTAMP | 创建时间(UTC)**
|
||
|
||
### 分层架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Flask Application Layer │
|
||
│ (app.py - 路由、业务逻辑、会话管理) │
|
||
└─────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ Database Layer │
|
||
│ (database.py - 数据库操作、时区转换) │
|
||
└─────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ SQLite Database │
|
||
│ (sms_receiver.db - 数据持久化) │
|
||
└─────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ Template Layer │
|
||
│ (templates/ - HTML、CSS、JS) │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 核心模块职责
|
||
|
||
| 模块 | 职责 |
|
||
|------|------|
|
||
| `app.py` | Flask 主应用,路由注册,业务逻辑 |
|
||
| `config.py` | 配置加载,从 config.json 读取配置 |
|
||
| `database.py` | 数据库模型,CRUD 操作,时区转换 |
|
||
| `sign_verify.py` | 签名生成和验证 |
|
||
| `templates/` | HTML 模板,前端展示 |
|
||
|
||
---
|
||
|
||
## 使用指南
|
||
|
||
### 前置要求
|
||
|
||
- Python 3.7+
|
||
- Flask 3.0+
|
||
- SQLite3
|
||
|
||
### 安装依赖
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### 配置文件
|
||
|
||
创建 `config.json`:
|
||
|
||
```json
|
||
{
|
||
"server": {
|
||
"host": "0.0.0.0",
|
||
"port": 9518,
|
||
"debug": false
|
||
},
|
||
"security": {
|
||
"enabled": true,
|
||
"username": "admin",
|
||
"password": "YourStrongPassword123",
|
||
"session_lifetime": 3600,
|
||
"secret_key": "RandomSecretKeyHere",
|
||
"sign_verify": true,
|
||
"sign_max_age": 3600000
|
||
},
|
||
"sms": {
|
||
"max_messages": 10000,
|
||
"auto_cleanup": true,
|
||
"cleanup_days": 30
|
||
},
|
||
"database": {
|
||
"path": "sms_receiver.db"
|
||
},
|
||
"timezone": "Asia/Shanghai",
|
||
"api_tokens": [
|
||
{
|
||
"name": "我的手机",
|
||
"token": "my_phone_token",
|
||
"secret": "my_phone_secret",
|
||
"enabled": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 启动服务
|
||
|
||
```bash
|
||
python3 app.py
|
||
```
|
||
|
||
服务启动后访问:http://你的IP:9518
|
||
|
||
### 配置 TranspondSms APP
|
||
|
||
1. 下载并安装 TranspondSms APP
|
||
2. 打开 APP,进入"发送方"页面
|
||
3. 添加"网页通知"
|
||
4. 填写配置:
|
||
|
||
```
|
||
Token (URL): http://你的服务器IP:9518/api/receive?token=my_phone_token
|
||
Secret: my_phone_secret
|
||
```
|
||
|
||
5. 点击"测试"按钮,验证是否成功
|
||
6. 配置转发规则(如"转发全部")
|
||
|
||
### 使用 Web 界面
|
||
|
||
#### 登录
|
||
|
||
- 访问 http://你的IP:9518
|
||
- 输入用户名和密码
|
||
- 登录成功后进入短信列表
|
||
|
||
#### 查看短信
|
||
|
||
- **短信列表**:主页显示所有收到短信
|
||
- **搜索**:支持按号码或内容搜索
|
||
- **筛选**:按发送方号码快捷筛选
|
||
- **详情**:点击短信查看完整内容和元数据
|
||
|
||
#### 查看日志
|
||
|
||
- 访问"接收日志"页面
|
||
- 查看每次请求的处理结果
|
||
- 包括签名验证状态、IP 地址、错误信息
|
||
|
||
#### 统计信息
|
||
|
||
- 访问"统计信息"页面
|
||
- 查看短信总数、今日、本周
|
||
- 签名验证比例
|
||
- 发送方号码排行榜
|
||
- 清理旧数据
|
||
|
||
---
|
||
|
||
## 部署指南
|
||
|
||
### 开发环境部署
|
||
|
||
```bash
|
||
# 克隆项目
|
||
git clone <your-repo-url>
|
||
cd smsweb
|
||
|
||
# 创建虚拟环境(推荐)
|
||
python3 -m venv venv
|
||
source venv/bin/activate
|
||
|
||
# 安装依赖
|
||
pip install -r requirements.txt
|
||
|
||
# 配置 config.json
|
||
cp config.example.json config.json
|
||
vim config.json
|
||
|
||
# 启动服务
|
||
python3 app.py
|
||
```
|
||
|
||
### 生产环境部署(推荐方案)
|
||
|
||
#### 1. 使用 Gunicorn + Nginx
|
||
|
||
**安装 Gunicorn**:
|
||
|
||
```bash
|
||
pip install gunicorn
|
||
```
|
||
|
||
**创建 systemd 服务**:
|
||
|
||
```bash
|
||
sudo vim /etc/systemd/system/sms-receiver.service
|
||
```
|
||
|
||
内容:
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=SMS Receiver Service
|
||
After=network.target
|
||
|
||
[Service]
|
||
Type=notify
|
||
User=www-data
|
||
WorkingDirectory=/var/www/sms-receiver
|
||
Environment="PATH=/var/www/sms-receiver/venv/bin"
|
||
ExecStart=/var/www/sms-receiver/venv/bin/gunicorn \
|
||
-w 4 -b 127.0.0.1:9518 \
|
||
--timeout 120 \
|
||
--access-logfile /var/log/sms-receiver/access.log \
|
||
--error-logfile /var/log/sms-receiver/error.log \
|
||
app:app
|
||
Restart=always
|
||
RestartSec=10
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
**启动服务**:
|
||
|
||
```bash
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl enable sms-receiver
|
||
sudo systemctl start sms-receiver
|
||
sudo systemctl status sms-receiver
|
||
```
|
||
|
||
**配置 Nginx 反向代理**:
|
||
|
||
```bash
|
||
sudo vim /etc/nginx/sites-available/sms-receiver
|
||
```
|
||
|
||
内容:
|
||
|
||
```nginx
|
||
upstream sms_receiver {
|
||
server 127.0.0.1:9518;
|
||
}
|
||
|
||
server {
|
||
listen 80;
|
||
server_name sms.example.com;
|
||
|
||
access_log /var/log/nginx/sms-receiver-access.log;
|
||
error_log /var/log/nginx/sms-receiver-error.log;
|
||
|
||
location / {
|
||
proxy_pass http://sms_receiver;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_redirect off;
|
||
proxy_buffering off;
|
||
}
|
||
|
||
# 接收 API 不需要登录,但对客户端透明
|
||
location /api/receive {
|
||
proxy_pass http://sms_receiver/api/receive;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
}
|
||
}
|
||
```
|
||
|
||
**启用站点**:
|
||
|
||
```bash
|
||
sudo ln -s /etc/nginx/sites-available/sms-receiver /etc/nginx/sites-enabled/
|
||
sudo nginx -t
|
||
sudo systemctl reload nginx
|
||
```
|
||
|
||
#### 2. 配置 HTTPS(Let's Encrypt)
|
||
|
||
```bash
|
||
sudo certbot --nginx -d sms.example.com
|
||
```
|
||
|
||
#### 3. 防火墙配置
|
||
|
||
```bash
|
||
sudo ufw allow 80/tcp
|
||
sudo ufw allow 443/tcp
|
||
sudo ufw enable
|
||
```
|
||
|
||
#### 4. 日志轮转
|
||
|
||
```bash
|
||
sudo vim /etc/logrotate.d/sms-receiver
|
||
```
|
||
|
||
内容:
|
||
|
||
```
|
||
/var/log/sms-receiver/*.log {
|
||
daily
|
||
rotate 14
|
||
compress
|
||
missingok
|
||
notifempty
|
||
create 0640 www-data www-data
|
||
sharedscripts
|
||
postrotate
|
||
systemctl reload sms-receiver >/dev/null 2>&1 || true
|
||
endscript
|
||
}
|
||
```
|
||
|
||
### Docker 部署
|
||
|
||
**创建 Dockerfile**:
|
||
|
||
```dockerfile
|
||
FROM python:3.11-slim
|
||
|
||
WORKDIR /app
|
||
|
||
RUN apt-get update && apt-get install -y \
|
||
gcc \
|
||
&& rm -rf /var/lib/apt/lists/*
|
||
|
||
COPY requirements.txt .
|
||
RUN pip install --no-cache-dir -r requirements.txt
|
||
|
||
COPY . .
|
||
|
||
EXPOSE 9518
|
||
|
||
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:9518", "app:app"]
|
||
```
|
||
|
||
**创建 docker-compose.yml**:
|
||
|
||
```yaml
|
||
version: '3.8'
|
||
|
||
services:
|
||
sms-receiver:
|
||
build: .
|
||
ports:
|
||
- "9518:9518"
|
||
volumes:
|
||
- ./sms_receiver.db:/app/sms_receiver.db
|
||
- ./config.json:/app/config.json
|
||
- ./logs:/app/logs
|
||
environment:
|
||
- FLASK_ENV=production
|
||
restart: unless-stopped
|
||
```
|
||
|
||
**启动**:
|
||
|
||
```bash
|
||
docker-compose up -d
|
||
```
|
||
|
||
### 安全加固
|
||
|
||
1. **修改默认密码**:首次部署后立即修改登录密码
|
||
2. **使用强密码**:至少16位,包含大小写字母、数字、特殊字符
|
||
3. **启用 HTTPS**:使用 Let's Encrypt 免费证书
|
||
4. **限制访问**:配置防火墙,只开放必要端口
|
||
5. **启用签名验证**:设置 Token 的 secret
|
||
6. **定期更新**:定期更新 Python 和 Flask 版本
|
||
|
||
### 监控和维护
|
||
|
||
**查看日志**:
|
||
|
||
```bash
|
||
# 应用日志
|
||
tail -f /var/log/sms-receiver/error.log
|
||
|
||
# Nginx 日志
|
||
tail -f /var/log/nginx/sms-receiver-error.log
|
||
```
|
||
|
||
**备份数据库**:
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
BACKUP_DIR="/backup/sms-receiver"
|
||
DATE=$(date +%Y%m%d_%H%M%S)
|
||
mkdir -p $BACKUP_DIR
|
||
|
||
# 备份数据库
|
||
cp /var/www/sms-receiver/sms_receiver.db $BACKUP_DIR/sms_receiver_$DATE.db
|
||
|
||
# 备份配置
|
||
cp /var/www/sms-receiver/config.json $BACKUP_DIR/config_$DATE.json
|
||
|
||
# 删除30天前的备份
|
||
find $BACKUP_DIR -name "*.db" -mtime +30 -delete
|
||
find $BACKUP_DIR -name "*.json" -mtime +30 -delete
|
||
```
|
||
|
||
---
|
||
|
||
## API 文档
|
||
|
||
### POST /api/receive
|
||
|
||
接收短信接口。
|
||
|
||
**请求方式**:POST multipart/form-data
|
||
|
||
**URL 参数**:
|
||
- `token` (可选): API Token,用于匹配对应的 secret
|
||
|
||
**表单参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| from | string | 是 | 发送方手机号 |
|
||
| content | string | 是 | 短信内容 |
|
||
| timestamp | string | 否 | 时间戳(毫秒),用于签名验证 |
|
||
| sign | string | 否 | 签名(HMAC-SHA256 + Base64 + URL Encode) |
|
||
| device | string | 否 | 设备信息 |
|
||
| sim | string | 否 | SIM 卡信息 |
|
||
|
||
**请求示例**:
|
||
|
||
```bash
|
||
curl -X POST http://your-server:9518/api/receive?token=my_token \
|
||
-F "from=10086" \
|
||
-F "content=验证码: 123456" \
|
||
-F "timestamp=1707223800000" \
|
||
-F "sign=xxx"
|
||
```
|
||
|
||
**响应示例**:
|
||
|
||
成功:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message_id": 123,
|
||
"message": "短信已接收"
|
||
}
|
||
```
|
||
|
||
失败:
|
||
```json
|
||
{
|
||
"error": "缺少必填参数"
|
||
}
|
||
```
|
||
|
||
**HTTP 状态码**:
|
||
- 200: 成功
|
||
- 400: 参数错误
|
||
- 403: 签名验证失败
|
||
- 500: 服务器错误
|
||
|
||
### GET /api/messages
|
||
|
||
获取短信列表(需要登录)。
|
||
|
||
**URL 参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| page | int | 否 | 页码,默认1 |
|
||
| limit | int | 否 | 每页数量,默认20 |
|
||
| from | string | 否 | 按发送方号码筛选 |
|
||
| search | string | 否 | 搜索内容或号码 |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"from_number": "10086",
|
||
"content": "验证码: 123456",
|
||
"timestamp": 1707223800000,
|
||
"local_timestamp": "2024-02-06 22:30:00",
|
||
"created_at": "2024-02-06 14:30:00",
|
||
"sign_verified": true
|
||
}
|
||
],
|
||
"total": 1,
|
||
"page": 1,
|
||
"limit": 20
|
||
}
|
||
```
|
||
|
||
### GET /api/statistics
|
||
|
||
获取统计信息(需要登录)。
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"total": 100,
|
||
"today": 10,
|
||
"week": 50,
|
||
"verified": 80,
|
||
"unverified": 20
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 配置说明
|
||
|
||
### 完整配置示例
|
||
|
||
```json
|
||
{
|
||
"app": {
|
||
"name": "短信转发接收端",
|
||
"version": "1.0.0"
|
||
},
|
||
"server": {
|
||
"host": "0.0.0.0",
|
||
"port": 9518,
|
||
"debug": false
|
||
},
|
||
"security": {
|
||
"enabled": true,
|
||
"username": "admin",
|
||
"password": "YourStrongPassword123",
|
||
"session_lifetime": 3600,
|
||
"secret_key": "RandomSecretKeyChangeMe",
|
||
"sign_verify": true,
|
||
"sign_max_age": 3600000
|
||
},
|
||
"sms": {
|
||
"max_messages": 10000,
|
||
"auto_cleanup": true,
|
||
"cleanup_days": 30
|
||
},
|
||
"database": {
|
||
"path": "sms_receiver.db"
|
||
},
|
||
"timezone": "Asia/Shanghai",
|
||
"api_tokens": [
|
||
{
|
||
"name": "主手机",
|
||
"token": "main_phone_token",
|
||
"secret": "main_phone_secret_key",
|
||
"enabled": true
|
||
},
|
||
{
|
||
"name": "备用机",
|
||
"token": "backup_phone_token",
|
||
"secret": "backup_phone_secret_key",
|
||
"enabled": true
|
||
},
|
||
{
|
||
"name": "测试设备",
|
||
"token": "test_token",
|
||
"secret": "",
|
||
"enabled": false
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 配置项详解
|
||
|
||
#### server - 服务器配置
|
||
|
||
| 字段 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| host | string | 0.0.0.0 | 监听地址 |
|
||
| port | int | 9518 | 监听端口 |
|
||
| debug | bool | false | 调试模式 |
|
||
|
||
#### security - 安全配置
|
||
|
||
| 字段 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| enabled | bool | true | 是否启用登录验证 |
|
||
| username | string | admin | 登录用户名 |
|
||
| password | string | admin123 | 登录密码 |
|
||
| session_lifetime | int | 3600 | 会话有效期(秒) |
|
||
| secret_key | string | - | Flask 会话密钥 |
|
||
| sign_verify | bool | true | 是否验证签名 |
|
||
| sign_max_age | int | 3600000 | 签名最大有效时间(毫秒) |
|
||
|
||
#### sms - 短信配置
|
||
|
||
| 字段 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| max_messages | int | 10000 | 最多保留短信数 |
|
||
| auto_cleanup | bool | true | 是否自动清理老数据 |
|
||
| cleanup_days | int | 30 | 清理多少天前的数据 |
|
||
|
||
#### api_tokens - API Token 配置
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| name | string | 配置名称(可选) |
|
||
| token | string | Token 值,用于匹配 secret |
|
||
| secret | string | 密钥,用于签名验证(可选) |
|
||
| enabled | bool | 是否启用此 Token |
|
||
|
||
---
|
||
|
||
## 常见问题
|
||
|
||
### Q1: 如何禁用登录验证?
|
||
|
||
在 `config.json` 中设置:
|
||
|
||
```json
|
||
{
|
||
"security": {
|
||
"enabled": false
|
||
}
|
||
}
|
||
```
|
||
|
||
### Q2:签名验证失败怎么办?
|
||
|
||
检查以下几点:
|
||
|
||
1. **时间戳是否正确**:确保客户端时间准确,误差不超过1小时
|
||
2. **Secret 是否匹配**:确保客户端和服务器端的 secret 完全一致
|
||
3. **签名生成算法**:使用正确的算法(HMAC-SHA256)
|
||
|
||
**调试签名**:
|
||
|
||
```python
|
||
# 生成签名
|
||
import time, hmac, hashlib, base64, urllib.parse
|
||
|
||
timestamp = str(int(time.time() * 1000))
|
||
secret = "your_secret"
|
||
string_to_sign = f"{timestamp}\n{secret}"
|
||
sign = urllib.parse.quote(base64.b64encode(
|
||
hmac.new(secret.encode(), string_to_sign.encode(), hashlib.sha256).digest()
|
||
).decode())
|
||
|
||
print(f"Timestamp: {timestamp}")
|
||
print(f"Sign: {sign}")
|
||
```
|
||
|
||
### Q3: 如何配置多个设备?
|
||
|
||
在 `api_tokens` 中添加多个配置:
|
||
|
||
```json
|
||
{
|
||
"api_tokens": [
|
||
{
|
||
"name": "设备A",
|
||
"token": "device_a",
|
||
"secret": "secret_a",
|
||
"enabled": true
|
||
},
|
||
{
|
||
"name": "设备B",
|
||
"token": "device_b",
|
||
"secret": "secret_b",
|
||
"enabled": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
在 APP 中配置不同的设备使用不同的 Token。
|
||
|
||
### Q4: 会话总是过期?
|
||
|
||
调整 `session_lifetime`:
|
||
|
||
```json
|
||
{
|
||
"security": {
|
||
"session_lifetime": 86400 // 24小时
|
||
}
|
||
}
|
||
```
|
||
|
||
### Q5: 如何备份数据?
|
||
|
||
直接复制数据库文件:
|
||
|
||
```bash
|
||
cp sms_receiver.db sms_receiver.db.backup
|
||
```
|
||
|
||
或者使用 SQLite 导出:
|
||
|
||
```bash
|
||
sqlite3 sms_receiver.db ".dump" > backup.sql
|
||
```
|
||
|
||
### Q6: 如何清理所有数据?
|
||
|
||
删除数据库文件,重启服务会自动重建:
|
||
|
||
```bash
|
||
rm sms_receiver.db
|
||
python3 app.py
|
||
```
|
||
|
||
### Q7: 时间显示不正确?
|
||
|
||
检查时区配置:
|
||
|
||
```json
|
||
{
|
||
"timezone": "Asia/Shanghai"
|
||
}
|
||
```
|
||
|
||
可用时区列表:https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||
|
||
---
|
||
|
||
## 开发规范
|
||
|
||
### 代码风格
|
||
|
||
- 遵循 PEP 8 Python 代码规范
|
||
- 使用有意义的变量和函数名
|
||
- 添加必要的类型注解
|
||
|
||
### Git 提交规范
|
||
|
||
```
|
||
feat: 添加新功能
|
||
fix: 修复 bug
|
||
docs: 更新文档
|
||
style: 代码格式化
|
||
refactor: 重构
|
||
test: 添加测试
|
||
chore: 构建/工具链
|
||
```
|
||
|
||
### 测试建议
|
||
|
||
```python
|
||
# 测试签名生成
|
||
python3 sign_verify.py
|
||
|
||
# 测试 API
|
||
curl -X POST http://localhost:9518/api/receive \
|
||
-F "from=10086" \
|
||
-F "content=test"
|
||
```
|
||
|
||
---
|
||
|
||
## 许可证
|
||
|
||
MIT License
|
||
|
||
## 联系方式
|
||
|
||
- 项目地址:https://gitea.king.nyc.mn/openclaw/smsweb
|
||
- 问题反馈:提交 Issue
|