From 1a9582213a407b9c4f092f1673265691bfc5bedb Mon Sep 17 00:00:00 2001 From: Danielle McLean Date: Fri, 27 Oct 2017 13:24:57 +1100 Subject: [PATCH] Add WebFinger support and refactor some of the request manip stuff --- home/views.py | 5 +-- lemoncurry/templatetags/lemoncurry_tags.py | 18 ++------- lemoncurry/utils.py | 22 +++++++++++ wellknowns/urls.py | 1 + wellknowns/views/__init__.py | 1 + wellknowns/views/host_meta.py | 13 ++++--- wellknowns/views/webfinger.py | 43 ++++++++++++++++++++++ 7 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 lemoncurry/utils.py create mode 100644 wellknowns/views/webfinger.py diff --git a/home/views.py b/home/views.py index 8d20de3..bc6e3e8 100644 --- a/home/views.py +++ b/home/views.py @@ -1,7 +1,6 @@ from django.shortcuts import get_object_or_404, render from users.models import User -from lemoncurry import breadcrumbs -from lemoncurry.templatetags.lemoncurry_tags import request_uri +from lemoncurry import breadcrumbs, utils breadcrumbs.add('home:index', 'home') @@ -9,7 +8,7 @@ breadcrumbs.add('home:index', 'home') def index(request): query = User.objects.prefetch_related('entries', 'profiles', 'keys') user = get_object_or_404(query, pk=1) - uri = request_uri(request) + uri = utils.uri(request) person = { '@context': 'http://schema.org', '@type': 'Person', diff --git a/lemoncurry/templatetags/lemoncurry_tags.py b/lemoncurry/templatetags/lemoncurry_tags.py index fa455b9..4dcc899 100644 --- a/lemoncurry/templatetags/lemoncurry_tags.py +++ b/lemoncurry/templatetags/lemoncurry_tags.py @@ -1,16 +1,13 @@ -import json -from os.path import join -from types import SimpleNamespace from django import template from django.conf import settings from django.urls import reverse +from ..utils import load_package_json, origin, uri from .. import breadcrumbs from entries import kinds register = template.Library() -cache = SimpleNamespace(package_json=None) class MenuItem: @@ -22,24 +19,17 @@ class MenuItem: @register.simple_tag def get_package_json(): - if cache.package_json: - return cache.package_json - with open(join(settings.BASE_DIR, 'package.json')) as f: - cache.package_json = json.load(f) - return cache.package_json + return load_package_json() @register.simple_tag def request_origin(request): - return '{scheme}://{host}'.format( - scheme=request.scheme, - host=request.META['HTTP_HOST'], - ) + return origin(request) @register.simple_tag def request_uri(request): - return request_origin(request) + request.path + return uri(request) @register.simple_tag diff --git a/lemoncurry/utils.py b/lemoncurry/utils.py new file mode 100644 index 0000000..814dfcf --- /dev/null +++ b/lemoncurry/utils.py @@ -0,0 +1,22 @@ +import json +from django.conf import settings +from os.path import join +from types import SimpleNamespace + +cache = SimpleNamespace(package_json=None) + + +def load_package_json(): + if cache.package_json: + return cache.package_json + with open(join(settings.BASE_DIR, 'package.json')) as f: + cache.package_json = json.load(f) + return cache.package_json + + +def origin(request): + return '{0}://{1}'.format(request.scheme, request.META['HTTP_HOST']) + + +def uri(request): + return origin(request) + request.path diff --git a/wellknowns/urls.py b/wellknowns/urls.py index 3c98532..2764545 100644 --- a/wellknowns/urls.py +++ b/wellknowns/urls.py @@ -7,4 +7,5 @@ urlpatterns = [ url(r'^keybase.txt$', views.keybase, name='keybase'), url(r'^host-meta$', views.host_meta_xml, name='host-meta'), url(r'^host-meta.json$', views.host_meta_json, name='host-meta.json'), + url(r'^webfinger$', views.webfinger, name='webfinger'), ] diff --git a/wellknowns/views/__init__.py b/wellknowns/views/__init__.py index b1d80d9..d50efaf 100644 --- a/wellknowns/views/__init__.py +++ b/wellknowns/views/__init__.py @@ -1,2 +1,3 @@ from .static import keybase from .host_meta import host_meta_xml, host_meta_json +from .webfinger import webfinger diff --git a/wellknowns/views/host_meta.py b/wellknowns/views/host_meta.py index 7c4d4d0..4687bb5 100644 --- a/wellknowns/views/host_meta.py +++ b/wellknowns/views/host_meta.py @@ -1,12 +1,15 @@ from django.http import HttpResponse -from django.conf import settings -from lemoncurry.templatetags.lemoncurry_tags import get_package_json +from django.urls import reverse +from lemoncurry.utils import load_package_json, origin +from urllib.parse import urljoin from xrd import XRD, Attribute, Element, Link -def add_links(dest): - package = get_package_json() +def add_links(request, dest): + base = origin(request) + package = load_package_json() links = ( + Link(rel='lrdd', template=urljoin(base, reverse('wellknowns:webfinger') + '?resource={uri}')), Link(rel='license', href='https://creativecommons.org/licenses/by-sa/4.0/'), Link(rel='code-repository', href=package['repository']), ) @@ -17,7 +20,7 @@ def host_meta(request): h = XRD() h.attributes.append(Attribute('xmlns:hm', 'http://host-meta.net/ns/1.0')) h.elements.append(Element('hm:Host', request.META['HTTP_HOST'])) - add_links(h.links) + add_links(request, h.links) return h diff --git a/wellknowns/views/webfinger.py b/wellknowns/views/webfinger.py new file mode 100644 index 0000000..442e94e --- /dev/null +++ b/wellknowns/views/webfinger.py @@ -0,0 +1,43 @@ +from django.http import HttpResponseBadRequest, HttpResponseNotFound +from django.http import JsonResponse +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' + + +def webfinger(request): + if 'resource' not in request.GET: + return HttpResponseBadRequest('resource parameter missing') + try: + resource = urlparse(request.GET['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} + + info = { + 'subject': 'acct:' + user.email, + 'aliases': ( + urljoin(base, user.url), + 'mailto:' + user.email, + ), + 'links': ( + link(rel=AVATAR, href=user.avatar.url, type='image/png'), + link(rel=PROFILE_PAGE, href=user.url, type='text/html'), + ), + } + return JsonResponse(info, content_type='application/jrd+json')