diff --git a/FEDERATION.md b/FEDERATION.md index eb91d9545fe..d5a176807b2 100644 --- a/FEDERATION.md +++ b/FEDERATION.md @@ -52,8 +52,8 @@ Mastodon requires all `POST` requests to be signed, and MAY require `GET` reques ## Size limits Mastodon imposes a few hard limits on federated content. -These limits are intended to be very generous and way above what the Mastodon user experience is optimized for, so as to accomodate future changes and unusual or unforeseen usage patterns, while still providing some limits for performance reasons. -The following table attempts to summary those limits. +These limits are intended to be very generous and way above what the Mastodon user experience is optimized for, so as to accommodate future changes and unusual or unforeseen usage patterns, while still providing some limits for performance reasons. +The following table summarizes those limits. | Limited property | Size limit | Consequence of exceeding the limit | | ------------------------------------------------------------- | ---------- | ---------------------------------- | diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 89a2f78c2e1..c9adaaff397 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -564,6 +564,8 @@ RSpec.describe Account do it { is_expected.to_not allow_values('username', 'Username').for(:username) } end + it { is_expected.to validate_length_of(:username).is_at_most(described_class::USERNAME_LENGTH_HARD_LIMIT) } + it { is_expected.to allow_values('the-doctor', username_over_limit).for(:username) } it { is_expected.to_not allow_values('the doctor').for(:username) } diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb index 244d0d126f1..ab757d39683 100644 --- a/spec/models/custom_emoji_spec.rb +++ b/spec/models/custom_emoji_spec.rb @@ -90,8 +90,14 @@ RSpec.describe CustomEmoji, :attachment_processing do subject { Fabricate.build :custom_emoji } it { is_expected.to validate_uniqueness_of(:shortcode).scoped_to(:domain) } - it { is_expected.to validate_length_of(:shortcode).is_at_least(described_class::MINIMUM_SHORTCODE_SIZE) } + it { is_expected.to validate_length_of(:shortcode).is_at_least(described_class::MINIMUM_SHORTCODE_SIZE).is_at_most(described_class::MAX_SHORTCODE_SIZE) } it { is_expected.to allow_values('cats').for(:shortcode) } it { is_expected.to_not allow_values('@#$@#$', 'X').for(:shortcode) } + + context 'when remote' do + subject { Fabricate.build :custom_emoji, domain: 'host.example' } + + it { is_expected.to validate_length_of(:shortcode).is_at_most(described_class::MAX_FEDERATED_SHORTCODE_SIZE) } + end end end diff --git a/spec/models/custom_filter_keyword_spec.rb b/spec/models/custom_filter_keyword_spec.rb index 4e3ab060a04..cc6558ea693 100644 --- a/spec/models/custom_filter_keyword_spec.rb +++ b/spec/models/custom_filter_keyword_spec.rb @@ -3,6 +3,11 @@ require 'rails_helper' RSpec.describe CustomFilterKeyword do + describe 'Validations' do + it { is_expected.to validate_length_of(:keyword).is_at_most(described_class::KEYWORD_LENGTH_LIMIT) } + it { is_expected.to validate_presence_of(:keyword) } + end + describe '#to_regex' do context 'when whole_word is true' do it 'builds a regex with boundaries and the keyword' do diff --git a/spec/models/custom_filter_spec.rb b/spec/models/custom_filter_spec.rb index 03914fa6b48..8a60f1dd491 100644 --- a/spec/models/custom_filter_spec.rb +++ b/spec/models/custom_filter_spec.rb @@ -6,8 +6,9 @@ RSpec.describe CustomFilter do it_behaves_like 'Expireable' describe 'Validations' do - it { is_expected.to validate_presence_of(:title) } + it { is_expected.to validate_length_of(:title).is_at_most(described_class::TITLE_LENGTH_LIMIT) } it { is_expected.to validate_presence_of(:context) } + it { is_expected.to validate_presence_of(:title) } it { is_expected.to_not allow_values([], %w(invalid)).for(:context) } it { is_expected.to allow_values(%w(home)).for(:context) } diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb index e2d91835ec7..bc6e67d8bff 100644 --- a/spec/models/list_spec.rb +++ b/spec/models/list_spec.rb @@ -6,6 +6,7 @@ RSpec.describe List do describe 'Validations' do subject { Fabricate.build :list } + it { is_expected.to validate_length_of(:title).is_at_most(described_class::TITLE_LENGTH_LIMIT) } it { is_expected.to validate_presence_of(:title) } context 'when account has hit max list limit' do diff --git a/spec/requests/activitypub/inboxes_spec.rb b/spec/requests/activitypub/inboxes_spec.rb index b21881b10fd..e33afa53c9b 100644 --- a/spec/requests/activitypub/inboxes_spec.rb +++ b/spec/requests/activitypub/inboxes_spec.rb @@ -20,6 +20,19 @@ RSpec.describe 'ActivityPub Inboxes' do end end + context 'with an excessively large payload' do + subject { post inbox_path, params: { this: :that, those: :these }.to_json, sign_with: remote_account } + + before { stub_const('ActivityPub::Activity::MAX_JSON_SIZE', 1.byte) } + + it 'returns http content too large' do + subject + + expect(response) + .to have_http_status(413) + end + end + context 'with a specific account' do subject { post account_inbox_path(account_username: account.username), params: {}.to_json, sign_with: remote_account } diff --git a/spec/requests/api/web/push_subscriptions_spec.rb b/spec/requests/api/web/push_subscriptions_spec.rb index 88c0302f860..3c33f0d2d29 100644 --- a/spec/requests/api/web/push_subscriptions_spec.rb +++ b/spec/requests/api/web/push_subscriptions_spec.rb @@ -190,6 +190,17 @@ RSpec.describe 'API Web Push Subscriptions' do .to eq(alerts_payload[:data][:alerts][type.to_sym].to_s) end end + + context 'when using other user subscription' do + let(:subscription) { Fabricate(:web_push_subscription) } + + it 'does not change settings' do + put api_web_push_subscription_path(subscription), params: alerts_payload + + expect(response) + .to have_http_status(404) + end + end end def created_push_subscription diff --git a/spec/services/fan_out_on_write_service_spec.rb b/spec/services/fan_out_on_write_service_spec.rb index c6dd020cdff..9f488995606 100644 --- a/spec/services/fan_out_on_write_service_spec.rb +++ b/spec/services/fan_out_on_write_service_spec.rb @@ -23,18 +23,30 @@ RSpec.describe FanOutOnWriteService do Fabricate(:media_attachment, status: status, account: alice) allow(redis).to receive(:publish) - - subject.call(status) end def home_feed_of(account) HomeFeed.new(account).get(10).map(&:id) end + context 'when status account is suspended' do + let(:visibility) { 'public' } + + before { alice.suspend! } + + it 'does not execute or broadcast' do + expect(subject.call(status)) + .to be_nil + expect_no_broadcasting + end + end + context 'when status is public' do let(:visibility) { 'public' } it 'adds status to home feed of author and followers and broadcasts', :inline_jobs do + subject.call(status) + expect(status.id) .to be_in(home_feed_of(alice)) .and be_in(home_feed_of(bob)) @@ -52,6 +64,8 @@ RSpec.describe FanOutOnWriteService do let(:visibility) { 'limited' } it 'adds status to home feed of author and mentioned followers and does not broadcast', :inline_jobs do + subject.call(status) + expect(status.id) .to be_in(home_feed_of(alice)) .and be_in(home_feed_of(bob)) @@ -66,6 +80,8 @@ RSpec.describe FanOutOnWriteService do let(:visibility) { 'private' } it 'adds status to home feed of author and followers and does not broadcast', :inline_jobs do + subject.call(status) + expect(status.id) .to be_in(home_feed_of(alice)) .and be_in(home_feed_of(bob)) @@ -79,6 +95,8 @@ RSpec.describe FanOutOnWriteService do let(:visibility) { 'direct' } it 'is added to the home feed of its author and mentioned followers and does not broadcast', :inline_jobs do + subject.call(status) + expect(status.id) .to be_in(home_feed_of(alice)) .and be_in(home_feed_of(bob))