From 6378feffa8935238bdb5f1f1c01fcb102440fe30 Mon Sep 17 00:00:00 2001 From: Darius Kazemi Date: Tue, 30 Apr 2019 15:29:28 -0700 Subject: [Feature, Federation, Port: hometown@b3e6597] Support locally cached inline images [+ Monsterfork additions] Changes added by Monsterfork: - Do not limit to only Articles - Reuse existing media; retroactively using more-detailed descriptions - Also scrub carrige returns between tags - Handle download failures - Attach to statuses and keep track of inlined media - Handle local edits Co-authored-by: Fire Demon --- app/lib/activitypub/activity.rb | 4 ++-- app/lib/activitypub/activity/create.rb | 6 +++++- app/lib/command_tag/processor.rb | 2 +- app/lib/formatter.rb | 9 ++++++++- app/lib/img_tag_handler.rb | 30 ++++++++++++++++++++++++++++++ app/lib/sanitize_config.rb | 23 ++--------------------- 6 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 app/lib/img_tag_handler.rb (limited to 'app/lib') diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index cff6b569a..9b58fabed 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -4,8 +4,8 @@ class ActivityPub::Activity include JsonLdHelper include Redisable - SUPPORTED_TYPES = %w(Note Question).freeze - CONVERTED_TYPES = %w(Image Audio Video Article Page Event).freeze + SUPPORTED_TYPES = %w(Note Question Article).freeze + CONVERTED_TYPES = %w(Image Audio Video Page Event).freeze def initialize(json, account, **options) @json = json diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index fbb4624e3..10a0a9498 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ActivityPub::Activity::Create < ActivityPub::Activity + include ImgProxyHelper + def perform dereference_object! @@ -94,6 +96,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity ApplicationRecord.transaction do @status = Status.create!(@params) + process_inline_images! attach_tags(@status) end @@ -138,6 +141,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity text: text_from_content || '', language: detected_language, spoiler_text: converted_object_type? ? '' : (text_from_summary || ''), + title: text_from_title, sensitive: @object['sensitive'] || false, visibility: visibility_from_audience, media_attachment_ids: process_attachments.take(4).map(&:id), @@ -433,7 +437,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity return Formatter.instance.linkify([[text_from_name, text_from_summary.presence].compact.join("\n\n"), object_url || @object['id']].join(' ')) if converted_object_type? if @object['content'].present? - @object['content'] + @object['type'] == 'Article' ? Formatter.instance.format_article(@object['content']) : @object['content'] elsif content_language_map? @object['contentMap'].values.first end diff --git a/app/lib/command_tag/processor.rb b/app/lib/command_tag/processor.rb index d9e49c84a..118affee4 100644 --- a/app/lib/command_tag/processor.rb +++ b/app/lib/command_tag/processor.rb @@ -39,7 +39,7 @@ class CommandTag::Processor end elsif @status.destroyed? %w(after_destroy once_after_destroy).each { |suffix| execute_statements(suffix) } - elsif @status.update(text: @text) + elsif @status.update(text: process_inline_images(@text)) %w(after_save once_after_save).each { |suffix| execute_statements(suffix) } else %w(after_save_fail once_after_save_fail).each { |suffix| execute_statements(suffix) } diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index d5408a30b..39c42c8db 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -24,6 +24,7 @@ class HTMLRenderer < Redcarpet::Render::HTML end end +# rubocop:disable Metrics/ClassLength class Formatter include Singleton include RoutingHelper @@ -75,6 +76,11 @@ class Formatter html.delete("\r").delete("\n") end + def format_article(text) + text = text.gsub(/>[\r\n]+<") + text.html_safe # rubocop:disable Rails/OutputSafety + end + def reformat(html, outgoing = false) sanitize(html, Sanitize::Config::MASTODON_STRICT.merge(outgoing: outgoing)) rescue ArgumentError @@ -154,7 +160,7 @@ class Formatter renderer = HTMLRenderer.new({ filter_html: false, escape_html: false, - no_images: true, + no_images: false, no_styles: true, safe_links_only: true, hard_wrap: true, @@ -389,3 +395,4 @@ class Formatter "@#{encode(account.username)}" end end +# rubocop:enable Metrics/ClassLength diff --git a/app/lib/img_tag_handler.rb b/app/lib/img_tag_handler.rb new file mode 100644 index 000000000..0263e1cbd --- /dev/null +++ b/app/lib/img_tag_handler.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class ImgTagHandler < ::Ox::Sax + attr_reader :srcs + attr_reader :alts + + def initialize + @stack = [] + @srcs = [] + @alts = {} + end + + def start_element(element_name) + @stack << [element_name, {}] + end + + def end_element(_) + self_name, self_attributes = @stack[-1] + if self_name == :img && !self_attributes[:src].nil? + @srcs << self_attributes[:src] + @alts[self_attributes[:src]] = self_attributes[:alt]&.strip + end + @stack.pop + end + + def attr(attribute_name, attribute_value) + _name, attributes = @stack.last + attributes[attribute_name] = attribute_value&.strip + end +end diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb index ccc3f4642..05131b674 100644 --- a/app/lib/sanitize_config.rb +++ b/app/lib/sanitize_config.rb @@ -35,25 +35,6 @@ class Sanitize node['class'] = class_list.join(' ') end - IMG_TAG_TRANSFORMER = lambda do |env| - node = env[:node] - - return unless env[:node_name] == 'img' - - node.name = 'a' - - node['href'] = node['src'] - if node['alt'].present? - node.content = "[🖼 #{node['alt']}]" - else - url = node['href'] - prefix = url.match(/\Ahttps?:\/\/(www\.)?/).to_s - text = url[prefix.length, 30] - text = text + "…" if url[prefix.length..-1].length > 30 - node.content = "[🖼 #{text}]" - end - end - LINK_REL_TRANSFORMER = lambda do |env| return unless env[:node_name] == 'a' and env[:node]['href'] @@ -83,7 +64,7 @@ class Sanitize end MASTODON_STRICT ||= freeze_config( - elements: %w(p br span a abbr del pre blockquote code b strong u sub sup i em h1 h2 h3 h4 h5 ul ol li), + elements: %w(p br span a abbr del pre blockquote code b strong u sub sup i em h1 h2 h3 h4 h5 ul ol li img), attributes: { 'a' => %w(href rel class title), @@ -92,6 +73,7 @@ class Sanitize 'blockquote' => %w(cite), 'ol' => %w(start reversed), 'li' => %w(value), + 'img' => %w(src alt title), }, add_attributes: { @@ -107,7 +89,6 @@ class Sanitize transformers: [ CLASS_WHITELIST_TRANSFORMER, - IMG_TAG_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, LINK_REL_TRANSFORMER, ] -- cgit