v0.1.35: query-mode XML-ответы, TOCTOU receive, валидации AWS, purge 60s, сужение локов
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user