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

This commit is contained in:
Danielle McLean 2018-05-11 13:23:47 +10:00
parent 9f3cbac3c4
commit 46c2224a4f
Signed by untrusted user: 00dani
GPG key ID: D111F8C5A2560F19
2 changed files with 50 additions and 37 deletions

View file

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

View file

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