mirror of
https://github.com/yingziwu/mastodon.git
synced 2026-02-04 03:25:14 +00:00
Merge commit from fork
* Add limit on inbox payload size The 1MB limit is consistent with the limit we use when fetching remote resources * Add limit to number of options from federated polls * Add a limit to the number of federated profile fields * Add limit on federated username length * Add hard limits for federated display name and account bio * Add hard limits for `alsoKnownAs` and `attributionDomains` * Add hard limit on federated custom emoji shortcode * Highlight most destructive limits and expand on their reasoning
This commit is contained in:
parent
9a25b12f0c
commit
1a74b74a40
7 changed files with 51 additions and 8 deletions
|
|
@ -3,6 +3,7 @@
|
|||
class ActivityPub::InboxesController < ActivityPub::BaseController
|
||||
include JsonLdHelper
|
||||
|
||||
before_action :skip_large_payload
|
||||
before_action :skip_unknown_actor_activity
|
||||
before_action :require_actor_signature!
|
||||
skip_before_action :authenticate_user!
|
||||
|
|
@ -16,6 +17,10 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
|
|||
|
||||
private
|
||||
|
||||
def skip_large_payload
|
||||
head 413 if request.content_length > ActivityPub::Activity::MAX_JSON_SIZE
|
||||
end
|
||||
|
||||
def skip_unknown_actor_activity
|
||||
head 202 if unknown_affected_account?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ class ActivityPub::Activity
|
|||
include Redisable
|
||||
include Lockable
|
||||
|
||||
MAX_JSON_SIZE = 1.megabyte
|
||||
SUPPORTED_TYPES = %w(Note Question).freeze
|
||||
CONVERTED_TYPES = %w(Image Audio Video Article Page Event).freeze
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
class ActivityPub::Parser::PollParser
|
||||
include JsonLdHelper
|
||||
|
||||
# Limit the number of items for performance purposes.
|
||||
# We truncate rather than error out to avoid missing the post entirely.
|
||||
MAX_ITEMS = 500
|
||||
|
||||
def initialize(json)
|
||||
@json = json
|
||||
end
|
||||
|
|
@ -48,6 +52,6 @@ class ActivityPub::Parser::PollParser
|
|||
private
|
||||
|
||||
def items
|
||||
@json['anyOf'] || @json['oneOf']
|
||||
(@json['anyOf'] || @json['oneOf'])&.take(MAX_ITEMS)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -80,6 +80,13 @@ class Account < ApplicationRecord
|
|||
DISPLAY_NAME_LENGTH_LIMIT = 30
|
||||
NOTE_LENGTH_LIMIT = 500
|
||||
|
||||
# Hard limits for federated content
|
||||
USERNAME_LENGTH_HARD_LIMIT = 2048
|
||||
DISPLAY_NAME_LENGTH_HARD_LIMIT = 2048
|
||||
NOTE_LENGTH_HARD_LIMIT = 20.kilobytes
|
||||
ATTRIBUTION_DOMAINS_HARD_LIMIT = 256
|
||||
ALSO_KNOWN_AS_HARD_LIMIT = 256
|
||||
|
||||
AUTOMATED_ACTOR_TYPES = %w(Application Service).freeze
|
||||
|
||||
include Attachmentable # Load prior to Avatar & Header concerns
|
||||
|
|
@ -112,7 +119,7 @@ class Account < ApplicationRecord
|
|||
validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? }
|
||||
|
||||
# Remote user validations, also applies to internal actors
|
||||
validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (remote? || actor_type_application?) && will_save_change_to_username? }
|
||||
validates :username, format: { with: USERNAME_ONLY_RE }, length: { maximum: USERNAME_LENGTH_HARD_LIMIT }, if: -> { (remote? || actor_type_application?) && will_save_change_to_username? }
|
||||
|
||||
# Remote user validations
|
||||
validates :uri, presence: true, unless: :local?, on: :create
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ class CustomEmoji < ApplicationRecord
|
|||
|
||||
LIMIT = 256.kilobytes
|
||||
MINIMUM_SHORTCODE_SIZE = 2
|
||||
MAX_SHORTCODE_SIZE = 128
|
||||
MAX_FEDERATED_SHORTCODE_SIZE = 2048
|
||||
|
||||
SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}'
|
||||
|
||||
|
|
@ -45,7 +47,8 @@ class CustomEmoji < ApplicationRecord
|
|||
normalizes :domain, with: ->(domain) { domain.downcase.strip }
|
||||
|
||||
validates_attachment :image, content_type: { content_type: IMAGE_MIME_TYPES }, presence: true, size: { less_than: LIMIT }
|
||||
validates :shortcode, uniqueness: { scope: :domain }, format: { with: SHORTCODE_ONLY_RE }, length: { minimum: MINIMUM_SHORTCODE_SIZE }
|
||||
validates :shortcode, uniqueness: { scope: :domain }, format: { with: SHORTCODE_ONLY_RE }, length: { minimum: MINIMUM_SHORTCODE_SIZE, maximum: MAX_FEDERATED_SHORTCODE_SIZE }
|
||||
validates :shortcode, length: { maximum: MAX_SHORTCODE_SIZE }, if: :local?
|
||||
|
||||
scope :local, -> { where(domain: nil) }
|
||||
scope :remote, -> { where.not(domain: nil) }
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||
include Redisable
|
||||
include Lockable
|
||||
|
||||
MAX_PROFILE_FIELDS = 50
|
||||
SUBDOMAINS_RATELIMIT = 10
|
||||
DISCOVERIES_PER_REQUEST = 400
|
||||
|
||||
|
|
@ -123,15 +124,15 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||
|
||||
def set_immediate_attributes!
|
||||
@account.featured_collection_url = valid_collection_uri(@json['featured'])
|
||||
@account.display_name = @json['name'] || ''
|
||||
@account.note = @json['summary'] || ''
|
||||
@account.display_name = (@json['name'] || '')[0...(Account::DISPLAY_NAME_LENGTH_HARD_LIMIT)]
|
||||
@account.note = (@json['summary'] || '')[0...(Account::NOTE_LENGTH_HARD_LIMIT)]
|
||||
@account.locked = @json['manuallyApprovesFollowers'] || false
|
||||
@account.fields = property_values || {}
|
||||
@account.also_known_as = as_array(@json['alsoKnownAs'] || []).map { |item| value_or_id(item) }
|
||||
@account.also_known_as = as_array(@json['alsoKnownAs'] || []).take(Account::ALSO_KNOWN_AS_HARD_LIMIT).map { |item| value_or_id(item) }
|
||||
@account.discoverable = @json['discoverable'] || false
|
||||
@account.indexable = @json['indexable'] || false
|
||||
@account.memorial = @json['memorial'] || false
|
||||
@account.attribution_domains = as_array(@json['attributionDomains'] || []).map { |item| value_or_id(item) }
|
||||
@account.attribution_domains = as_array(@json['attributionDomains'] || []).take(Account::ATTRIBUTION_DOMAINS_HARD_LIMIT).map { |item| value_or_id(item) }
|
||||
end
|
||||
|
||||
def set_fetchable_key!
|
||||
|
|
@ -252,7 +253,10 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||
def property_values
|
||||
return unless @json['attachment'].is_a?(Array)
|
||||
|
||||
as_array(@json['attachment']).select { |attachment| attachment['type'] == 'PropertyValue' }.map { |attachment| attachment.slice('name', 'value') }
|
||||
as_array(@json['attachment'])
|
||||
.select { |attachment| attachment['type'] == 'PropertyValue' }
|
||||
.take(MAX_PROFILE_FIELDS)
|
||||
.map { |attachment| attachment.slice('name', 'value') }
|
||||
end
|
||||
|
||||
def mismatching_origin?(url)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue