From 2ff95f0e60ffb6316b4acca7cff5593676dce11e Mon Sep 17 00:00:00 2001 From: Jeremy Carbaugh Date: Thu, 11 Feb 2010 17:52:34 -0500 Subject: [PATCH] initial commit --- .gitignore | 1 + README.rst | 1 + example_hostmeta.xml | 10 +++++ example_xrd.xml | 20 +++++++++ pywebfinger.py | 101 +++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + 6 files changed, 134 insertions(+) create mode 100644 .gitignore create mode 100644 README.rst create mode 100644 example_hostmeta.xml create mode 100644 example_xrd.xml create mode 100644 pywebfinger.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e99e36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..26ae532 --- /dev/null +++ b/README.rst @@ -0,0 +1 @@ +Very early version of simple Python client. \ No newline at end of file diff --git a/example_hostmeta.xml b/example_hostmeta.xml new file mode 100644 index 0000000..9dfac7a --- /dev/null +++ b/example_hostmeta.xml @@ -0,0 +1,10 @@ + + + + + gmail.com + + + This is my webfinger service + + diff --git a/example_xrd.xml b/example_xrd.xml new file mode 100644 index 0000000..3c1a5dd --- /dev/null +++ b/example_xrd.xml @@ -0,0 +1,20 @@ + + + acct:joe@example.com + http://example.com/profiles/joe + + http://portablecontacts.net/spec/1.0 + http://example.com/api/people/ + + + http://webfinger.net/rel/profile-page + http://microformats.org/profile/hcard + describedby + text/html + http://example.com/profiles/joe + + + http://webfinger.net/rel/avatar + http://example.com/profiles/joe/photo + + \ No newline at end of file diff --git a/pywebfinger.py b/pywebfinger.py new file mode 100644 index 0000000..27c2e22 --- /dev/null +++ b/pywebfinger.py @@ -0,0 +1,101 @@ +from xrd import XRD +import re +import urllib, urllib2 + +# +# get webfinger response +# + +ACCT_RE = re.compile(r'acct:([\w_.]+)@([\w:_.]+)') +URLTEMPLATE_RE = re.compile(r'\{(%?)(id|uri|userinfo|host)\}') + +def _var_replacer(email): + (local, host) = email.split('@') + 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): + + # 1) resolve host-meta URL for acct URI + + (local, host) = email.split('@') + hostmeta_url = "http://%s/.well-known/host-meta" % host + + # 2) obtain host-meta file + + 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: + + xrd_url = URLTEMPLATE_RE.sub(_var_replacer(email), links[0].template) + + conn = opener.open(xrd_url) + xrd_response = conn.read() if raw else XRD.parse(conn.read()) + conn.close() + + return xrd_response + +# +# methods to parse finger response +# + +def _link(resource, rel, type_=None): + for link in resource.links: + if link.rel == rel and (type_ is None or link.type == type_): + return link.href + +def service(resource): + return _link(resource, 'http://portablecontacts.net/spec/1.0') + +def profile(resource): + return _link(resource, 'http://webfinger.net/rel/profile-page') + +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') + + +if __name__ == '__main__': + import sys + res = finger(sys.argv[1]) + print "Profile:", profile(res) + print "HCard: ", hcard(res) + print "XFN: ", xfn(res) + print "OpenID: ", openid(res) + print "Avatar: ", avatar(res) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2b137f0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +python-xrd \ No newline at end of file