Browse Source

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

tags/v1.9.8
Danielle McLean 1 year ago
parent
commit
46c2224a4f
Signed by: Danielle McLean <dani@00dani.me> GPG Key ID: D111F8C5A2560F19
2 changed files with 51 additions and 38 deletions
  1. +5
    -1
      users/models.py
  2. +46
    -37
      wellknowns/views/webfinger.py

+ 5
- 1
users/models.py View File

@@ -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

@property
def absolute_url(self):
return self.full_url

@property
def full_url(self):

+ 46
- 37
wellknowns/views/webfinger.py View File

@@ -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

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:
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)
else:
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(
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')
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)

Loading…
Cancel
Save