From 8a5b8a7b0ffabc488ef9c9f9dcfc4192a51d511f Mon Sep 17 00:00:00 2001 From: Saiqul Haq Date: Sat, 14 Sep 2024 14:10:51 +0700 Subject: [PATCH 1/4] feat: add Ciphers option to SSL Option --- Gemfile | 8 ++++---- lib/faraday/adapter/httpclient.rb | 14 +++++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index c804688..31775d7 100644 --- a/Gemfile +++ b/Gemfile @@ -4,13 +4,13 @@ source 'https://rubygems.org' gemspec gem 'faraday', '>= 1.0' - gem 'rake', '~> 13.0' gem 'rspec', '~> 3.0' -gem 'simplecov', '~> 0.19.0' +gem 'simplecov', '~> 0.22.0' gem 'webmock', '~> 3.4' -gem 'rubocop', '~> 1.12.0' +less_than_ruby_v27 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7.0') +gem 'rubocop', less_than_ruby_v27 ? '~> 1.12.0' : '~> 1.66.0' gem 'rubocop-packaging', '~> 0.5' -gem 'rubocop-performance', '~> 1.0' +gem 'rubocop-performance', '~> 1.20' diff --git a/lib/faraday/adapter/httpclient.rb b/lib/faraday/adapter/httpclient.rb index de3e9e6..2709523 100644 --- a/lib/faraday/adapter/httpclient.rb +++ b/lib/faraday/adapter/httpclient.rb @@ -48,7 +48,7 @@ def call(env) if (req = env[:request]).stream_response? warn "Streaming downloads for #{self.class.name} " \ - 'are not yet implemented.' + 'are not yet implemented.' req.on_data.call(resp.body, resp.body.bytesize) end save_response env, resp.status, resp.body, resp.headers, resp.reason @@ -101,6 +101,11 @@ def configure_ssl(client, ssl) ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path] ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert] ssl_config.client_key = ssl[:client_key] if ssl[:client_key] + + if support_ciphers?(ssl) + ssl_config.ciphers = ssl[:ciphers] + end + ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] end @@ -147,6 +152,13 @@ def ssl_verify_mode(ssl) end end end + + private + + def support_ciphers?(ssl_param) + Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('2.11.0') && + ssl_param.respond_to?(:ciphers=) + end end end end From 9aa53d26e26ba87b1ebdbe93f533cc6cb27a9f62 Mon Sep 17 00:00:00 2001 From: Saiqul Haq Date: Mon, 9 Sep 2024 09:42:46 +0700 Subject: [PATCH 2/4] chore: update Github Actions to newer version and add dependabot --- .github/dependabot.yml | 10 ++++++++++ .github/workflows/ci.yml | 10 +++++----- .github/workflows/publish.yml | 18 ++++++++++++------ Gemfile | 3 ++- faraday-httpclient.gemspec | 1 + 5 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..403b308 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "bundler" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 130e2d3..3a00415 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,12 +15,12 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - name: Set up Ruby 2.7 + - name: Set up Ruby 3.x uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7 + ruby-version: 3 bundler-cache: true - name: Rubocop @@ -31,10 +31,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby: ['2.6', '2.7', '3.0', '3.1'] + ruby: ['3.0', '3.1', '3.2', '3.3'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a374890..e664ccf 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,14 +10,20 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby 2.7 - uses: actions/setup-ruby@v1 + uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7.x + ruby-version: 2.7 - name: Publish to RubyGems - uses: dawidd6/action-publish-gem@v1 - with: - api_key: ${{secrets.RUBYGEMS_AUTH_TOKEN}} + run: | + mkdir -p $HOME/.gem + touch $HOME/.gem/credentials + chmod 0600 $HOME/.gem/credentials + printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials + gem build faraday-httpclient.gemspec + gem push faraday-httpclient-*.gem + env: + GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }} diff --git a/Gemfile b/Gemfile index 31775d7..cee2e2a 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,7 @@ source 'https://rubygems.org' gemspec gem 'faraday', '>= 1.0' + gem 'rake', '~> 13.0' gem 'rspec', '~> 3.0' gem 'simplecov', '~> 0.22.0' @@ -11,6 +12,6 @@ gem 'simplecov', '~> 0.22.0' gem 'webmock', '~> 3.4' less_than_ruby_v27 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7.0') -gem 'rubocop', less_than_ruby_v27 ? '~> 1.12.0' : '~> 1.66.0' +gem 'rubocop', less_than_ruby_v27 ? '~> 1.12.0' : '~> 1.67.0' gem 'rubocop-packaging', '~> 0.5' gem 'rubocop-performance', '~> 1.20' diff --git a/faraday-httpclient.gemspec b/faraday-httpclient.gemspec index 65ee3a5..c4df1ba 100644 --- a/faraday-httpclient.gemspec +++ b/faraday-httpclient.gemspec @@ -16,6 +16,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0') spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['rubygems_mfa_required'] = 'true' spec.metadata['source_code_uri'] = 'https://github.com/lostisland/faraday-httpclient' spec.metadata['changelog_uri'] = 'https://github.com/lostisland/faraday-httpclient' From b38a51c725be434eafb98451627dcd4a10b1be7a Mon Sep 17 00:00:00 2001 From: Saiqul Haq Date: Sun, 15 Sep 2024 00:09:17 +0700 Subject: [PATCH 3/4] fix: extract SSL configuration to fix linter --- faraday-httpclient.gemspec | 1 + lib/faraday/adapter/httpclient.rb | 54 +---------------- lib/faraday/httpclient/ssl_configurator.rb | 70 ++++++++++++++++++++++ 3 files changed, 74 insertions(+), 51 deletions(-) create mode 100644 lib/faraday/httpclient/ssl_configurator.rb diff --git a/faraday-httpclient.gemspec b/faraday-httpclient.gemspec index c4df1ba..b1e33e6 100644 --- a/faraday-httpclient.gemspec +++ b/faraday-httpclient.gemspec @@ -24,4 +24,5 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_dependency 'httpclient', '>= 2.2' + spec.metadata['rubygems_mfa_required'] = 'true' end diff --git a/lib/faraday/adapter/httpclient.rb b/lib/faraday/adapter/httpclient.rb index 2709523..28fb1d6 100644 --- a/lib/faraday/adapter/httpclient.rb +++ b/lib/faraday/adapter/httpclient.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'faraday/httpclient/ssl_configurator' + module Faraday class Adapter # This class provides the main implementation for your adapter. @@ -26,7 +28,7 @@ def build_connection(env) end if env[:url].scheme == 'https' && (ssl = env[:ssl]) - configure_ssl @client, ssl + ::Faraday::HTTPClient::SSLConfigurator.configure @client, ssl end configure_client @client @@ -91,24 +93,6 @@ def configure_proxy(client, proxy) client.set_proxy_auth(proxy[:user], proxy[:password]) end - # @param ssl [Hash] - def configure_ssl(client, ssl) - ssl_config = client.ssl_config - ssl_config.verify_mode = ssl_verify_mode(ssl) - ssl_config.cert_store = ssl_cert_store(ssl) - - ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file] - ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path] - ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert] - ssl_config.client_key = ssl[:client_key] if ssl[:client_key] - - if support_ciphers?(ssl) - ssl_config.ciphers = ssl[:ciphers] - end - - ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] - end - # @param req [Hash] def configure_timeouts(client, req) if (sec = request_timeout(:open, req)) @@ -127,38 +111,6 @@ def configure_timeouts(client, req) def configure_client(client) @config_block&.call(client) end - - # @param ssl [Hash] - # @return [OpenSSL::X509::Store] - def ssl_cert_store(ssl) - return ssl[:cert_store] if ssl[:cert_store] - - # Memoize the cert store so that the same one is passed to - # HTTPClient each time, to avoid resyncing SSL sessions when - # it's changed - - # Use the default cert store by default, i.e. system ca certs - @ssl_cert_store ||= OpenSSL::X509::Store.new.tap(&:set_default_paths) - end - - # @param ssl [Hash] - def ssl_verify_mode(ssl) - ssl[:verify_mode] || begin - if ssl.fetch(:verify, true) - OpenSSL::SSL::VERIFY_PEER | - OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT - else - OpenSSL::SSL::VERIFY_NONE - end - end - end - - private - - def support_ciphers?(ssl_param) - Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('2.11.0') && - ssl_param.respond_to?(:ciphers=) - end end end end diff --git a/lib/faraday/httpclient/ssl_configurator.rb b/lib/faraday/httpclient/ssl_configurator.rb new file mode 100644 index 0000000..2688b4e --- /dev/null +++ b/lib/faraday/httpclient/ssl_configurator.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Faraday + module HTTPClient + # Configures SSL options for HTTPClient + class SSLConfigurator + def self.configure(client, ssl) + new(client, ssl).configure + end + + def initialize(client, ssl) + @client = client + @ssl = ssl + end + + def configure + ssl_config = @client.ssl_config + ssl_config.verify_mode = ssl_verify_mode + ssl_config.cert_store = ssl_cert_store + + configure_ssl_options(ssl_config) + configure_ciphers(ssl_config) + end + + private + + attr_reader :ssl + + def configure_ssl_options(ssl_config) + ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file] + ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path] + ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert] + ssl_config.client_key = ssl[:client_key] if ssl[:client_key] + ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] + end + + def configure_ciphers(ssl_config) + if Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('2.11.0') && + ssl_config.respond_to?(:ciphers=) + ssl_config.ciphers = ssl[:ciphers] + end + end + + # @param ssl [Hash] + # @return [OpenSSL::X509::Store] + def ssl_cert_store + return ssl[:cert_store] if ssl[:cert_store] + + # Memoize the cert store so that the same one is passed to + # HTTPClient each time, to avoid resyncing SSL sessions when + # it's changed + + # Use the default cert store by default, i.e. system ca certs + @ssl_cert_store ||= OpenSSL::X509::Store.new.tap(&:set_default_paths) + end + + # @param ssl [Hash] + def ssl_verify_mode + ssl[:verify_mode] || begin + if ssl.fetch(:verify, true) + OpenSSL::SSL::VERIFY_PEER | + OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + else + OpenSSL::SSL::VERIFY_NONE + end + end + end + end + end +end From f40eb653d0208eab8f10bb29912d31d90bcb63dc Mon Sep 17 00:00:00 2001 From: Olle Jonsson Date: Tue, 22 Oct 2024 10:41:20 +0200 Subject: [PATCH 4/4] Lint: auto-correct Style/RedundantLineContinuation --- lib/faraday/adapter/httpclient.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/faraday/adapter/httpclient.rb b/lib/faraday/adapter/httpclient.rb index 28fb1d6..935abce 100644 --- a/lib/faraday/adapter/httpclient.rb +++ b/lib/faraday/adapter/httpclient.rb @@ -69,7 +69,7 @@ def call(env) rescue Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED, IOError, SocketError raise Faraday::ConnectionFailed, $ERROR_INFO rescue StandardError => e - if defined?(::OpenSSL::SSL::SSLError) && \ + if defined?(::OpenSSL::SSL::SSLError) && e.is_a?(::OpenSSL::SSL::SSLError) raise Faraday::SSLError, e end