Merge tag 'v4.3.0-rc.1'

This commit is contained in:
Mike Barnes 2024-10-02 10:34:27 +10:00
commit 26c9b9ba39
3459 changed files with 130932 additions and 69993 deletions

View file

@ -8,44 +8,11 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
dereference_object!
case @object['type']
when 'EncryptedMessage'
create_encrypted_message
else
create_status
end
create_status
end
private
def create_encrypted_message
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'))
return if target_device.nil?
target_device.encrypted_messages.create!(
from_account: @account,
from_device_id: @object.dig('attributedTo', 'deviceId'),
type: @object['messageType'],
body: @object['cipherText'],
digest: @object.dig('digest', 'digestValue'),
message_franking: message_franking.to_token
)
end
def message_franking
MessageFranking.new(
hmac: @object.dig('digest', 'digestValue'),
original_franking: @object['messageFranking'],
source_account_id: @account.id,
target_account_id: @options[:delivered_to_account_id],
timestamp: Time.now.utc
)
end
def create_status
return reject_payload! if unsupported_object_type? || non_matching_uri_hosts?(@account.uri, object_uri) || tombstone_exists? || !related_to_local_activity?
@ -108,7 +75,9 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end
def process_status_params
@status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url)
@status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url, object: @object)
attachment_ids = process_attachments.take(Status::MEDIA_ATTACHMENTS_LIMIT).map(&:id)
@params = {
uri: @status_parser.uri,
@ -125,7 +94,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
visibility: @status_parser.visibility,
thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id),
media_attachment_ids: attachment_ids,
ordered_media_attachment_ids: attachment_ids,
poll: process_poll,
}
end
@ -257,7 +227,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
as_array(@object['attachment']).each do |attachment|
media_attachment_parser = ActivityPub::Parser::MediaAttachmentParser.new(attachment)
next if media_attachment_parser.remote_url.blank? || media_attachments.size >= 4
next if media_attachment_parser.remote_url.blank? || media_attachments.size >= Status::MEDIA_ATTACHMENTS_LIMIT
begin
media_attachment = MediaAttachment.create(
@ -280,6 +250,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id)
rescue Seahorse::Client::NetworkingError => e
Rails.logger.warn "Error storing media attachment: #{e}"
RedownloadMediaWorker.perform_async(media_attachment.id)
end
end
@ -316,7 +287,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
already_voted = true
with_redis_lock("vote:#{replied_to_status.poll_id}:#{@account.id}") do
already_voted = poll.votes.where(account: @account).exists?
already_voted = poll.votes.exists?(account: @account)
poll.votes.create!(account: @account, choice: poll.options.index(@object['name']), uri: object_uri)
end
@ -371,7 +342,15 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end
def converted_text
linkify([@status_parser.title.presence, @status_parser.spoiler_text.presence, @status_parser.url || @status_parser.uri].compact.join("\n\n"))
[formatted_title, @status_parser.spoiler_text.presence, formatted_url].compact.join("\n\n")
end
def formatted_title
"<h2>#{@status_parser.title}</h2>" if @status_parser.title.present?
end
def formatted_url
linkify(@status_parser.url || @status_parser.uri)
end
def unsupported_media_type?(mime_type)
@ -404,7 +383,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
return false if local_usernames.empty?
Account.local.where(username: local_usernames).exists?
Account.local.exists?(username: local_usernames)
end
def tombstone_exists?

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true
class ActivityPub::Activity::Flag < ActivityPub::Activity
COMMENT_SIZE_LIMIT = 5000
def perform
return if skip_reports?
@ -38,7 +40,7 @@ class ActivityPub::Activity::Flag < ActivityPub::Activity
end
def report_comment
(@json['content'] || '')[0...5000]
(@json['content'] || '')[0...COMMENT_SIZE_LIMIT]
end
def report_comment

View file

@ -9,7 +9,7 @@ class ActivityPub::Activity::Move < ActivityPub::Activity
target_account = ActivityPub::FetchRemoteAccountService.new.call(target_uri)
if target_account.nil? || target_account.suspended? || !target_account.also_known_as.include?(origin_account.uri)
if target_account.nil? || target_account.unavailable? || !target_account.also_known_as.include?(origin_account.uri)
unmark_as_processing!
return
end

View file

@ -4,6 +4,7 @@ class ActivityPub::LinkedDataSignature
include JsonLdHelper
CONTEXT = 'https://w3id.org/identity/v1'
SIGNATURE_CONTEXT = 'https://w3id.org/security/v1'
def initialize(json)
@json = json.with_indifferent_access
@ -46,7 +47,13 @@ class ActivityPub::LinkedDataSignature
signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), to_be_signed))
@json.merge('signature' => options.merge('signatureValue' => signature))
# Mastodon's context is either an array or a single URL
context_with_security = Array(@json['@context'])
context_with_security << 'https://w3id.org/security/v1'
context_with_security.uniq!
context_with_security = context_with_security.first if context_with_security.size == 1
@json.merge('signature' => options.merge('signatureValue' => signature), '@context' => context_with_security)
end
private

View file

@ -6,12 +6,13 @@ class ActivityPub::Parser::StatusParser
NORMALIZED_LOCALE_NAMES = LanguagesHelper::SUPPORTED_LOCALES.keys.index_by(&:downcase).freeze
# @param [Hash] json
# @param [Hash] magic_values
# @option magic_values [String] :followers_collection
def initialize(json, magic_values = {})
@json = json
@object = json['object'] || json
@magic_values = magic_values
# @param [Hash] options
# @option options [String] :followers_collection
# @option options [Hash] :object
def initialize(json, **options)
@json = json
@object = options[:object] || json['object'] || json
@options = options
end
def uri
@ -80,7 +81,7 @@ class ActivityPub::Parser::StatusParser
:public
elsif audience_cc.any? { |cc| ActivityPub::TagManager.instance.public_collection?(cc) }
:unlisted
elsif audience_to.include?(@magic_values[:followers_collection])
elsif audience_to.include?(@options[:followers_collection])
:private
else
:direct

View file

@ -33,6 +33,6 @@ class ActivityPub::Serializer < ActiveModel::Serializer
adapter_options[:named_contexts].merge!(_named_contexts)
adapter_options[:context_extensions].merge!(_context_extensions)
end
super(adapter_options, options, adapter_instance)
super
end
end

View file

@ -74,6 +74,18 @@ class ActivityPub::TagManager
account_status_replies_url(target.account, target, page_params)
end
def likes_uri_for(target)
raise ArgumentError, 'target must be a local activity' unless %i(note comment activity).include?(target.object_type) && target.local?
account_status_likes_url(target.account, target)
end
def shares_uri_for(target)
raise ArgumentError, 'target must be a local activity' unless %i(note comment activity).include?(target.object_type) && target.local?
account_status_shares_url(target.account, target)
end
def followers_uri_for(target)
target.local? ? account_followers_url(target) : target.followers_url.presence
end