fix(invites): код приглашения не подменяется слабым при отказе crypto/rand

Вместо предсказуемого запасного кода ручка возвращает 500: приглашение —
это доступ к серверу, маскировать отказ источника энтропии нельзя.
This commit is contained in:
2026-09-19 23:33:59 +03:00
parent 61a84bfeae
commit 63bf1e63b5
5 changed files with 84 additions and 13 deletions
+10 -8
View File
@@ -93,8 +93,12 @@ func (s *Server) registerInviteRoutes(api huma.API) {
if err != nil {
return nil, err
}
code, err := newInviteCode()
if err != nil {
return nil, humaErrorStatus(http.StatusInternalServerError, "internal.error", "cannot generate invite code")
}
params := store.CreateInviteParams{
Code: newInviteCode(),
Code: code,
GuildID: guildID,
CreatorID: user.ID,
MaxUses: input.Body.MaxUses,
@@ -359,20 +363,18 @@ func (s *Server) inviteOutput(ctx context.Context, user *store.User, invite *sto
}
// newInviteCode генерирует код приглашения криптографическим источником.
func newInviteCode() string {
// Ошибка источника энтропии не маскируется слабым кодом: приглашение —
// это доступ к серверу, поэтому лучше вернуть ошибку (AGENT.md 9.2).
func newInviteCode() (string, error) {
const length = 10
buf := make([]byte, length)
if _, err := rand.Read(buf); err != nil {
// Откат на время: код остаётся уникальным за счёт монотонности.
seed := uint64(time.Now().UnixNano()) //nolint:gosec // не криптография: запасной путь при отказе rand
for i := range buf {
buf[i] = byte(seed >> (uint(i) * 5))
}
return "", err
}
var builder strings.Builder
builder.Grow(length)
for _, value := range buf {
builder.WriteByte(inviteCodeAlphabet[int(value)%len(inviteCodeAlphabet)])
}
return builder.String()
return builder.String(), nil
}