From 751909d348b17f990943f120d0772d927693d86b Mon Sep 17 00:00:00 2001 From: fef Date: Fri, 2 Dec 2022 17:02:06 +0000 Subject: [PATCH] download remote custom emojis from reactions Emoji reactions containing custom emojis from remote instances were assumed to already have been downloaded and stored in the database. This might obviously not be the case. --- app/lib/activitypub/activity.rb | 26 +++++++++++++++++ app/lib/activitypub/activity/emoji_react.rb | 13 +++++++-- app/lib/activitypub/activity/like.rb | 32 ++++++++++++++------- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 9baac1d01..bb7ce80b7 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -178,4 +178,30 @@ class ActivityPub::Activity Rails.logger.info("Rejected #{@json['type']} activity #{@json['id']} from #{@account.uri}#{@options[:relayed_through_actor] && "via #{@options[:relayed_through_actor].uri}"}") nil end + + # Ensure all emojis declared in the activity's tags are + # present in the database and downloaded to the local cache. + def process_emoji_tags + as_array(@object['tag']).each do |tag| + process_single_emoji(tag) if tag['type'] == 'Emoji' + end + end + + def process_single_emoji(tag) + parser = ActivityPub::Parser::CustomEmojiParser.new(tag) + return if parser.shortcode.blank? || parser.image_remote_url.blank? + + emoji = CustomEmoji.find_by(shortcode: parser.shortcode, domain: @account.domain) + return unless emoji.nil? || + parser.image_remote_url != emoji.image_remote_url || + (parser.updated_at && parser.updated_at >= emoji.updated_at) + + begin + emoji ||= CustomEmoji.new(domain: @account.domain, shortcode: parser.shortcode, uri: parser.uri) + emoji.image_remote_url = parser.image_remote_url + emoji.save + rescue Seahorse::Client::NetworkingError => e + Rails.logger.warn "Error fetching emoji: #{e}" + end + end end diff --git a/app/lib/activitypub/activity/emoji_react.rb b/app/lib/activitypub/activity/emoji_react.rb index 595751aaa..c3d50b1e0 100644 --- a/app/lib/activitypub/activity/emoji_react.rb +++ b/app/lib/activitypub/activity/emoji_react.rb @@ -5,9 +5,16 @@ class ActivityPub::Activity::EmojiReact < ActivityPub::Activity original_status = status_from_uri(object_uri) name = @json['content'] return if original_status.nil? || - !original_status.account.local? || - delete_arrived_first?(@json['id']) || - @account.reacted?(original_status, name) + !original_status.account.local? || + delete_arrived_first?(@json['id']) || + @account.reacted?(original_status, name) + + if name =~ /^:.*:$/ + process_emoji_tags + + name.delete! ':' + return if CustomEmoji.find_by(shortcode: name, domain: @account.domain).nil? + end reaction = original_status.status_reactions.create!(account: @account, name: name) diff --git a/app/lib/activitypub/activity/like.rb b/app/lib/activitypub/activity/like.rb index 6af516d10..311a58d3c 100644 --- a/app/lib/activitypub/activity/like.rb +++ b/app/lib/activitypub/activity/like.rb @@ -5,16 +5,7 @@ class ActivityPub::Activity::Like < ActivityPub::Activity original_status = status_from_uri(object_uri) return if original_status.nil? || !original_status.account.local? || delete_arrived_first?(@json['id']) - # misskey delivers reactions as likes and attaches the emoji in _misskey_reaction - mk_reaction = @json['_misskey_reaction'] - unless mk_reaction.nil? - custom_emoji = CustomEmoji.find_by(shortcode: mk_reaction, domain: @account.domain) - return if @account.reacted?(original_status, mk_reaction, custom_emoji) - - reaction = original_status.status_reactions.create!(account: @account, name: mk_reaction, custom_emoji: custom_emoji) - LocalNotificationWorker.perform_async(original_status.account_id, reaction.id, 'StatusReaction', 'reaction') - return - end + return if maybe_process_misskey_reaction(original_status) return if @account.favourited?(original_status) @@ -23,4 +14,25 @@ class ActivityPub::Activity::Like < ActivityPub::Activity LocalNotificationWorker.perform_async(original_status.account_id, favourite.id, 'Favourite', 'favourite') Trends.statuses.register(original_status) end + + # Misskey delivers reactions as likes with the emoji in _misskey_reaction + # see https://misskey-hub.net/ns.html#misskey-reaction for details + def maybe_process_misskey_reaction(original_status) + name = @json['_misskey_reaction'] + return false if name.nil? + + custom_emoji = nil + if name =~ /^:.*:$/ + process_emoji_tags + + name.delete! ':' + custom_emoji = CustomEmoji.find_by(shortcode: name, domain: @account.domain) + return false if custom_emoji.nil? # invalid custom emoji, treat it as a regular like + end + return true if @account.reacted?(original_status, name, custom_emoji) + + reaction = original_status.status_reactions.create!(account: @account, name: name, custom_emoji: custom_emoji) + LocalNotificationWorker.perform_async(original_status.account_id, reaction.id, 'StatusReaction', 'reaction') + return true + end end