about summary refs log tree commit diff
path: root/app/lib
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2017-04-27 14:42:22 +0200
committerGitHub <noreply@github.com>2017-04-27 14:42:22 +0200
commit88725d6ce85115ea3b0652007db5d40a1c069be3 (patch)
tree7a8965abda1cfc3b6c319ea19ee216755ac2f2df /app/lib
parentbe0a01145b5f303c5c506858146ccf6c6d5cee72 (diff)
OEmbed support for PreviewCard (#2337)
* OEmbed support for PreviewCard

* Improve ProviderDiscovery code failure treatment

* Do not crawl links if there is a content warning, since those
don't display a link card anyway

* Reset db schema

* Fresh migrate

* Fix rubocop style issues
Fix #1681 - return existing access token when applicable instead of creating new

* Fix test

* Extract http client to helper

* Improve oembed controller
Diffstat (limited to 'app/lib')
-rw-r--r--app/lib/formatter.rb8
-rw-r--r--app/lib/provider_discovery.rb36
-rw-r--r--app/lib/sanitize_config.rb42
3 files changed, 84 insertions, 2 deletions
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index 1d8e90d1f..5ae6238d9 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -1,13 +1,13 @@
 # frozen_string_literal: true
 
 require 'singleton'
+require_relative './sanitize_config'
 
 class Formatter
   include Singleton
   include RoutingHelper
 
   include ActionView::Helpers::TextHelper
-  include ActionView::Helpers::SanitizeHelper
 
   def format(status)
     return reformat(status.content) unless status.local?
@@ -23,7 +23,7 @@ class Formatter
   end
 
   def reformat(html)
-    sanitize(html, tags: %w(a br p span), attributes: %w(href rel class))
+    sanitize(html, Sanitize::Config::MASTODON_STRICT)
   end
 
   def plaintext(status)
@@ -43,6 +43,10 @@ class Formatter
     html.html_safe # rubocop:disable Rails/OutputSafety
   end
 
+  def sanitize(html, config)
+    Sanitize.fragment(html, config)
+  end
+
   private
 
   def encode(html)
diff --git a/app/lib/provider_discovery.rb b/app/lib/provider_discovery.rb
new file mode 100644
index 000000000..761ddae0f
--- /dev/null
+++ b/app/lib/provider_discovery.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+class ProviderDiscovery < OEmbed::ProviderDiscovery
+  include HttpHelper
+
+  class << self
+    def discover_provider(url, options = {})
+      res    = http_client.get(url)
+      format = options[:format]
+
+      raise OEmbed::NotFound, url if res.code != 200 || res.mime_type != 'text/html'
+
+      html = Nokogiri::HTML(res.to_s)
+
+      if format.nil? || format == :json
+        provider_endpoint ||= html.at_xpath('//link[@type="application/json+oembed"]')&.attribute('href')&.value
+        format ||= :json if provider_endpoint
+      end
+
+      if format.nil? || format == :xml
+        provider_endpoint ||= html.at_xpath('//link[@type="application/xml+oembed"]')&.attribute('href')&.value
+        format ||= :xml if provider_endpoint
+      end
+
+      begin
+        provider_endpoint = Addressable::URI.parse(provider_endpoint)
+        provider_endpoint.query = nil
+        provider_endpoint = provider_endpoint.to_s
+      rescue Addressable::URI::InvalidURIError
+        raise OEmbed::NotFound, url
+      end
+
+      OEmbed::Provider.new(provider_endpoint, format || OEmbed::Formatter.default)
+    end
+  end
+end
diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb
new file mode 100644
index 000000000..7cf1c3062
--- /dev/null
+++ b/app/lib/sanitize_config.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+class Sanitize
+  module Config
+    HTTP_PROTOCOLS ||= ['http', 'https', :relative].freeze
+
+    MASTODON_STRICT ||= freeze_config(
+      elements: %w(p br span a),
+
+      attributes: {
+        'a'    => %w(href),
+        'span' => %w(class),
+      },
+
+      protocols: {
+        'a' => { 'href' => HTTP_PROTOCOLS },
+      }
+    )
+
+    MASTODON_OEMBED ||= freeze_config merge(
+      RELAXED,
+      elements: RELAXED[:elements] + %w(audio embed iframe source video),
+
+      attributes: merge(
+        RELAXED[:attributes],
+        'audio'  => %w(controls),
+        'embed'  => %w(height src type width),
+        'iframe' => %w(allowfullscreen frameborder height scrolling src width),
+        'source' => %w(src type),
+        'video'  => %w(controls height loop width),
+        'div'    => [:data]
+      ),
+
+      protocols: merge(
+        RELAXED[:protocols],
+        'embed'  => { 'src' => HTTP_PROTOCOLS },
+        'iframe' => { 'src' => HTTP_PROTOCOLS },
+        'source' => { 'src' => HTTP_PROTOCOLS }
+      )
+    )
+  end
+end