bridgetown-webfinger 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3c1086d7e337e4a0654b54bac8d38521cbe18c7502cfd816d8c6f164a40553b4
4
+ data.tar.gz: b014d6ffbb34b2b839af88730993d376d2dd1a4ff0ad43e51110eb397e03c6e2
5
+ SHA512:
6
+ metadata.gz: 1dd3dbc3a4097dbeb8283cf3c92bc1a8d9eb9d88e3555a1f3a61a65a13f2a048f25e09d69c4e1c25def7d68748ac9c1f32a494a3ff314e812c463c27e9b3311a
7
+ data.tar.gz: e3452f05f6cedd25bf31e99752aedec2d30b4e747fe7f9e094995ad2909b7a89dccf38203b70b47288a1c07f802f69654b8f722ee95c7dd8f889283e1b6acc58
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0](https://github.com/michaelherold/bridgetown-webfinger/tree/v0.1.0) - 2023-02-25
9
+
10
+ ### Added
11
+
12
+ - Static file support for rendering a `.well-known/webfinger` file that always responds with the same information.
13
+ - Dynamic support via a Roda plugin for handling multiple authors and proper filtering for `rel` filters. This includes the ability to set `Access-Control-Allow-Origin` headers via the `allowed_hosts` option.
14
+ - Validation of all Webfinger properties and printed warnings for invalid values to help ensure you write interoperable Webfinger properties.
15
+ - An automation to quickly bootstrap your site's Webfinger capabilities.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,55 @@
1
+ # Contributing
2
+
3
+ In the spirit of [free software](http://www.fsf.org/licensing/essays/free-sw.html), we encourage **everyone** to help improve this project. Here are some ways _you_ can contribute:
4
+
5
+ * Use alpha, beta, and pre-release versions.
6
+ * Report bugs.
7
+ * Suggest new features.
8
+ * Write or edit documentation.
9
+ * Write specifications.
10
+ * Write code (**no patch is too small**: fix typos, add comments, clean up inconsistent whitespace).
11
+ * Refactor code.
12
+ * Fix [issues].
13
+ * Review patches.
14
+
15
+ [issues]: https://github.com/michaelherold/bridgetown-webfinger/issues
16
+
17
+ ## Submitting an Issue
18
+
19
+ We use the [GitHub issue tracker][issues] to track bugs and features. Before submitting a bug report or feature request, check to make sure no one has already submitted it.
20
+
21
+ When submitting a bug report, please include a `<details>` block that includes a stack trace and any details that may be necessary to reproduce the bug, including your gem version, Ruby version, and operating system. This looks like the following:
22
+
23
+ ```markdown
24
+ <details>
25
+ <summary>A description of the details block</summary>
26
+
27
+ All of the content that you want in here, perhaps with code fences. Note that
28
+ if you only have a code fence in here, you _must_ separate it from the <summary>
29
+ tag and the closing </details> or it won't render correctly.
30
+
31
+ Notice the empty line here ↓
32
+
33
+ </details>
34
+ ```
35
+
36
+ Ideally, a bug report should include a pull request with failing specs.
37
+
38
+ ## Submitting a Pull Request
39
+
40
+ 1. Fork the repository.
41
+ 2. Create a topic branch.
42
+ 3. Add specs for your unimplemented feature or bug fix.
43
+ 4. Run `bundle exec rake test`. If your specs pass, return to step 3.
44
+ 5. Implement your feature or bug fix.
45
+ 6. Run `bundle exec rake`. If your specs or any of the linters fail, return to step 5.
46
+ 7. Open `coverage/index.html`. If your changes are not fully covered by your tests, return to step 3.
47
+ 8. Add documentation for your feature or bug fix.
48
+ 9. Commit and push your changes.
49
+ 10. Submit a pull request.
50
+
51
+ ## Tools to Help You Succeed
52
+
53
+ After checking out the repository, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
54
+
55
+ Before committing code, run `bundle exec rake` to check that the code conforms to the style guidelines of the project, that all of the tests are green (if you're writing a feature; if you're only submitting a failing test, then it does not have to pass!), and that you sufficiently documented the changes.
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ # The MIT License (MIT)
2
+
3
+ Copyright © 2023-present
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # Bridgetown Webfinger plugin
2
+
3
+ A [Bridgetown][1] plugin for handling [Webfinger][2] requests for the Fediverse and [IndieWeb][3].
4
+
5
+ Whether you run a single-author, statically rendered site or a multi-author site with a dynamic backend, this is your one-stop shop for Webfinger support.
6
+
7
+ This plugin allows for hosting Webfinger lookups on your website for [`acct:` URIs][4]. This is the first step to giving your site the ability to post to Fediverse apps like [Mastodon][5], [Pleroma][6], or [PeerTube][7]. While not all Fediverse apps use Webfinger, enough do that adding Webfinger support will be necessary to have your site participate in the Fediverse.
8
+
9
+ [1]: https://www.bridgetownrb.com
10
+ [2]: https://webfinger.net/
11
+ [3]: https://indieweb.org/
12
+ [4]: https://datatracker.ietf.org/doc/html/rfc7565
13
+ [5]: https://joinmastodon.org/
14
+ [6]: https://pleroma.social/
15
+ [7]: https://joinpeertube.org/
16
+
17
+ ## Installation
18
+
19
+ Run this command to add this plugin to your site's Gemfile:
20
+
21
+ bundle add bridgetown-webfinger
22
+
23
+ Or you can use [an automation script][8] instead for guided setup:
24
+
25
+ bin/bt apply https://github.com/michaelherold/bridgetown-webfinger
26
+
27
+ [8]: https://www.bridgetownrb.com/docs/automations
28
+
29
+ ## Usage
30
+
31
+ This plugin runs in one of two modes: static mode or dynamic mode.
32
+
33
+ Static mode is for when you run a single-author, fully static website without using any of Bridgetown's Server-Side Rendering (SSR) capabilities. It is mildly non-compliant with the Webfinger specification, but is an accepted practice for static sites.
34
+
35
+ Dynamic mode uses a Roda plugin to serve author data for all accounts defined in your `src/_data/authors.yml` file.
36
+
37
+ ### Authors data file
38
+
39
+ Within your authors data file, each author requires a `webfinger` associative array with data about the account. For example, for the account `bilbo`, who has a Twitter account at `https://twitter.com/bilbobaggins` and hosts an avatar at `https://bagend.com/bilbo.png`, the authors data file entry might look like:
40
+
41
+ ```yaml
42
+ # src/_data/authors.yml
43
+ ---
44
+ bilbo:
45
+ webfinger:
46
+ aliases:
47
+ - https://twitter.com/bilbobaggins
48
+ links:
49
+ - href: https://bagend.com/bilbo.png
50
+ rel: http://webfinger.net/rel/avatar
51
+ type: image/png
52
+ ```
53
+
54
+ You may configure any number of authors in this way, however static mode works with only a single author.
55
+
56
+ ### Static mode
57
+
58
+ To use static mode, configure your [authors data file](#authors-data-file) and add the following to your `config/initializers.rb` file:
59
+
60
+ ```ruby
61
+ # config/initializers.rb
62
+ Bridgetown.configure do
63
+ init "bridgetown-webfinger", static: true
64
+ end
65
+ ```
66
+
67
+ Bridgetown will now generate a `.well-known/webfinger` file using your first author's information when building the site.
68
+
69
+ #### Deploying to Netlify
70
+
71
+ To have the correct headers for your static file, add the following to your `netlify.toml`.
72
+
73
+ ```toml
74
+ [[headers]]
75
+ for = "/.well-known/webfinger"
76
+
77
+ [headers.values]
78
+ Access-Control-Allow-Origin = "*"
79
+ Content-Type = "application/jrd+json"
80
+ ```
81
+
82
+ See [the allowed hosts section below](#allowed-hosts) for more information about the access control header.
83
+
84
+ ### Dynamic mode
85
+
86
+ To use dynamic mode, configure your [authors data file](#authors-data-file) and add the following to your `config/initializers.rb` file:
87
+
88
+ ```ruby
89
+ # config/initializers.rb
90
+ Bridgetown.configure do
91
+ init "bridgetown-webfinger", static: false, allowed_hosts: "*"
92
+ end
93
+ ```
94
+
95
+ Then, add the `bridgetown_webfinger` plugin to your `RodaApp` and call the `bridgetown_webfinger` request method:
96
+
97
+ ```ruby
98
+ # server/roda_app.rb
99
+ class RodaApp < Bridgetown::Rack::Roda
100
+ plugin :bridgetown_ssr # required
101
+ plugin :bridgetown_webfinger
102
+
103
+ route do |r|
104
+ r.bridgetown_webfinger
105
+ end
106
+ end
107
+ ```
108
+
109
+ This generates a `.well-known/webfinger` route that serves `acct:` URI requests for authors on your site.
110
+
111
+ #### Allowed hosts
112
+
113
+ The [Webfinger specification][9] states that [servers must include the `Access-Control-Allow-Origin`][10] header to enable Cross-Origin Resource Sharing (CORS) requests and that they should use the least restrictive setting.
114
+
115
+ Unless you are hosting private Webfinger information — e.g. within a corporate network, to only authenticated followers, or for any other reason — you should set this to `"*"` using the configuration above.
116
+
117
+ If this is private information that you wish to restrict [set the header value appropriately][11].
118
+
119
+ [9]: https://datatracker.ietf.org/doc/html/rfc7033
120
+ [10]: https://datatracker.ietf.org/doc/html/rfc7033#section-5
121
+ [11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
122
+
123
+ ## Contributing
124
+
125
+ So you're interested in contributing to Bridgetown Webfinger? Check out our [contributing guidelines](CONTRIBUTING.md) for more information on how to do that.
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/bridgetown/webfinger/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "bridgetown-webfinger"
7
+ spec.version = Bridgetown::Webfinger::VERSION
8
+ spec.author = "Michael Herold"
9
+ spec.email = "opensource@michaeljherold.com"
10
+ spec.summary = "Adds structured support for Webfinger to Bridgetown sites"
11
+ spec.homepage = "https://github.com/michaelherold/bridgetown-webfinger"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = %w[CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md]
15
+ spec.files += %w[bridgetown-webfinger.gemspec]
16
+ spec.files += Dir["lib/**/*.rb"]
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.required_ruby_version = ">= 3.0.0"
20
+
21
+ spec.add_dependency "bridgetown", ">= 1.2", "< 2.0"
22
+ spec.add_dependency "uri", ">= 0.12.0"
23
+ spec.add_dependency "zeitwerk"
24
+
25
+ spec.add_development_dependency "bundler", ">= 2"
26
+
27
+ spec.metadata = {
28
+ "bug_tracker_uri" => "https://github.com/michaelherold/bridgetown-webfinger/issues",
29
+ "changelog_uri" => "https://github.com/michaelherold/bridgetown-webfinger/blob/main/CHANGELOG.md",
30
+ "documentation_uri" => "https://rubydoc.info/gems/bridgetown-webfinger/#{Bridgetown::Webfinger::VERSION}",
31
+ "homepage_uri" => "https://github.com/michaelherold/bridgetown-webfinger",
32
+ "rubygems_mfa_required" => "true",
33
+ "source_code_uri" => "https://github.com/michaelherold/bridgetown-webfinger"
34
+ }
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Webfinger
5
+ # Wraps an `alias` member within a {JRD}, which is a URI identifying the same subject
6
+ class Alias < Model
7
+ # Parses and maybe-returns an {Alias} when the value is one
8
+ #
9
+ # Aliases [must be URIs][1] so when the value is not a proper URI, it is
10
+ # ignored.
11
+ #
12
+ # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.2
13
+ #
14
+ # @since 0.1.0
15
+ # @api private
16
+ #
17
+ # @return [Alias, nil] an {Alias} when the value is a URI, nil otherwise
18
+ def self.parse(moniker)
19
+ if Webfinger.uri?(moniker)
20
+ new(moniker)
21
+ else
22
+ warn(
23
+ "Webfinger alias is malformed: #{moniker.inspect}, ignoring"
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Webfinger
5
+ # The [builder class][1] for working with Webfinger in Bridgetown
6
+ #
7
+ # [1]: https://www.bridgetownrb.com/docs/plugins#introduction-to-the-builder-api
8
+ class Builder < Bridgetown::Builder
9
+ include Logging
10
+
11
+ # The hook method for enabling the builder's behavior
12
+ #
13
+ # @since 0.1.0
14
+ # @api private
15
+ #
16
+ # @return [void]
17
+ def build
18
+ generator :static_file
19
+ end
20
+
21
+ private
22
+
23
+ # Builds a static Webfinger file when correctly configured
24
+ #
25
+ # @since 0.1.0
26
+ # @api private
27
+ #
28
+ # @return [void]
29
+ def static_file
30
+ return unless config.webfinger.static
31
+ return unless (host = extract_site_host)
32
+ return unless (account, data = extract_authors_from_site_data)
33
+
34
+ site.add_generated_page StaticFile.new(site, account: account, data: data, host: host)
35
+ end
36
+
37
+ # Extracts the site's host from its configuration
38
+ #
39
+ # @since 0.1.0
40
+ # @api private
41
+ #
42
+ # @return [String, nil] String when configured correctly, nil otherwise
43
+ def extract_site_host
44
+ host = site.config.url
45
+
46
+ if !host || host.empty?
47
+ warn(
48
+ "bridgetown-webfinger did not find your site's host configured at " \
49
+ "`site.config.url`; this is unsupported by static files so will be ignored"
50
+ )
51
+ return
52
+ end
53
+
54
+ uri = URI(host)
55
+
56
+ if uri.is_a?(URI::HTTP)
57
+ uri.host
58
+ elsif uri.instance_of?(URI::Generic)
59
+ uri.to_s
60
+ else
61
+ warn(
62
+ "bridgetown-webfinger detected a malformed host in your site configuration " \
63
+ "(#{uri} from `site.config.url`); this is unsupported and will be ignored"
64
+ )
65
+ end
66
+ end
67
+
68
+ # Extracts the author from the site's data
69
+ #
70
+ # @since 0.1.0
71
+ # @api private
72
+ #
73
+ # @return [HashWithDotAccess::Hash, nil] Hash when configured correctly, nil otherwise
74
+ def extract_authors_from_site_data
75
+ unless (authors = site.data.authors) && !authors.empty?
76
+ warn(
77
+ "bridgetown-webfinger did not detect any authors at `site.data.authors`; " \
78
+ "this is unsupported by static files so will be ignored"
79
+ )
80
+ return
81
+ end
82
+
83
+ unless authors.size == 1
84
+ warn(
85
+ "bridgetown-webfinger discovered multiple authors; this is unsupported " \
86
+ "by static files so will be ignored"
87
+ )
88
+ return
89
+ end
90
+
91
+ authors.first
92
+ end
93
+
94
+ # The static Webfinger file to serve
95
+ class StaticFile < Bridgetown::GeneratedPage
96
+ # Initializes a new static Webfinger file
97
+ #
98
+ # @since 0.1.0
99
+ # @api private
100
+ #
101
+ # @param site [Bridgetown::Site] the site object
102
+ # @param account [String] the account for the {URI::Acct}
103
+ # @param data [HashWithDotAccess::Hash] the data for the Webfinger JRD
104
+ # @param host [String] the host for the {URI::Acct}
105
+ # @return [void]
106
+ def initialize(site, account:, data:, host:)
107
+ super(site, __dir__, "/.well-known", "webfinger", from_plugin: true)
108
+
109
+ @subject = URI::Acct.build({account: account, host: host}).to_s
110
+ @jrd = JRD.parse(@subject, data.webfinger)
111
+
112
+ self.content = JSON.pretty_generate(@jrd.to_h)
113
+ end
114
+
115
+ # The {JRD} forming the data model for the static Webfinger page
116
+ #
117
+ # @since 0.1.0
118
+ # @api private
119
+ #
120
+ # @return [JRD] the JSON Resource Descriptor to serve for Webfinger
121
+ attr_reader :jrd
122
+
123
+ # The subject of the {JRD}
124
+ #
125
+ # @since 0.1.0
126
+ # @api private
127
+ #
128
+ # @return [String] the subject for the JRD to serve
129
+ attr_reader :subject
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Webfinger
5
+ # Wraps an `href` member within a {Link}, which is the target URI
6
+ class Href < Model
7
+ # Parses and maybe-returns an {Href} when the value is one
8
+ #
9
+ # Hrefs [must be URIs][1] so when the value is not a proper URI, it is
10
+ # ignored.
11
+ #
12
+ # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4.3
13
+ #
14
+ # @since 0.1.0
15
+ # @api private
16
+ #
17
+ # @return [Href, nil] an {Href} when the value is a URI, nil otherwise
18
+ def self.parse(href)
19
+ if Webfinger.uri?(href)
20
+ new(href)
21
+ else
22
+ warn(
23
+ "Webfinger link href is malformed: #{href.inspect}, ignoring"
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @param config [Bridgetown::Configuration::ConfigurationDSL]
4
+ # @param allowed_origins [String] the value to use for the
5
+ # `Access-Control-Allow-Origin` header in the Roda plugin. Only override this
6
+ # if you're hosting private Webfinger data due to the [spec][1] saying, "servers
7
+ # SHOULD support the least restrictive setting"
8
+ # @param static [Boolean] whether to use static file rendering or not
9
+ #
10
+ # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-5
11
+ Bridgetown.initializer "bridgetown-webfinger" do |config, allowed_origins: "*", static: true|
12
+ options = {allowed_origins: allowed_origins, static: static}
13
+
14
+ # :nocov: Because it's not possible to show coverage for both branches
15
+ if config.webfinger
16
+ config.webfinger Bridgetown::Utils.deep_merge_hashes(options, config.webfinger)
17
+ else
18
+ config.webfinger(options)
19
+ end
20
+ # :nocov:
21
+
22
+ config.builder Bridgetown::Webfinger::Builder
23
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Webfinger
5
+ # A model of a [JSON Resource Descriptor][1]
6
+ #
7
+ # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.4
8
+ class JRD
9
+ include Logging
10
+
11
+ # Parses and maybe-returns a {JRD} when the subject and data form one
12
+ #
13
+ # {JRD}s can describe any resource identifiable via a URI, whether you want
14
+ # to give public directory information about people via `acct:` URIs,
15
+ # copyright information about an article, or perhaps license information
16
+ # about a library.
17
+ #
18
+ # @since 0.1.0
19
+ # @api public
20
+ #
21
+ # @example Convert a Hash into a sanitized {JRD}
22
+ #
23
+ # Bridgetown::Webfinger::JRD.parse(
24
+ # "acct:bilbo@bagend.com",
25
+ # {
26
+ # aliases: ["https://bilbobaggins.com/"],
27
+ # links: [
28
+ # {
29
+ # href: "https://bagend.com/bilbo",
30
+ # rel: "http://webfinger.net/rel/profile-page",
31
+ # type: "text/html",
32
+ # properties: {
33
+ # "http://packetizer.com/ns/name" => "Bilbo @ Bag End"
34
+ # },
35
+ # titles: {
36
+ # "en-us" => "Bilbo Baggins's blog"
37
+ # }
38
+ # }
39
+ # ],
40
+ # properties: {
41
+ # "http://packetizer.com/ns/name" => "Bilbo Baggins"
42
+ # }
43
+ # }
44
+ # )
45
+ #
46
+ # @param subject [String] the (nominally) optional subject identified by
47
+ # the JRD; _should_ be present but is not _required_
48
+ # @param data [Hash] the data hash containing information to add to the
49
+ # JRD
50
+ # @return [JRD, nil] a {JRD} when the information is valid, nil otherwise
51
+ def self.parse(subject, data)
52
+ aliases = Array(data[:aliases]).filter_map { |moniker| Alias.parse(moniker) }
53
+ links = Array(data[:links]).filter_map { |link| Link.parse(link) }
54
+ properties = Properties.parse(data[:properties])
55
+ subject = Webfinger.uri?(subject) ? subject : nil
56
+
57
+ new(
58
+ aliases: (!aliases.empty?) ? aliases : nil,
59
+ links: (!links.empty?) ? links : nil,
60
+ properties: properties,
61
+ subject: subject
62
+ )
63
+ end
64
+
65
+ # Creates a new {JRD}
66
+ #
67
+ # @since 0.1.0
68
+ # @api public
69
+ #
70
+ # @example Creating a new {JRD} without parsing a Hash
71
+ #
72
+ # Bridgetown::Webfinger::JRD.new(
73
+ # subject: "acct:bilbo@bagend.com",
74
+ # aliases: [Bridgetown::Webfinger::Alias.new("https://bilbobaggins.com/")]
75
+ # )
76
+ #
77
+ # @param aliases [Array<Alias>, nil] the optional {Alias}es for the resource
78
+ # @param links [Array<Link>, nil] the optional {Link}s related to the resource
79
+ # @param properties [Properties] the optional {Properties} describing the resource
80
+ # @param subject [String, nil] the (nominally) optional subject URI for the resource
81
+ def initialize(aliases: nil, links: nil, properties: nil, subject: nil)
82
+ @aliases = aliases
83
+ @links = links
84
+ @properties = properties
85
+ @subject = subject
86
+ end
87
+
88
+ # The list of {Alias}es for the resource
89
+ #
90
+ # @since 0.1.0
91
+ # @api public
92
+ #
93
+ # @example Read the {Alias}es for a {JRD}
94
+ #
95
+ # jrd = Bridgetown::Webfinger::JRD.parse(
96
+ # "acct:bilbo@bagend.com",
97
+ # {aliases: ["https://bilbobaggins.com"]}
98
+ # )
99
+ # jrd.aliases
100
+ #
101
+ # @return [Array<Alias>, nil] the optional {Alias}es for the resource
102
+ attr_reader :aliases
103
+
104
+ # The list of {Link}s for the resource
105
+ #
106
+ # @since 0.1.0
107
+ # @api public
108
+ #
109
+ # @example Read the {Link}s for a {JRD}
110
+ #
111
+ # jrd = Bridgetown::Webfinger::JRD.parse(
112
+ # "acct:bilbo@bagend.com",
113
+ # {links: [{href: "https://bilbobaggins.com", rel: "https://webfinger.net/rel/avatar"}]}
114
+ # )
115
+ # jrd.links
116
+ #
117
+ # @return [Array<Link>, nil] the optional {Link}s related to the resource
118
+ attr_reader :links
119
+
120
+ # The list of {Properties} for the resource
121
+ #
122
+ # @since 0.1.0
123
+ # @api public
124
+ #
125
+ # @example Read the {Properties} for a {JRD}
126
+ #
127
+ # jrd = Bridgetown::Webfinger::JRD.parse(
128
+ # "acct:bilbo@bagend.com",
129
+ # {properties: {"http://packetizer.com/ns/name" => "Bilbo Baggins"}}
130
+ # )
131
+ # jrd.properties
132
+ #
133
+ # @return [Properties, nil] the optional {Properties} describing the resource
134
+ attr_reader :properties
135
+
136
+ # The subject of the {JRD}
137
+ #
138
+ # @since 0.1.0
139
+ # @api public
140
+ #
141
+ # @example Read the subject for a {JRD}
142
+ #
143
+ # jrd = Bridgetown::Webfinger::JRD.parse("acct:bilbo@bagend.com")
144
+ # jrd.subject #=> "acct:bilbo@bagend.com"
145
+ #
146
+ # @return [String, nil] the (nominally) optional subject URI for the resource
147
+ attr_reader :subject
148
+
149
+ # Converts the {JRD} to a JSON-serializable Hash
150
+ #
151
+ # @since 0.1.0
152
+ # @api private
153
+ #
154
+ # @return [Hash] the JRD as a JSON-compatible Hash
155
+ def to_h
156
+ result = {subject: subject}
157
+ result[:aliases] = aliases if aliases
158
+ result[:links] = links.map(&:to_h) if links
159
+ result[:properties] = properties.to_h if properties
160
+ result
161
+ end
162
+ end
163
+ end
164
+ end