Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
SECURITY: Limit chat drafts length and preloaded count (#19987)
Only allow maximum of `50_000` characters for chat drafts. A hidden `max_chat_draft_length` setting can control this limit. A migration is also provided to delete any abusive draft in the database. The number of drafts loaded on current user has also been limited and ordered by most recent update. Note that spec files moved are not directly related to the fix. Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com> Co-authored-by: Régis Hanol <regis@hanol.fr>
- Loading branch information
1 parent
ec2ed5b
commit 5eaf080
Showing
11 changed files
with
121 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -110,3 +110,6 @@ chat: | |
| default: 5 | ||
| max: 10 | ||
| min: 0 | ||
| max_chat_draft_length: | ||
| default: 50_000 | ||
| hidden: true | ||
17 changes: 17 additions & 0 deletions
17
plugins/chat/db/post_migrate/20230116090324_drop_chat_drafts_over_max_length.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class DropChatDraftsOverMaxLength < ActiveRecord::Migration[7.0] | ||
| def up | ||
| if table_exists?(:chat_drafts) | ||
| # Delete abusive drafts | ||
| execute <<~SQL | ||
| DELETE FROM chat_drafts | ||
| WHERE LENGTH(data) > 50000 | ||
| SQL | ||
| end | ||
| end | ||
|
|
||
| def down | ||
| raise ActiveRecord::IrreversibleMigration | ||
| end | ||
| end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| RSpec.describe ChatDraft do | ||
| before { SiteSetting.max_chat_draft_length = 100 } | ||
|
|
||
| it "errors when data.value is greater than `max_chat_draft_length`" do | ||
| draft = | ||
| described_class.create( | ||
| user_id: Fabricate(:user).id, | ||
| chat_channel_id: Fabricate(:chat_channel).id, | ||
| data: { value: "A" * (SiteSetting.max_chat_draft_length + 1) }.to_json, | ||
| ) | ||
|
|
||
| expect(draft.errors.full_messages).to eq( | ||
| [I18n.t("chat.errors.draft_too_long", { maximum: SiteSetting.max_chat_draft_length })], | ||
| ) | ||
| end | ||
| end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
plugins/chat/spec/serializer/core_ext/current_user_serializer_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| RSpec.describe CurrentUserSerializer do | ||
| fab!(:current_user) { Fabricate(:user) } | ||
|
|
||
| let(:serializer) do | ||
| described_class.new(current_user, scope: Guardian.new(current_user), root: false) | ||
| end | ||
|
|
||
| before do | ||
| SiteSetting.chat_enabled = true | ||
| SiteSetting.chat_allowed_groups = Group::AUTO_GROUPS[:everyone] | ||
| current_user.user_option.update(chat_enabled: true) | ||
| end | ||
|
|
||
| describe "#chat_drafts" do | ||
| context "when user can't chat" do | ||
| before { SiteSetting.chat_allowed_groups = Group::AUTO_GROUPS[:staff] } | ||
|
|
||
| it "is not present" do | ||
| expect(serializer.as_json[:chat_drafts]).to be_blank | ||
| end | ||
| end | ||
|
|
||
| it "is ordered by most recent drafts" do | ||
| Fabricate(:chat_draft, user: current_user, value: "second draft") | ||
| Fabricate(:chat_draft, user: current_user, value: "first draft") | ||
|
|
||
| values = | ||
| serializer.as_json[:chat_drafts].map { |draft| MultiJson.load(draft[:data])["value"] } | ||
| expect(values).to eq(["first draft", "second draft"]) | ||
| end | ||
|
|
||
| it "limits the numbers of drafts" do | ||
| 21.times { Fabricate(:chat_draft, user: current_user) } | ||
|
|
||
| expect(serializer.as_json[:chat_drafts].length).to eq(20) | ||
| end | ||
| end | ||
| end |