python-webfinger/webfinger.py

135 wiersze
4.1 KiB
Python
Czysty Zwykły widok Historia

import urllib
import urllib2
2010-02-11 22:52:34 +00:00
__version__ = '0.2'
2012-04-04 22:19:34 +00:00
RELS = {
2012-04-04 21:58:54 +00:00
'activity_streams': 'http://activitystrea.ms/spec/1.0',
'avatar': 'http://webfinger.net/rel/avatar',
'hcard': 'http://microformats.org/profile/hcard',
'open_id': 'http://specs.openid.net/auth/2.0/provider',
2012-04-04 21:58:54 +00:00
'opensocial': 'http://ns.opensocial.org/2008/opensocial/activitystreams',
'portable_contacts': 'http://portablecontacts.net/spec/1.0',
'profile': 'http://webfinger.net/rel/profile-page',
'xfn': 'http://gmpg.org/xfn/11',
}
2010-02-11 22:52:34 +00:00
WEBFINGER_TYPES = (
'lrdd', # current
'http://lrdd.net/rel/descriptor', # deprecated on 12/11/2009
'http://webfinger.net/rel/acct-desc', # deprecated on 11/26/2009
'http://webfinger.info/rel/service', # deprecated on 09/17/2009
)
2010-02-11 22:52:34 +00:00
UNOFFICIAL_ENDPOINTS = {
2012-04-04 22:01:56 +00:00
'facebook.com': 'facebook-webfinger.appspot.com',
'twitter.com': 'twitter-webfinger.appspot.com',
}
2012-04-03 23:38:59 +00:00
class WebFingerException(Exception):
pass
2010-02-11 22:52:34 +00:00
class WebFingerResponse(object):
2012-04-03 23:34:45 +00:00
def __init__(self, xrd, insecure):
self.insecure = insecure
self._xrd = xrd
2012-04-03 23:34:45 +00:00
def __getattr__(self, name):
if name in RELS:
return self._xrd.find_link(RELS[name], attr='href')
return getattr(self._xrd, name)
class WebFingerClient(object):
2012-04-03 23:34:45 +00:00
def __init__(self, host, timeout=None, official=False):
self._host = host
self._official = official
self._opener = urllib2.build_opener(urllib2.HTTPRedirectHandler())
self._opener.addheaders = [('User-agent', 'python-webfinger')]
2012-04-03 23:34:45 +00:00
2012-04-04 00:42:59 +00:00
self._timeout = timeout
def _hm_hosts(self, xrd):
hosts = [e.value for e in xrd.elements if e.name == 'hm:Host']
if not self._official and hosts and self._host in UNOFFICIAL_ENDPOINTS:
hosts.append(UNOFFICIAL_ENDPOINTS[self._host])
return hosts
2012-04-03 23:34:45 +00:00
def xrd(self, url, raw=False):
2012-04-04 22:22:34 +00:00
from xrd import XRD
2012-04-04 00:42:59 +00:00
conn = self._opener.open(url, timeout=self._timeout)
response = conn.read()
conn.close()
return response if raw else XRD.parse(response)
2012-04-03 23:34:45 +00:00
def hostmeta(self, protocol):
if not self._official and self._host in UNOFFICIAL_ENDPOINTS:
host = UNOFFICIAL_ENDPOINTS[self._host]
else:
host = self._host
hostmeta_url = "%s://%s/.well-known/host-meta" % (protocol, host)
return self.xrd(hostmeta_url)
2012-04-03 23:34:45 +00:00
def finger(self, username):
try:
hm = self.hostmeta('https')
insecure = False
except (urllib2.URLError, urllib2.HTTPError):
hm = self.hostmeta('http')
insecure = True
hm_hosts = self._hm_hosts(hm)
2012-04-03 23:34:45 +00:00
if hm_hosts and self._host not in hm_hosts:
2012-04-03 23:38:59 +00:00
raise WebFingerException("hostmeta host did not match account host")
2012-04-03 23:34:45 +00:00
template = hm.find_link(WEBFINGER_TYPES, attr='template')
if not template.startswith('https://'):
insecure = True
xrd_url = template.replace('{uri}',
urllib.quote_plus('acct:%s@%s' % (username, self._host)))
2012-04-03 23:34:45 +00:00
data = self.xrd(xrd_url)
return WebFingerResponse(data, insecure)
2010-02-11 22:52:34 +00:00
def finger(identifier, timeout=None, official=False):
if identifier.startswith('acct:'):
(acct, identifier) = identifier.split(':', 1)
(username, host) = identifier.split('@')
client = WebFingerClient(host, timeout=timeout, official=official)
return client.finger(username)
2010-02-11 22:52:34 +00:00
2010-02-11 22:52:34 +00:00
if __name__ == '__main__':
2012-04-04 22:19:34 +00:00
# example usage
2010-02-11 22:52:34 +00:00
import sys
2012-04-04 22:19:34 +00:00
try:
acct = sys.argv[1]
except IndexError:
acct = "jcarbaugh@twitter.com"
wf = finger(acct)
2012-04-04 21:58:54 +00:00
print "Activity Streams: ", wf.activity_streams
print "Avatar: ", wf.avatar
print "HCard: ", wf.hcard
print "OpenID: ", wf.open_id
print "Open Social: ", wf.opensocial
print "Profile: ", wf.profile
print "Portable Contacts: ", wf.portable_contacts
print "XFN: ", wf.find_link('http://gmpg.org/xfn/11', attr='href')
2012-04-04 22:19:34 +00:00
if wf.insecure:
2012-04-04 22:19:34 +00:00
print "*** Warning: Data was retrieved over an insecure connection"