bridgetown-webfinger 0.1.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 +7 -0
 - data/CHANGELOG.md +15 -0
 - data/CONTRIBUTING.md +55 -0
 - data/LICENSE.md +22 -0
 - data/README.md +125 -0
 - data/bridgetown-webfinger.gemspec +35 -0
 - data/lib/bridgetown/webfinger/alias.rb +29 -0
 - data/lib/bridgetown/webfinger/builder.rb +133 -0
 - data/lib/bridgetown/webfinger/href.rb +29 -0
 - data/lib/bridgetown/webfinger/initializer.rb +23 -0
 - data/lib/bridgetown/webfinger/jrd.rb +164 -0
 - data/lib/bridgetown/webfinger/link.rb +118 -0
 - data/lib/bridgetown/webfinger/link_relation_type.rb +159 -0
 - data/lib/bridgetown/webfinger/logging.rb +38 -0
 - data/lib/bridgetown/webfinger/model.rb +13 -0
 - data/lib/bridgetown/webfinger/parameters.rb +166 -0
 - data/lib/bridgetown/webfinger/properties.rb +44 -0
 - data/lib/bridgetown/webfinger/titles.rb +40 -0
 - data/lib/bridgetown/webfinger/uri/acct.rb +138 -0
 - data/lib/bridgetown/webfinger/version.rb +8 -0
 - data/lib/bridgetown-webfinger.rb +49 -0
 - data/lib/roda/plugins/bridgetown_webfinger.rb +149 -0
 - metadata +131 -0
 
| 
         @@ -0,0 +1,118 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Bridgetown
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Webfinger
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Wraps a [link][1] object within a {JRD}
         
     | 
| 
      
 6 
     | 
    
         
            +
                #
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Links represent links to resources external to the entity. They are
         
     | 
| 
      
 8 
     | 
    
         
            +
                # _optional_ within a JRD so may not appear in your Webfinger setup.
         
     | 
| 
      
 9 
     | 
    
         
            +
                #
         
     | 
| 
      
 10 
     | 
    
         
            +
                # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4
         
     | 
| 
      
 11 
     | 
    
         
            +
                class Link
         
     | 
| 
      
 12 
     | 
    
         
            +
                  extend Logging
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  # Parses and maybe-returns a {Link} when the value is one
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # [Links][1] within the {JRD} are member objects representing a link to
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # another resource.
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #
         
     | 
| 
      
 24 
     | 
    
         
            +
                  # @param data [Hash] the data to parse as a link object
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # @return [Link, nil] the link parsed from the data
         
     | 
| 
      
 26 
     | 
    
         
            +
                  def self.parse(data)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    unless (rel = LinkRelationType.parse(data[:rel]))
         
     | 
| 
      
 28 
     | 
    
         
            +
                      return warn(
         
     | 
| 
      
 29 
     | 
    
         
            +
                        "Webfinger link rel is missing or malformed: #{data.inspect}, ignoring"
         
     | 
| 
      
 30 
     | 
    
         
            +
                      )
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    new(
         
     | 
| 
      
 34 
     | 
    
         
            +
                      rel: rel,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      href: Href.parse(data[:href]),
         
     | 
| 
      
 36 
     | 
    
         
            +
                      properties: Properties.parse(data[:properties]),
         
     | 
| 
      
 37 
     | 
    
         
            +
                      titles: Titles.parse(data[:titles]),
         
     | 
| 
      
 38 
     | 
    
         
            +
                      type: data[:type]
         
     | 
| 
      
 39 
     | 
    
         
            +
                    )
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  # Creates a new {Link}
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # @param rel [LinkRelationType] the type of relation the {Link} represents
         
     | 
| 
      
 48 
     | 
    
         
            +
                  # @param href [Href, nil] the optional {Href} URI of the link
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # @param properties [Properties, nil] the optional list of {Properties}
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #   describing the link
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # @param titles [Titles, nil] the optional list of {Titles} naming the link
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # @param type [String, nil] the optional media type of the target resource
         
     | 
| 
      
 53 
     | 
    
         
            +
                  def initialize(rel:, href: nil, properties: nil, titles: nil, type: nil)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    @href = href
         
     | 
| 
      
 55 
     | 
    
         
            +
                    @properties = properties
         
     | 
| 
      
 56 
     | 
    
         
            +
                    @rel = rel
         
     | 
| 
      
 57 
     | 
    
         
            +
                    @titles = titles
         
     | 
| 
      
 58 
     | 
    
         
            +
                    @type = type
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  # The optional hypertext reference to a URI for the {Link}
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #
         
     | 
| 
      
 66 
     | 
    
         
            +
                  # @return [Href, nil] the optional {Href} URI of the link
         
     | 
| 
      
 67 
     | 
    
         
            +
                  attr_reader :href
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  # The optional {Properties} characterizing the {Link}
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #
         
     | 
| 
      
 71 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 72 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #
         
     | 
| 
      
 74 
     | 
    
         
            +
                  # @return [Properties, nil] the optional list of {Properties} describing
         
     | 
| 
      
 75 
     | 
    
         
            +
                  #   the link
         
     | 
| 
      
 76 
     | 
    
         
            +
                  attr_reader :properties
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  # The {LinkRelationType} describing what the {Link} links to
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #
         
     | 
| 
      
 80 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 81 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # @return [LinkRelationType] the type of relation the {Link} represents
         
     | 
| 
      
 84 
     | 
    
         
            +
                  attr_reader :rel
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  # The optional {Titles} describing the {Link}
         
     | 
| 
      
 87 
     | 
    
         
            +
                  #
         
     | 
| 
      
 88 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 89 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 90 
     | 
    
         
            +
                  #
         
     | 
| 
      
 91 
     | 
    
         
            +
                  # @return [Titles, nil] the optional list of {Titles} naming the link
         
     | 
| 
      
 92 
     | 
    
         
            +
                  attr_reader :titles
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  # The optional media type of the {#href} for the {Link}
         
     | 
| 
      
 95 
     | 
    
         
            +
                  #
         
     | 
| 
      
 96 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 97 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 98 
     | 
    
         
            +
                  #
         
     | 
| 
      
 99 
     | 
    
         
            +
                  # @return [String, nil] the optional media type of the target resource
         
     | 
| 
      
 100 
     | 
    
         
            +
                  attr_reader :type
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                  # Converts the {Link} into a JSON-serializable Hash
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #
         
     | 
| 
      
 104 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 105 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 106 
     | 
    
         
            +
                  #
         
     | 
| 
      
 107 
     | 
    
         
            +
                  # @return [Hash] the Link as a JSON-compatible Hash
         
     | 
| 
      
 108 
     | 
    
         
            +
                  def to_h
         
     | 
| 
      
 109 
     | 
    
         
            +
                    result = {rel: rel}
         
     | 
| 
      
 110 
     | 
    
         
            +
                    result[:href] = href if href
         
     | 
| 
      
 111 
     | 
    
         
            +
                    result[:properties] = properties if properties
         
     | 
| 
      
 112 
     | 
    
         
            +
                    result[:titles] = titles if titles
         
     | 
| 
      
 113 
     | 
    
         
            +
                    result[:type] = type if type
         
     | 
| 
      
 114 
     | 
    
         
            +
                    result
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
              end
         
     | 
| 
      
 118 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,159 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Bridgetown
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Webfinger
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Wraps the type of a {Link} relation
         
     | 
| 
      
 6 
     | 
    
         
            +
                class LinkRelationType < Model
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # The list of relation types, as [registered with IANA][1]
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # This constant can be regenerated with the `data:link_relations` Rake
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # task.
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # [1]: https://www.iana.org/assignments/link-relations
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 16 
     | 
    
         
            +
                  REGISTERED = Set.new(%w[
         
     | 
| 
      
 17 
     | 
    
         
            +
                    about
         
     | 
| 
      
 18 
     | 
    
         
            +
                    acl
         
     | 
| 
      
 19 
     | 
    
         
            +
                    alternate
         
     | 
| 
      
 20 
     | 
    
         
            +
                    amphtml
         
     | 
| 
      
 21 
     | 
    
         
            +
                    appendix
         
     | 
| 
      
 22 
     | 
    
         
            +
                    apple-touch-icon
         
     | 
| 
      
 23 
     | 
    
         
            +
                    apple-touch-startup-image
         
     | 
| 
      
 24 
     | 
    
         
            +
                    archives
         
     | 
| 
      
 25 
     | 
    
         
            +
                    author
         
     | 
| 
      
 26 
     | 
    
         
            +
                    blocked-by
         
     | 
| 
      
 27 
     | 
    
         
            +
                    bookmark
         
     | 
| 
      
 28 
     | 
    
         
            +
                    canonical
         
     | 
| 
      
 29 
     | 
    
         
            +
                    chapter
         
     | 
| 
      
 30 
     | 
    
         
            +
                    cite-as
         
     | 
| 
      
 31 
     | 
    
         
            +
                    collection
         
     | 
| 
      
 32 
     | 
    
         
            +
                    contents
         
     | 
| 
      
 33 
     | 
    
         
            +
                    convertedfrom
         
     | 
| 
      
 34 
     | 
    
         
            +
                    copyright
         
     | 
| 
      
 35 
     | 
    
         
            +
                    create-form
         
     | 
| 
      
 36 
     | 
    
         
            +
                    current
         
     | 
| 
      
 37 
     | 
    
         
            +
                    describedby
         
     | 
| 
      
 38 
     | 
    
         
            +
                    describes
         
     | 
| 
      
 39 
     | 
    
         
            +
                    disclosure
         
     | 
| 
      
 40 
     | 
    
         
            +
                    dns-prefetch
         
     | 
| 
      
 41 
     | 
    
         
            +
                    duplicate
         
     | 
| 
      
 42 
     | 
    
         
            +
                    edit
         
     | 
| 
      
 43 
     | 
    
         
            +
                    edit-form
         
     | 
| 
      
 44 
     | 
    
         
            +
                    edit-media
         
     | 
| 
      
 45 
     | 
    
         
            +
                    enclosure
         
     | 
| 
      
 46 
     | 
    
         
            +
                    external
         
     | 
| 
      
 47 
     | 
    
         
            +
                    first
         
     | 
| 
      
 48 
     | 
    
         
            +
                    glossary
         
     | 
| 
      
 49 
     | 
    
         
            +
                    help
         
     | 
| 
      
 50 
     | 
    
         
            +
                    hosts
         
     | 
| 
      
 51 
     | 
    
         
            +
                    hub
         
     | 
| 
      
 52 
     | 
    
         
            +
                    icon
         
     | 
| 
      
 53 
     | 
    
         
            +
                    index
         
     | 
| 
      
 54 
     | 
    
         
            +
                    intervalafter
         
     | 
| 
      
 55 
     | 
    
         
            +
                    intervalbefore
         
     | 
| 
      
 56 
     | 
    
         
            +
                    intervalcontains
         
     | 
| 
      
 57 
     | 
    
         
            +
                    intervaldisjoint
         
     | 
| 
      
 58 
     | 
    
         
            +
                    intervalduring
         
     | 
| 
      
 59 
     | 
    
         
            +
                    intervalequals
         
     | 
| 
      
 60 
     | 
    
         
            +
                    intervalfinishedby
         
     | 
| 
      
 61 
     | 
    
         
            +
                    intervalfinishes
         
     | 
| 
      
 62 
     | 
    
         
            +
                    intervalin
         
     | 
| 
      
 63 
     | 
    
         
            +
                    intervalmeets
         
     | 
| 
      
 64 
     | 
    
         
            +
                    intervalmetby
         
     | 
| 
      
 65 
     | 
    
         
            +
                    intervaloverlappedby
         
     | 
| 
      
 66 
     | 
    
         
            +
                    intervaloverlaps
         
     | 
| 
      
 67 
     | 
    
         
            +
                    intervalstartedby
         
     | 
| 
      
 68 
     | 
    
         
            +
                    intervalstarts
         
     | 
| 
      
 69 
     | 
    
         
            +
                    item
         
     | 
| 
      
 70 
     | 
    
         
            +
                    last
         
     | 
| 
      
 71 
     | 
    
         
            +
                    latest-version
         
     | 
| 
      
 72 
     | 
    
         
            +
                    license
         
     | 
| 
      
 73 
     | 
    
         
            +
                    linkset
         
     | 
| 
      
 74 
     | 
    
         
            +
                    lrdd
         
     | 
| 
      
 75 
     | 
    
         
            +
                    manifest
         
     | 
| 
      
 76 
     | 
    
         
            +
                    mask-icon
         
     | 
| 
      
 77 
     | 
    
         
            +
                    media-feed
         
     | 
| 
      
 78 
     | 
    
         
            +
                    memento
         
     | 
| 
      
 79 
     | 
    
         
            +
                    micropub
         
     | 
| 
      
 80 
     | 
    
         
            +
                    modulepreload
         
     | 
| 
      
 81 
     | 
    
         
            +
                    monitor
         
     | 
| 
      
 82 
     | 
    
         
            +
                    monitor-group
         
     | 
| 
      
 83 
     | 
    
         
            +
                    next
         
     | 
| 
      
 84 
     | 
    
         
            +
                    next-archive
         
     | 
| 
      
 85 
     | 
    
         
            +
                    nofollow
         
     | 
| 
      
 86 
     | 
    
         
            +
                    noopener
         
     | 
| 
      
 87 
     | 
    
         
            +
                    noreferrer
         
     | 
| 
      
 88 
     | 
    
         
            +
                    opener
         
     | 
| 
      
 89 
     | 
    
         
            +
                    openid2.local_id
         
     | 
| 
      
 90 
     | 
    
         
            +
                    openid2.provider
         
     | 
| 
      
 91 
     | 
    
         
            +
                    original
         
     | 
| 
      
 92 
     | 
    
         
            +
                    p3pv1
         
     | 
| 
      
 93 
     | 
    
         
            +
                    payment
         
     | 
| 
      
 94 
     | 
    
         
            +
                    pingback
         
     | 
| 
      
 95 
     | 
    
         
            +
                    preconnect
         
     | 
| 
      
 96 
     | 
    
         
            +
                    predecessor-version
         
     | 
| 
      
 97 
     | 
    
         
            +
                    prefetch
         
     | 
| 
      
 98 
     | 
    
         
            +
                    preload
         
     | 
| 
      
 99 
     | 
    
         
            +
                    prerender
         
     | 
| 
      
 100 
     | 
    
         
            +
                    prev
         
     | 
| 
      
 101 
     | 
    
         
            +
                    preview
         
     | 
| 
      
 102 
     | 
    
         
            +
                    previous
         
     | 
| 
      
 103 
     | 
    
         
            +
                    prev-archive
         
     | 
| 
      
 104 
     | 
    
         
            +
                    privacy-policy
         
     | 
| 
      
 105 
     | 
    
         
            +
                    profile
         
     | 
| 
      
 106 
     | 
    
         
            +
                    publication
         
     | 
| 
      
 107 
     | 
    
         
            +
                    related
         
     | 
| 
      
 108 
     | 
    
         
            +
                    restconf
         
     | 
| 
      
 109 
     | 
    
         
            +
                    replies
         
     | 
| 
      
 110 
     | 
    
         
            +
                    ruleinput
         
     | 
| 
      
 111 
     | 
    
         
            +
                    search
         
     | 
| 
      
 112 
     | 
    
         
            +
                    section
         
     | 
| 
      
 113 
     | 
    
         
            +
                    self
         
     | 
| 
      
 114 
     | 
    
         
            +
                    service
         
     | 
| 
      
 115 
     | 
    
         
            +
                    service-desc
         
     | 
| 
      
 116 
     | 
    
         
            +
                    service-doc
         
     | 
| 
      
 117 
     | 
    
         
            +
                    service-meta
         
     | 
| 
      
 118 
     | 
    
         
            +
                    sip-trunking-capability
         
     | 
| 
      
 119 
     | 
    
         
            +
                    sponsored
         
     | 
| 
      
 120 
     | 
    
         
            +
                    start
         
     | 
| 
      
 121 
     | 
    
         
            +
                    status
         
     | 
| 
      
 122 
     | 
    
         
            +
                    stylesheet
         
     | 
| 
      
 123 
     | 
    
         
            +
                    subsection
         
     | 
| 
      
 124 
     | 
    
         
            +
                    successor-version
         
     | 
| 
      
 125 
     | 
    
         
            +
                    sunset
         
     | 
| 
      
 126 
     | 
    
         
            +
                    tag
         
     | 
| 
      
 127 
     | 
    
         
            +
                    terms-of-service
         
     | 
| 
      
 128 
     | 
    
         
            +
                    timegate
         
     | 
| 
      
 129 
     | 
    
         
            +
                    timemap
         
     | 
| 
      
 130 
     | 
    
         
            +
                    type
         
     | 
| 
      
 131 
     | 
    
         
            +
                    ugc
         
     | 
| 
      
 132 
     | 
    
         
            +
                    up
         
     | 
| 
      
 133 
     | 
    
         
            +
                    version-history
         
     | 
| 
      
 134 
     | 
    
         
            +
                    via
         
     | 
| 
      
 135 
     | 
    
         
            +
                    webmention
         
     | 
| 
      
 136 
     | 
    
         
            +
                    working-copy
         
     | 
| 
      
 137 
     | 
    
         
            +
                    working-copy-of
         
     | 
| 
      
 138 
     | 
    
         
            +
                  ]).freeze
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                  # Parses a maybe-returns a {LinkRelationType} when the value is one
         
     | 
| 
      
 141 
     | 
    
         
            +
                  #
         
     | 
| 
      
 142 
     | 
    
         
            +
                  # Link relation types may either be a URI to a relation type description
         
     | 
| 
      
 143 
     | 
    
         
            +
                  # or a value [registered with IANA][1].
         
     | 
| 
      
 144 
     | 
    
         
            +
                  #
         
     | 
| 
      
 145 
     | 
    
         
            +
                  # [1]: https://www.iana.org/assignments/link-relations
         
     | 
| 
      
 146 
     | 
    
         
            +
                  #
         
     | 
| 
      
 147 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 148 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 149 
     | 
    
         
            +
                  #
         
     | 
| 
      
 150 
     | 
    
         
            +
                  # @param rel [String] the rel to parse and validate
         
     | 
| 
      
 151 
     | 
    
         
            +
                  # @return [LinkRelationType, nil] the link relation type parsed from the rel
         
     | 
| 
      
 152 
     | 
    
         
            +
                  def self.parse(rel)
         
     | 
| 
      
 153 
     | 
    
         
            +
                    return unless Webfinger.uri?(rel) || REGISTERED.include?(rel)
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                    new(rel)
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
              end
         
     | 
| 
      
 159 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Bridgetown
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Webfinger
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Helper methods for logging purposes
         
     | 
| 
      
 6 
     | 
    
         
            +
                module Logging
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # When including the module, also extend it as well
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @private
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # @param base [Module] the base module or class including the module
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @return [void]
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def self.included(base)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    super
         
     | 
| 
      
 17 
     | 
    
         
            +
                    base.extend(self)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  # Sends a warning message through the Bridgetown logger
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # @example Print a warning in the logger
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #    extend Bridgetown::Webfinger::Logging
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #    warn "I like some of you less than you deserve"
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # @param msg [String] the message to log
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # @return [void]
         
     | 
| 
      
 32 
     | 
    
         
            +
                  def warn(msg)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    Bridgetown.logger.warn(msg)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,166 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "uri"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Bridgetown
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Webfinger
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Parses URI parameters in the Webfinger style
         
     | 
| 
      
 8 
     | 
    
         
            +
                #
         
     | 
| 
      
 9 
     | 
    
         
            +
                # This is necessary because Rack handles parameters differently than the
         
     | 
| 
      
 10 
     | 
    
         
            +
                # Webfinger specification. In Rack, repeated parameters compete in a
         
     | 
| 
      
 11 
     | 
    
         
            +
                # last-one-wins scheme. For example:
         
     | 
| 
      
 12 
     | 
    
         
            +
                #
         
     | 
| 
      
 13 
     | 
    
         
            +
                #     https://example.com?foo=1&foo=2&bar=3
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                # parses into:
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                #     {"foo" => 2, "bar" => 3}
         
     | 
| 
      
 18 
     | 
    
         
            +
                #
         
     | 
| 
      
 19 
     | 
    
         
            +
                # whereas Webfinger's processing [wants this][1]:
         
     | 
| 
      
 20 
     | 
    
         
            +
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                #     {"foo" => [1, 2], "bar" => 3}
         
     | 
| 
      
 22 
     | 
    
         
            +
                #
         
     | 
| 
      
 23 
     | 
    
         
            +
                # per the phrasing “the "rel" parameter MAY be included multiple times in
         
     | 
| 
      
 24 
     | 
    
         
            +
                # order to request multiple link relation types.”
         
     | 
| 
      
 25 
     | 
    
         
            +
                #
         
     | 
| 
      
 26 
     | 
    
         
            +
                # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.3
         
     | 
| 
      
 27 
     | 
    
         
            +
                #
         
     | 
| 
      
 28 
     | 
    
         
            +
                # @since 0.1.0
         
     | 
| 
      
 29 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 30 
     | 
    
         
            +
                class Parameters
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # Splits query parameters at the ampersand and optional spaces
         
     | 
| 
      
 32 
     | 
    
         
            +
                  #
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # This was borrowed from [Rack::QueryParser][2] and simplified.
         
     | 
| 
      
 34 
     | 
    
         
            +
                  #
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # [2]: https://rubydoc.info/gems/rack/Rack/QueryParser
         
     | 
| 
      
 36 
     | 
    
         
            +
                  SPLITTER = %r{& *}n
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  # Parses a query string for a webfinger request into a hash
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # This method cleans any unrelated parameters from the result and combines
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # multiple requests for `rel`s into an array. It also handles unescaping
         
     | 
| 
      
 42 
     | 
    
         
            +
                  # terms.
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # @param [String] query_string the query string for a webfinger request
         
     | 
| 
      
 48 
     | 
    
         
            +
                  # @return [Parameters] the cleaned param values
         
     | 
| 
      
 49 
     | 
    
         
            +
                  def self.from_query_string(query_string)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    query_string
         
     | 
| 
      
 51 
     | 
    
         
            +
                      .split(SPLITTER)
         
     | 
| 
      
 52 
     | 
    
         
            +
                      .map { |pair| pair.split("=", 2).map! { |component| decode(component) } }
         
     | 
| 
      
 53 
     | 
    
         
            +
                      .each_with_object(Parameters.new) do |(param, value), result|
         
     | 
| 
      
 54 
     | 
    
         
            +
                        case param
         
     | 
| 
      
 55 
     | 
    
         
            +
                        when "resource" then result.resource = value
         
     | 
| 
      
 56 
     | 
    
         
            +
                        when "rel" then result.add_rel(value)
         
     | 
| 
      
 57 
     | 
    
         
            +
                        end
         
     | 
| 
      
 58 
     | 
    
         
            +
                      end
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  # Decodes a URI component; an alias to the URI method, for brevity
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # @private
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #
         
     | 
| 
      
 67 
     | 
    
         
            +
                  # @param component [String] the component from the URI
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # @return [String] the decoded component
         
     | 
| 
      
 69 
     | 
    
         
            +
                  private_class_method def self.decode(component)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    URI.decode_uri_component(component)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  # Creates a new {Parameters} from an optional resource and rel
         
     | 
| 
      
 74 
     | 
    
         
            +
                  #
         
     | 
| 
      
 75 
     | 
    
         
            +
                  #
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #
         
     | 
| 
      
 77 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 78 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #
         
     | 
| 
      
 80 
     | 
    
         
            +
                  # @example Create an empty
         
     | 
| 
      
 81 
     | 
    
         
            +
                  #
         
     | 
| 
      
 82 
     | 
    
         
            +
                  # @param resource [String, nil] the resource for the request
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # @param rel [Array<String>, nil] the types of relation to scope the links to
         
     | 
| 
      
 84 
     | 
    
         
            +
                  # @return [void]
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def initialize(resource: nil, rel: nil)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    @resource = resource
         
     | 
| 
      
 87 
     | 
    
         
            +
                    @rel = rel
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  # The list of link relations requested within the {Parameters}
         
     | 
| 
      
 91 
     | 
    
         
            +
                  #
         
     | 
| 
      
 92 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 93 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 94 
     | 
    
         
            +
                  #
         
     | 
| 
      
 95 
     | 
    
         
            +
                  # @example Reading the link relations requested as a URL parameter
         
     | 
| 
      
 96 
     | 
    
         
            +
                  #
         
     | 
| 
      
 97 
     | 
    
         
            +
                  #   params = Bridgetown::Webfinger::Parameters.from_query_string(
         
     | 
| 
      
 98 
     | 
    
         
            +
                  #     "resource=acct%3Abilbo%40bagend.com&" \
         
     | 
| 
      
 99 
     | 
    
         
            +
                  #     "rel=http%3A%2F%2Fwebfinger.net%2Frel%2Favatar&" \
         
     | 
| 
      
 100 
     | 
    
         
            +
                  #     "rel=http%3A%2F%2Fwebfinger.net%2Frel%2Fprofile-page"
         
     | 
| 
      
 101 
     | 
    
         
            +
                  #   )
         
     | 
| 
      
 102 
     | 
    
         
            +
                  #   params.rel
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #   #=> ["https://webfinger.net/rel/avatar", "https://webfinger.net/rel/profile-page"]
         
     | 
| 
      
 104 
     | 
    
         
            +
                  # @return [Array<String>, nil] the types of relation to scope the links to
         
     | 
| 
      
 105 
     | 
    
         
            +
                  attr_reader :rel
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  # The decoded resource requested within the {Parameters}
         
     | 
| 
      
 108 
     | 
    
         
            +
                  #
         
     | 
| 
      
 109 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 110 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 111 
     | 
    
         
            +
                  #
         
     | 
| 
      
 112 
     | 
    
         
            +
                  # @example Reading the resource requested as a URL parameter
         
     | 
| 
      
 113 
     | 
    
         
            +
                  #
         
     | 
| 
      
 114 
     | 
    
         
            +
                  #    params = Bridgetown::Webfinger::Parameters.from_query_string(
         
     | 
| 
      
 115 
     | 
    
         
            +
                  #      "resource=acct%3Abilbo%40bagend.com"
         
     | 
| 
      
 116 
     | 
    
         
            +
                  #    )
         
     | 
| 
      
 117 
     | 
    
         
            +
                  #    params.resource #=> "acct:bilbo@bagend.com"
         
     | 
| 
      
 118 
     | 
    
         
            +
                  #
         
     | 
| 
      
 119 
     | 
    
         
            +
                  # @return [String, nil] the resource for the request
         
     | 
| 
      
 120 
     | 
    
         
            +
                  attr_accessor :resource
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                  # Checks for value object equality
         
     | 
| 
      
 123 
     | 
    
         
            +
                  #
         
     | 
| 
      
 124 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 125 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 126 
     | 
    
         
            +
                  #
         
     | 
| 
      
 127 
     | 
    
         
            +
                  # @param other [Parameters] the other parameter set to compare against
         
     | 
| 
      
 128 
     | 
    
         
            +
                  # @return [Boolean] true when they are equal, false otherwise
         
     | 
| 
      
 129 
     | 
    
         
            +
                  def ==(other)
         
     | 
| 
      
 130 
     | 
    
         
            +
                    other.instance_of?(Parameters) &&
         
     | 
| 
      
 131 
     | 
    
         
            +
                      resource == other.resource &&
         
     | 
| 
      
 132 
     | 
    
         
            +
                      rel == other.rel
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
                  alias_method :eql?, :==
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  # Adds a link relation, or "rel," to the {Parameters}
         
     | 
| 
      
 137 
     | 
    
         
            +
                  #
         
     | 
| 
      
 138 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 139 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 140 
     | 
    
         
            +
                  #
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # @example Adding a link relation to a new {Parameters} instance
         
     | 
| 
      
 142 
     | 
    
         
            +
                  #
         
     | 
| 
      
 143 
     | 
    
         
            +
                  #   params = Bridgetown::Webfinger::Parameters.new
         
     | 
| 
      
 144 
     | 
    
         
            +
                  #   params.add_rel("http://webfinger.net/rel/avatar")
         
     | 
| 
      
 145 
     | 
    
         
            +
                  #   params.rel  #=> ["http://webfinger.net/rel/avatar"]
         
     | 
| 
      
 146 
     | 
    
         
            +
                  #
         
     | 
| 
      
 147 
     | 
    
         
            +
                  # @param rel [String] a type of relation to add to the scope request
         
     | 
| 
      
 148 
     | 
    
         
            +
                  # @return [void]
         
     | 
| 
      
 149 
     | 
    
         
            +
                  def add_rel(rel)
         
     | 
| 
      
 150 
     | 
    
         
            +
                    return unless rel
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                    (@rel ||= []).push(rel)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  end
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                  # Allows the {Parameters} to be used in a Hash key; part of value object semantics
         
     | 
| 
      
 156 
     | 
    
         
            +
                  #
         
     | 
| 
      
 157 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 158 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 159 
     | 
    
         
            +
                  #
         
     | 
| 
      
 160 
     | 
    
         
            +
                  # @return [Integer]
         
     | 
| 
      
 161 
     | 
    
         
            +
                  def hash
         
     | 
| 
      
 162 
     | 
    
         
            +
                    [resource, *rel].hash
         
     | 
| 
      
 163 
     | 
    
         
            +
                  end
         
     | 
| 
      
 164 
     | 
    
         
            +
                end
         
     | 
| 
      
 165 
     | 
    
         
            +
              end
         
     | 
| 
      
 166 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Bridgetown
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Webfinger
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Wraps a `properties` member within a {Link} or {JRD}
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Properties < Model
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # Parses and maybe-returns {Properties} when the value is one
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # Properties within the {JRD} are name/value pairs [with URIs for names
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # and strings or nulls for values][1].
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4.5
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # @param data [Hash] the data to parse as a properties object
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # @return [Properties, nil] the properties parsed from the data
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def self.parse(data)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    return unless data
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    unless data.is_a?(Hash)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      return warn("Webfinger link properties are malformed: #{data.inspect}, ignoring")
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    properties = data.select do |name, value|
         
     | 
| 
      
 27 
     | 
    
         
            +
                      if !Webfinger.uri?(name)
         
     | 
| 
      
 28 
     | 
    
         
            +
                        next warn("Webfinger property name is not a URI: #{name}, ignoring")
         
     | 
| 
      
 29 
     | 
    
         
            +
                      elsif !value.is_a?(String) || value.nil?
         
     | 
| 
      
 30 
     | 
    
         
            +
                        next warn("Webfinger property value is not a nullable string: #{value}, ignoring")
         
     | 
| 
      
 31 
     | 
    
         
            +
                      else
         
     | 
| 
      
 32 
     | 
    
         
            +
                        true
         
     | 
| 
      
 33 
     | 
    
         
            +
                      end
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    if !properties.empty?
         
     | 
| 
      
 37 
     | 
    
         
            +
                      new(properties)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    else
         
     | 
| 
      
 39 
     | 
    
         
            +
                      warn("All Webfinger link properties pruned: #{data.inspect}, ignoring")
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Bridgetown
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Webfinger
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Wraps a `titles` member within a {Link}
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Titles < Model
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # Parses and maybe-returns {Titles} when the value is one
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # Titles within the {JRD} are name/value pairs [with language tag names
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # and string values][2]. When the language is indeterminate, use `"und"`.
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # [1]: https://datatracker.ietf.org/doc/html/rfc7033#section-4.4.4.4
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @since 0.1.0
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # @param data [Hash] the data to parse as a titles object
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # @return [Titles, nil] the titles parsed from the data
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def self.parse(data)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    return unless data.is_a?(Hash)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    data = data.select do |key, value|
         
     | 
| 
      
 23 
     | 
    
         
            +
                      if !key.is_a?(String)
         
     | 
| 
      
 24 
     | 
    
         
            +
                        next warn("Webfinger title key is not a string: #{key}, ignoring")
         
     | 
| 
      
 25 
     | 
    
         
            +
                      elsif !value.is_a?(String)
         
     | 
| 
      
 26 
     | 
    
         
            +
                        next warn("Webfinger title value for #{key} is not a string: #{value}, ignoring")
         
     | 
| 
      
 27 
     | 
    
         
            +
                      else
         
     | 
| 
      
 28 
     | 
    
         
            +
                        true
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    if !data.empty?
         
     | 
| 
      
 33 
     | 
    
         
            +
                      new(data)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    else
         
     | 
| 
      
 35 
     | 
    
         
            +
                      warn("All Webfinger link titles pruned: #{data.inspect}, ignoring")
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     |