xrds.rb
155 lines
| 3.7 KiB
| text/x-ruby
|
RubyLexer
|
r2376 | 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 | ||||