Merge tag 'v4.2.12' into chinwag-next

This commit is contained in:
Mike Barnes 2024-09-24 20:03:33 +10:00
commit 9bcb7630b3
3138 changed files with 94619 additions and 59187 deletions

View file

@ -143,11 +143,11 @@ class ActivityPub::Activity
end
def follow_request_from_object
@follow_request ||= FollowRequest.find_by(target_account: @account, uri: object_uri) unless object_uri.nil?
@follow_request_from_object ||= FollowRequest.find_by(target_account: @account, uri: object_uri) unless object_uri.nil?
end
def follow_from_object
@follow ||= ::Follow.find_by(target_account: @account, uri: object_uri) unless object_uri.nil?
@follow_from_object ||= ::Follow.find_by(target_account: @account, uri: object_uri) unless object_uri.nil?
end
def fetch_remote_original_status

View file

@ -4,7 +4,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
def perform
return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity?
with_lock("announce:#{value_or_id(@object)}") do
with_redis_lock("announce:#{value_or_id(@object)}") do
original_status = status_from_object
return reject_payload! if original_status.nil? || !announceable?(original_status)

View file

@ -4,6 +4,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
include FormattingHelper
def perform
@account.schedule_refresh_if_stale!
dereference_object!
case @object['type']
@ -17,7 +19,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
private
def create_encrypted_message
return reject_payload! if invalid_origin?(object_uri) || @options[:delivered_to_account_id].blank?
return reject_payload! if non_matching_uri_hosts?(@account.uri, object_uri) || @options[:delivered_to_account_id].blank?
target_account = Account.find(@options[:delivered_to_account_id])
target_device = target_account.devices.find_by(device_id: @object.dig('to', 'deviceId'))
@ -45,9 +47,9 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end
def create_status
return reject_payload! if unsupported_object_type? || invalid_origin?(object_uri) || tombstone_exists? || !related_to_local_activity?
return reject_payload! if unsupported_object_type? || non_matching_uri_hosts?(@account.uri, object_uri) || tombstone_exists? || !related_to_local_activity?
with_lock("create:#{object_uri}") do
with_redis_lock("create:#{object_uri}") do
return if delete_arrived_first?(object_uri) || poll_vote?
@status = find_existing_status
@ -108,26 +110,24 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
def process_status_params
@status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url)
@params = begin
{
uri: @status_parser.uri,
url: @status_parser.url || @status_parser.uri,
account: @account,
text: converted_object_type? ? converted_text : (@status_parser.text || ''),
language: @status_parser.language,
spoiler_text: converted_object_type? ? '' : (@status_parser.spoiler_text || ''),
created_at: @status_parser.created_at,
edited_at: @status_parser.edited_at && @status_parser.edited_at != @status_parser.created_at ? @status_parser.edited_at : nil,
override_timestamps: @options[:override_timestamps],
reply: @status_parser.reply,
sensitive: @account.sensitized? || @status_parser.sensitive || false,
visibility: @status_parser.visibility,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id),
poll: process_poll,
}
end
@params = {
uri: @status_parser.uri,
url: @status_parser.url || @status_parser.uri,
account: @account,
text: converted_object_type? ? converted_text : (@status_parser.text || ''),
language: @status_parser.language,
spoiler_text: converted_object_type? ? '' : (@status_parser.spoiler_text || ''),
created_at: @status_parser.created_at,
edited_at: @status_parser.edited_at && @status_parser.edited_at != @status_parser.created_at ? @status_parser.edited_at : nil,
override_timestamps: @options[:override_timestamps],
reply: @status_parser.reply,
sensitive: @account.sensitized? || @status_parser.sensitive || false,
visibility: @status_parser.visibility,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id),
poll: process_poll,
}
end
def process_audience
@ -315,7 +315,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
poll = replied_to_status.preloadable_poll
already_voted = true
with_lock("vote:#{replied_to_status.poll_id}:#{@account.id}") do
with_redis_lock("vote:#{replied_to_status.poll_id}:#{@account.id}") do
already_voted = poll.votes.where(account: @account).exists?
poll.votes.create!(account: @account, choice: poll.options.index(@object['name']), uri: object_uri)
end
@ -327,18 +327,20 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
def resolve_thread(status)
return unless status.reply? && status.thread.nil? && Request.valid_url?(in_reply_to_uri)
ThreadResolveWorker.perform_async(status.id, in_reply_to_uri, { 'request_id' => @options[:request_id]})
ThreadResolveWorker.perform_async(status.id, in_reply_to_uri, { 'request_id' => @options[:request_id] })
end
def fetch_replies(status)
collection = @object['replies']
return if collection.nil?
return if collection.blank?
replies = ActivityPub::FetchRepliesService.new.call(status, collection, allow_synchronous_requests: false, request_id: @options[:request_id])
return unless replies.nil?
uri = value_or_id(collection)
ActivityPub::FetchRepliesWorker.perform_async(status.id, uri, { 'request_id' => @options[:request_id]}) unless uri.nil?
ActivityPub::FetchRepliesWorker.perform_async(status.id, uri, { 'request_id' => @options[:request_id] }) unless uri.nil?
rescue => e
Rails.logger.warn "Error fetching replies: #{e}"
end
def conversation_from_uri(uri)

View file

@ -12,7 +12,7 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
private
def delete_person
with_lock("delete_in_progress:#{@account.id}", autorelease: 2.hours, raise_on_failure: false) do
with_redis_lock("delete_in_progress:#{@account.id}", autorelease: 2.hours, raise_on_failure: false) do
DeleteAccountService.new.call(@account, reserve_username: false, skip_activitypub: true)
end
end
@ -20,14 +20,14 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
def delete_note
return if object_uri.nil?
with_lock("delete_status_in_progress:#{object_uri}", raise_on_failure: false) do
unless invalid_origin?(object_uri)
with_redis_lock("delete_status_in_progress:#{object_uri}", raise_on_failure: false) do
unless non_matching_uri_hosts?(@account.uri, object_uri)
# This lock ensures a concurrent `ActivityPub::Activity::Create` either
# does not create a status at all, or has finished saving it to the
# database before we try to load it.
# Without the lock, `delete_later!` could be called after `delete_arrived_first?`
# and `Status.find` before `Status.create!`
with_lock("create:#{object_uri}") { delete_later!(object_uri) }
with_redis_lock("create:#{object_uri}") { delete_later!(object_uri) }
Tombstone.find_or_create_by(uri: object_uri, account: @account)
end

View file

@ -4,13 +4,14 @@ class ActivityPub::Activity::Flag < ActivityPub::Activity
def perform
return if skip_reports?
target_accounts = object_uris.filter_map { |uri| account_from_uri(uri) }.select(&:local?)
target_statuses_by_account = object_uris.filter_map { |uri| status_from_uri(uri) }.select(&:local?).group_by(&:account_id)
target_accounts = object_uris.filter_map { |uri| account_from_uri(uri) }
target_statuses_by_account = object_uris.filter_map { |uri| status_from_uri(uri) }.group_by(&:account_id)
target_accounts.each do |target_account|
target_statuses = target_statuses_by_account[target_account.id]
target_statuses = target_statuses_by_account[target_account.id]
replied_to_accounts = target_statuses.nil? ? [] : Account.local.where(id: target_statuses.filter_map(&:in_reply_to_account_id))
next if target_account.suspended?
next if target_account.suspended? || (!target_account.local? && replied_to_accounts.none?)
ReportService.new.call(
@account,
@ -33,7 +34,11 @@ class ActivityPub::Activity::Flag < ActivityPub::Activity
end
def report_uri
@json['id'] unless @json['id'].nil? || invalid_origin?(@json['id'])
@json['id'] unless @json['id'].nil? || non_matching_uri_hosts?(@account.uri, @json['id'])
end
def report_comment
(@json['content'] || '')[0...5000]
end
def report_comment

View file

@ -2,6 +2,8 @@
class ActivityPub::Activity::Update < ActivityPub::Activity
def perform
@account.schedule_refresh_if_stale!
dereference_object!
if equals_or_includes_any?(@object['type'], %w(Application Group Organization Person Service))
@ -22,7 +24,7 @@ class ActivityPub::Activity::Update < ActivityPub::Activity
end
def update_status
return reject_payload! if invalid_origin?(object_uri)
return reject_payload! if non_matching_uri_hosts?(@account.uri, object_uri)
@status = Status.find_by(uri: object_uri, account_id: @account.id)

View file

@ -20,6 +20,6 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
serialized_hash = serialized_hash.select { |k, _| options[:fields].include?(k) } if options[:fields]
serialized_hash = self.class.transform_key_casing!(serialized_hash, instance_options)
{ '@context' => serialized_context(named_contexts, context_extensions) }.merge(serialized_hash)
{ '@context': serialized_context(named_contexts, context_extensions) }.merge(serialized_hash)
end
end

View file

@ -13,7 +13,9 @@ module ActivityPub::CaseTransform
when Symbol then camel_lower(value.to_s).to_sym
when String
camel_lower_cache[value] ||= if value.start_with?('_:')
'_:' + value.gsub(/\A_:/, '').underscore.camelize(:lower)
"_:#{value.delete_prefix('_:').underscore.camelize(:lower)}"
elsif LanguagesHelper::ISO_639_1_REGIONAL.key?(value.to_sym)
value
else
value.underscore.camelize(:lower)
end

View file

@ -40,7 +40,7 @@ class ActivityPub::Dereferencer
end
def perform_request(uri, headers: nil)
return if invalid_origin?(uri)
return if non_matching_uri_hosts?(@permitted_origin, uri)
req = Request.new(:get, uri)
@ -57,13 +57,4 @@ class ActivityPub::Dereferencer
end
end
end
def invalid_origin?(uri)
return true if unsupported_uri_scheme?(uri)
needle = Addressable::URI.parse(uri).host
haystack = Addressable::URI.parse(@permitted_origin).host
!haystack.casecmp(needle).zero?
end
end

View file

@ -12,7 +12,7 @@ class ActivityPub::Forwarder
end
def forward!
ActivityPub::LowPriorityDeliveryWorker.push_bulk(inboxes) do |inbox_url|
ActivityPub::LowPriorityDeliveryWorker.push_bulk(inboxes, limit: 1_000) do |inbox_url|
[payload, signature_account_id, inbox_url]
end
end
@ -28,13 +28,11 @@ class ActivityPub::Forwarder
end
def signature_account_id
@signature_account_id ||= begin
if in_reply_to_local?
in_reply_to.account_id
else
reblogged_by_account_ids.first
end
end
@signature_account_id ||= if in_reply_to_local?
in_reply_to.account_id
else
reblogged_by_account_ids.first
end
end
def inboxes

View file

@ -34,7 +34,7 @@ class ActivityPub::LinkedDataSignature
def sign!(creator, sign_with: nil)
options = {
'type' => 'RsaSignature2017',
'type' => 'RsaSignature2017',
'creator' => ActivityPub::TagManager.instance.key_uri_for(creator),
'created' => Time.now.utc.iso8601,
}

View file

@ -50,9 +50,7 @@ class ActivityPub::Parser::MediaAttachmentParser
components = begin
blurhash = @json['blurhash']
if blurhash.present? && /^[\w#$%*+,-.:;=?@\[\]^{|}~]+$/.match?(blurhash)
Blurhash.components(blurhash)
end
Blurhash.components(blurhash) if blurhash.present? && /^[\w#$%*+,-.:;=?@\[\]^{|}~]+$/.match?(blurhash)
end
components.present? && components.none? { |comp| comp > 5 }

View file

@ -26,6 +26,7 @@ class ActivityPub::TagManager
target.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(target)
when :note, :comment, :activity
return activity_account_status_url(target.account, target) if target.reblog?
short_account_status_url(target.account, target)
when :flag
target.uri
@ -40,6 +41,7 @@ class ActivityPub::TagManager
target.instance_actor? ? instance_actor_url : account_url(target)
when :note, :comment, :activity
return activity_account_status_url(target.account, target) if target.reblog?
account_status_url(target.account, target)
when :emoji
emoji_url(target)