feat(backend): 授权改为时长兑换券体系 + 退役 ed25519/HMAC + 平台生码工具

- 新增 license_codes 码池表 + model.LicenseCode;licenses 加 tier 档位列
- LicenseService.Redeem:单事务 FOR UPDATE 校验码未用 → 时长叠加(可叠加,0=永久)
  → 写 type/tier/max_devices → 绑设备(超限整笔回滚) → 标记已用 → 即时失效 phase 缓存
  路由仍 POST /license/activate,客户端零破坏
- util.GenerateRedeemCode/NormalizeCode:JIUKU-XXXX-XXXX 短码(crypto/rand)
- cmd/gencode:平台批量生成兑换码并落库;删除 cmd/issue、cmd/genkey
- 退役 ed25519 + HMAC:删 util/license_key、GenerateKey、License 全部 config 字段
  及生产启动私钥校验;trial 改直接建行(无需私钥、去 Fatal)
- tier 档位钩子默认 standard,分档消费模式后续设计
- 测试:Redeem 全场景(叠加/过期重置/永久/一码一次/无效/设备上限回滚)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-19 12:14:27 +08:00
parent 914e2fb533
commit 23dff69c62
20 changed files with 541 additions and 642 deletions
+1 -3
View File
@@ -24,9 +24,6 @@ func main() {
if config.C.Server.CORSOrigin == "*" {
log.Fatal("server.cors_origin must not be '*' in production — set it to the actual frontend origin")
}
if config.C.License.Ed25519PrivateKey == "" {
log.Fatal("license.ed25519_private_key is required in production — store the key in Bitwarden and inject via env LICENSE_ED25519PRIVATEKEY")
}
}
// 初始化数据库
@@ -101,6 +98,7 @@ func autoMigrate(db *gorm.DB) {
&model.User{},
&model.License{},
&model.LicenseDevice{},
&model.LicenseCode{},
&model.UserSession{},
&model.LoginAttempt{},
&model.ProductCategory{},