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
This commit is contained in:
Eugen Rochko 2017-04-27 16:25:20 +02:00
parent 73a44507c6
commit eddf330c22
6 changed files with 70 additions and 35 deletions

View File

@ -1,7 +1,7 @@
PATH PATH
remote: . remote: .
specs: specs:
goldfinger (1.1.0) goldfinger (1.2.0)
addressable (~> 2.4) addressable (~> 2.4)
http (~> 2.0) http (~> 2.0)
nokogiri (~> 1.6) nokogiri (~> 1.6)
@ -9,18 +9,19 @@ PATH
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
addressable (2.4.0) addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
coderay (1.1.1) coderay (1.1.1)
crack (0.4.3) crack (0.4.3)
safe_yaml (~> 1.0.0) safe_yaml (~> 1.0.0)
diff-lcs (1.2.5) diff-lcs (1.3)
domain_name (0.5.20160826) domain_name (0.5.20170404)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
fuubar (2.2.0) fuubar (2.2.0)
rspec-core (~> 3.0) rspec-core (~> 3.0)
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.4)
hashdiff (0.3.0) hashdiff (0.3.2)
http (2.0.3) http (2.2.1)
addressable (~> 2.3) addressable (~> 2.3)
http-cookie (~> 1.0) http-cookie (~> 1.0)
http-form_data (~> 1.0.1) http-form_data (~> 1.0.1)
@ -31,18 +32,19 @@ GEM
http_parser.rb (0.6.0) http_parser.rb (0.6.0)
method_source (0.8.2) method_source (0.8.2)
mini_portile2 (2.1.0) mini_portile2 (2.1.0)
nokogiri (1.6.8.1) nokogiri (1.7.1)
mini_portile2 (~> 2.1.0) mini_portile2 (~> 2.1.0)
pry (0.10.4) pry (0.10.4)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
rake (11.2.2) public_suffix (2.0.5)
rake (12.0.0)
rspec (3.5.0) rspec (3.5.0)
rspec-core (~> 3.5.0) rspec-core (~> 3.5.0)
rspec-expectations (~> 3.5.0) rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0) rspec-mocks (~> 3.5.0)
rspec-core (3.5.3) rspec-core (3.5.4)
rspec-support (~> 3.5.0) rspec-support (~> 3.5.0)
rspec-expectations (3.5.0) rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
@ -56,8 +58,8 @@ GEM
slop (3.6.0) slop (3.6.0)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.2) unf_ext (0.0.7.4)
webmock (2.1.0) webmock (3.0.1)
addressable (>= 2.3.6) addressable (>= 2.3.6)
crack (>= 0.3.2) crack (>= 0.3.2)
hashdiff hashdiff

View File

@ -1,6 +1,6 @@
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = 'goldfinger' s.name = 'goldfinger'
s.version = '1.1.0' s.version = '1.2.0'
s.platform = Gem::Platform::RUBY s.platform = Gem::Platform::RUBY
s.required_ruby_version = '>= 2.0.0' s.required_ruby_version = '>= 2.0.0'
s.date = '2016-02-17' s.date = '2016-02-17'

View File

@ -13,35 +13,56 @@ module Goldfinger
ssl = true ssl = true
begin 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 rescue HTTP::Error
if ssl raise Goldfinger::NotFoundError unless ssl
ssl = false
retry ssl = false
else retry
raise Goldfinger::NotFoundError
end
end 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 rescue HTTP::Error
raise Goldfinger::NotFoundError raise Goldfinger::NotFoundError
rescue OpenSSL::SSL::SSLError rescue OpenSSL::SSL::SSLError
raise Goldfinger::SSLError raise Goldfinger::SSLError
rescue Addressable::URI::InvalidURIError
raise Goldfinger::NotFoundError, 'Invalid URI'
end end
private 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) def url(ssl = true)
"http#{'s' if ssl}://#{domain}/.well-known/host-meta" "http#{'s' if ssl}://#{domain}/.well-known/host-meta"
end end
def standard_url(ssl = true)
"http#{'s' if ssl}://#{domain}/.well-known/webfinger?resource=#{@uri}"
end
def url_from_template(template) def url_from_template(template)
xml = Nokogiri::XML(template) xml = Nokogiri::XML(template)
links = xml.xpath('//xmlns:Link[@rel="lrdd"]') links = xml.xpath('//xmlns:Link[@rel="lrdd"]')

View File

@ -1,15 +1,18 @@
module Goldfinger module Goldfinger
# @!attribute [r] href # @!attribute [r] href
# @return [String] The href the link points to # @return [String] The href the link points to
# @!attribute [r] template
# @return [String] The template the link contains
# @!attribute [r] type # @!attribute [r] type
# @return [String] The mime type of the link # @return [String] The mime type of the link
# @!attribute [r] rel # @!attribute [r] rel
# @return [String] The relation descriptor of the link # @return [String] The relation descriptor of the link
class Link class Link
attr_reader :href, :type, :rel attr_reader :href, :template, :type, :rel
def initialize(a) def initialize(a)
@href = a[:href] @href = a[:href]
@template = a[:template]
@type = a[:type] @type = a[:type]
@rel = a[:rel] @rel = a[:rel]
@titles = a[:titles] @titles = a[:titles]

View File

@ -2,7 +2,6 @@ describe Goldfinger::Client do
context 'with HTTPS available' do context 'with HTTPS available' do
describe '#finger' do describe '#finger' do
before 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' }) 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 end
@ -11,15 +10,19 @@ describe Goldfinger::Client do
it 'returns a result' do it 'returns a result' do
expect(subject.finger).to be_instance_of Goldfinger::Result expect(subject.finger).to be_instance_of Goldfinger::Result
end 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
end end
context 'with only HTTP available' do context 'with only HTTP available' do
describe '#finger' do describe '#finger' do
before do before do
stub_request(:get, 'https://quitter.no/.well-known/host-meta').to_raise(HTTP::Error) 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/host-meta').to_return(body: fixture('quitter.no_.well-known_host-meta'), headers: { content_type: 'application/xrd+xml' }) 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' })
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 end
subject { Goldfinger::Client.new('acct:gargron@quitter.no') } subject { Goldfinger::Client.new('acct:gargron@quitter.no') }
@ -27,12 +30,20 @@ describe Goldfinger::Client do
it 'returns a result' do it 'returns a result' do
expect(subject.finger).to be_instance_of Goldfinger::Result expect(subject.finger).to be_instance_of Goldfinger::Result
end 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
end end
context 'with XRD missing' do context 'with XRD missing' do
describe '#finger' do describe '#finger' do
before 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, '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) stub_request(:get, 'http://quitter.no/.well-known/host-meta').to_raise(HTTP::Error)
end end
@ -40,7 +51,7 @@ describe Goldfinger::Client do
subject { Goldfinger::Client.new('acct:gargron@quitter.no') } subject { Goldfinger::Client.new('acct:gargron@quitter.no') }
it 'raises an error' do it 'raises an error' do
expect {subject.finger }.to raise_error(Goldfinger::NotFoundError) expect { subject.finger }.to raise_error(Goldfinger::NotFoundError)
end end
end end
end end

View File

@ -5,7 +5,6 @@ require 'pry'
WebMock.disable_net_connect! WebMock.disable_net_connect!
RSpec.configure do |config| RSpec.configure do |config|
config.expect_with :rspec do |expectations| config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end end
@ -13,7 +12,6 @@ RSpec.configure do |config|
config.mock_with :rspec do |mocks| config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true mocks.verify_partial_doubles = true
end end
end end
def fixture_path(path) def fixture_path(path)