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):
84 84
         return '{0} {1}'.format(self.first_name, self.last_name)
85 85
 
86 86
     def get_absolute_url(self):
87
-        return self.url
87
+        return self.absolute_url
88
+
89
+    @property
90
+    def absolute_url(self):
91
+        return self.full_url
88 92
 
89 93
     @property
90 94
     def full_url(self):

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

@@ -1,50 +1,59 @@
1
-from django.http import HttpResponseBadRequest, HttpResponseNotFound
2
-from django.http import JsonResponse
1
+from django.http import HttpResponseBadRequest, HttpResponseRedirect
2
+from urllib.parse import urlencode, urlparse
3
+
3 4
 from users.models import User
4
-from django.shortcuts import get_object_or_404
5
-from urllib.parse import urlparse, urljoin
6
-from lemoncurry.utils import origin
7 5
 
8 6
 AVATAR = 'http://webfinger.net/rel/avatar'
9 7
 PROFILE_PAGE = 'http://webfinger.net/rel/profile-page'
8
+BRIDGY_FED = 'https://fed.brid.gy/.well-known/webfinger'
9
+
10
+
11
+def https_resource_matching(resource):
12
+    """
13
+    Takes a `urllib.parse.urlparse` tuple representing a WebFinger resource and
14
+    translates ``mailto:`` and ``xmpp:`` resources to an equivalent ``https:``
15
+    resource, if a user with matching email or XMPP address exists locally.
16
+    Will throw `User.DoesNotExist` if no such user exists.
17
+    """
18
+    if resource.scheme == 'mailto':
19
+        query = {'email': resource.path}
20
+    else:
21
+        query = {'xmpp': resource.path}
22
+    return User.objects.get(**query).absolute_url
10 23
 
11 24
 
12 25
 def webfinger(request):
26
+    """
27
+    A thin wrapper around Bridgy Fed's implementation of WebFinger.
28
+
29
+    In most cases, this view simply redirects to the same endpoint at Bridgy.
30
+    However, Bridgy does not support the ``mailto:`` and ``xmpp:`` resource
31
+    schemes - quite reasonably, since there's no possible way to discover the
32
+    ``acct:`` they go with! - so resources with those schemes are translated
33
+    locally into an ``https:`` URL representing the same person, and *then*
34
+    redirected to Bridgy.
35
+
36
+    Additionally, WebFinger requests with a missing or malformed resource will
37
+    be rejected immediately rather than passed on to Bridgy.
38
+
39
+    Note that the translation step will only be applied if there exists a
40
+    :model:`users.User` with matching email or XMPP address. Otherwise, the
41
+    original resource will be preserved in the redirect - and likely fail to
42
+    find anything at Bridgy's end either.
43
+    """
13 44
     if 'resource' not in request.GET:
14 45
         return HttpResponseBadRequest('resource parameter missing')
46
+    resource = request.GET['resource']
15 47
     try:
16
-        resource = urlparse(request.GET['resource'])
48
+        res = urlparse(resource)
17 49
     except ValueError:
18 50
         return HttpResponseBadRequest('resource parameter malformed')
19 51
 
20
-    if resource.scheme in ('mailto', 'acct', 'xmpp'):
21
-        user = get_object_or_404(User, email=resource.path)
22
-    elif resource.scheme in ('http', 'https'):
23
-        user = get_object_or_404(User, pk=1)
24
-    else:
25
-        return HttpResponseNotFound('resource not found on this server')
26
-
27
-    base = origin(request)
28
-
29
-    def link(rel, href, type):
30
-        return {'rel': rel, 'href': urljoin(base, href), 'type': type}
31
-
32
-    key_links = tuple(link(
33
-        rel='pgpkey',
34
-        href=key.file.url,
35
-        type='application/pgp-keys',
36
-    ) for key in user.keys.all())
37
-
38
-    info = {
39
-        'subject': 'acct:' + user.email,
40
-        'aliases': (
41
-            urljoin(base, user.url),
42
-            'mailto:' + user.email,
43
-            'xmpp:' + user.xmpp,
44
-        ),
45
-        'links': (
46
-            link(rel=AVATAR, href=user.avatar.url, type='image/png'),
47
-            link(rel=PROFILE_PAGE, href=user.url, type='text/html'),
48
-        ) + key_links,
49
-    }
50
-    return JsonResponse(info, content_type='application/jrd+json')
52
+    if res.scheme in ('mailto', 'xmpp'):
53
+        try:
54
+            resource = https_resource_matching(res)
55
+        except User.DoesNotExist:
56
+            pass
57
+
58
+    query = urlencode({'resource': resource})
59
+    return HttpResponseRedirect(BRIDGY_FED + '?' + query)

Loading…
Cancel
Save