diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index a6b91f62da..29df445061 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -176,4 +176,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 595751aaae..c3d50b1e05 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 6af516d109..311a58d3cd 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