From 4b766f984689311523b89e1b68d2a11dff3fc396 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 10 May 2020 11:41:43 +0200 Subject: [PATCH] Refactor monkey-patching of Goldfinger (#12561) --- app/helpers/webfinger_helper.rb | 19 ++++++++++++++++++ app/models/remote_follow.rb | 3 ++- .../fetch_remote_account_service.rb | 5 +++-- app/services/resolve_account_service.rb | 3 ++- config/initializers/http_client_proxy.rb | 20 +++++++++---------- .../remote_follow_controller_spec.rb | 10 +++++----- 6 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 app/helpers/webfinger_helper.rb diff --git a/app/helpers/webfinger_helper.rb b/app/helpers/webfinger_helper.rb new file mode 100644 index 000000000..70c493210 --- /dev/null +++ b/app/helpers/webfinger_helper.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module WebfingerHelper + def webfinger!(uri) + hidden_service_uri = /\.(onion|i2p)(:\d+)?$/.match(uri) + + raise Mastodon::HostValidationError, 'Instance does not support hidden service connections' if !Rails.configuration.x.access_to_hidden_service && hidden_service_uri + + opts = { + ssl: !hidden_service_uri, + + headers: { + 'User-Agent': Mastodon::Version.user_agent, + }, + } + + Goldfinger::Client.new(uri, opts.merge(Rails.configuration.x.http_client_proxy)).finger + end +end diff --git a/app/models/remote_follow.rb b/app/models/remote_follow.rb index 5ea535287..30b84f7d5 100644 --- a/app/models/remote_follow.rb +++ b/app/models/remote_follow.rb @@ -3,6 +3,7 @@ class RemoteFollow include ActiveModel::Validations include RoutingHelper + include WebfingerHelper attr_accessor :acct, :addressable_template @@ -71,7 +72,7 @@ class RemoteFollow end def acct_resource - @acct_resource ||= Goldfinger.finger("acct:#{acct}") + @acct_resource ||= webfinger!("acct:#{acct}") rescue Goldfinger::Error, HTTP::ConnectionError nil end diff --git a/app/services/activitypub/fetch_remote_account_service.rb b/app/services/activitypub/fetch_remote_account_service.rb index d65c8f951..83fbf6d07 100644 --- a/app/services/activitypub/fetch_remote_account_service.rb +++ b/app/services/activitypub/fetch_remote_account_service.rb @@ -3,6 +3,7 @@ class ActivityPub::FetchRemoteAccountService < BaseService include JsonLdHelper include DomainControlHelper + include WebfingerHelper SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze @@ -35,12 +36,12 @@ class ActivityPub::FetchRemoteAccountService < BaseService private def verified_webfinger? - webfinger = Goldfinger.finger("acct:#{@username}@#{@domain}") + webfinger = webfinger!("acct:#{@username}@#{@domain}") confirmed_username, confirmed_domain = split_acct(webfinger.subject) return webfinger.link('self')&.href == @uri if @username.casecmp(confirmed_username).zero? && @domain.casecmp(confirmed_domain).zero? - webfinger = Goldfinger.finger("acct:#{confirmed_username}@#{confirmed_domain}") + webfinger = webfinger!("acct:#{confirmed_username}@#{confirmed_domain}") @username, @domain = split_acct(webfinger.subject) self_reference = webfinger.link('self') diff --git a/app/services/resolve_account_service.rb b/app/services/resolve_account_service.rb index 1ad9ed407..17ace100c 100644 --- a/app/services/resolve_account_service.rb +++ b/app/services/resolve_account_service.rb @@ -3,6 +3,7 @@ class ResolveAccountService < BaseService include JsonLdHelper include DomainControlHelper + include WebfingerHelper class WebfingerRedirectError < StandardError; end @@ -76,7 +77,7 @@ class ResolveAccountService < BaseService end def process_webfinger!(uri, redirected = false) - @webfinger = Goldfinger.finger("acct:#{uri}") + @webfinger = webfinger!("acct:#{uri}") confirmed_username, confirmed_domain = @webfinger.subject.gsub(/\Aacct:/, '').split('@') if confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero? diff --git a/config/initializers/http_client_proxy.rb b/config/initializers/http_client_proxy.rb index 9d7b16e69..7a9b7b86d 100644 --- a/config/initializers/http_client_proxy.rb +++ b/config/initializers/http_client_proxy.rb @@ -1,24 +1,22 @@ Rails.application.configure do config.x.http_client_proxy = {} + if ENV['http_proxy'].present? proxy = URI.parse(ENV['http_proxy']) + raise "Unsupported proxy type: #{proxy.scheme}" unless %w(http https).include? proxy.scheme raise "No proxy host" unless proxy.host host = proxy.host host = host[1...-1] if host[0] == '[' # for IPv6 address - config.x.http_client_proxy[:proxy] = { proxy_address: host, proxy_port: proxy.port, proxy_username: proxy.user, proxy_password: proxy.password }.compact + + config.x.http_client_proxy[:proxy] = { + proxy_address: host, + proxy_port: proxy.port, + proxy_username: proxy.user, + proxy_password: proxy.password, + }.compact end config.x.access_to_hidden_service = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true' end - -module Goldfinger - def self.finger(uri, opts = {}) - to_hidden = /\.(onion|i2p)(:\d+)?$/.match(uri) - raise Mastodon::HostValidationError, 'Instance does not support hidden service connections' if !Rails.configuration.x.access_to_hidden_service && to_hidden - opts = { ssl: !to_hidden, headers: {} }.merge(Rails.configuration.x.http_client_proxy).merge(opts) - opts[:headers]['User-Agent'] ||= Mastodon::Version.user_agent - Goldfinger::Client.new(uri, opts).finger - end -end diff --git a/spec/controllers/remote_follow_controller_spec.rb b/spec/controllers/remote_follow_controller_spec.rb index d79dd2949..3ef8f14d9 100644 --- a/spec/controllers/remote_follow_controller_spec.rb +++ b/spec/controllers/remote_follow_controller_spec.rb @@ -35,7 +35,7 @@ describe RemoteFollowController do context 'when webfinger values are wrong' do it 'renders new when redirect url is nil' do resource_with_nil_link = double(link: nil) - allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_nil_link) + allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_return(resource_with_nil_link) post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } } expect(response).to render_template(:new) @@ -45,7 +45,7 @@ describe RemoteFollowController do it 'renders new when template is nil' do link_with_nil_template = double(template: nil) resource_with_link = double(link: link_with_nil_template) - allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_link) + allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_return(resource_with_link) post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } } expect(response).to render_template(:new) @@ -57,7 +57,7 @@ describe RemoteFollowController do before do link_with_template = double(template: 'http://example.com/follow_me?acct={uri}') resource_with_link = double(link: link_with_template) - allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_link) + allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_return(resource_with_link) post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } } end @@ -79,7 +79,7 @@ describe RemoteFollowController do end it 'renders new with error when goldfinger fails' do - allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_raise(Goldfinger::Error) + allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_raise(Goldfinger::Error) post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } } expect(response).to render_template(:new) @@ -87,7 +87,7 @@ describe RemoteFollowController do end it 'renders new when occur HTTP::ConnectionError' do - allow(Goldfinger).to receive(:finger).with('acct:user@unknown').and_raise(HTTP::ConnectionError) + allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@unknown').and_raise(HTTP::ConnectionError) post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@unknown' } } expect(response).to render_template(:new)