11 KiB
11 KiB
MeshSeed 生成功能实现报告
完成时间: 2026-03-24
状态: ✅ 框架已完成
优先级: P1 - 高优先级
📋 实现内容
1. MeshSeedService 服务层
文件: internal/service/meshseed.go (新建,205 行)
核心功能
GenerateMeshSeed - 生成组网凭证
func (s *MeshSeedService) GenerateMeshSeed(
networkID uint, // 网络 ID
maxUses int, // 最大使用次数
expiresAt time.Time, // 过期时间
ddnsEnabled bool // DDNS 开关
) (*model.MeshSeed, error)
实现步骤:
- ✅ 验证网络是否存在
- ✅ 生成 16 字节随机 SeedID(Base64 编码)
- ✅ 构建 JoinToken(包含网络信息的 JSON)
- ✅ Ed25519 数字签名
- ✅ 保存到数据库
数据结构:
// JoinToken = Base64(JSON({
{
"seed_id": "abc123...",
"network_id": 1,
"network_name": "MyNetwork",
"subnet_ipv4": "10.0.0.0/24",
"mode": "enhanced",
"ddns_enabled": true,
"expires_at": 1711234567, // Unix 时间戳
"max_uses": 10
}))
VerifyMeshSeed - 验证凭证
func (s *MeshSeedService) VerifyMeshSeed(
joinToken string, // Base64 编码的 Token
signature string // Base64 编码的签名
) (*model.MeshSeed, error)
验证步骤:
- ✅ 解码 JoinToken 和签名
- ✅ Ed25519 签名验证
- ✅ 解析 Token 内容
- ✅ 查询 MeshSeed 记录
- ✅ 检查吊销状态
- ✅ 检查使用次数
- ✅ 检查过期时间
安全检查清单:
- ✅ 签名有效性(密码学保证)
- ✅ 是否被吊销
- ✅ 使用次数限制
- ✅ 过期时间验证
其他方法:
IncrementUseCount(seedID)- 增加使用次数(事务)RevokeMeshSeed(seedID)- 吊销凭证ListMeshSeeds(networkID)- 获取网络的 MeshSeed 列表
2. API Handler 更新
文件: internal/api/handler/network.go
POST /api/v1/networks/:id/meshseed
请求参数:
{
"expires_in_hours": 24, // 可选,默认 24 小时
"max_uses": 10, // 可选,默认 10 次
"ddns_enabled": true // 可选,默认 false
}
响应示例(当前临时实现):
{
"message": "MeshSeed 生成成功(待实现完整逻辑)",
"data": {
"meshseed": "meshray://seed-1",
"expires_at": "2026-03-25T12:00:00Z",
"max_uses": 10,
"ddns_enabled": true
}
}
最终实现(需要注入 service):
// 在 server.go 中初始化
meshSeedService := service.NewMeshSeedService(s.store, s.logger, signingKey, issuerNodeID)
// 在 handler 中调用
meshSeed, err := h.meshSeedService.GenerateMeshSeed(
networkID,
req.MaxUses,
expiresAt,
req.DDNSEnabled,
)
// 返回完整的 MeshSeed URL
c.JSON(http.StatusOK, gin.H{
"data": gin.H{
"meshseed": "meshray://" + meshSeed.JoinToken,
"signature": meshSeed.Signature,
"expires_at": meshSeed.ExpiresAt.Format(time.RFC3339),
"max_uses": meshSeed.MaxUses,
},
})
🔐 安全技术方案
1. Ed25519 数字签名
为什么选择 Ed25519?
- ✅ 高性能(比 RSA 快 100 倍)
- ✅ 高安全性(256 位密钥)
- ✅ 确定性签名(相同输入总是相同输出)
- ✅ 抗侧信道攻击
签名流程:
私钥 (Ed25519.PrivateKey)
↓
JoinToken → ed25519.Sign() → Signature
↓
Base64 编码 → "base64(signature_bytes)"
验证流程:
公钥 (Ed25519.PublicKey) + JoinToken + Signature
↓
ed25519.Verify() → true/false
2. SeedID 生成
代码:
seedBytes := make([]byte, 16)
crypto/rand.Read(seedBytes) // 加密安全的随机数
seedID := base64.RawURLEncoding.EncodeToString(seedBytes)
特点:
- ✅ 16 字节(128 位)随机数
- ✅ 使用
crypto/rand(不是math/rand) - ✅ Base64 URL 安全编码
- ✅ 碰撞概率:2^128 ≈ 3.4×10^38
3. JoinToken 结构
JSON 格式:
{
"seed_id": "abc123...",
"network_id": 1,
"network_name": "测试网络",
"subnet_ipv4": "10.0.0.0/24",
"mode": "enhanced",
"ddns_enabled": true,
"expires_at": 1711234567,
"max_uses": 10
}
编码:
JSON → Base64.StdEncoding → "eyJzZWVkX2lkIjoiYWJjMTIz..."
URL 格式:
meshray://eyJzZWVkX2lkIjoiYWJjMTIz...
📊 使用流程
场景 1:管理员生成 MeshSeed
1. 用户点击"生成 MeshSeed"
↓
2. 设置参数(有效期、使用次数)
↓
3. 调用 POST /api/v1/networks/:id/meshseed
↓
4. 后端生成并保存
↓
5. 前端显示二维码或分享链接
二维码内容:
meshray://eyJzZWVkX2lkIjoiYWJjMTIz...
场景 2:新设备加入网络
1. 新设备扫描二维码/点击链接
↓
2. 客户端解析 meshray:// URL
↓
3. 提取 JoinToken 和 Signature
↓
4. 调用 POST /api/v1/join
{
"join_token": "...",
"signature": "..."
}
↓
5. 后端验证 MeshSeed
↓
6. 验证通过,创建设备
↓
7. 返回 WireGuard 配置
🎯 API 设计
完整 API 列表
| 方法 | 路径 | 说明 | 状态 |
|---|---|---|---|
| POST | /networks/:id/meshseed |
生成 MeshSeed | ✅ 框架完成 |
| GET | /networks/:id/meshseeds |
获取 MeshSeed 列表 | 🔲 待实现 |
| DELETE | /meshseeds/:seed_id |
吊销 MeshSeed | 🔲 待实现 |
| POST | /join |
使用 MeshSeed 加入 | 🔲 待实现 |
| POST | /meshseeds/:seed_id/use |
增加使用次数 | 🔲 待实现 |
📝 代码变更统计
| 文件 | 新增行 | 删除行 | 说明 |
|---|---|---|---|
| service/meshseed.go | 205 | 0 | 新建 Service 层 |
| handler/network.go | 32 | 11 | 更新 Handler |
| 合计 | 237 | 11 | 净增 226 行 |
⚠️ TODO 事项
1. 初始化签名密钥
问题: MeshSeedService 需要 Ed25519 私钥
解决方案:
// internal/service/meshseed.go
type MeshSeedService struct {
store *sqlite.Store
logger *zap.Logger
signingKey ed25519.PrivateKey // ← 需要初始化
issuerNodeID string
}
初始化方式:
方案 A: 启动时生成
// server.go
_, signingKey, _ := ed25519.GenerateKey(rand.Reader)
meshSeedService := service.NewMeshSeedService(s.store, s.logger, signingKey, "node-1")
方案 B: 从配置文件读取
// config.yaml
security:
meshseed_signing_key: "base64_encoded_private_key"
// server.go
keyBytes, _ := base64.StdEncoding.DecodeString(cfg.Security.SigningKey)
signingKey := ed25519.PrivateKey(keyBytes)
方案 C: 从数据库读取
// 首次启动时生成并保存
var key model.SecurityKey
db.First(&key, "meshseed_signing")
if key.Value == "" {
_, newKey, _ := ed25519.GenerateKey(rand.Reader)
db.Create(&model.SecurityKey{
Name: "meshseed_signing",
Value: base64.StdEncoding.EncodeToString(newKey),
})
}
推荐: 方案 C(最安全,支持持久化)
2. 完善 Handler 注入
当前问题:
// network.go
// TODO: 需要初始化 meshSeedService
// meshSeed, err := h.meshSeedService.GenerateMeshSeed(...)
解决:
// server.go
// 1. 创建 MeshSeedService
meshSeedService := service.NewMeshSeedService(s.store, s.logger, signingKey, "node-1")
// 2. 创建 NetworkHandler 时注入
networkHandler := handler.NewNetworkHandler(networkService, s.logger, meshSeedService)
// ↑ 新增参数
3. 前端对接
前端需要实现:
- ✅ 生成 MeshSeed 的 UI(已调用 API)
- ✅ 显示二维码(qrcode 库)
- ✅ 分享功能(复制链接)
- ✅ MeshSeed 列表管理
- ✅ 吊销功能
二维码生成:
<template>
<qrcode-vue :value="meshSeedUrl" :size="200"></qrcode-vue>
</template>
<script setup>
const meshSeedUrl = computed(() => {
return `meshray://${meshSeedData.value.join_token}`
})
</script>
🔍 与其他功能的集成
1. DDNS 集成
当 DDNSEnabled=true 时:
// 自动生成 DDNS 记录
if ddnsEnabled {
deviceName := "device-" + randomString(6)
ddnsDomain := setting.DDNSDomain // 从 Settings 读取
fullDomain := deviceName + "." + ddnsDomain
// 调用 DDNS 服务创建记录
ddnsService.CreateRecord(fullDomain, deviceIP)
}
2. 设备配置生成
使用 MeshSeed 加入后:
// 自动填充 Endpoint
config += "Endpoint = " + setting.ServerIP + ":" + strconv.Itoa(setting.ServerPort) + "\n"
// 如果使用 DDNS
if ddnsEnabled {
config += "Endpoint = " + deviceDDNSDomain + ":51820\n"
}
3. 审计日志
记录所有 MeshSeed 操作:
logger.Info("MeshSeed 已生成",
zap.String("seed_id", seedID),
zap.Uint("network_id", networkID),
zap.Int("max_uses", maxUses),
zap.Time("expires_at", expiresAt))
logger.Info("MeshSeed 已使用",
zap.String("seed_id", seedID),
zap.String("device_name", deviceName),
zap.String("request_ip", requestIP))
🚀 下一步计划
剩余工作(按优先级)
| 任务 | 工作量 | 说明 |
|---|---|---|
| 1. 初始化签名密钥 | 0.5 天 | 在 server.go 中生成/加载密钥 |
| 2. 注入 MeshSeedService | 0.5 天 | 更新 NetworkHandler 构造函数 |
| 3. 完善 Handler 实现 | 0.5 天 | 调用真实 Service 方法 |
| 4. 添加 MeshSeed 列表 API | 0.5 天 | GET /networks/:id/meshseeds |
| 5. 添加吊销 API | 0.5 天 | DELETE /meshseeds/:seed_id |
| 6. 实现 Join 接口 | 1 天 | POST /join 完整逻辑 |
总计: 约 3.5 天完成全部功能
✅ 验证结果
编译测试
cd e:\Project\MeshRay
go build -o meshray-test.exe ./cmd/meshray
# ✅ 编译成功,无错误
代码质量
- ✅ 使用加密安全的随机数
- ✅ Ed25519 签名算法
- ✅ 完整的安全检查
- ✅ 事务保证数据一致性
- ✅ 详细的日志记录
📚 相关文档
- [Dashboard 统计功能实现报告.md](./Dashboard 统计功能实现报告.md)
- [Settings 持久化功能实现报告.md](./Settings 持久化功能实现报告.md)
- 前后端问题全面修复报告.md
✅ 总结
实现成果
- ✅ 创建了完整的 MeshSeedService 服务层(205 行)
- ✅ 实现了基于 Ed25519 的数字签名
- ✅ 提供了完整的安全验证逻辑
- ✅ 更新了 Handler 框架(待注入依赖)
- ✅ 代码编译通过,无错误
技术亮点
- 🔐 Ed25519 签名: 密码学级别的安全性
- 🎲 加密随机数: 使用 crypto/rand
- ✅ 多重验证: 签名 + 吊销 + 次数 + 过期
- 💾 事务支持: 保证数据一致性
- 📝 详细日志: 便于审计和调试
用户体验提升(预期)
- ⭐⭐⭐⭐⭐ 一键生成组网凭证
- ⭐⭐⭐⭐⭐ 扫码快速加入网络
- ⭐⭐⭐⭐⭐ 可视化的使用次数和过期时间
- ⭐⭐⭐⭐⭐ 支持吊销,增强安全性
状态: ✅ MeshSeed 框架已完成
下一项: 注入签名密钥和完善实现(约 3.5 天)
建议: 继续实现设备密钥管理
MeshRay - 安全便捷的组网凭证系统! 🔐✨