324 lines
14 KiB
Markdown
Executable File
324 lines
14 KiB
Markdown
Executable File
# 设备激活流程 v2
|
||
|
||
## 概述
|
||
|
||
当前流程是虾哥设备认证v2版本
|
||
|
||
## 激活流程
|
||
|
||
每个设备都有一个唯一的序列号(Serial Number)和HMAC密钥(HMAC Key),用于身份验证和安全通信。新设备首次使用时需要通过以下流程进行激活:
|
||
|
||
1. 客户端启动时,向服务器发送设备信息,包括序列号、MAC地址和客户端ID
|
||
2. 服务器检查设备是否已激活:
|
||
- 如果已激活,客户端正常工作
|
||
- 如果未激活,服务器返回包含验证码和Challenge的激活请求
|
||
3. 客户端显示验证码,提示用户前往xiaozhi.me网站输入验证码
|
||
4. 客户端使用HMAC密钥对Challenge进行签名,并发送给服务器验证
|
||
5. 客户端通过轮询方式等待服务器确认验证结果:
|
||
- 如果验证成功,设备激活完成
|
||
- 如果验证失败或超时,设备激活失败
|
||
|
||
### 小智 ESP32 设备激活流程图
|
||
|
||
```
|
||
┌────────────────────┐
|
||
│ 设备启动 │
|
||
└──────────┬─────────┘
|
||
↓
|
||
┌────────────────────┐
|
||
│ 初始化各组件 │
|
||
│ 连接WiFi/网络 │
|
||
└──────────┬─────────┘
|
||
↓
|
||
┌────────────────────┐
|
||
│ 调用CheckVersion │
|
||
│ 访问OTA服务器 │──→ POST /xiaozhi/ota/
|
||
└──────────┬─────────┘
|
||
↓
|
||
┌────────────────────┐
|
||
│ 解析服务器响应 │
|
||
└──────────┬─────────┘
|
||
↓
|
||
┌─────┴─────┐
|
||
↓ ↓
|
||
┌─────────┐ ┌─────────┐
|
||
│是否有新版本│ │是否需要激活│
|
||
└─────┬───┘ └─────┬───┘
|
||
│ │
|
||
┌─────▼───┐ └───┬─── 否 ──┐
|
||
│升级固件 │ ↓ ↓
|
||
└─────────┘ ┌─────────────┐ ┌─────────────┐
|
||
│是否有激活码 │ │初始化协议连接│
|
||
└──────┬──────┘ │MQTT/WebSocket│
|
||
│ └─────────────┘
|
||
┌────▼───┐
|
||
│ 是 │
|
||
└────┬───┘
|
||
↓
|
||
┌──────────────────┐
|
||
│显示激活码给用户 │
|
||
│播放语音提示 │
|
||
└────────┬─────────┘
|
||
↓
|
||
┌──────────────────┐
|
||
│ 开始激活流程 │
|
||
└────────┬─────────┘
|
||
↓
|
||
┌────────────────────────────────┐
|
||
│ 检查设备序列号 │
|
||
└───────────────┬────────────────┘
|
||
↓
|
||
┌──────┴───────┐
|
||
↓ ↓
|
||
┌─────────┐ ┌─────────┐
|
||
│ 有序列号 │ │ 无序列号 │
|
||
└─────┬────┘ └────┬────┘
|
||
│ │
|
||
┌─────────▼────────┐ │
|
||
│构造激活载荷JSON: │ │
|
||
│- serial_number │ │
|
||
│- challenge │ │
|
||
│- hmac签名 │ │
|
||
└─────────┬─────────┘ │
|
||
│ │
|
||
└──────┬───────┘
|
||
↓
|
||
┌───────────────────────┐
|
||
│发送POST请求到激活端点 │──→ POST /xiaozhi/ota/activate
|
||
└────────────┬──────────┘
|
||
↓
|
||
┌───────────┴───────────┐
|
||
↓ ↓ ↓
|
||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||
│状态码200 │ │状态码202 │ │其他状态码│
|
||
│激活成功 │ │超时重试 │ │激活失败 │
|
||
└────┬────┘ └────┬────┘ └────┬────┘
|
||
│ │ │
|
||
│ ┌────▼─────┐ │
|
||
│ │延迟后重试 │ │
|
||
│ │最多10次 │ │
|
||
│ └────┬─────┘ │
|
||
│ │ │
|
||
└───────────┼───────────┘
|
||
↓
|
||
┌──────────────────┐
|
||
│设置激活状态标志位 │
|
||
└────────┬─────────┘
|
||
↓
|
||
┌──────────────────┐
|
||
│ 继续正常运行 │
|
||
│ 连接MQTT/WS协议 │
|
||
└──────────────────┘
|
||
```
|
||
|
||
### 激活数据交互详细流程
|
||
|
||
```
|
||
┌────────────┐ ┌────────────┐ ┌────────────┐
|
||
│ │ │ │ │ │
|
||
│ 设备客户端 │ │ 服务器 │ │ 用户浏览器 │
|
||
│ │ │ │ │ │
|
||
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘
|
||
│ │ │
|
||
│ 请求设备状态 (MAC, ClientID, SN) │ │
|
||
│ ────────────────────────────────> │ │
|
||
│ │ │
|
||
│ 返回激活请求 (验证码, Challenge) │ │
|
||
│ <──────────────────────────────── │ │
|
||
│ │ │
|
||
│ 显示验证码 │ │
|
||
│ ┌─────────────┐ │ │
|
||
│ │请前往网站输入 │ │ │
|
||
│ │验证码: 123456│ │ │
|
||
│ └─────────────┘ │ │
|
||
│ │ │
|
||
│ │ 用户访问xiaozhi.me │
|
||
│ │ <─────────────────────────────────│
|
||
│ │ │
|
||
│ │ 输入验证码 123456 │
|
||
│ │ <─────────────────────────────────│
|
||
│ │ │
|
||
│ 计算HMAC签名 │ │
|
||
│ ┌─────────────┐ │ │
|
||
│ │ HMAC(密钥, │ │ │
|
||
│ │ Challenge) │ │ │
|
||
│ └─────────────┘ │ │
|
||
│ │ │
|
||
│ 发送激活请求 (SN, Challenge, 签名) │ │
|
||
│ ────────────────────────────────> │ │
|
||
│ │ ┌───────────────┐ │
|
||
│ │ │ 等待用户输入验证码 │ │
|
||
│ │ │ 超时返回202 │ │
|
||
│ │ └───────────────┘ │
|
||
│ │ │
|
||
│ 轮询等待 (HTTP Long Polling) │ │
|
||
│ ────────────────────────────────> │ │
|
||
│ HTTP 202 (Pending) │ │
|
||
│ <──────────────────────────────── │ │
|
||
│ │ │
|
||
│ 继续轮询... │ │
|
||
│ ────────────────────────────────> │ │
|
||
│ │ │
|
||
│ │ 验证码验证成功 │
|
||
│ │───────────────────────────────────│
|
||
│ │ │
|
||
│ 激活成功 (HTTP 200) │ │
|
||
│ <──────────────────────────────── │ │
|
||
│ │ │
|
||
│ ┌─────────────┐ │ │
|
||
│ │设备激活成功! │ │ │
|
||
│ └─────────────┘ │ │
|
||
│ │ │
|
||
```
|
||
|
||
## 设备与服务器通信内容详解
|
||
|
||
### 1. 设备信息请求 (POST /xiaozhi/ota/)
|
||
|
||
**请求头**:
|
||
```
|
||
Activation-Version: 2 // 表示支持序列号激活
|
||
Device-Id: AA:BB:CC:DD:EE:FF // MAC地址
|
||
Client-Id: xxxx-xxxx-xxxx-xxxx // 设备UUID
|
||
User-Agent: BOARD_NAME/1.0.0 // 开发板名称和固件版本
|
||
Content-Type: application/json
|
||
```
|
||
|
||
**请求体** (POST时):
|
||
```json
|
||
{
|
||
"version": 2,
|
||
"flash_size": 16777216,
|
||
"psram_size": 8388608,
|
||
"minimum_free_heap_size": 7265024,
|
||
"mac_address": "你的mac地址",
|
||
"uuid": "你的client_id",
|
||
"chip_model_name": "esp32s3",
|
||
"chip_info": {
|
||
"model": 9,
|
||
"cores": 2,
|
||
"revision": 0,
|
||
"features": 20
|
||
},
|
||
"application": {
|
||
"name": "xiaozhi",
|
||
"version": "1.6.0",
|
||
"compile_time": "2025-04-16T12:00:00Z",
|
||
"idf_version": "v5.3.2"
|
||
},
|
||
"partition_table": [
|
||
{
|
||
"label": "nvs",
|
||
"type": 1,
|
||
"subtype": 2,
|
||
"address": 36864,
|
||
"size": 24576
|
||
},
|
||
{
|
||
"label": "otadata",
|
||
"type": 1,
|
||
"subtype": 0,
|
||
"address": 61440,
|
||
"size": 8192
|
||
},
|
||
{
|
||
"label": "app0",
|
||
"type": 0,
|
||
"subtype": 0,
|
||
"address": 65536,
|
||
"size": 1966080
|
||
},
|
||
{
|
||
"label": "app1",
|
||
"type": 0,
|
||
"subtype": 0,
|
||
"address": 2031616,
|
||
"size": 1966080
|
||
},
|
||
{
|
||
"label": "spiffs",
|
||
"type": 1,
|
||
"subtype": 130,
|
||
"address": 3997696,
|
||
"size": 1966080
|
||
}
|
||
],
|
||
"ota": {
|
||
"label": "app0"
|
||
},
|
||
"board": {
|
||
"type": "lc-esp32-s3",
|
||
"name": "立创ESP32-S3开发板",
|
||
"features": ["wifi", "ble", "psram", "octal_flash"],
|
||
"ip": "你的ip地址",
|
||
"mac": "你的mac地址"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 服务器响应
|
||
|
||
**响应体**:
|
||
```json
|
||
{
|
||
"firmware": {
|
||
"version": "1.0.1",
|
||
"url": ""
|
||
},
|
||
"activation": {
|
||
"message": "请访问xiaozhi.me输入激活码",
|
||
"code": "123456",
|
||
"challenge": "randomstring123456",
|
||
"timeout_ms": 30000
|
||
},
|
||
"mqtt": {
|
||
"endpoint": "mqtt.xiaozhi.me",
|
||
"client_id": "device123",
|
||
"username": "user123",
|
||
"password": "pass123",
|
||
"publish_topic": ""
|
||
},
|
||
"websocket": {
|
||
"url": "wss://api.tenclass.net/xiaozhi/v1/",
|
||
"token": "test-token"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 设备激活请求 (POST /xiaozhi/ota/activate)
|
||
|
||
**请求体**:
|
||
```json
|
||
{
|
||
"Payload": {
|
||
"algorithm": "hmac-sha256",
|
||
"serial_number": "SN-5CD8467B47FB4920",
|
||
"challenge": "dac852d6-4ac4-4650-ba1a-c2a5bf00a766",
|
||
"hmac": "ada4775e3ed93cf9c0eb9ed00444138554ba416af41283a0e5603c77681a8022"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. 激活响应
|
||
|
||
- **成功**: 状态码 200
|
||
- **等待用户输入验证码**: 状态码 202
|
||
- **失败**: 状态码 4xx (如401表示未授权,400表示请求错误)
|
||
|
||
**响应体** (失败时):
|
||
|
||
```json
|
||
{
|
||
"error": "错误原因描述"
|
||
}
|
||
```
|
||
|
||
|
||
## 安全机制
|
||
|
||
设备激活流程v2版本采用以下安全机制:
|
||
|
||
1. **设备唯一标识**:每个设备有一个唯一的序列号(Serial Number)
|
||
2. **HMAC签名验证**:使用HMAC-SHA256算法对Challenge进行签名,确保设备身份的真实性
|
||
3. **验证码验证**:通过要求用户在网页端输入验证码,防止自动化的激活攻击
|
||
4. **轮询等待机制**:使用HTTP Long Polling等待服务器验证结果,适应各种网络环境 |