summaryrefslogtreecommitdiffstats
path: root/vendor/gems/ruby-openid-2.1.4/lib/openid/yadis/xrds.rb
blob: 0ebf34ab41d2e30bf16d3fa3c2bd3a5f58c1a959 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
require 'rexml/document'
require 'rexml/element'
require 'rexml/xpath'

require 'openid/yadis/xri'

module OpenID
  module Yadis

    XRD_NS_2_0 = 'xri://$xrd*($v*2.0)'
    XRDS_NS = 'xri://$xrds'

    XRDS_NAMESPACES = {
      'xrds' => XRDS_NS,
      'xrd' => XRD_NS_2_0,
    }

    class XRDSError < StandardError; end

    # Raised when there's an assertion in the XRDS that it does not
    # have the authority to make.
    class XRDSFraud < XRDSError
    end

    def Yadis::get_canonical_id(iname, xrd_tree)
      # Return the CanonicalID from this XRDS document.
      #
      # @param iname: the XRI being resolved.
      # @type iname: unicode
      #
      # @param xrd_tree: The XRDS output from the resolver.
      #
      # @returns: The XRI CanonicalID or None.
      # @returntype: unicode or None

      xrd_list = []
      REXML::XPath::match(xrd_tree.root, '/xrds:XRDS/xrd:XRD', XRDS_NAMESPACES).each { |el|
        xrd_list << el
      }

      xrd_list.reverse!

      cid_elements = []

      if !xrd_list.empty?
        xrd_list[0].elements.each { |e|
          if !e.respond_to?('name')
            next
          end
          if e.name == 'CanonicalID'
            cid_elements << e
          end
        }
      end

      cid_element = cid_elements[0]

      if !cid_element
        return nil
      end

      canonicalID = XRI.make_xri(cid_element.text)

      childID = canonicalID.downcase

      xrd_list[1..-1].each { |xrd|
        parent_sought = childID[0...childID.rindex('!')]

        parent = XRI.make_xri(xrd.elements["CanonicalID"].text)

        if parent_sought != parent.downcase
          raise XRDSFraud.new(sprintf("%s can not come from %s", parent_sought,
                                      parent))
        end

        childID = parent_sought
      }

      root = XRI.root_authority(iname)
      if not XRI.provider_is_authoritative(root, childID)
        raise XRDSFraud.new(sprintf("%s can not come from root %s", childID, root))
      end

      return canonicalID
    end

    class XRDSError < StandardError
    end

    def Yadis::parseXRDS(text)
      if text.nil?
        raise XRDSError.new("Not an XRDS document.")
      end

      begin
        d = REXML::Document.new(text)
      rescue RuntimeError => why
        raise XRDSError.new("Not an XRDS document. Failed to parse XML.")
      end

      if is_xrds?(d)
        return d
      else
        raise XRDSError.new("Not an XRDS document.")
      end
    end

    def Yadis::is_xrds?(xrds_tree)
      xrds_root = xrds_tree.root
      return (!xrds_root.nil? and
        xrds_root.name == 'XRDS' and
        xrds_root.namespace == XRDS_NS)
    end

    def Yadis::get_yadis_xrd(xrds_tree)
      REXML::XPath.each(xrds_tree.root,
                        '/xrds:XRDS/xrd:XRD[last()]',
                        XRDS_NAMESPACES) { |el|
        return el
      }
      raise XRDSError.new("No XRD element found.")
    end

    # aka iterServices in Python
    def Yadis::each_service(xrds_tree, &block)
      xrd = get_yadis_xrd(xrds_tree)
      xrd.each_element('Service', &block)
    end

    def Yadis::services(xrds_tree)
      s = []
      each_service(xrds_tree) { |service|
        s << service
      }
      return s
    end

    def Yadis::expand_service(service_element)
      es = service_element.elements
      uris = es.each('URI') { |u| }
      uris = prio_sort(uris)
      types = es.each('Type/text()')
      # REXML::Text objects are not strings.
      types = types.collect { |t| t.to_s }
      uris.collect { |uri| [types, uri.text, service_element] }
    end

    # Sort a list of elements that have priority attributes.
    def Yadis::prio_sort(elements)
      elements.sort { |a,b|
        a.attribute('priority').to_s.to_i <=> b.attribute('priority').to_s.to_i
      }
    end
  end
end