Work towards the security stuff described at

http://code.google.com/p/webfinger/wiki/WebFingerProtocol

The code now looks for the host-meta file via https. If it doesn't find it it
falls back to http, but causes the response's 'insecure' attribute to be set
to True.

The 'insecure' attribute also gets set to True if the user's XRD URL is not an
https:// url.

This doesn't do any checking of certificate validity, or check whether the XML
is signed.
pull/1/head
buttoj3 2011-04-11 12:12:16 +01:00
rodzic b893ca3fa8
commit 142bba7a6d
1 zmienionych plików z 20 dodań i 11 usunięć

Wyświetl plik

@ -22,7 +22,8 @@ class WebFingerExpection(Exception):
class WebFingerResponse(object): class WebFingerResponse(object):
def __init__(self, xrd): def __init__(self, xrd, insecure):
self.insecure = insecure
self._xrd = xrd self._xrd = xrd
def __getattr__(self, name): def __getattr__(self, name):
@ -32,9 +33,8 @@ class WebFingerResponse(object):
class WebFingerClient(object): class WebFingerClient(object):
def __init__(self, host, secure=False): def __init__(self, host):
self._host = host self._host = host
self._secure = secure
self._opener = urllib2.build_opener(urllib2.HTTPRedirectHandler()) self._opener = urllib2.build_opener(urllib2.HTTPRedirectHandler())
self._opener.addheaders = [('User-agent', 'python-webfinger')] self._opener.addheaders = [('User-agent', 'python-webfinger')]
@ -47,39 +47,48 @@ class WebFingerClient(object):
conn.close() conn.close()
return response if raw else XRD.parse(response) return response if raw else XRD.parse(response)
def hostmeta(self): def hostmeta(self, protocol):
protocol = "https" if self._secure else "http"
hostmeta_url = "%s://%s/.well-known/host-meta" % (protocol, self._host) hostmeta_url = "%s://%s/.well-known/host-meta" % (protocol, self._host)
return self.xrd(hostmeta_url) return self.xrd(hostmeta_url)
def finger(self, username): def finger(self, username):
try:
hm = self.hostmeta() hm = self.hostmeta('https')
insecure = False
except (urllib2.URLError, urllib2.HTTPError):
hm = self.hostmeta('http')
insecure = True
hm_hosts = self._hm_hosts(hm) hm_hosts = self._hm_hosts(hm)
if self._host not in hm_hosts: if self._host not in hm_hosts:
raise WebFingerExpection("hostmeta host did not match account host") raise WebFingerExpection("hostmeta host did not match account host")
template = hm.find_link(WEBFINGER_TYPES, attr='template') template = hm.find_link(WEBFINGER_TYPES, attr='template')
if not template.startswith('https://'):
insecure = True
xrd_url = template.replace('{uri}', xrd_url = template.replace('{uri}',
urllib.quote_plus('acct:%s@%s' % (username, self._host))) urllib.quote_plus('acct:%s@%s' % (username, self._host)))
return WebFingerResponse(self.xrd(xrd_url)) data = self.xrd(xrd_url)
return WebFingerResponse(data, insecure)
def finger(identifier, secure=False): def finger(identifier):
if identifier.startswith('acct:'): if identifier.startswith('acct:'):
(acct, identifier) = identifier.split(':', 1) (acct, identifier) = identifier.split(':', 1)
(username, host) = identifier.split('@') (username, host) = identifier.split('@')
client = WebFingerClient(host, secure) client = WebFingerClient(host)
return client.finger(username) return client.finger(username)
# example main method # example main method
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
wf = finger(sys.argv[1], True) wf = finger(sys.argv[1])
print "Avatar: ", wf.avatar print "Avatar: ", wf.avatar
print "HCard: ", wf.hcard print "HCard: ", wf.hcard
print "OpenID: ", wf.open_id print "OpenID: ", wf.open_id
print "Profile:", wf.profile print "Profile:", wf.profile
print "XFN: ", wf.find_link('http://gmpg.org/xfn/11', attr='href') print "XFN: ", wf.find_link('http://gmpg.org/xfn/11', attr='href')
if wf.insecure:
print "Warning: Data was retrieved over an insecure connection"