diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..de671ad --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,100 @@ +AllCops: + TargetRubyVersion: 2.3 + Exclude: + - 'spec/**/*' + - 'bin/*' + - 'Rakefile' + - 'vendor/**/*' + +Bundler/OrderedGems: + Enabled: false + +Layout/AccessModifierIndentation: + EnforcedStyle: indent + +Layout/EmptyLineAfterMagicComment: + Enabled: false + +Layout/SpaceInsideHashLiteralBraces: + EnforcedStyle: space + +Metrics/AbcSize: + Max: 100 + +Metrics/BlockNesting: + Max: 3 + +Metrics/ClassLength: + CountComments: false + Max: 200 + +Metrics/CyclomaticComplexity: + Max: 15 + +Metrics/LineLength: + AllowURI: true + Enabled: false + +Metrics/MethodLength: + CountComments: false + Max: 55 + +Metrics/ModuleLength: + CountComments: false + Max: 200 + +Metrics/ParameterLists: + Max: 4 + CountKeywordArgs: true + +Metrics/PerceivedComplexity: + Max: 10 + +Rails: + Enabled: true + +Rails/HasAndBelongsToMany: + Enabled: false + +Rails/SkipsModelValidations: + Enabled: false + +Style/ClassAndModuleChildren: + Enabled: false + +Style/CollectionMethods: + Enabled: true + PreferredMethods: + find_all: 'select' + +Style/Documentation: + Enabled: false + +Style/DoubleNegation: + Enabled: true + +Style/FrozenStringLiteralComment: + Enabled: true + +Style/GuardClause: + Enabled: false + +Style/Lambda: + Enabled: false + +Style/PercentLiteralDelimiters: + PreferredDelimiters: + '%i': '()' + '%w': '()' + +Style/PerlBackrefs: + AutoCorrect: false + +Style/RegexpLiteral: + Enabled: false + +Style/SymbolArray: + Enabled: false + +Style/TrailingCommaInLiteral: + EnforcedStyleForMultiline: 'comma' diff --git a/.ruby-version b/.ruby-version index 42ad437..005119b 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1,2 +1 @@ -2.2.4 - +2.4.1 diff --git a/.travis.yml b/.travis.yml index 15db7f0..132c8d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,9 @@ language: ruby cache: bundler +notifications: + email: false + rvm: - 2.3.1 - 2.4.1 diff --git a/Gemfile.lock b/Gemfile.lock index f1d6740..f942492 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,10 +1,11 @@ PATH remote: . specs: - goldfinger (1.2.0) - addressable (~> 2.4) - http (~> 2.0) - nokogiri (~> 1.6) + goldfinger (2.0.0) + addressable (~> 2.5) + http (~> 2.2) + nokogiri (~> 1.8) + oj (~> 3.0) GEM remote: https://rubygems.org/ @@ -20,39 +21,40 @@ GEM fuubar (2.2.0) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) - hashdiff (0.3.2) - http (2.2.1) + hashdiff (0.3.4) + http (2.2.2) addressable (~> 2.3) http-cookie (~> 1.0) http-form_data (~> 1.0.1) http_parser.rb (~> 0.6.0) http-cookie (1.0.3) domain_name (~> 0.5) - http-form_data (1.0.1) + http-form_data (1.0.3) http_parser.rb (0.6.0) method_source (0.8.2) - mini_portile2 (2.1.0) - nokogiri (1.7.1) - mini_portile2 (~> 2.1.0) + mini_portile2 (2.2.0) + nokogiri (1.8.0) + mini_portile2 (~> 2.2.0) + oj (3.3.2) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) 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.4) - rspec-support (~> 3.5.0) - rspec-expectations (3.5.0) + rspec (3.6.0) + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) + rspec-core (3.6.0) + rspec-support (~> 3.6.0) + rspec-expectations (3.6.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.5.0) - rspec-mocks (3.5.0) + rspec-support (~> 3.6.0) + rspec-mocks (3.6.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.5.0) - rspec-support (3.5.0) + rspec-support (~> 3.6.0) + rspec-support (3.6.0) ruby-progressbar (1.8.1) safe_yaml (1.0.4) slop (3.6.0) @@ -68,7 +70,7 @@ PLATFORMS ruby DEPENDENCIES - bundler (~> 1.3) + bundler (~> 1.15) fuubar goldfinger! pry (>= 0.10.3) @@ -77,4 +79,4 @@ DEPENDENCIES webmock BUNDLED WITH - 1.13.0 + 1.15.2 diff --git a/README.md b/README.md index 52049a1..1e70d3e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Goldfinger, a Webfinger client for Ruby +Goldfinger, a WebFinger client for Ruby ======================================= [![Gem Version](http://img.shields.io/gem/v/goldfinger.svg)][gem] @@ -9,7 +9,10 @@ Goldfinger, a Webfinger client for Ruby [travis]: https://travis-ci.org/tootsuite/goldfinger [gemnasium]: https://gemnasium.com/tootsuite/goldfinger -A Webfinger client for Ruby. Supports `application/xrd+xml` and `application/jrd+json` responses. Raises `Goldfinger::NotFoundError` on failure to fetch the Webfinger or XRD data, or `Goldfinger::SSLError` if something is wrong with the HTTPS connection it uses. +A WebFinger client for Ruby. Supports `application/xrd+xml` and `application/jrd+json` responses. Raises `Goldfinger::NotFoundError` on failure to fetch the Webfinger or XRD data, can also raise `HTTP:Error` or `OpenSSL::SSL::SSLError` if something is wrong with the HTTPS connection it uses. + +- **Does not** fall back to HTTP if HTTPS is not available +- **Does** check host-meta XRD, but *only* if the standard WebFinger path yielded no result ## Installation @@ -30,4 +33,4 @@ A Webfinger client for Ruby. Supports `application/xrd+xml` and `application/jrd ## RFC support -The official Webfinger RFC is [7033](https://tools.ietf.org/html/rfc7033). +The official WebFinger RFC is [7033](https://tools.ietf.org/html/rfc7033). diff --git a/goldfinger.gemspec b/goldfinger.gemspec index 9248cc9..a990f19 100644 --- a/goldfinger.gemspec +++ b/goldfinger.gemspec @@ -1,12 +1,14 @@ +# frozen_string_literal: true + Gem::Specification.new do |s| s.name = 'goldfinger' - s.version = '1.2.1' + s.version = '2.0.0' s.platform = Gem::Platform::RUBY - s.required_ruby_version = '>= 2.0.0' + s.required_ruby_version = '>= 2.3.0' s.date = '2016-02-17' - s.summary = "A Webfinger utility for Ruby" - s.description = "A Webfinger utility for Ruby" - s.authors = ["Eugen Rochko"] + s.summary = 'A Webfinger utility for Ruby' + s.description = 'A Webfinger utility for Ruby' + s.authors = ['Eugen Rochko'] s.email = 'eugen@zeonfederated.com' s.files = `git ls-files lib LICENSE README.md`.split($RS) s.homepage = 'https://github.com/Gargron/goldfinger' @@ -14,7 +16,8 @@ Gem::Specification.new do |s| s.add_dependency('http', '~> 2.2') s.add_dependency('addressable', '~> 2.5') - s.add_dependency('nokogiri', '~> 1.7') + s.add_dependency('nokogiri', '~> 1.8') + s.add_dependency('oj', '~> 3.0') - s.add_development_dependency('bundler', '~> 1.3') + s.add_development_dependency('bundler', '~> 1.15') end diff --git a/lib/goldfinger.rb b/lib/goldfinger.rb index a811942..70b7c4d 100644 --- a/lib/goldfinger.rb +++ b/lib/goldfinger.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'goldfinger/request' require 'goldfinger/link' require 'goldfinger/result' @@ -11,9 +13,6 @@ module Goldfinger class NotFoundError < Error end - class SSLError < Error - end - # Returns result for the Webfinger query # # @raise [Goldfinger::NotFoundError] Error raised when the Webfinger resource could not be retrieved diff --git a/lib/goldfinger/client.rb b/lib/goldfinger/client.rb index 3774ac7..5c693a6 100644 --- a/lib/goldfinger/client.rb +++ b/lib/goldfinger/client.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'addressable' require 'nokogiri' @@ -10,24 +12,11 @@ module Goldfinger end def finger - ssl = true + response = perform_get(standard_url) - begin - response = perform_get(standard_url(ssl)) + return finger_from_template if response.code != 200 - return finger_from_template if response.code != 200 - - Goldfinger::Result.new(response) - rescue HTTP::Error - raise Goldfinger::NotFoundError unless ssl - - ssl = false - retry - end - rescue HTTP::Error - raise Goldfinger::NotFoundError - rescue OpenSSL::SSL::SSLError - raise Goldfinger::SSLError + Goldfinger::Result.new(response) rescue Addressable::URI::InvalidURIError raise Goldfinger::NotFoundError, 'Invalid URI' end @@ -35,16 +24,7 @@ module Goldfinger 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 + template = perform_get(url) raise Goldfinger::NotFoundError, 'No host-meta on the server' if template.code != 200 @@ -55,12 +35,12 @@ module Goldfinger Goldfinger::Result.new(response) end - def url(ssl = true) - "http#{'s' if ssl}://#{domain}/.well-known/host-meta" + def url + "https://#{domain}/.well-known/host-meta" end - def standard_url(ssl = true) - "http#{'s' if ssl}://#{domain}/.well-known/webfinger?resource=#{@uri}" + def standard_url + "https://#{domain}/.well-known/webfinger?resource=#{@uri}" end def url_from_template(template) diff --git a/lib/goldfinger/link.rb b/lib/goldfinger/link.rb index b3766c5..9d81cf5 100644 --- a/lib/goldfinger/link.rb +++ b/lib/goldfinger/link.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Goldfinger # @!attribute [r] href # @return [String] The href the link points to diff --git a/lib/goldfinger/request.rb b/lib/goldfinger/request.rb index a5fca1c..b98802b 100644 --- a/lib/goldfinger/request.rb +++ b/lib/goldfinger/request.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'http' require 'addressable' diff --git a/lib/goldfinger/result.rb b/lib/goldfinger/result.rb index 949240c..6eec64d 100644 --- a/lib/goldfinger/result.rb +++ b/lib/goldfinger/result.rb @@ -1,13 +1,23 @@ +# frozen_string_literal: true + +require 'oj' + module Goldfinger + # @!attribute [r] subject + # @return [String] URI that identifies the entity that the JRD describes. + # @!attribute [r] aliases + # @return [Array] Zero or more URI strings that identify the same entity as the "subject" URI. class Result MIME_TYPES = [ 'application/jrd+json', 'application/json', 'application/xrd+xml', 'application/xml', - 'text/xml' + 'text/xml', ].freeze + attr_reader :subject, :aliases + def initialize(response) @mime_type = response.mime_type @body = response.body @@ -19,20 +29,6 @@ module Goldfinger parse end - # The value of the "subject" member is a URI that identifies the entity - # that the JRD describes. - # @return [String] - def subject - @subject - end - - # The "aliases" array is an array of zero or more URI strings that - # identify the same entity as the "subject" URI. - # @return [Array] - def aliases - @aliases - end - # The "properties" object comprises zero or more name/value pairs whose # names are URIs (referred to as "property identifiers") and whose # values are strings or nil. @@ -78,7 +74,7 @@ module Goldfinger end def parse_json - json = JSON.parse(@body) + json = Oj.load(@body, mode: :null) @subject = json['subject'] @aliases = json['aliases'] || [] @@ -94,7 +90,7 @@ module Goldfinger xml = Nokogiri::XML(@body) @subject = xml.at_xpath('//xmlns:Subject').content - @aliases = xml.xpath('//xmlns:Alias').map { |a| a.content } + @aliases = xml.xpath('//xmlns:Alias').map(&:content) properties = xml.xpath('/xmlns:XRD/xmlns:Property') properties.each { |prop| @properties[prop.attribute('type').value] = prop.attribute('nil') ? nil : prop.content } diff --git a/lib/goldfinger/utils.rb b/lib/goldfinger/utils.rb index 5e60b25..f8325d2 100644 --- a/lib/goldfinger/utils.rb +++ b/lib/goldfinger/utils.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Goldfinger module Utils def perform_get(path, options = {}) diff --git a/spec/goldfinger/client_spec.rb b/spec/goldfinger/client_spec.rb index 3d332c2..95a079f 100644 --- a/spec/goldfinger/client_spec.rb +++ b/spec/goldfinger/client_spec.rb @@ -27,14 +27,8 @@ describe Goldfinger::Client do subject { Goldfinger::Client.new('acct:gargron@quitter.no') } - 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 + it 'raises an error' do + expect { subject.finger }.to raise_error HTTP::Error end end end @@ -51,7 +45,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(HTTP::Error) end end end