lemoncurry/wellknowns/views/webfinger.py

60 lines
2.3 KiB
Python
Raw Permalink Normal View History

from django.http import HttpResponseBadRequest, HttpResponseRedirect
from urllib.parse import urlencode, urlparse
from users.models import User
AVATAR = 'http://webfinger.net/rel/avatar'
PROFILE_PAGE = 'http://webfinger.net/rel/profile-page'
BRIDGY_FED = 'https://fed.brid.gy/.well-known/webfinger'
def https_resource_matching(resource):
"""
Takes a `urllib.parse.urlparse` tuple representing a WebFinger resource and
translates ``mailto:`` and ``xmpp:`` resources to an equivalent ``https:``
resource, if a user with matching email or XMPP address exists locally.
Will throw `User.DoesNotExist` if no such user exists.
"""
if resource.scheme == 'mailto':
query = {'email': resource.path}
else:
query = {'xmpp': resource.path}
return User.objects.get(**query).absolute_url
def webfinger(request):
"""
A thin wrapper around Bridgy Fed's implementation of WebFinger.
In most cases, this view simply redirects to the same endpoint at Bridgy.
However, Bridgy does not support the ``mailto:`` and ``xmpp:`` resource
schemes - quite reasonably, since there's no possible way to discover the
``acct:`` they go with! - so resources with those schemes are translated
locally into an ``https:`` URL representing the same person, and *then*
redirected to Bridgy.
Additionally, WebFinger requests with a missing or malformed resource will
be rejected immediately rather than passed on to Bridgy.
Note that the translation step will only be applied if there exists a
:model:`users.User` with matching email or XMPP address. Otherwise, the
original resource will be preserved in the redirect - and likely fail to
find anything at Bridgy's end either.
"""
if 'resource' not in request.GET:
return HttpResponseBadRequest('resource parameter missing')
resource = request.GET['resource']
try:
res = urlparse(resource)
except ValueError:
return HttpResponseBadRequest('resource parameter malformed')
if res.scheme in ('mailto', 'xmpp'):
try:
resource = https_resource_matching(res)
except User.DoesNotExist:
pass
query = urlencode({'resource': resource})
return HttpResponseRedirect(BRIDGY_FED + '?' + query)