324 lines
14 KiB
Markdown
324 lines
14 KiB
Markdown
|
|
# 设备激活流程 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等待服务器验证结果,适应各种网络环境
|