Meta topic: https://meta.discourse.org/t/prevent-to-linkify-when-there-is-a-redirect/226964/2?u=osama. This commit adds a new site setting `block_onebox_on_redirect` (default off) for blocking oneboxes (full and inline) of URLs that redirect. Note that an initial http → https redirect is still allowed if the redirect location is identical to the source (minus the scheme of course). For example, if a user includes a link to `http://example.com/page` and the link resolves to `https://example.com/page`, then the link will onebox (assuming it can be oneboxed) even if the setting is enabled. The reason for this is a user may type out a URL (i.e. the URL is short and memorizable) with http and since a lot of sites support TLS with http traffic automatically redirected to https, so we should still allow the URL to onebox.
118 lines
3.1 KiB
Ruby
118 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class InlineOneboxer
|
|
|
|
MIN_TITLE_LENGTH = 2
|
|
|
|
def initialize(urls, opts = nil)
|
|
@urls = urls
|
|
@opts = opts || {}
|
|
end
|
|
|
|
def process
|
|
@urls.map { |url| InlineOneboxer.lookup(url, @opts) }.compact
|
|
end
|
|
|
|
def self.invalidate(url)
|
|
Discourse.cache.delete(cache_key(url))
|
|
end
|
|
|
|
def self.cache_lookup(url)
|
|
Discourse.cache.read(cache_key(url))
|
|
end
|
|
|
|
def self.lookup(url, opts = nil)
|
|
opts ||= {}
|
|
opts = opts.with_indifferent_access
|
|
|
|
unless opts[:skip_cache] || opts[:invalidate]
|
|
cached = cache_lookup(url)
|
|
return cached if cached.present?
|
|
end
|
|
|
|
return unless url
|
|
|
|
if route = Discourse.route_for(url)
|
|
if route[:controller] == "topics"
|
|
if topic = Oneboxer.local_topic(url, route, opts)
|
|
opts[:skip_cache] = true
|
|
post_number = [route[:post_number].to_i, topic.highest_post_number].min
|
|
if post_number > 1
|
|
opts[:post_number] = post_number
|
|
opts[:post_author] = post_author_for_title(topic, post_number)
|
|
end
|
|
return onebox_for(url, topic.title, opts)
|
|
else
|
|
# not permitted to see topic
|
|
return nil
|
|
end
|
|
end
|
|
end
|
|
|
|
always_allow = SiteSetting.enable_inline_onebox_on_all_domains
|
|
allowed_domains = SiteSetting.allowed_inline_onebox_domains&.split('|') unless always_allow
|
|
|
|
if always_allow || allowed_domains
|
|
uri = begin
|
|
URI(url)
|
|
rescue URI::Error
|
|
end
|
|
|
|
if uri.present? &&
|
|
uri.hostname.present? &&
|
|
(always_allow || allowed_domains.include?(uri.hostname)) &&
|
|
!Onebox::DomainChecker.is_blocked?(uri.hostname)
|
|
if SiteSetting.block_onebox_on_redirect
|
|
max_redirects = 0
|
|
end
|
|
title = RetrieveTitle.crawl(
|
|
url,
|
|
max_redirects: max_redirects,
|
|
initial_https_redirect_ignore_limit: SiteSetting.block_onebox_on_redirect
|
|
)
|
|
title = nil if title && title.length < MIN_TITLE_LENGTH
|
|
return onebox_for(url, title, opts)
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
private
|
|
|
|
def self.onebox_for(url, title, opts)
|
|
title = title && Emoji.gsub_emoji_to_unicode(title)
|
|
if title && opts[:post_number]
|
|
title += " - "
|
|
if opts[:post_author]
|
|
title += I18n.t(
|
|
"inline_oneboxer.topic_page_title_post_number_by_user",
|
|
post_number: opts[:post_number],
|
|
username: opts[:post_author]
|
|
)
|
|
else
|
|
title += I18n.t(
|
|
"inline_oneboxer.topic_page_title_post_number",
|
|
post_number: opts[:post_number]
|
|
)
|
|
end
|
|
end
|
|
onebox = { url: url, title: title && Emoji.gsub_emoji_to_unicode(title) }
|
|
Discourse.cache.write(cache_key(url), onebox, expires_in: 1.day) if !opts[:skip_cache]
|
|
onebox
|
|
end
|
|
|
|
def self.cache_key(url)
|
|
"inline_onebox:#{url}"
|
|
end
|
|
|
|
def self.post_author_for_title(topic, post_number)
|
|
guardian = Guardian.new
|
|
post = topic.posts.find_by(post_number: post_number)
|
|
author = post&.user
|
|
if author && guardian.can_see_post?(post) && post.post_type == Post.types[:regular]
|
|
author.username
|
|
end
|
|
end
|
|
end
|