From 15638e9b8b0eb0d397c509a4d58e300e999f1915 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Thu, 18 Apr 2024 00:14:59 -0700 Subject: [PATCH] chore: Add validation to prevent message flooding (#9254) - Add a validation to limit messages created per minute to avoid message flooding cases. --- app/models/message.rb | 13 +++++++++++++ lib/limits.rb | 4 ++++ spec/models/message_spec.rb | 13 ++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/models/message.rb b/app/models/message.rb index 143e35041936..465c7e988352 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -59,6 +59,7 @@ class Message < ApplicationRecord }.to_json.freeze before_validation :ensure_content_type + before_validation :prevent_message_flooding before_save :ensure_processed_message_content before_save :ensure_in_reply_to @@ -227,6 +228,18 @@ def save_story_info(story_info) private + def prevent_message_flooding + # Added this to cover the validation specs in messages + # We can revisit and see if we can remove this later + return if conversation.blank? + + # there are cases where automations can result in message loops, we need to prevent such cases. + if conversation.messages.where('created_at >= ?', 1.minute.ago).count >= Limits.conversation_message_per_minute_limit + Rails.logger.error "Too many message: Account Id - #{account_id} : Conversation id - #{conversation_id}" + errors.add(:base, 'Too many messages') + end + end + def ensure_processed_message_content text_content_quoted = content_attributes.dig(:email, :text_content, :quoted) html_content_quoted = content_attributes.dig(:email, :html_content, :quoted) diff --git a/lib/limits.rb b/lib/limits.rb index 720f302a8cea..b6b449d0d7a0 100644 --- a/lib/limits.rb +++ b/lib/limits.rb @@ -4,4 +4,8 @@ module Limits URL_LENGTH_LIMIT = 2048 # https://stackoverflow.com/questions/417142 OUT_OF_OFFICE_MESSAGE_MAX_LENGTH = 10_000 GREETING_MESSAGE_MAX_LENGTH = 10_000 + + def self.conversation_message_per_minute_limit + ENV.fetch('CONVERSATION_MESSAGE_PER_MINUTE_LIMIT', '200').to_i + end end diff --git a/spec/models/message_spec.rb b/spec/models/message_spec.rb index 9f8ea00a168e..bb1bdec1a0df 100644 --- a/spec/models/message_spec.rb +++ b/spec/models/message_spec.rb @@ -11,7 +11,7 @@ end describe 'length validations' do - let(:message) { create(:message) } + let!(:message) { create(:message) } context 'when it validates name length' do it 'valid when within limit' do @@ -27,6 +27,17 @@ expect(message.errors[:processed_message_content]).to include('is too long (maximum is 150000 characters)') expect(message.errors[:content]).to include('is too long (maximum is 150000 characters)') end + + it 'adds error in case of message flooding' do + with_modified_env 'CONVERSATION_MESSAGE_PER_MINUTE_LIMIT': '2' do + conversation = message.conversation + create(:message, conversation: conversation) + conv_new_message = build(:message, conversation: message.conversation) + + expect(conv_new_message.valid?).to be false + expect(conv_new_message.errors[:base]).to eq(['Too many messages']) + end + end end end