23dff69c62
- 新增 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>
41 lines
1.3 KiB
Go
41 lines
1.3 KiB
Go
package util
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"strings"
|
||
)
|
||
|
||
// codeAlphabet 兑换码字母表:剔除易混字符 0/O/1/I/L,避免人工抄录歧义。
|
||
const codeAlphabet = "23456789ABCDEFGHJKMNPQRSTUVWXYZ"
|
||
|
||
// codePrefix 兑换码固定前缀,便于一眼识别归属。
|
||
const codePrefix = "JIUKU"
|
||
|
||
// GenerateRedeemCode 生成一个随机兑换码,展示格式 JIUKU-XXXX-XXXX(8 位随机段)。
|
||
// 使用 crypto/rand + 无歧义字母表;归一化(NormalizeCode)后入库与比对。
|
||
func GenerateRedeemCode() string {
|
||
const n = 8
|
||
buf := make([]byte, n)
|
||
if _, err := rand.Read(buf); err != nil {
|
||
// crypto/rand 失败属系统级异常,调用方(CLI 生码)应直接失败而非产出弱码。
|
||
panic("crypto/rand failed: " + err.Error())
|
||
}
|
||
out := make([]byte, n)
|
||
for i, b := range buf {
|
||
out[i] = codeAlphabet[int(b)%len(codeAlphabet)]
|
||
}
|
||
return codePrefix + "-" + string(out[:4]) + "-" + string(out[4:])
|
||
}
|
||
|
||
// NormalizeCode 归一化兑换码:转大写、去掉连字符/空格,得到入库与查表用的规范形式。
|
||
func NormalizeCode(code string) string {
|
||
var b strings.Builder
|
||
for _, r := range strings.ToUpper(code) {
|
||
if r == '-' || r == ' ' || r == '\t' || r == '\n' || r == '\r' {
|
||
continue
|
||
}
|
||
b.WriteRune(r)
|
||
}
|
||
return b.String()
|
||
}
|