Merge branch 'master' into glitch-soc/merge-upstream

Conflicts:
- `app/javascript/mastodon/actions/compose.js`:
  Not a “real” conflict, but change too close to a change we made to
  fix the vanilla WebUI locally pushing authored local-only toots in the
  public TL view.
This commit is contained in:
Thibaut Girka
2020-07-22 13:38:17 +02:00
90 changed files with 414 additions and 144 deletions

View File

@@ -157,6 +157,34 @@ class ActivityPub::Activity
fetch_remote_original_status
end
def dereference_object!
return unless @object.is_a?(String)
return if invalid_origin?(@object)
object = fetch_resource(@object, true, signed_fetch_account)
return unless object.present? && object.is_a?(Hash) && supported_context?(object)
@object = object
end
def signed_fetch_account
first_mentioned_local_account || first_local_follower
end
def first_mentioned_local_account
audience = (as_array(@json['to']) + as_array(@json['cc'])).uniq
local_usernames = audience.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) }
.map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) }
return if local_usernames.empty?
Account.local.where(username: local_usernames).first
end
def first_local_follower
@account.followers.local.first
end
def follow_request_from_object
@follow_request ||= FollowRequest.find_by(target_account: @account, uri: object_uri) unless object_uri.nil?
end

View File

@@ -4,25 +4,32 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
def perform
return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity?
original_status = status_from_object
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
original_status = status_from_object
return reject_payload! if original_status.nil? || !announceable?(original_status)
return reject_payload! if original_status.nil? || !announceable?(original_status)
status = Status.find_by(account: @account, reblog: original_status)
@status = Status.find_by(account: @account, reblog: original_status)
return status unless status.nil?
return @status unless @status.nil?
status = Status.create!(
account: @account,
reblog: original_status,
uri: @json['id'],
created_at: @json['published'],
override_timestamps: @options[:override_timestamps],
visibility: visibility_from_audience
)
@status = Status.create!(
account: @account,
reblog: original_status,
uri: @json['id'],
created_at: @json['published'],
override_timestamps: @options[:override_timestamps],
visibility: visibility_from_audience
)
distribute(status)
status
distribute(@status)
else
raise Mastodon::RaceConditionError
end
end
@status
end
private
@@ -54,4 +61,8 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
def reblog_of_local_status?
status_from_uri(object_uri)&.account&.local?
end
def lock_options
{ redis: Redis.current, key: "announce:#{@object['id']}" }
end
end

View File

@@ -4,7 +4,12 @@ class ActivityPub::Activity::Block < ActivityPub::Activity
def perform
target_account = account_from_uri(object_uri)
return if target_account.nil? || !target_account.local? || @account.blocking?(target_account)
return if target_account.nil? || !target_account.local?
if @account.blocking?(target_account)
@account.block_relationships.find_by(target_account: target_account).update(uri: @json['id']) if @json['id'].present?
return
end
UnfollowService.new.call(target_account, @account) if target_account.following?(@account)

View File

@@ -2,6 +2,8 @@
class ActivityPub::Activity::Create < ActivityPub::Activity
def perform
dereference_object!
case @object['type']
when 'EncryptedMessage'
create_encrypted_message

View File

@@ -13,11 +13,62 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
undo_like
when 'Block'
undo_block
when nil
handle_reference
end
end
private
def handle_reference
# Some implementations do not inline the object, and as we don't have a
# global index, we have to guess what object it is.
return if object_uri.nil?
try_undo_announce || try_undo_accept || try_undo_follow || try_undo_like || try_undo_block || delete_later!(object_uri)
end
def try_undo_announce
status = Status.where.not(reblog_of_id: nil).find_by(uri: object_uri, account: @account)
if status.present?
RemoveStatusService.new.call(status)
true
else
false
end
end
def try_undo_accept
# We can't currently handle `Undo Accept` as we don't record `Accept`'s uri
false
end
def try_undo_follow
follow = @account.follow_requests.find_by(uri: object_uri) || @account.active_relationships.find_by(uri: object_uri)
if follow.present?
follow.destroy
true
else
false
end
end
def try_undo_like
# There is an index on accounts, but an account may have *many* favs, so this may be too costly
false
end
def try_undo_block
block = @account.block_relationships.find_by(uri: object_uri)
if block.present?
UnblockService.new.call(@account, block.target_account)
true
else
false
end
end
def undo_announce
return if object_uri.nil?

View File

@@ -4,6 +4,8 @@ class ActivityPub::Activity::Update < ActivityPub::Activity
SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze
def perform
dereference_object!
if equals_or_includes_any?(@object['type'], SUPPORTED_TYPES)
update_account
elsif equals_or_includes_any?(@object['type'], %w(Question))

View File

@@ -7,6 +7,7 @@ module Mastodon
class HostValidationError < ValidationError; end
class LengthValidationError < ValidationError; end
class DimensionsValidationError < ValidationError; end
class StreamValidationError < ValidationError; end
class RaceConditionError < Error; end
class RateLimitExceededError < Error; end

View File

@@ -139,9 +139,15 @@ class FeedManager
end
def clear_from_timeline(account, target_account)
# Clear from timeline all statuses from or mentionning target_account
timeline_key = key(:home, account.id)
timeline_status_ids = redis.zrange(timeline_key, 0, -1)
target_statuses = Status.where(id: timeline_status_ids, account: target_account)
statuses = Status.where(id: timeline_status_ids).select(:id, :reblog_of_id, :account_id).to_a
reblogged_ids = Status.where(id: statuses.map(&:reblog_of_id).compact, account: target_account).pluck(:id)
with_mentions_ids = Mention.active.where(status_id: statuses.flat_map { |s| [s.id, s.reblog_of_id] }.compact, account: target_account).pluck(:status_id)
target_statuses = statuses.filter do |status|
status.account_id == target_account.id || reblogged_ids.include?(status.reblog_of_id) || with_mentions_ids.include?(status.id) || with_mentions_ids.include?(status.reblog_of_id)
end
target_statuses.each do |status|
unpush_from_home(account, status)