Files
杭州明婳科技 ffcb1a77b9 docs: 注释/文档一致性审查修复(A/B/C 三档共 23 项)
对 60 个非测试源文件做文档/注释/代码一致性审查,修复 23 项。全部为注释/文档
改动 + 1 处死代码删除,无运行逻辑变更,无 breaking change。

A 档·实质错误(10 项,会误导下游):
- app.go: closeResources 三连契约注释统一修正--failAfterInit 走
  rollbackReplacedResources 不走 closeResources,closeResources 仅供 doShutdown 复用
- database/manager.go: RandomPicker 注释从过时的 rand.Intn/issue 54899 改为 crypto/rand
- model/base.go: datetime(0) 与“亚秒精度”矛盾,改为 datetime(6)
- cache/keybuilder.go: 三处示例下划线分隔符改为冒号(与默认分隔符 : 一致)
- repository/repository.go: Delete 接口注释从绝对“软删除”改为条件性;
  UpdateFields 示例移除把字段名当 WHERE 条件的误用写法
- middleware/csrf.go: CSRFToken 注释从“用于 API 模式”改为 Cookie/双重提交模式说明
- examples/full/main.go: POST /users 补上“需 Authorization”标注;删除 _ = app 死代码
- utils/random.go: RandInt/RandInt64 补 min==max 边界说明(对齐 RandIntSecure 写法)

B 档·导出符号注释缺失/不完整(6 项):
- ws/ws.go: 5 个 Type* 常量、4 个 Err* 变量补注释
- console/console.go: 5 个 Level 常量补注释
- jwt/jwt.go: 2 个 Blacklist 常量补注释
- router/router.go: 包级 GroupWithMiddlewareGroup 补注释
- middleware/ratelimit.go: NewRateLimiter 补 panic 条件与 Stop 生命周期说明

C 档·描述不完整(7 项):
- utils/strings.go Substr、convert.go CalcPageCount/CalcOffset、datetime.go
  StartOfMonth/EndOfMonth、file.go CopyFile、validator.go IsChinese、crypto.go HashFile
  补全边界/默认行为/返回值语义
- response/error.go: WithDetail 补 nil 接收者行为说明

验证:go build / go vet / go test -race 全绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 18:47:12 +08:00

142 lines
4.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package utils
import (
"crypto/rand"
"errors"
"math/big"
mrand "math/rand"
"sync"
"time"
)
// 本文件提供两类随机数:
// - 密码学安全(RandStringSecure/RandDigitSecure/RandIntSecure/RandInt64Secure):基于
// crypto/rand,不可预测,适用于 token/OTP/重置码/会话 ID/安全 nonce 范围等。
// - 非密码学(RandInt/RandInt64):基于 math/rand + sync.Pool,高性能但可预测,
// 仅用于非安全场景(负载均衡、游戏、A/B 分桶等)。
//
// 注意(H1 收紧):RandString/RandDigit 已移除——字符串随机的用途几乎都是安全场景
// token/ID/验证码),保留 math/rand 版本会诱导误用。请用 RandStringSecure/RandDigitSecure。
var (
// #nosec G404 -- math/rand 用于 RandInt/RandInt64 等非密码学函数(性能优先,仅非安全场景:
// 负载均衡、游戏、A/B 分桶等)。安全场景(token/OTP/重置码)用 RandStringSecure/RandDigitSecure。
randPool = sync.Pool{
New: func() any {
return mrand.New(mrand.NewSource(time.Now().UnixNano()))
},
}
)
const (
letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
digitBytes = "0123456789"
)
// ErrRandInvalidLength 长度过大(超过 1<<20,保护熵池)。n<=0 时返回空串而非此错误。
var ErrRandInvalidLength = errors.New("invalid random length")
// RandInt 返回 [min, max) 范围内的随机整数。min==max 时返回 minmax<min 自动交换。
//
// 非密码学安全(math/rand + sync.Pool),仅用于非安全场景(负载均衡、游戏、A/B 分桶等);
// 不适用于 token/OTP 等安全场景。
func RandInt(min, max int) int {
if min == max {
return min
}
if max < min {
min, max = max, min
}
r := randPool.Get().(*mrand.Rand)
defer randPool.Put(r)
return min + r.Intn(max-min)
}
// RandInt64 返回 [min, max) 范围内的随机 int64(非密码学安全)。min==max 返回 minmax<min 自动交换。
func RandInt64(min, max int64) int64 {
if min == max {
return min
}
if max < min {
min, max = max, min
}
r := randPool.Get().(*mrand.Rand)
defer randPool.Put(r)
return min + r.Int63n(max-min)
}
// RandStringSecure 生成指定长度的密码学安全随机字符串(字母+数字)。
// 基于 crypto/rand,不可预测,适用于 token、会话 ID、API key 等安全场景。
// n<=0 返回空,n 过大(>1<<20)返回错误避免过度消耗熵池。
func RandStringSecure(n int) (string, error) {
if n <= 0 {
return "", nil
}
if n > 1<<20 {
return "", ErrRandInvalidLength
}
b := make([]byte, n)
for i := range b {
idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(letterBytes))))
if err != nil {
return "", err
}
b[i] = letterBytes[idx.Int64()]
}
return string(b), nil
}
// RandDigitSecure 生成指定长度的密码学安全随机数字字符串。
// 基于 crypto/rand,不可预测,适用于 OTP 验证码、密码重置码等安全场景。
// n<=0 返回空,n 过大(>1<<20)返回错误。
func RandDigitSecure(n int) (string, error) {
if n <= 0 {
return "", nil
}
if n > 1<<20 {
return "", ErrRandInvalidLength
}
b := make([]byte, n)
for i := range b {
idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(digitBytes))))
if err != nil {
return "", err
}
b[i] = digitBytes[idx.Int64()]
}
return string(b), nil
}
// RandIntSecure 返回 [min, max) 范围内的密码学安全随机整数。
// 基于 crypto/rand + big.Int 拒绝采样(无偏),适用于安全 nonce 范围、防猜抽奖、密钥分桶等。
// min==max 返回 minmax<min 自动交换。crypto/rand 读取失败时返回错误。
func RandIntSecure(min, max int) (int, error) {
if min == max {
return min, nil
}
if max < min {
min, max = max, min
}
n, err := rand.Int(rand.Reader, big.NewInt(int64(max-min)))
if err != nil {
return 0, err
}
return min + int(n.Int64()), nil
}
// RandInt64Secure 返回 [min, max) 范围内的密码学安全随机 int64。
// 基于 crypto/rand + big.Int 拒绝采样(无偏)。min==max 返回 minmax<min 自动交换。
func RandInt64Secure(min, max int64) (int64, error) {
if min == max {
return min, nil
}
if max < min {
min, max = max, min
}
n, err := rand.Int(rand.Reader, big.NewInt(max-min))
if err != nil {
return 0, err
}
return min + n.Int64(), nil
}