webfinger.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. """
  2. Methods for retrieving and parsing webfinger information.
  3. """
  4. from xml.dom import minidom
  5. from ostatus.fetcher import fetch
  6. class WebFingerError(Exception):
  7. """
  8. Raised when some kind of webfinger related error needs to
  9. be reported.
  10. """
  11. pass
  12. def finger(identifier):
  13. """
  14. Find the host-meta for a host and then access its
  15. webfinger endpoint, returning the LinkS found there.
  16. """
  17. if not identifier.startswith('acct:'):
  18. identifier = 'acct:%s' % identifier
  19. host = parse_for_host(identifier)
  20. host_meta = get_host_meta(host)
  21. template = parse_host_meta(host_meta)
  22. if template:
  23. template = template.replace('{uri}', identifier)
  24. else:
  25. raise WebFingerError('no lrdd template found')
  26. finger_links = _finger(template)
  27. links = parse_links(finger_links)
  28. return links
  29. def _finger(uri):
  30. """Actual implementation of finger, now that we know where to look"""
  31. content = fetch(uri)
  32. doc = minidom.parseString(content).documentElement
  33. return doc.getElementsByTagName('Link')
  34. def parse_links(links):
  35. """Turn the webfinger links into a python list of dicts."""
  36. link_info = []
  37. for link in links:
  38. attr_data = {}
  39. for attribute in list(link.attributes.keys()):
  40. attr = link.attributes[attribute]
  41. attr_data[attr.name] = attr.value
  42. link_info.append(attr_data)
  43. return link_info
  44. def parse_host_meta(host_meta):
  45. """Extract the lrdd template from host meta."""
  46. doc = minidom.parseString(host_meta).documentElement
  47. template = None
  48. for link in doc.getElementsByTagName('Link'):
  49. if link.getAttribute('rel') == 'lrdd':
  50. template = link.getAttribute('template')
  51. return template
  52. def parse_for_host(identifier):
  53. """
  54. Get the host portion of a webfinger address.
  55. """
  56. domain = identifier.split('@')[1]
  57. return domain
  58. def get_host_meta(host):
  59. """Ping a host for its host-meta file."""
  60. url = 'http://%s/.well-known/host-meta' % host
  61. return fetch(url)