Replace the previous WebFinger implementation with a fairly simple forwarder to Bridgy Fed, so that Bridgy Fed will work eventually

Danielle McLean 4 years ago
parent 9f3cbac3c4
commit 46c2224a4f
Signed by: 00dani
GPG Key ID: D111F8C5A2560F19
  1. 6
  2. 83

@ -84,7 +84,11 @@ class User(ModelMeta, AbstractUser):
return '{0} {1}'.format(self.first_name, self.last_name)
def get_absolute_url(self):
return self.url
return self.absolute_url
def absolute_url(self):
return self.full_url
def full_url(self):

@ -1,50 +1,59 @@
from django.http import HttpResponseBadRequest, HttpResponseNotFound
from django.http import JsonResponse
from django.http import HttpResponseBadRequest, HttpResponseRedirect
from urllib.parse import urlencode, urlparse
from users.models import User
from django.shortcuts import get_object_or_404
from urllib.parse import urlparse, urljoin
from lemoncurry.utils import origin
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}
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']
resource = urlparse(request.GET['resource'])
res = urlparse(resource)
except ValueError:
return HttpResponseBadRequest('resource parameter malformed')
if resource.scheme in ('mailto', 'acct', 'xmpp'):
user = get_object_or_404(User, email=resource.path)
elif resource.scheme in ('http', 'https'):
user = get_object_or_404(User, pk=1)
return HttpResponseNotFound('resource not found on this server')
base = origin(request)
def link(rel, href, type):
return {'rel': rel, 'href': urljoin(base, href), 'type': type}
key_links = tuple(link(
) for key in user.keys.all())
info = {
'subject': 'acct:' +,
'aliases': (
urljoin(base, user.url),
'mailto:' +,
'xmpp:' + user.xmpp,
'links': (
link(rel=AVATAR, href=user.avatar.url, type='image/png'),
link(rel=PROFILE_PAGE, href=user.url, type='text/html'),
) + key_links,
return JsonResponse(info, content_type='application/jrd+json')
if res.scheme in ('mailto', 'xmpp'):
resource = https_resource_matching(res)
except User.DoesNotExist:
query = urlencode({'resource': resource})
return HttpResponseRedirect(BRIDGY_FED + '?' + query)