kopia lustrzana https://github.com/jcarbaugh/python-webfinger
big ol' refactor. add web finger relation shortcuts. add class-based webfinger client.
rodzic
0df7a42a8e
commit
2e1d9ed252
17
README.rst
17
README.rst
|
@ -9,7 +9,22 @@ Example::
|
||||||
|
|
||||||
from pywebfinger import finger
|
from pywebfinger import finger
|
||||||
|
|
||||||
res = finger('user@host.com')
|
wf = finger('user@host.com')
|
||||||
|
print wf.profile
|
||||||
|
print wf.hcard
|
||||||
|
|
||||||
|
The following relation types are supported:
|
||||||
|
|
||||||
|
* avatar: http://webfinger.net/rel/avatar
|
||||||
|
* hcard: http://microformats.org/profile/hcard
|
||||||
|
* open_id: http://specs.openid.net/auth/2.0/provider
|
||||||
|
* portable_contacts: http://portablecontacts.net/spec/1.0
|
||||||
|
* profile: http://webfinger.net/rel/profile-page
|
||||||
|
* xfn: http://gmpg.org/xfn/11
|
||||||
|
|
||||||
|
Other relation types can be accessed directly from the XRD document.::
|
||||||
|
|
||||||
|
print wf.find_link('http://example.com/example/spec', attr='href')
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
============
|
============
|
||||||
|
|
151
pywebfinger.py
151
pywebfinger.py
|
@ -2,100 +2,85 @@ from xrd import XRD
|
||||||
import re
|
import re
|
||||||
import urllib, urllib2
|
import urllib, urllib2
|
||||||
|
|
||||||
#
|
RELS = {
|
||||||
# get webfinger response
|
'avatar': 'http://webfinger.net/rel/avatar',
|
||||||
#
|
'hcard': 'http://microformats.org/profile/hcard',
|
||||||
|
'open_id': 'http://specs.openid.net/auth/2.0/provider',
|
||||||
|
'portable_contacts': 'http://portablecontacts.net/spec/1.0',
|
||||||
|
'profile': 'http://webfinger.net/rel/profile-page',
|
||||||
|
'xfn': 'http://gmpg.org/xfn/11',
|
||||||
|
}
|
||||||
|
|
||||||
ACCT_RE = re.compile(r'acct:([\w_.]+)@([\w:_.]+)')
|
WEBFINGER_TYPES = (
|
||||||
URLTEMPLATE_RE = re.compile(r'\{(%?)(id|uri|userinfo|host)\}')
|
'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
|
||||||
|
)
|
||||||
|
|
||||||
def _var_replacer(email):
|
class WebFingerExpection(Exception):
|
||||||
(local, host) = email.split('@')
|
pass
|
||||||
uri = 'acct:%s' % email
|
|
||||||
rvars = {
|
|
||||||
'id': uri, # deprecated on 9/17/2009
|
|
||||||
'uri': uri,
|
|
||||||
'userinfo': local,
|
|
||||||
'host': host,
|
|
||||||
}
|
|
||||||
def _replacer(match):
|
|
||||||
(encode, var) = match.groups()
|
|
||||||
val = rvars[var]
|
|
||||||
if encode == '%':
|
|
||||||
val = urllib.quote_plus(val)
|
|
||||||
return val
|
|
||||||
return _replacer
|
|
||||||
|
|
||||||
def finger(email, raw=False):
|
class WebFingerResponse(object):
|
||||||
|
|
||||||
# 1) resolve host-meta URL for acct URI
|
def __init__(self, xrd):
|
||||||
|
self._xrd = xrd
|
||||||
|
|
||||||
(local, host) = email.split('@')
|
def __getattr__(self, name):
|
||||||
hostmeta_url = "http://%s/.well-known/host-meta" % host
|
if name in RELS:
|
||||||
|
return self._xrd.find_link(RELS[name], attr='href')
|
||||||
# 2) obtain host-meta file
|
return getattr(self._xrd, name)
|
||||||
|
|
||||||
redirect_handler = urllib2.HTTPRedirectHandler()
|
|
||||||
opener = urllib2.build_opener(redirect_handler)
|
|
||||||
opener.addheaders = [('User-agent', 'python-webfinger')]
|
|
||||||
conn = opener.open(hostmeta_url)
|
|
||||||
xrd = XRD.parse(conn.read())
|
|
||||||
#xrd = XRD.parse(open('example_hostmeta.xml').read())
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
# verify resource.host == host
|
|
||||||
|
|
||||||
webfinger_types = (
|
|
||||||
'http://webfinger.net/rel/acct-desc', # current
|
|
||||||
'http://webfinger.info/rel/service', # deprecated on 9/17/2009
|
|
||||||
'lrdd', # used by Google
|
|
||||||
)
|
|
||||||
|
|
||||||
links = [link for link in xrd.links if link.rel in webfinger_types]
|
|
||||||
|
|
||||||
if links:
|
class WebFingerClient(object):
|
||||||
|
|
||||||
xrd_url = URLTEMPLATE_RE.sub(_var_replacer(email), links[0].template)
|
def __init__(self, host, secure=False):
|
||||||
|
self._host = host
|
||||||
conn = opener.open(xrd_url)
|
self._secure = secure
|
||||||
xrd_response = conn.read() if raw else XRD.parse(conn.read())
|
self._opener = urllib2.build_opener(urllib2.HTTPRedirectHandler())
|
||||||
|
self._opener.addheaders = [('User-agent', 'python-webfinger')]
|
||||||
|
|
||||||
|
def _hm_hosts(self, xrd):
|
||||||
|
return [e.value for e in xrd.elements if e.name == 'hm:Host']
|
||||||
|
|
||||||
|
def xrd(self, url, raw=False):
|
||||||
|
conn = self._opener.open(url)
|
||||||
|
response = conn.read()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
return response if raw else XRD.parse(response)
|
||||||
|
|
||||||
|
def hostmeta(self):
|
||||||
|
protocol = "https" if self._secure else "http"
|
||||||
|
hostmeta_url = "%s://%s/.well-known/host-meta" % (protocol, self._host)
|
||||||
|
return self.xrd(hostmeta_url)
|
||||||
|
|
||||||
|
def finger(self, username):
|
||||||
|
|
||||||
return xrd_response
|
hm = self.hostmeta()
|
||||||
|
hm_hosts = self._hm_hosts(hm)
|
||||||
#
|
|
||||||
# methods to parse finger response
|
|
||||||
#
|
|
||||||
|
|
||||||
def _link(resource, rel, type_=None):
|
if self._host not in hm_hosts:
|
||||||
for link in resource.links:
|
raise WebFingerExpection("hostmeta host did not match account host")
|
||||||
if link.rel == rel and (type_ is None or link.type == type_):
|
|
||||||
return link.href
|
template = hm.find_link(WEBFINGER_TYPES, attr='template')
|
||||||
|
xrd_url = template.replace('{uri}',
|
||||||
|
urllib.quote_plus('acct:%s@%s' % (username, self._host)))
|
||||||
|
|
||||||
|
return WebFingerResponse(self.xrd(xrd_url))
|
||||||
|
|
||||||
def service(resource):
|
def finger(identifier, secure=False):
|
||||||
return _link(resource, 'http://portablecontacts.net/spec/1.0')
|
if identifier.startswith('acct:'):
|
||||||
|
(acct, identifier) = identifier.split(':', 1)
|
||||||
def profile(resource):
|
(username, host) = identifier.split('@')
|
||||||
return _link(resource, 'http://webfinger.net/rel/profile-page')
|
client = WebFingerClient(host, secure)
|
||||||
|
return client.finger(username)
|
||||||
def hcard(resource):
|
|
||||||
return _link(resource, 'http://microformats.org/profile/hcard')
|
|
||||||
|
|
||||||
def openid(resource):
|
|
||||||
return _link(resource, 'http://specs.openid.net/auth/2.0/provider')
|
|
||||||
|
|
||||||
def xfn(resource):
|
|
||||||
return _link(resource, 'http://gmpg.org/xfn/11')
|
|
||||||
|
|
||||||
def avatar(resource):
|
|
||||||
return _link(resource, 'http://webfinger.net/rel/avatar')
|
|
||||||
|
|
||||||
|
# example main method
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
res = finger(sys.argv[1])
|
wf = finger(sys.argv[1], True)
|
||||||
print "Profile:", profile(res)
|
print "Avatar: ", wf.avatar
|
||||||
print "HCard: ", hcard(res)
|
print "HCard: ", wf.hcard
|
||||||
print "XFN: ", xfn(res)
|
print "OpenID: ", wf.open_id
|
||||||
print "OpenID: ", openid(res)
|
print "Profile:", wf.profile
|
||||||
print "Avatar: ", avatar(res)
|
print "XFN: ", wf.find_link('http://gmpg.org/xfn/11', attr='href')
|
||||||
|
|
Ładowanie…
Reference in New Issue