feat(security): проверка Origin, строгий CSP и лимиты загрузок
- middleware OriginCheck: state-changing запросы с чужого Origin отклоняются (AGENT.md 9.7); запросы без Origin пропускаются — cookie уже SameSite=Lax - CSP перечисляет директивы явно (script-src/worker-src/manifest-src 'self', style-src с inline для React, img-src с внешними https для аватаров вебхуков, connect-src с доменом файлов и LiveKit); добавлены Permissions-Policy, Cross-Origin-Opener-Policy и X-Permitted-Cross-Domain-Policies - лимиты по AGENT.md 8.6: загрузки 10/мин и 100/сутки (вложения и аватары), реакции 20/мин; администратор инстанса лимиты обходит - step-up: смена прав роли (в теле PATCH) и удаление сервера (перед вызовом /auth/step-up) требуют свежего подтверждения личности - тесты: Origin (свой/чужой/GET), состав CSP, лимит реакций, step-up на права роли; исправлен вызов NewRateLimiter (второй аргумент — burst, не окно)
This commit is contained in:
@@ -332,7 +332,7 @@ func (s *Server) registerGuildCoreRoutes(api huma.API) {
|
||||
GuildID string `path:"guild_id"`
|
||||
},
|
||||
) (*okOutput, error) {
|
||||
user, _, err := requireUser(ctx)
|
||||
user, session, err := requireUser(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -343,6 +343,11 @@ func (s *Server) registerGuildCoreRoutes(api huma.API) {
|
||||
if !resolved.IsOwner && !user.IsInstanceAdmin {
|
||||
return nil, humaErrorStatus(http.StatusForbidden, "perm.denied", "only the owner can delete the guild")
|
||||
}
|
||||
// Удаление сервера требует свежего подтверждения личности (AGENT.md 9.3).
|
||||
// Тело у DELETE не спрашиваем: клиент сначала вызывает /auth/step-up.
|
||||
if err := s.auth.RequireStepUp(ctx, user, session, "", ""); err != nil {
|
||||
return nil, humaError(err)
|
||||
}
|
||||
if err := s.deleteGuild(ctx, user, guildID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1274,10 +1279,13 @@ func (s *Server) registerRoleRoutes(api huma.API) {
|
||||
CosmeticBadgeID *string `json:"cosmetic_badge_id,omitempty"`
|
||||
NickColor *int64 `json:"nick_color,omitempty"`
|
||||
NickEffect *string `json:"nick_effect,omitempty"`
|
||||
// Step-up обязателен при смене прав роли (AGENT.md 9.3).
|
||||
StepUpPassword string `json:"step_up_password,omitempty"`
|
||||
StepUpTOTP string `json:"step_up_totp,omitempty"`
|
||||
}
|
||||
},
|
||||
) (*roleOutput, error) {
|
||||
user, _, err := requireUser(ctx)
|
||||
user, session, err := requireUser(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1285,6 +1293,13 @@ func (s *Server) registerRoleRoutes(api huma.API) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Смена набора прав роли — чувствительная операция: подтверждаем
|
||||
// личность свежим паролем (AGENT.md 9.3).
|
||||
if input.Body.Permissions != nil {
|
||||
if err := s.auth.RequireStepUp(ctx, user, session, input.Body.StepUpPassword, input.Body.StepUpTOTP); err != nil {
|
||||
return nil, humaError(err)
|
||||
}
|
||||
}
|
||||
roleID, err := parseID("role_id", input.RoleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user