diff --git a/app/lib/active_storage/service/ds_proxy_service.rb b/app/lib/active_storage/service/ds_proxy_service.rb new file mode 100644 index 000000000..fe540d591 --- /dev/null +++ b/app/lib/active_storage/service/ds_proxy_service.rb @@ -0,0 +1,57 @@ +module ActiveStorage + # Wraps an ActiveStorage::Service to route direct upload and direct download URLs through our proxy, + # thus avoiding exposing the storage provider’s URL to our end-users. + class Service::DsProxyService < SimpleDelegator + attr_reader :wrapped + + def self.build(wrapped:, configurator:, **options) + new(wrapped: configurator.build(wrapped)) + end + + def initialize(wrapped:) + @wrapped = wrapped + super(wrapped) + end + + def url(*args) + url = wrapped.url(*args) + publicize(url) + end + + def url_for_direct_upload(*args) + url = wrapped.url_for_direct_upload(*args) + publicize(url) + end + + private + + def object_for(key, &block) + blob_url = url(key) + if block_given? + request = Typhoeus::Request.new(blob_url) + request.on_headers do |response| + if response.code != 200 + raise Fog::OpenStack::Storage::NotFound.new + end + end + request.on_body do |chunk| + yield chunk + end + request.run + else + response = Typhoeus.get(blob_url) + if response.success? + response + else + raise Fog::OpenStack::Storage::NotFound.new + end + end + end + + def publicize(url) + search = %r{^https://[^/]+/v1/AUTH_[a-f0-9]{32}} + replace = 'https://static.demarches-simplifiees.fr' + url.gsub(search, replace) + end + end +end diff --git a/config/environments/production.rb b/config/environments/production.rb index 8837fb88b..0c93feb51 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -93,7 +93,7 @@ Rails.application.configure do # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true - config.active_storage.service = :openstack + config.active_storage.service = :proxied # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify diff --git a/config/initializers/active_storage.rb b/config/initializers/active_storage.rb index 1d600d89c..7357c9267 100644 --- a/config/initializers/active_storage.rb +++ b/config/initializers/active_storage.rb @@ -7,33 +7,3 @@ ActiveStorage::Service.url_expires_in = 1.hour # cleaner (as it allows to enqueue the virus scan on attachment creation, rather # than on blob creation). ActiveSupport.on_load(:active_storage_blob) { include BlobVirusScanner } - -# When an OpenStack service is initialized it makes a request to fetch -# `publicURL` to use for all operations. We intercept the method that reads -# this url and replace the host with DS_Proxy host. This way all the operation -# are performed through DS_Proxy. -# -# https://github.com/fog/fog-openstack/blob/37621bb1d5ca78d037b3c56bd307f93bba022ae1/lib/fog/openstack/auth/catalog/v2.rb#L16 -require 'fog/openstack/auth/catalog/v2' - -module Fog::OpenStack::Auth::Catalog - class V2 - def endpoint_url(endpoint, interface) - url = endpoint["#{interface}URL"] - - if interface == 'public' - publicize(url) - else - url - end - end - - private - - def publicize(url) - search = %r{^https://[^/]+/} - replace = 'https://static.demarches-simplifiees.fr/' - url.gsub(search, replace) - end - end -end diff --git a/config/storage.yml b/config/storage.yml index 0427a3f7a..11de850f6 100644 --- a/config/storage.yml +++ b/config/storage.yml @@ -4,6 +4,9 @@ local: test: service: Disk root: <%= Rails.root.join("tmp/storage") %> +proxied: + service: DsProxy + wrapped: openstack openstack: service: OpenStack container: "<%= ENV['FOG_ACTIVESTORAGE_DIRECTORY'] %>"