debian-mirror-gitlab/lib/banzai/filter/asset_proxy_filter.rb
2023-05-08 21:46:49 +05:30

111 lines
4 KiB
Ruby

# frozen_string_literal: true
module Banzai
module Filter
# Proxy's images/assets to another server. Reduces mixed content warnings
# as well as hiding the customer's IP address when requesting images.
# Copies the original img `src` to `data-canonical-src` then replaces the
# `src` with a new url to the proxy server.
#
# Based on https://github.com/gjtorikian/html-pipeline/blob/v2.14.3/lib/html/pipeline/camo_filter.rb
class AssetProxyFilter < HTML::Pipeline::Filter
def initialize(text, context = nil, result = nil)
super
end
def call
return doc unless asset_proxy_enabled?
doc.search('img').each do |element|
original_src = element['src']
next unless original_src
begin
uri = URI.parse(original_src)
rescue StandardError
next
end
next if uri.host.nil? && !original_src.start_with?('///')
next if asset_host_allowed?(uri.host)
element['src'] = asset_proxy_url(original_src)
element['data-canonical-src'] = original_src
end
doc
end
def validate
needs(:asset_proxy, :asset_proxy_secret_key) if asset_proxy_enabled?
end
def asset_host_allowed?(host)
context[:asset_proxy_domain_regexp] ? context[:asset_proxy_domain_regexp].match?(host) : false
end
def self.transform_context(context)
context[:disable_asset_proxy] = !Gitlab.config.asset_proxy.enabled
unless context[:disable_asset_proxy]
context[:asset_proxy_enabled] = !context[:disable_asset_proxy]
context[:asset_proxy] = Gitlab.config.asset_proxy.url
context[:asset_proxy_secret_key] = Gitlab.config.asset_proxy.secret_key
context[:asset_proxy_domain_regexp] = Gitlab.config.asset_proxy.domain_regexp
end
context
end
# called during an initializer. Caching the values in Gitlab.config significantly increased
# performance, rather than querying Gitlab::CurrentSettings.current_application_settings
# over and over. However, this does mean that the Rails servers need to get restarted
# whenever the application settings are changed
def self.initialize_settings
application_settings = Gitlab::CurrentSettings.current_application_settings
Gitlab.config['asset_proxy'] ||= Settingslogic.new({})
if application_settings.respond_to?(:asset_proxy_enabled)
Gitlab.config.asset_proxy['enabled'] = application_settings.asset_proxy_enabled
Gitlab.config.asset_proxy['url'] = application_settings.asset_proxy_url
Gitlab.config.asset_proxy['secret_key'] = application_settings.asset_proxy_secret_key
Gitlab.config.asset_proxy['allowlist'] = determine_allowlist(application_settings)
Gitlab.config.asset_proxy['domain_regexp'] = compile_allowlist(Gitlab.config.asset_proxy.allowlist)
else
Gitlab.config.asset_proxy['enabled'] = ::ApplicationSetting.defaults[:asset_proxy_enabled]
end
end
def self.compile_allowlist(domain_list)
return if domain_list.empty?
escaped = domain_list.map { |domain| Regexp.escape(domain).gsub('\*', '.*?') }
Regexp.new("^(#{escaped.join('|')})$", Regexp::IGNORECASE)
end
def self.determine_allowlist(application_settings)
application_settings.try(:asset_proxy_allowlist).presence ||
application_settings.try(:asset_proxy_whitelist).presence ||
[Gitlab.config.gitlab.host]
end
private
def asset_proxy_enabled?
!context[:disable_asset_proxy]
end
def asset_proxy_url(url)
"#{context[:asset_proxy]}/#{asset_url_hash(url)}/#{hexencode(url)}"
end
def asset_url_hash(url)
OpenSSL::HMAC.hexdigest('sha1', context[:asset_proxy_secret_key], url)
end
def hexencode(str)
str.unpack1('H*')
end
end
end
end