File: xrds.rb

package info (click to toggle)
ruby-openid 2.1.8debian-6
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 1,676 kB
  • sloc: ruby: 16,506; xml: 219; sh: 24; makefile: 2
file content (165 lines) | stat: -rw-r--r-- 4,133 bytes parent folder | download | duplicates (2)
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
156
157
158
159
160
161
162
163
164
165
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)
      disable_entity_expansion do
        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
    end

    def Yadis::disable_entity_expansion
      _previous_ = REXML::Document::entity_expansion_limit
      REXML::Document::entity_expansion_limit = 0
      yield
    ensure
      REXML::Document::entity_expansion_limit = _previous_
    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