From eddf330c22d010ad42fd4e71b1900ac30bce5d58 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 27 Apr 2017 16:25:20 +0200 Subject: [PATCH] The Webfinger spec now mandates a standard URL. Check that URL first, instead of checking host-meta first (which may actually not be present). Bump to 1.2.0 --- Gemfile.lock | 24 ++++++++-------- goldfinger.gemspec | 2 +- lib/goldfinger/client.rb | 51 ++++++++++++++++++++++++---------- lib/goldfinger/link.rb | 5 +++- spec/goldfinger/client_spec.rb | 21 ++++++++++---- spec/spec_helper.rb | 2 -- 6 files changed, 70 insertions(+), 35 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b5c54f0..f1d6740 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - goldfinger (1.1.0) + goldfinger (1.2.0) addressable (~> 2.4) http (~> 2.0) nokogiri (~> 1.6) @@ -9,18 +9,19 @@ PATH GEM remote: https://rubygems.org/ specs: - addressable (2.4.0) + addressable (2.5.1) + public_suffix (~> 2.0, >= 2.0.2) coderay (1.1.1) crack (0.4.3) safe_yaml (~> 1.0.0) - diff-lcs (1.2.5) - domain_name (0.5.20160826) + diff-lcs (1.3) + domain_name (0.5.20170404) unf (>= 0.0.5, < 1.0.0) fuubar (2.2.0) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) - hashdiff (0.3.0) - http (2.0.3) + hashdiff (0.3.2) + http (2.2.1) addressable (~> 2.3) http-cookie (~> 1.0) http-form_data (~> 1.0.1) @@ -31,18 +32,19 @@ GEM http_parser.rb (0.6.0) method_source (0.8.2) mini_portile2 (2.1.0) - nokogiri (1.6.8.1) + nokogiri (1.7.1) mini_portile2 (~> 2.1.0) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - rake (11.2.2) + public_suffix (2.0.5) + rake (12.0.0) rspec (3.5.0) rspec-core (~> 3.5.0) rspec-expectations (~> 3.5.0) rspec-mocks (~> 3.5.0) - rspec-core (3.5.3) + rspec-core (3.5.4) rspec-support (~> 3.5.0) rspec-expectations (3.5.0) diff-lcs (>= 1.2.0, < 2.0) @@ -56,8 +58,8 @@ GEM slop (3.6.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.2) - webmock (2.1.0) + unf_ext (0.0.7.4) + webmock (3.0.1) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff diff --git a/goldfinger.gemspec b/goldfinger.gemspec index 27af897..a77b7e5 100644 --- a/goldfinger.gemspec +++ b/goldfinger.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'goldfinger' - s.version = '1.1.0' + s.version = '1.2.0' s.platform = Gem::Platform::RUBY s.required_ruby_version = '>= 2.0.0' s.date = '2016-02-17' diff --git a/lib/goldfinger/client.rb b/lib/goldfinger/client.rb index 85de1ed..3774ac7 100644 --- a/lib/goldfinger/client.rb +++ b/lib/goldfinger/client.rb @@ -13,35 +13,56 @@ module Goldfinger ssl = true begin - template = perform_get(url(ssl)) + response = perform_get(standard_url(ssl)) + + return finger_from_template if response.code != 200 + + Goldfinger::Result.new(response) rescue HTTP::Error - if ssl - ssl = false - retry - else - raise Goldfinger::NotFoundError - end + raise Goldfinger::NotFoundError unless ssl + + ssl = false + retry end - - raise Goldfinger::NotFoundError, "No host-meta on the server" if template.code != 200 - - response = perform_get(url_from_template(template.body)) - - raise Goldfinger::NotFoundError, "No such user on the server" if response.code != 200 - - Goldfinger::Result.new(response) rescue HTTP::Error raise Goldfinger::NotFoundError rescue OpenSSL::SSL::SSLError raise Goldfinger::SSLError + rescue Addressable::URI::InvalidURIError + raise Goldfinger::NotFoundError, 'Invalid URI' end private + def finger_from_template + ssl = true + + begin + template = perform_get(url(ssl)) + rescue HTTP::Error + raise Goldfinger::NotFoundError unless ssl + + ssl = false + retry + end + + raise Goldfinger::NotFoundError, 'No host-meta on the server' if template.code != 200 + + response = perform_get(url_from_template(template.body)) + + raise Goldfinger::NotFoundError, 'No such user on the server' if response.code != 200 + + Goldfinger::Result.new(response) + end + def url(ssl = true) "http#{'s' if ssl}://#{domain}/.well-known/host-meta" end + def standard_url(ssl = true) + "http#{'s' if ssl}://#{domain}/.well-known/webfinger?resource=#{@uri}" + end + def url_from_template(template) xml = Nokogiri::XML(template) links = xml.xpath('//xmlns:Link[@rel="lrdd"]') diff --git a/lib/goldfinger/link.rb b/lib/goldfinger/link.rb index 1b4c34c..b3766c5 100644 --- a/lib/goldfinger/link.rb +++ b/lib/goldfinger/link.rb @@ -1,15 +1,18 @@ module Goldfinger # @!attribute [r] href # @return [String] The href the link points to + # @!attribute [r] template + # @return [String] The template the link contains # @!attribute [r] type # @return [String] The mime type of the link # @!attribute [r] rel # @return [String] The relation descriptor of the link class Link - attr_reader :href, :type, :rel + attr_reader :href, :template, :type, :rel def initialize(a) @href = a[:href] + @template = a[:template] @type = a[:type] @rel = a[:rel] @titles = a[:titles] diff --git a/spec/goldfinger/client_spec.rb b/spec/goldfinger/client_spec.rb index 375db38..3d332c2 100644 --- a/spec/goldfinger/client_spec.rb +++ b/spec/goldfinger/client_spec.rb @@ -2,7 +2,6 @@ describe Goldfinger::Client do context 'with HTTPS available' do describe '#finger' do before do - stub_request(:get, 'https://quitter.no/.well-known/host-meta').to_return(body: fixture('quitter.no_.well-known_host-meta'), headers: { content_type: 'application/xrd+xml' }) stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_return(body: fixture('quitter.no_.well-known_webfinger.json'), headers: { content_type: 'application/jrd+json' }) end @@ -11,15 +10,19 @@ describe Goldfinger::Client do it 'returns a result' do expect(subject.finger).to be_instance_of Goldfinger::Result end + + it 'performs a single HTTP request' do + subject.finger + expect(a_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no')).to have_been_made.once + end end end context 'with only HTTP available' do describe '#finger' do before do - stub_request(:get, 'https://quitter.no/.well-known/host-meta').to_raise(HTTP::Error) - stub_request(:get, 'http://quitter.no/.well-known/host-meta').to_return(body: fixture('quitter.no_.well-known_host-meta'), headers: { content_type: 'application/xrd+xml' }) - stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_return(body: fixture('quitter.no_.well-known_webfinger.json'), headers: { content_type: 'application/jrd+json' }) + stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_raise(HTTP::Error) + stub_request(:get, 'http://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_return(body: fixture('quitter.no_.well-known_webfinger.json'), headers: { content_type: 'application/jrd+json' }) end subject { Goldfinger::Client.new('acct:gargron@quitter.no') } @@ -27,12 +30,20 @@ describe Goldfinger::Client do it 'returns a result' do expect(subject.finger).to be_instance_of Goldfinger::Result end + + it 'performs two HTTP requests' do + subject.finger + expect(a_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no')).to have_been_made.once + expect(a_request(:get, 'http://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no')).to have_been_made.once + end end end context 'with XRD missing' do describe '#finger' do before do + stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_raise(HTTP::Error) + stub_request(:get, 'http://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_raise(HTTP::Error) stub_request(:get, 'https://quitter.no/.well-known/host-meta').to_raise(HTTP::Error) stub_request(:get, 'http://quitter.no/.well-known/host-meta').to_raise(HTTP::Error) end @@ -40,7 +51,7 @@ describe Goldfinger::Client do subject { Goldfinger::Client.new('acct:gargron@quitter.no') } it 'raises an error' do - expect {subject.finger }.to raise_error(Goldfinger::NotFoundError) + expect { subject.finger }.to raise_error(Goldfinger::NotFoundError) end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 850ba93..f8bc231 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,7 +5,6 @@ require 'pry' WebMock.disable_net_connect! RSpec.configure do |config| - config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end @@ -13,7 +12,6 @@ RSpec.configure do |config| config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end - end def fixture_path(path)