about summary refs log tree commit diff
path: root/app/lib
diff options
context:
space:
mode:
authorDarius Kazemi <darius.kazemi@gmail.com>2019-04-30 15:29:28 -0700
committerFire Demon <firedemon@creature.cafe>2020-08-30 05:45:15 -0500
commit6378feffa8935238bdb5f1f1c01fcb102440fe30 (patch)
treeb1eea210ace7eb72a00ab4604c3ec10c5ae4db4b /app/lib
parent4eb49257fc618219709b357fb68f4d6156cab249 (diff)
[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 <firedemon@creature.cafe>
Diffstat (limited to 'app/lib')
-rw-r--r--app/lib/activitypub/activity.rb4
-rw-r--r--app/lib/activitypub/activity/create.rb6
-rw-r--r--app/lib/command_tag/processor.rb2
-rw-r--r--app/lib/formatter.rb9
-rw-r--r--app/lib/img_tag_handler.rb30
-rw-r--r--app/lib/sanitize_config.rb23
6 files changed, 48 insertions, 26 deletions
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
     "<span class=\"h-card\"><a href=\"#{encode(ActivityPub::TagManager.instance.url_for(account))}\" class=\"u-url mention\">@<span>#{encode(account.username)}</span></a></span>"
   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,
       ]