package gosqs import ( "fmt" "strings" log "github.com/sirupsen/logrus" "shared-sqs/app/models" ) // 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") } } // Шаг 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.MaximumMessageSize != 0 { if attr.MaximumMessageSize.Int() < MinMessageSizeLimit || attr.MaximumMessageSize.Int() > MaxMessageSizeLimit { return fmt.Errorf("InvalidParameterValue") } q.MaximumMessageSize = attr.MaximumMessageSize.Int() } if attr.MessageRetentionPeriod != 0 { if attr.MessageRetentionPeriod.Int() < MinMessageRetentionPeriod || attr.MessageRetentionPeriod.Int() > MaxMessageRetentionPeriod { return fmt.Errorf("InvalidParameterValue") } q.MessageRetentionPeriod = attr.MessageRetentionPeriod.Int() } 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] deadLetterQueue, ok := models.SyncQueues.Queues[queueName] if !ok { log.Error("Invalid RedrivePolicy Attribute") return fmt.Errorf("InvalidAttributeValue") } q.DeadLetterQueue = deadLetterQueue q.MaxReceiveCount = attr.RedrivePolicy.MaxReceiveCount.Int() } return nil } // attrNameWhitelist — имена атрибутов, которые SetQueueAttributes может изменять. // Всё, чего нет в списке, отклоняется с ошибкой InvalidAttributeName. var attrNameWhitelist = map[string]bool{ "DelaySeconds": true, "MaximumMessageSize": true, "MessageRetentionPeriod": true, "ReceiveMessageWaitTimeSeconds": true, "VisibilityTimeout": true, "RedrivePolicy": true, }