2019-05-03 06:17:27 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-07-20 03:08:54 +08:00
|
|
|
class InlineOneboxer
|
|
|
|
|
2018-01-30 05:39:41 +08:00
|
|
|
MIN_TITLE_LENGTH = 2
|
|
|
|
|
2017-07-22 03:29:04 +08:00
|
|
|
def initialize(urls, opts = nil)
|
2017-07-20 03:08:54 +08:00
|
|
|
@urls = urls
|
2017-07-22 03:29:04 +08:00
|
|
|
@opts = opts || {}
|
2017-07-20 03:08:54 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def process
|
2017-07-22 03:29:04 +08:00
|
|
|
@urls.map { |url| InlineOneboxer.lookup(url, @opts) }.compact
|
2017-07-20 03:08:54 +08:00
|
|
|
end
|
|
|
|
|
2020-06-24 17:54:54 +08:00
|
|
|
def self.invalidate(url)
|
2019-11-27 09:35:14 +08:00
|
|
|
Discourse.cache.delete(cache_key(url))
|
2017-07-20 03:08:54 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.cache_lookup(url)
|
2019-11-27 09:35:14 +08:00
|
|
|
Discourse.cache.read(cache_key(url))
|
2017-07-20 03:08:54 +08:00
|
|
|
end
|
|
|
|
|
2022-05-24 01:02:02 +08:00
|
|
|
def self.local_handlers
|
|
|
|
@local_handlers ||= {}
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.register_local_handler(controller, &handler)
|
|
|
|
local_handlers[controller] = handler
|
|
|
|
end
|
|
|
|
|
2017-07-22 03:29:04 +08:00
|
|
|
def self.lookup(url, opts = nil)
|
|
|
|
opts ||= {}
|
2018-09-04 01:03:43 +08:00
|
|
|
opts = opts.with_indifferent_access
|
2017-07-22 03:29:04 +08:00
|
|
|
|
2018-09-04 01:03:43 +08:00
|
|
|
unless opts[:skip_cache] || opts[:invalidate]
|
2017-07-22 03:29:04 +08:00
|
|
|
cached = cache_lookup(url)
|
|
|
|
return cached if cached.present?
|
|
|
|
end
|
2017-07-20 03:08:54 +08:00
|
|
|
|
2018-03-28 16:20:08 +08:00
|
|
|
return unless url
|
|
|
|
|
2017-07-20 03:08:54 +08:00
|
|
|
if route = Discourse.route_for(url)
|
2020-02-12 18:11:28 +08:00
|
|
|
if route[:controller] == "topics"
|
|
|
|
if topic = Oneboxer.local_topic(url, route, opts)
|
|
|
|
opts[:skip_cache] = true
|
2020-12-17 08:19:13 +08:00
|
|
|
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
|
2020-02-12 18:11:28 +08:00
|
|
|
return onebox_for(url, topic.title, opts)
|
2020-12-18 07:27:32 +08:00
|
|
|
else
|
|
|
|
# not permitted to see topic
|
|
|
|
return nil
|
2020-02-12 18:11:28 +08:00
|
|
|
end
|
2022-05-24 01:02:02 +08:00
|
|
|
elsif handler = local_handlers[route[:controller]]
|
|
|
|
return handler.call(url, route)
|
2017-07-22 03:29:04 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-08-03 02:27:21 +08:00
|
|
|
always_allow = SiteSetting.enable_inline_onebox_on_all_domains
|
2021-02-04 00:15:22 +08:00
|
|
|
allowed_domains = SiteSetting.allowed_inline_onebox_domains&.split('|') unless always_allow
|
2017-08-03 02:27:21 +08:00
|
|
|
|
2021-02-04 00:15:22 +08:00
|
|
|
if always_allow || allowed_domains
|
2018-03-28 16:20:08 +08:00
|
|
|
uri = begin
|
|
|
|
URI(url)
|
2018-08-14 18:23:32 +08:00
|
|
|
rescue URI::Error
|
2018-03-28 16:20:08 +08:00
|
|
|
end
|
2017-07-22 03:29:04 +08:00
|
|
|
|
|
|
|
if uri.present? &&
|
|
|
|
uri.hostname.present? &&
|
2021-02-04 00:15:22 +08:00
|
|
|
(always_allow || allowed_domains.include?(uri.hostname)) &&
|
2022-01-31 15:35:12 +08:00
|
|
|
!Onebox::DomainChecker.is_blocked?(uri.hostname)
|
2022-05-23 18:52:06 +08:00
|
|
|
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
|
|
|
|
)
|
2018-01-30 05:39:41 +08:00
|
|
|
title = nil if title && title.length < MIN_TITLE_LENGTH
|
2017-07-22 03:29:04 +08:00
|
|
|
return onebox_for(url, title, opts)
|
2017-07-20 03:08:54 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2017-07-22 03:29:04 +08:00
|
|
|
def self.onebox_for(url, title, opts)
|
2020-12-17 08:19:13 +08:00
|
|
|
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
|
2020-06-24 17:54:54 +08:00
|
|
|
onebox = { url: url, title: title && Emoji.gsub_emoji_to_unicode(title) }
|
2022-05-25 19:51:47 +08:00
|
|
|
onebox[:title] = WordWatcher.censor_text(onebox[:title])
|
2020-06-24 17:54:54 +08:00
|
|
|
Discourse.cache.write(cache_key(url), onebox, expires_in: 1.day) if !opts[:skip_cache]
|
2018-06-07 13:28:18 +08:00
|
|
|
onebox
|
|
|
|
end
|
|
|
|
|
2017-07-20 03:08:54 +08:00
|
|
|
def self.cache_key(url)
|
|
|
|
"inline_onebox:#{url}"
|
|
|
|
end
|
|
|
|
|
2020-12-17 08:19:13 +08:00
|
|
|
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
|
2017-07-20 03:08:54 +08:00
|
|
|
end
|