indieweb-endpoints 1.0.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0f792d375c1f3a3bd75d775b83bafba558576b43fdcd55a4f2f6609631776d1
4
- data.tar.gz: 285dd5905c4305c91a922575d97f579b03b29cb20e6037051ab7e2c420d5d9f8
3
+ metadata.gz: f89e56b8a2f2bac61305a9d0012bdd54f4f2623b539ea19f58e0d81b6af1a966
4
+ data.tar.gz: 3f0e860760e5bed119e2be2cbc40dc235a179b53a880f9a2f0a4efada8e6b739
5
5
  SHA512:
6
- metadata.gz: ff2be853683341b8da8c3aa35db8dc423e1d0a046fe892230e8704a4e86d6a9b0d8cdae5f355df758937ea4159de1eb992d0b3cbba46083356013f66660e47be
7
- data.tar.gz: 0033ebce96813205b2c70ef9f57348e3fb6b07374e55eb519c1937680c1337d36dd4bb58ca9d200f34bc7c9e5cccd866b242f8f596a09fb515ed088c4843b4d8
6
+ metadata.gz: 47f6d68cb1894fee56ee0f23d3caf90c5bd143980a52085dff2a35b37467c0e6a222e2eea926b6cb904437f4b196f75bf5051cf5a47e09bfb262da4b2bc04fdb
7
+ data.tar.gz: '0891cbfb3831d7a2b85e9b7b3068c3679a1e9a86938e4237e1ab3f10c6760b6a5f8ff0c92456bb52314802a4c42551c936973e8956fa85a39cdc8543ef7e0420'
data/.reek.yml CHANGED
@@ -1,11 +1,6 @@
1
1
  detectors:
2
2
  IrresponsibleModule:
3
3
  enabled: false
4
- UtilityFunction:
5
- exclude:
6
- - FixtureHelpers#read_fixture
7
- - IndieWeb::Endpoints::Services::ResponseBodyParserService#parse
8
- - IndieWeb::Endpoints::Services::ResponseHeadersParserService#parse
9
4
 
10
5
  exclude_paths:
11
6
  - vendor/
@@ -2,17 +2,16 @@ require:
2
2
  - rubocop-performance
3
3
  - rubocop-rspec
4
4
 
5
- Layout/AlignHash:
6
- EnforcedHashRocketStyle: table
5
+ AllCops:
6
+ NewCops: enable
7
+
8
+ Layout/LineLength:
9
+ Enabled: false
7
10
 
8
11
  Metrics/BlockLength:
9
12
  Exclude:
10
- - indieweb-endpoints.gemspec
11
13
  - spec/**/*.rb
12
14
 
13
- Metrics/LineLength:
14
- Enabled: false
15
-
16
15
  Naming/RescuedExceptionsVariableName:
17
16
  PreferredName: exception
18
17
 
@@ -1 +1 @@
1
- 2.4.7
1
+ 2.5.8
data/.simplecov CHANGED
@@ -2,9 +2,11 @@ require 'simplecov-console'
2
2
 
3
3
  formatters = [SimpleCov::Formatter::HTMLFormatter]
4
4
 
5
+ # rubocop:disable Style/IfUnlessModifier
5
6
  if RSpec.configuration.files_to_run.length > 1
6
7
  formatters << SimpleCov::Formatter::Console
7
8
  end
9
+ # rubocop:enable Style/IfUnlessModifier
8
10
 
9
11
  SimpleCov.start do
10
12
  formatter SimpleCov::Formatter::MultiFormatter.new(formatters)
@@ -1,13 +1,10 @@
1
+ dist: bionic
1
2
  language: ruby
2
3
  rvm:
3
- - 2.4
4
4
  - 2.5
5
5
  - 2.6
6
- cache:
7
- - bundler
8
- before_install:
9
- - gem update --system
10
- - gem install bundler
6
+ - 2.7
7
+ cache: bundler
11
8
  before_script:
12
9
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
13
10
  - chmod +x ./cc-test-reporter
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.0.0 / 2020-11-11
4
+
5
+ - Update absolutely and link-header-parser dependencies (064696e)
6
+
7
+ ## 4.0.0 / 2020-07-21
8
+
9
+ - **Breaking change:** Return a Hash of endpoints instead of an OpenStruct (15dc387)
10
+ - Update [link-header-parser](https://rubygems.org/gems/link-header-parser) dependency to v2.0.0 (2255e6b)
11
+ - **Breaking change:** Update development Ruby version to 2.5.8 and minimum Ruby version to 2.5 (dd5a142)
12
+ - Refactor response headers/body parsers into a single class (ee02da3)
13
+ - Refactor `IndieWeb::Endpoints::Client` and remove `HttpRequestService` (2732616)
14
+ - Add offending url to exception message (#5) (4bf7a54)
15
+
16
+ ## 3.0.0 / 2020-05-14
17
+
18
+ - Update Absolutely and LinkHeaderParser dependencies (9e0a64a)
19
+ - Move development dependencies to `Gemfile` (67067f3)
20
+ - Update development Ruby version to 2.4.10 (f5430f9)
21
+
22
+ ## 2.0.0 / 2020-01-25
23
+
24
+ - Downgrade HTTP gem version constraint to ~> 4.3 (cb63230)
25
+
26
+ ## 1.1.0 / 2020-01-20
27
+
28
+ - Expand supported Ruby versions to include 2.7 (ae63ed0)
29
+ - Update project Ruby version to 2.4.9 (e576ad6)
30
+
3
31
  ## 1.0.2 / 2019-08-31
4
32
 
5
33
  - Update WebMock and Addressable gems (298da63)
@@ -8,9 +8,9 @@ There are a couple ways you can help improve indieweb-endpoints-ruby:
8
8
 
9
9
  ## Getting Started
10
10
 
11
- indieweb-endpoints-ruby is developed using Ruby 2.4.7 and is additionally tested against Ruby 2.5 and 2.6 using [Travis CI](https://travis-ci.com/indieweb/indieweb-endpoints-ruby).
11
+ indieweb-endpoints-ruby is developed using Ruby 2.5.8 and is additionally tested against Ruby 2.6 and 2.7 using [Travis CI](https://travis-ci.com/indieweb/indieweb-endpoints-ruby).
12
12
 
13
- Before making changes to indieweb-endpoints-ruby, you'll want to install Ruby 2.4.7. It's recommended that you use a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm). Once you've installed Ruby 2.4.7 using your method of choice, install the project's gems by running:
13
+ Before making changes to indieweb-endpoints-ruby, you'll want to install Ruby 2.5.8. It's recommended that you use a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm). Once you've installed Ruby 2.5.8 using your method of choice, install the project's gems by running:
14
14
 
15
15
  ```sh
16
16
  bundle install
data/Gemfile CHANGED
@@ -2,3 +2,14 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in indieweb-endpoints.gemspec
4
4
  gemspec
5
+
6
+ gem 'pry-byebug', '~> 3.9'
7
+ gem 'rake', '~> 13.0'
8
+ gem 'reek', '~> 6.0'
9
+ gem 'rspec', '~> 3.10'
10
+ gem 'rubocop', '~> 1.2'
11
+ gem 'rubocop-performance', '~> 1.8'
12
+ gem 'rubocop-rspec', '~> 2.0'
13
+ gem 'simplecov', '~> 0.19.1'
14
+ gem 'simplecov-console', '~> 0.8.0'
15
+ gem 'webmock', '~> 3.9'
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![Gem](https://img.shields.io/gem/v/indieweb-endpoints.svg?style=for-the-badge)](https://rubygems.org/gems/indieweb-endpoints)
6
6
  [![Downloads](https://img.shields.io/gem/dt/indieweb-endpoints.svg?style=for-the-badge)](https://rubygems.org/gems/indieweb-endpoints)
7
- [![Build](https://img.shields.io/travis/com/indieweb/indieweb-endpoints-ruby/master.svg?style=for-the-badge)](https://travis-ci.com/indieweb/indieweb-endpoints-ruby)
7
+ [![Build](https://img.shields.io/travis/com/indieweb/indieweb-endpoints-ruby/main.svg?style=for-the-badge)](https://travis-ci.com/indieweb/indieweb-endpoints-ruby)
8
8
  [![Maintainability](https://img.shields.io/codeclimate/maintainability/indieweb/indieweb-endpoints-ruby.svg?style=for-the-badge)](https://codeclimate.com/github/indieweb/indieweb-endpoints-ruby)
9
9
  [![Coverage](https://img.shields.io/codeclimate/c/indieweb/indieweb-endpoints-ruby.svg?style=for-the-badge)](https://codeclimate.com/github/indieweb/indieweb-endpoints-ruby/code)
10
10
 
@@ -12,13 +12,13 @@
12
12
 
13
13
  - Compliant with [Section 4.1](https://www.w3.org/TR/indieauth/#discovery-by-clients) and [Section 4.2.2](https://www.w3.org/TR/indieauth/#redirect-url) of [the W3C's IndieAuth Working Group Note](https://www.w3.org/TR/indieauth/), [Section 5.3](https://www.w3.org/TR/micropub/#endpoint-discovery) of [the W3C's Micropub Recommendation](https://www.w3.org/TR/micropub/), and [Section 3.1.2](https://www.w3.org/TR/webmention/#sender-discovers-receiver-webmention-endpoint) of [the W3C's Webmention Recommendation](https://www.w3.org/TR/webmention/).
14
14
  - Passes all Endpoint Discovery tests on [webmention.rocks](https://webmention.rocks).
15
- - Supports Ruby 2.4 and newer.
15
+ - Supports Ruby 2.5 and newer.
16
16
 
17
17
  ## Getting Started
18
18
 
19
- Before installing and using indieweb-endpoints-ruby, you'll want to have [Ruby](https://www.ruby-lang.org) 2.4 (or newer) installed. It's recommended that you use a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm).
19
+ Before installing and using indieweb-endpoints-ruby, you'll want to have [Ruby](https://www.ruby-lang.org) 2.5 (or newer) installed. It's recommended that you use a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm).
20
20
 
21
- indieweb-endpoints-ruby is developed using Ruby 2.4.7 and is additionally tested against Ruby 2.5 and 2.6 using [Travis CI](https://travis-ci.com/indieweb/indieweb-endpoints-ruby).
21
+ indieweb-endpoints-ruby is developed using Ruby 2.5.8 and is additionally tested against Ruby 2.6 and 2.7 using [Travis CI](https://travis-ci.com/indieweb/indieweb-endpoints-ruby).
22
22
 
23
23
  ## Installation
24
24
 
@@ -45,25 +45,11 @@ With indieweb-endpoints-ruby added to your project's `Gemfile` and installed, yo
45
45
  ```ruby
46
46
  require 'indieweb/endpoints'
47
47
 
48
- endpoints = IndieWeb::Endpoints.get('https://aaronparecki.com')
49
-
50
- puts endpoints # => #<OpenStruct authorization_endpoint="https://aaronparecki.com/auth", micropub="https://aaronparecki.com/micropub", microsub="https://aperture.p3k.io/microsub/1", redirect_uri=nil, token_endpoint="https://aaronparecki.com/auth/token", webmention="https://webmention.io/aaronpk/webmention">
51
- ```
52
-
53
- This example will search `https://aaronparecki.com` for valid IndieAuth, Micropub, and Webmention endpoints. In this case, the program returns an `OpenStruct` with the following attributes (represented below as a `Hash`):
54
-
55
- ```ruby
56
- {
57
- authorization_endpoint: 'https://aaronparecki.com/auth',
58
- micropub: 'https://aaronparecki.com/micropub',
59
- microsub: 'https://aperture.p3k.io/microsub/1',
60
- redirect_uri: nil,
61
- token_endpoint: 'https://aaronparecki.com/auth/token',
62
- webmention: 'https://webmention.io/aaronpk/webmention'
63
- }
48
+ IndieWeb::Endpoints.get('https://aaronparecki.com')
49
+ #=> { authorization_endpoint: "https://aaronparecki.com/auth", micropub: "https://aaronparecki.com/micropub", microsub: "https://aperture.p3k.io/microsub/1", redirect_uri: nil, token_endpoint: "https://aaronparecki.com/auth/token", webmention: "https://webmention.io/aaronpk/webmention" }
64
50
  ```
65
51
 
66
- Each attribute will return either a `String` representing a URL or `nil`. The `redirect_uri` attribute will return either an `Array` or `nil` since a given URL may register multiple callback URLs.
52
+ This example will search `https://aaronparecki.com` for valid IndieAuth, Micropub, and Webmention endpoints and return a `Hash` of results. Each key in the returned `Hash` will have a value of either a `String` representing a URL or `nil`. The `redirect_uri` key's value will be either an `Array` or `nil` since a given URL may register multiple callback URLs.
67
53
 
68
54
  ### Advanced Usage
69
55
 
@@ -73,17 +59,13 @@ Should the need arise, you may work with the `IndieWeb::Endpoints::Client` class
73
59
  require 'indieweb/endpoints'
74
60
 
75
61
  client = IndieWeb::Endpoints::Client.new('https://aaronparecki.com')
62
+ #=> #<IndieWeb::Endpoints::Client url: "https://aaronparecki.com">
76
63
 
77
- puts client.response # => #<HTTP::Response/1.1 200 OK {…}>
78
-
79
- endpoints = client.endpoints
64
+ client.response
65
+ #=> #<HTTP::Response/1.1 200 OK {…}>
80
66
 
81
- puts endpoints.authorization_endpoint # => 'https://aaronparecki.com/auth'
82
- puts endpoints.micropub # => 'https://aaronparecki.com/micropub'
83
- puts endpoints.microsub # => 'https://aperture.p3k.io/microsub/1'
84
- puts endpoints.redirect_uri # => nil
85
- puts endpoints.token_endpoint # => 'https://aaronparecki.com/auth/token'
86
- puts endpoints.webmention # => 'https://webmention.io/aaronpk/webmention'
67
+ client.endpoints
68
+ #=> { authorization_endpoint: "https://aaronparecki.com/auth", micropub: "https://aaronparecki.com/micropub", microsub: "https://aperture.p3k.io/microsub/1", redirect_uri: nil, token_endpoint: "https://aaronparecki.com/auth/token", webmention: "https://webmention.io/aaronpk/webmention" }
87
69
  ```
88
70
 
89
71
  ### Exception Handling
@@ -102,7 +84,7 @@ From [httprb/http](https://github.com/httprb/http):
102
84
 
103
85
  ## Contributing
104
86
 
105
- Interested in helping improve indieweb-endpoints-ruby? Awesome! Your help is greatly appreciated. See [CONTRIBUTING.md](https://github.com/indieweb/indieweb-endpoints-ruby/blob/master/CONTRIBUTING.md) for details.
87
+ Interested in helping improve indieweb-endpoints-ruby? Awesome! Your help is greatly appreciated. See [CONTRIBUTING.md](https://github.com/indieweb/indieweb-endpoints-ruby/blob/main/CONTRIBUTING.md) for details.
106
88
 
107
89
  By contributing to and participating in the development of indieweb-endpoints-ruby, you acknowledge that you have read and agree to the [IndieWeb Code of Conduct](https://indieweb.org/code-of-conduct).
108
90
 
@@ -1,10 +1,7 @@
1
- lib = File.expand_path('lib', __dir__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
-
4
- require 'indieweb/endpoints/version'
1
+ require_relative 'lib/indieweb/endpoints/version'
5
2
 
6
3
  Gem::Specification.new do |spec|
7
- spec.required_ruby_version = ['>= 2.4', '< 2.7']
4
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5', '< 2.8')
8
5
 
9
6
  spec.name = 'indieweb-endpoints'
10
7
  spec.version = IndieWeb::Endpoints::VERSION
@@ -16,28 +13,18 @@ Gem::Specification.new do |spec|
16
13
  spec.homepage = 'https://github.com/indieweb/indieweb-endpoints-ruby'
17
14
  spec.license = 'MIT'
18
15
 
19
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(bin|spec)/}) }
16
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(bin|spec)/}) }
18
+ end
20
19
 
21
20
  spec.require_paths = ['lib']
22
21
 
23
- spec.metadata = {
24
- 'bug_tracker_uri' => "#{spec.homepage}/issues",
25
- 'changelog_uri' => "#{spec.homepage}/blob/v#{spec.version}/CHANGELOG.md"
26
- }
27
-
28
- spec.add_development_dependency 'rake', '~> 12.3'
29
- spec.add_development_dependency 'reek', '~> 5.4'
30
- spec.add_development_dependency 'rspec', '~> 3.8'
31
- spec.add_development_dependency 'rubocop', '~> 0.74.0'
32
- spec.add_development_dependency 'rubocop-performance', '~> 1.4'
33
- spec.add_development_dependency 'rubocop-rspec', '~> 1.35'
34
- spec.add_development_dependency 'simplecov', '~> 0.17.0'
35
- spec.add_development_dependency 'simplecov-console', '~> 0.5.0'
36
- spec.add_development_dependency 'webmock', '~> 3.7'
22
+ spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
23
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/v#{spec.version}/CHANGELOG.md"
37
24
 
38
- spec.add_runtime_dependency 'absolutely', '~> 3.0'
25
+ spec.add_runtime_dependency 'absolutely', '~> 5.0'
39
26
  spec.add_runtime_dependency 'addressable', '~> 2.7'
40
- spec.add_runtime_dependency 'http', '~> 5.0.0.pre'
41
- spec.add_runtime_dependency 'link-header-parser', '~> 0.2.0'
27
+ spec.add_runtime_dependency 'http', '~> 4.4'
28
+ spec.add_runtime_dependency 'link-header-parser', '~> 2.1'
42
29
  spec.add_runtime_dependency 'nokogiri', '~> 1.10'
43
30
  end
@@ -1,5 +1,3 @@
1
- require 'ostruct'
2
-
3
1
  require 'absolutely'
4
2
  require 'addressable/uri'
5
3
  require 'http'
@@ -9,15 +7,12 @@ require 'nokogiri'
9
7
  require 'indieweb/endpoints/version'
10
8
  require 'indieweb/endpoints/exceptions'
11
9
 
12
- require 'indieweb/endpoints/concerns/registerable'
13
-
14
- require 'indieweb/endpoints/services/http_request_service'
15
- require 'indieweb/endpoints/services/response_body_parser_service'
16
- require 'indieweb/endpoints/services/response_headers_parser_service'
10
+ require 'indieweb/endpoints/services/response_parser_service'
17
11
 
18
12
  require 'indieweb/endpoints/client'
19
13
  require 'indieweb/endpoints/parsers'
20
14
 
15
+ require 'indieweb/endpoints/parsers/base_parser'
21
16
  require 'indieweb/endpoints/parsers/authorization_endpoint_parser'
22
17
  require 'indieweb/endpoints/parsers/micropub_parser'
23
18
  require 'indieweb/endpoints/parsers/microsub_parser'
@@ -27,6 +22,12 @@ require 'indieweb/endpoints/parsers/webmention_parser'
27
22
 
28
23
  module IndieWeb
29
24
  module Endpoints
25
+ # Discover a URL's IndieAuth, Micropub, Microsub, and Webmention endpoints
26
+ #
27
+ # IndieWeb::Endpoints.get('https://aaronparecki.com')
28
+ #
29
+ # @param url [String] an absolute URL
30
+ # @return [Hash{Symbol => String, Array, nil}]
30
31
  def self.get(url)
31
32
  Client.new(url).endpoints
32
33
  end
@@ -1,27 +1,54 @@
1
1
  module IndieWeb
2
2
  module Endpoints
3
3
  class Client
4
+ HTTP_HEADERS_OPTS = {
5
+ accept: '*/*',
6
+ user_agent: 'IndieWeb Endpoint Discovery (https://rubygems.org/gems/indieweb-endpoints)'
7
+ }.freeze
8
+
9
+ # Create a new client with a URL to parse for IndieWeb endpoints
10
+ #
11
+ # client = IndieWeb::Endpoints::Client.new('https://aaronparecki.com')
12
+ #
13
+ # @param url [String] an absolute URL
4
14
  def initialize(url)
5
- @uri = Addressable::URI.parse(url)
15
+ raise ArgumentError, "url must be a String (given #{url.class})" unless url.is_a?(String)
6
16
 
7
- raise ArgumentError, 'url must be an absolute URL (e.g. https://example.com)' unless @uri.absolute? && @uri.scheme.match?(/^https?$/)
8
- rescue Addressable::URI::InvalidURIError => exception
9
- raise InvalidURIError, exception
10
- rescue NoMethodError, TypeError
11
- raise ArgumentError, "url must be a String (given #{url.class})"
17
+ @url = url
18
+
19
+ raise ArgumentError, "url (#{url}) must be an absolute URL (e.g. https://example.com)" unless uri.absolute? && uri.scheme.match?(/^https?$/)
20
+ end
21
+
22
+ # @return [String]
23
+ def inspect
24
+ format(%(#<#{self.class.name}:%#0x url: #{url.inspect}>), object_id)
12
25
  end
13
26
 
27
+ # @return [Hash{Symbol => String, Array, nil}]
14
28
  def endpoints
15
- @endpoints ||= OpenStruct.new(Parsers.registered.transform_values { |parser| parser.new(response).results })
29
+ @endpoints ||= Parsers.registered.transform_values { |parser| parser.new(response).results }
16
30
  end
17
31
 
32
+ # @see https://www.w3.org/TR/webmention/#limits-on-get-requests
33
+ #
34
+ # @return [HTTP::Response]
18
35
  def response
19
- @response ||= Services::HttpRequestService.new.get(uri)
36
+ @response ||= HTTP.follow(max_hops: 20).headers(HTTP_HEADERS_OPTS).timeout(connect: 5, read: 5).get(uri)
37
+ rescue HTTP::ConnectionError,
38
+ HTTP::TimeoutError,
39
+ HTTP::Redirector::TooManyRedirectsError => exception
40
+ raise IndieWeb::Endpoints.const_get(exception.class.name.split('::').last), exception
20
41
  end
21
42
 
22
43
  private
23
44
 
24
- attr_accessor :uri
45
+ attr_accessor :url
46
+
47
+ def uri
48
+ @uri ||= Addressable::URI.parse(url)
49
+ rescue Addressable::URI::InvalidURIError => exception
50
+ raise InvalidURIError, exception
51
+ end
25
52
  end
26
53
  end
27
54
  end
@@ -1,40 +1,12 @@
1
1
  module IndieWeb
2
2
  module Endpoints
3
3
  module Parsers
4
- extend Concerns::Registerable
5
-
6
- class BaseParser
7
- def initialize(response)
8
- raise ArgumentError, "response must be an HTTP::Response (given #{response.class.name})" unless response.is_a?(HTTP::Response)
9
-
10
- @response = response
11
- end
12
-
13
- def results
14
- mapped_results.shift
15
- end
16
-
17
- private
18
-
19
- attr_reader :response
20
-
21
- def mapped_results
22
- @mapped_results ||= results_from_http_request.map { |endpoint| Absolutely.to_abs(base: response.uri.to_s, relative: endpoint) }.uniq.sort
23
- rescue Absolutely::InvalidURIError => exception
24
- raise InvalidURIError, exception
25
- end
26
-
27
- def results_from_body
28
- @results_from_body ||= Services::ResponseBodyParserService.new.parse(response, self.class.identifier)
29
- end
30
-
31
- def results_from_headers
32
- @results_from_headers ||= Services::ResponseHeadersParserService.new.parse(response, self.class.identifier)
33
- end
4
+ def self.register(klass)
5
+ registered[klass.identifier] = klass
6
+ end
34
7
 
35
- def results_from_http_request
36
- @results_from_http_request ||= [results_from_headers, results_from_body].flatten.compact
37
- end
8
+ def self.registered
9
+ @registered ||= {}
38
10
  end
39
11
  end
40
12
  end
@@ -2,9 +2,7 @@ module IndieWeb
2
2
  module Endpoints
3
3
  module Parsers
4
4
  class AuthorizationEndpointParser < BaseParser
5
- def self.identifier
6
- :authorization_endpoint
7
- end
5
+ @identifier = :authorization_endpoint
8
6
 
9
7
  Parsers.register(self)
10
8
  end
@@ -0,0 +1,45 @@
1
+ module IndieWeb
2
+ module Endpoints
3
+ module Parsers
4
+ class BaseParser
5
+ class << self
6
+ attr_reader :identifier
7
+ end
8
+
9
+ # @param response [HTTP::Response]
10
+ def initialize(response)
11
+ raise ArgumentError, "response must be an HTTP::Response (given #{response.class.name})" unless response.is_a?(HTTP::Response)
12
+
13
+ @response = response
14
+ end
15
+
16
+ # @return [String]
17
+ def results
18
+ mapped_results.shift
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :response
24
+
25
+ def mapped_results
26
+ @mapped_results ||= results_from_http_request.map { |endpoint| Absolutely.to_abs(base: response.uri.to_s, relative: endpoint) }.uniq.sort
27
+ rescue Absolutely::InvalidURIError => exception
28
+ raise InvalidURIError, exception
29
+ end
30
+
31
+ def results_from_body
32
+ @results_from_body ||= Services::ResponseParserService.parse_body(response, self.class.identifier)
33
+ end
34
+
35
+ def results_from_headers
36
+ @results_from_headers ||= Services::ResponseParserService.parse_headers(response, self.class.identifier)
37
+ end
38
+
39
+ def results_from_http_request
40
+ @results_from_http_request ||= [results_from_headers, results_from_body].flatten.compact
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -2,9 +2,7 @@ module IndieWeb
2
2
  module Endpoints
3
3
  module Parsers
4
4
  class MicropubParser < BaseParser
5
- def self.identifier
6
- :micropub
7
- end
5
+ @identifier = :micropub
8
6
 
9
7
  Parsers.register(self)
10
8
  end
@@ -2,9 +2,7 @@ module IndieWeb
2
2
  module Endpoints
3
3
  module Parsers
4
4
  class MicrosubParser < BaseParser
5
- def self.identifier
6
- :microsub
7
- end
5
+ @identifier = :microsub
8
6
 
9
7
  Parsers.register(self)
10
8
  end
@@ -2,12 +2,11 @@ module IndieWeb
2
2
  module Endpoints
3
3
  module Parsers
4
4
  class RedirectUriParser < BaseParser
5
- def self.identifier
6
- :redirect_uri
7
- end
5
+ @identifier = :redirect_uri
8
6
 
9
7
  Parsers.register(self)
10
8
 
9
+ # @return [Array<String>, nil]
11
10
  def results
12
11
  return unless mapped_results.any?
13
12
 
@@ -2,9 +2,7 @@ module IndieWeb
2
2
  module Endpoints
3
3
  module Parsers
4
4
  class TokenEndpointParser < BaseParser
5
- def self.identifier
6
- :token_endpoint
7
- end
5
+ @identifier = :token_endpoint
8
6
 
9
7
  Parsers.register(self)
10
8
  end
@@ -2,16 +2,14 @@ module IndieWeb
2
2
  module Endpoints
3
3
  module Parsers
4
4
  class WebmentionParser < BaseParser
5
- def self.identifier
6
- :webmention
7
- end
5
+ @identifier = :webmention
8
6
 
9
7
  Parsers.register(self)
10
8
 
11
9
  private
12
10
 
13
11
  def results_for_node(node)
14
- Services::ResponseBodyParserService.new.parse(response, self.class.identifier, node)
12
+ Services::ResponseParserService.parse_body(response, self.class.identifier, node)
15
13
  end
16
14
 
17
15
  # https://www.w3.org/TR/webmention/#sender-discovers-receiver-webmention-endpoint
@@ -0,0 +1,29 @@
1
+ module IndieWeb
2
+ module Endpoints
3
+ module Services
4
+ class ResponseParserService
5
+ # @param response [HTTP::Response]
6
+ # @param identifier [Symbol]
7
+ # @return [Array<String>]
8
+ def self.parse_body(response, identifier, node = 'link')
9
+ return unless response.mime_type == 'text/html'
10
+
11
+ # Reject endpoints that contain a fragment identifier
12
+ Nokogiri::HTML(response.body.to_s).css(%(#{node}[rel~="#{identifier}"][href]:not([href*="#"]))).map { |element| element['href'] }
13
+ end
14
+
15
+ # @param response [HTTP::Response]
16
+ # @param identifier [Symbol]
17
+ # @return [Array<String>, nil]
18
+ def self.parse_headers(response, identifier)
19
+ headers = LinkHeaderParser.parse(response.headers.get('link'), base: response.uri.to_s).group_by_relation_type[identifier]
20
+
21
+ return unless headers
22
+
23
+ # Reject endpoints that contain a fragment identifier
24
+ headers.reject { |header| Addressable::URI.parse(header.target_uri).fragment }.map(&:target_uri)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  module IndieWeb
2
2
  module Endpoints
3
- VERSION = '1.0.2'.freeze
3
+ VERSION = '5.0.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,155 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: indieweb-endpoints
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Garber
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-31 00:00:00.000000000 Z
11
+ date: 2020-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rake
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '12.3'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '12.3'
27
- - !ruby/object:Gem::Dependency
28
- name: reek
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '5.4'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '5.4'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '3.8'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '3.8'
55
- - !ruby/object:Gem::Dependency
56
- name: rubocop
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 0.74.0
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 0.74.0
69
- - !ruby/object:Gem::Dependency
70
- name: rubocop-performance
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '1.4'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.4'
83
- - !ruby/object:Gem::Dependency
84
- name: rubocop-rspec
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '1.35'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '1.35'
97
- - !ruby/object:Gem::Dependency
98
- name: simplecov
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 0.17.0
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 0.17.0
111
- - !ruby/object:Gem::Dependency
112
- name: simplecov-console
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 0.5.0
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 0.5.0
125
- - !ruby/object:Gem::Dependency
126
- name: webmock
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '3.7'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '3.7'
139
13
  - !ruby/object:Gem::Dependency
140
14
  name: absolutely
141
15
  requirement: !ruby/object:Gem::Requirement
142
16
  requirements:
143
17
  - - "~>"
144
18
  - !ruby/object:Gem::Version
145
- version: '3.0'
19
+ version: '5.0'
146
20
  type: :runtime
147
21
  prerelease: false
148
22
  version_requirements: !ruby/object:Gem::Requirement
149
23
  requirements:
150
24
  - - "~>"
151
25
  - !ruby/object:Gem::Version
152
- version: '3.0'
26
+ version: '5.0'
153
27
  - !ruby/object:Gem::Dependency
154
28
  name: addressable
155
29
  requirement: !ruby/object:Gem::Requirement
@@ -170,28 +44,28 @@ dependencies:
170
44
  requirements:
171
45
  - - "~>"
172
46
  - !ruby/object:Gem::Version
173
- version: 5.0.0.pre
47
+ version: '4.4'
174
48
  type: :runtime
175
49
  prerelease: false
176
50
  version_requirements: !ruby/object:Gem::Requirement
177
51
  requirements:
178
52
  - - "~>"
179
53
  - !ruby/object:Gem::Version
180
- version: 5.0.0.pre
54
+ version: '4.4'
181
55
  - !ruby/object:Gem::Dependency
182
56
  name: link-header-parser
183
57
  requirement: !ruby/object:Gem::Requirement
184
58
  requirements:
185
59
  - - "~>"
186
60
  - !ruby/object:Gem::Version
187
- version: 0.2.0
61
+ version: '2.1'
188
62
  type: :runtime
189
63
  prerelease: false
190
64
  version_requirements: !ruby/object:Gem::Requirement
191
65
  requirements:
192
66
  - - "~>"
193
67
  - !ruby/object:Gem::Version
194
- version: 0.2.0
68
+ version: '2.1'
195
69
  - !ruby/object:Gem::Dependency
196
70
  name: nokogiri
197
71
  requirement: !ruby/object:Gem::Requirement
@@ -233,26 +107,24 @@ files:
233
107
  - indieweb-endpoints.gemspec
234
108
  - lib/indieweb/endpoints.rb
235
109
  - lib/indieweb/endpoints/client.rb
236
- - lib/indieweb/endpoints/concerns/registerable.rb
237
110
  - lib/indieweb/endpoints/exceptions.rb
238
111
  - lib/indieweb/endpoints/parsers.rb
239
112
  - lib/indieweb/endpoints/parsers/authorization_endpoint_parser.rb
113
+ - lib/indieweb/endpoints/parsers/base_parser.rb
240
114
  - lib/indieweb/endpoints/parsers/micropub_parser.rb
241
115
  - lib/indieweb/endpoints/parsers/microsub_parser.rb
242
116
  - lib/indieweb/endpoints/parsers/redirect_uri_parser.rb
243
117
  - lib/indieweb/endpoints/parsers/token_endpoint_parser.rb
244
118
  - lib/indieweb/endpoints/parsers/webmention_parser.rb
245
- - lib/indieweb/endpoints/services/http_request_service.rb
246
- - lib/indieweb/endpoints/services/response_body_parser_service.rb
247
- - lib/indieweb/endpoints/services/response_headers_parser_service.rb
119
+ - lib/indieweb/endpoints/services/response_parser_service.rb
248
120
  - lib/indieweb/endpoints/version.rb
249
121
  homepage: https://github.com/indieweb/indieweb-endpoints-ruby
250
122
  licenses:
251
123
  - MIT
252
124
  metadata:
253
125
  bug_tracker_uri: https://github.com/indieweb/indieweb-endpoints-ruby/issues
254
- changelog_uri: https://github.com/indieweb/indieweb-endpoints-ruby/blob/v1.0.2/CHANGELOG.md
255
- post_install_message:
126
+ changelog_uri: https://github.com/indieweb/indieweb-endpoints-ruby/blob/v5.0.0/CHANGELOG.md
127
+ post_install_message:
256
128
  rdoc_options: []
257
129
  require_paths:
258
130
  - lib
@@ -260,18 +132,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
260
132
  requirements:
261
133
  - - ">="
262
134
  - !ruby/object:Gem::Version
263
- version: '2.4'
135
+ version: '2.5'
264
136
  - - "<"
265
137
  - !ruby/object:Gem::Version
266
- version: '2.7'
138
+ version: '2.8'
267
139
  required_rubygems_version: !ruby/object:Gem::Requirement
268
140
  requirements:
269
141
  - - ">="
270
142
  - !ruby/object:Gem::Version
271
143
  version: '0'
272
144
  requirements: []
273
- rubygems_version: 3.0.6
274
- signing_key:
145
+ rubygems_version: 3.1.2
146
+ signing_key:
275
147
  specification_version: 4
276
148
  summary: Discover a URL’s IndieAuth, Micropub, Microsub, and Webmention endpoints.
277
149
  test_files: []
@@ -1,15 +0,0 @@
1
- module IndieWeb
2
- module Endpoints
3
- module Concerns
4
- module Registerable
5
- def register(klass)
6
- registered[klass.identifier] = klass
7
- end
8
-
9
- def registered
10
- @registered ||= {}
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,39 +0,0 @@
1
- module IndieWeb
2
- module Endpoints
3
- module Services
4
- class HttpRequestService
5
- # Defaults derived from Webmention specification examples
6
- # https://www.w3.org/TR/webmention/#limits-on-get-requests
7
- HTTP_CLIENT_OPTS = {
8
- follow: {
9
- max_hops: 20
10
- },
11
- headers: {
12
- accept: '*/*',
13
- user_agent: 'IndieWeb Endpoint Discovery (https://rubygems.org/gems/indieweb-endpoints)'
14
- },
15
- timeout_options: {
16
- connect_timeout: 5,
17
- read_timeout: 5
18
- }
19
- }.freeze
20
-
21
- def initialize
22
- @client = HTTP::Client.new(HTTP_CLIENT_OPTS)
23
- end
24
-
25
- def get(uri)
26
- client.request(:get, uri)
27
- rescue HTTP::ConnectionError,
28
- HTTP::TimeoutError,
29
- HTTP::Redirector::TooManyRedirectsError => exception
30
- raise IndieWeb::Endpoints.const_get(exception.class.name.split('::').last), exception
31
- end
32
-
33
- private
34
-
35
- attr_accessor :client
36
- end
37
- end
38
- end
39
- end
@@ -1,14 +0,0 @@
1
- module IndieWeb
2
- module Endpoints
3
- module Services
4
- class ResponseBodyParserService
5
- def parse(response, identifier, node = 'link')
6
- return unless response.mime_type == 'text/html'
7
-
8
- # Reject endpoints that contain a fragment identifier
9
- Nokogiri::HTML(response.body.to_s).css(%(#{node}[rel~="#{identifier}"][href]:not([href*="#"]))).map { |element| element['href'] }
10
- end
11
- end
12
- end
13
- end
14
- end
@@ -1,16 +0,0 @@
1
- module IndieWeb
2
- module Endpoints
3
- module Services
4
- class ResponseHeadersParserService
5
- def parse(response, identifier)
6
- headers = LinkHeaderParser.parse(response.headers.get('link'), base: response.uri.to_s).by_relation_type[identifier]
7
-
8
- return unless headers
9
-
10
- # Reject endpoints that contain a fragment identifier
11
- headers.reject { |header| Addressable::URI.parse(header.target_uri).fragment }.map(&:target_uri)
12
- end
13
- end
14
- end
15
- end
16
- end