v0.1.35: query-mode XML-ответы, TOCTOU receive, валидации AWS, purge 60s, сужение локов

This commit is contained in:
“Naeel”
2026-08-14 15:53:08 +04:00
parent 8c40ca592f
commit ec10acc99e
15 changed files with 919 additions and 172 deletions
+65 -16
View File
@@ -9,27 +9,65 @@ import (
"shared-sqs/app/models"
)
// TODO - Support:
// - attr.MessageRetentionPeriod
// - attr.Policy
// - attr.RedriveAllowPolicy
func setQueueAttributesV1(q *models.Queue, attr models.QueueAttributes) error {
// AWS-совместимые лимиты: clamp значений к допустимым диапазонам
if attr.DelaySeconds >= 0 {
q.DelaySeconds = ClampInt(attr.DelaySeconds.Int(), 0, MaxDelaySeconds)
// setQueueAttributesV1 — применяет атрибуты очереди с валидацией по AWS-спецификации.
//
// Логическая схема:
// 1. Whitelist имён: неизвестное имя атрибута → InvalidAttributeName.
// Список имён (provided) доступен для Query-протокола (form-параметры
// Attribute.N.Name); для JSON-протокола provided == nil и проверка пропускается
// (структура уже разобрана из тела, неизвестные поля отброшены).
// 2. Применяются ТОЛЬКО явно переданные атрибуты (значение != 0).
// ВАЖНО (фикс): раньше условие `attr.X >= 0` срабатывало и для НЕ переданных
// полей (zero-value = 0) — вызов SetQueueAttributes с одним атрибутом
// обнулял все остальные атрибуты очереди.
// 3. Значения вне диапазонов AWS → ошибка InvalidParameterValue
// (раньше значения молча клэмпились в допустимый диапазон).
// 4. RedrivePolicy: ARN DLQ разбирается, DLQ должна существовать, иначе
// InvalidAttributeValue.
func setQueueAttributesV1(q *models.Queue, attr models.QueueAttributes, provided map[string]string) error {
// Шаг 1: whitelist имён атрибутов.
for name := range provided {
if !attrNameWhitelist[name] {
return fmt.Errorf("InvalidAttributeName")
}
}
if attr.MaximumMessageSize >= 0 {
q.MaximumMessageSize = ClampInt(attr.MaximumMessageSize.Int(), MinMessageSizeLimit, MaxMessageSizeLimit)
// Шаг 2: применяем только явно переданные атрибуты с проверкой диапазонов.
// Диапазоны AWS: DelaySeconds 0–900, MaximumMessageSize 1024–262144,
// MessageRetentionPeriod 60–1209600, ReceiveMessageWaitTimeSeconds 0–20,
// VisibilityTimeout 0–43200.
if attr.DelaySeconds != 0 {
if attr.DelaySeconds.Int() < 0 || attr.DelaySeconds.Int() > MaxDelaySeconds {
return fmt.Errorf("InvalidParameterValue")
}
q.DelaySeconds = attr.DelaySeconds.Int()
}
if attr.MessageRetentionPeriod > 0 {
q.MessageRetentionPeriod = ClampInt(attr.MessageRetentionPeriod.Int(), MinMessageRetentionPeriod, MaxMessageRetentionPeriod)
if attr.MaximumMessageSize != 0 {
if attr.MaximumMessageSize.Int() < MinMessageSizeLimit || attr.MaximumMessageSize.Int() > MaxMessageSizeLimit {
return fmt.Errorf("InvalidParameterValue")
}
q.MaximumMessageSize = attr.MaximumMessageSize.Int()
}
if attr.ReceiveMessageWaitTimeSeconds > 0 {
q.ReceiveMessageWaitTimeSeconds = ClampInt(attr.ReceiveMessageWaitTimeSeconds.Int(), 0, MaxReceiveMessageWaitTimeSeconds)
if attr.MessageRetentionPeriod != 0 {
if attr.MessageRetentionPeriod.Int() < MinMessageRetentionPeriod || attr.MessageRetentionPeriod.Int() > MaxMessageRetentionPeriod {
return fmt.Errorf("InvalidParameterValue")
}
q.MessageRetentionPeriod = attr.MessageRetentionPeriod.Int()
}
if attr.VisibilityTimeout >= 0 {
q.VisibilityTimeout = ClampInt(attr.VisibilityTimeout.Int(), 0, MaxVisibilityTimeout)
if attr.ReceiveMessageWaitTimeSeconds != 0 {
if attr.ReceiveMessageWaitTimeSeconds.Int() < 0 || attr.ReceiveMessageWaitTimeSeconds.Int() > MaxReceiveMessageWaitTimeSeconds {
return fmt.Errorf("InvalidParameterValue")
}
q.ReceiveMessageWaitTimeSeconds = attr.ReceiveMessageWaitTimeSeconds.Int()
}
if attr.VisibilityTimeout != 0 {
if attr.VisibilityTimeout.Int() < 0 || attr.VisibilityTimeout.Int() > MaxVisibilityTimeout {
return fmt.Errorf("InvalidParameterValue")
}
q.VisibilityTimeout = attr.VisibilityTimeout.Int()
}
// Шаг 3: RedrivePolicy (dead-letter queue).
if attr.RedrivePolicy != (models.RedrivePolicy{}) {
arnArray := strings.Split(attr.RedrivePolicy.DeadLetterTargetArn, ":")
queueName := arnArray[len(arnArray)-1]
@@ -43,3 +81,14 @@ func setQueueAttributesV1(q *models.Queue, attr models.QueueAttributes) error {
}
return nil
}
// attrNameWhitelist — имена атрибутов, которые SetQueueAttributes может изменять.
// Всё, чего нет в списке, отклоняется с ошибкой InvalidAttributeName.
var attrNameWhitelist = map[string]bool{
"DelaySeconds": true,
"MaximumMessageSize": true,
"MessageRetentionPeriod": true,
"ReceiveMessageWaitTimeSeconds": true,
"VisibilityTimeout": true,
"RedrivePolicy": true,
}