mirror of https://github.com/mastodon/mastodon
				
				
				
			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 controllerpull/2526/head^2
							parent
							
								
									be0a01145b
								
							
						
					
					
						commit
						88725d6ce8
					
				@ -0,0 +1,13 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module HttpHelper
 | 
			
		||||
  USER_AGENT = "#{HTTP::Request::USER_AGENT} (Mastodon/#{Mastodon::VERSION}; +http://#{Rails.configuration.x.local_domain}/)"
 | 
			
		||||
 | 
			
		||||
  def http_client(options = {})
 | 
			
		||||
    timeout = { write: 10, connect: 10, read: 10 }.merge(options)
 | 
			
		||||
 | 
			
		||||
    HTTP.headers(user_agent: USER_AGENT)
 | 
			
		||||
        .timeout(:per_operation, timeout)
 | 
			
		||||
        .follow
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -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
 | 
			
		||||
@ -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
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
object @card
 | 
			
		||||
 | 
			
		||||
attributes :url, :title, :description
 | 
			
		||||
attributes :url, :title, :description, :type,
 | 
			
		||||
           :author_name, :author_url, :provider_name,
 | 
			
		||||
           :provider_url, :html, :width, :height
 | 
			
		||||
 | 
			
		||||
node(:image) { |card| card.image? ? full_asset_url(card.image.url(:original)) : nil }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,4 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require_relative '../../app/lib/provider_discovery'
 | 
			
		||||
OEmbed::Providers.register_fallback(ProviderDiscovery)
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
class AddOEmbedToPreviewCards < ActiveRecord::Migration[5.0]
 | 
			
		||||
  def change
 | 
			
		||||
    add_column :preview_cards, :type, :integer, default: 0, null: false
 | 
			
		||||
    add_column :preview_cards, :html, :text, null: false, default: ''
 | 
			
		||||
    add_column :preview_cards, :author_name, :string, null: false, default: ''
 | 
			
		||||
    add_column :preview_cards, :author_url, :string, null: false, default: ''
 | 
			
		||||
    add_column :preview_cards, :provider_name, :string, null: false, default: ''
 | 
			
		||||
    add_column :preview_cards, :provider_url, :string, null: false, default: ''
 | 
			
		||||
    add_column :preview_cards, :width, :integer, default: 0, null: false
 | 
			
		||||
    add_column :preview_cards, :height, :integer, default: 0, null: false
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue