kopia lustrzana https://gitlab.com/jaywink/federation
Merge pull request #116 from jaywink/add-more-to-json-webfinger
Add more things to JSON webfingermerge-requests/130/head
commit
fe762d383d
|
@ -111,11 +111,18 @@ Some settings need to be set in Django settings. An example is below:
|
||||||
|
|
||||||
FEDERATION = {
|
FEDERATION = {
|
||||||
"base_url": "https://myserver.domain.tld,
|
"base_url": "https://myserver.domain.tld,
|
||||||
"profile_id_function": "myproject.utils.get_profile_id_by_handle",
|
"get_profile_function": "myproject.utils.get_profile_by_handle",
|
||||||
|
"search_path": "/search/?q=",
|
||||||
}
|
}
|
||||||
|
|
||||||
* ``base_url`` is the base URL of the server, ie protocol://domain.tld.
|
* ``base_url`` is the base URL of the server, ie protocol://domain.tld.
|
||||||
* ``profile_id_function`` should be the full path to a function that given a handle will return the Diaspora URI format profile ID.
|
* ``profile_id_function`` should be the full path to a function that given a handle will return a dictionary with information that will be used to generate the webfinger document. The dict should contain the following elements:
|
||||||
|
|
||||||
|
* ``id`` - Diaspora URI format ID.
|
||||||
|
* ``profile_path`` - profile path for generating an absolute URL to the profile page of the user.
|
||||||
|
* ``atom_path`` - (optional) atom feed path for the profile
|
||||||
|
|
||||||
|
* ``search_path`` (optional) site search path which ends in a parameter for search input, for example "/search?q="
|
||||||
|
|
||||||
Protocols
|
Protocols
|
||||||
---------
|
---------
|
||||||
|
|
|
@ -16,23 +16,23 @@ def get_configuration():
|
||||||
"""
|
"""
|
||||||
configuration = {
|
configuration = {
|
||||||
"hcard_path": "/hcard/users/",
|
"hcard_path": "/hcard/users/",
|
||||||
|
"search_path": None,
|
||||||
}
|
}
|
||||||
configuration.update(settings.FEDERATION)
|
configuration.update(settings.FEDERATION)
|
||||||
if not all([
|
if not all([
|
||||||
"profile_id_function" in configuration,
|
"get_profile_function" in configuration,
|
||||||
"base_url" in configuration,
|
"base_url" in configuration,
|
||||||
"hcard_path" in configuration,
|
|
||||||
]):
|
]):
|
||||||
raise ImproperlyConfigured("Missing required FEDERATION settings, please check documentation.")
|
raise ImproperlyConfigured("Missing required FEDERATION settings, please check documentation.")
|
||||||
return configuration
|
return configuration
|
||||||
|
|
||||||
|
|
||||||
def get_profile_id_func():
|
def get_profile_func():
|
||||||
"""
|
"""
|
||||||
Import the function to get profile ID by handle.
|
Import the function to get profile by handle.
|
||||||
"""
|
"""
|
||||||
config = get_configuration()
|
config = get_configuration()
|
||||||
profile_func_path = config.get("profile_id_function")
|
profile_func_path = config.get("get_profile_function")
|
||||||
module_path, func_name = profile_func_path.rsplit(".", 1)
|
module_path, func_name = profile_func_path.rsplit(".", 1)
|
||||||
module = importlib.import_module(module_path)
|
module = importlib.import_module(module_path)
|
||||||
profile_func = getattr(module, func_name)
|
profile_func = getattr(module, func_name)
|
||||||
|
@ -50,19 +50,22 @@ def rfc3033_webfinger_view(request, *args, **kwargs):
|
||||||
return HttpResponseBadRequest("Invalid resource")
|
return HttpResponseBadRequest("Invalid resource")
|
||||||
|
|
||||||
handle = resource.replace("acct:", "")
|
handle = resource.replace("acct:", "")
|
||||||
profile_id_func = get_profile_id_func()
|
profile_func = get_profile_func()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
profile_id = profile_id_func(handle)
|
profile = profile_func(handle)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("rfc3033_webfinger_view - Failed to get profile ID by handle %s: %s", handle, exc)
|
logger.warning("rfc3033_webfinger_view - Failed to get profile by handle %s: %s", handle, exc)
|
||||||
return HttpResponseNotFound()
|
return HttpResponseNotFound()
|
||||||
|
|
||||||
config = get_configuration()
|
config = get_configuration()
|
||||||
webfinger = RFC3033Webfinger(
|
webfinger = RFC3033Webfinger(
|
||||||
id=profile_id,
|
id=profile.get('id'),
|
||||||
base_url=config.get('base_url'),
|
base_url=config.get('base_url'),
|
||||||
|
profile_path=profile.get('profile_path'),
|
||||||
hcard_path=config.get('hcard_path'),
|
hcard_path=config.get('hcard_path'),
|
||||||
|
atom_path=profile.get('atom_path'),
|
||||||
|
search_path=config.get('search_path'),
|
||||||
)
|
)
|
||||||
|
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
|
|
|
@ -287,16 +287,21 @@ class RFC3033Webfinger:
|
||||||
|
|
||||||
:param id: Diaspora ID in URI format
|
:param id: Diaspora ID in URI format
|
||||||
:param base_url: The base URL of the server (protocol://domain.tld)
|
:param base_url: The base URL of the server (protocol://domain.tld)
|
||||||
|
:param profile_path: Profile path for the user (for example `/profile/johndoe/`)
|
||||||
:param hcard_path: (Optional) hCard path, defaults to ``/hcard/users/``.
|
:param hcard_path: (Optional) hCard path, defaults to ``/hcard/users/``.
|
||||||
|
:param atom_path: (Optional) atom feed path
|
||||||
:returns: dict
|
:returns: dict
|
||||||
"""
|
"""
|
||||||
def __init__(self, id, base_url, hcard_path="/hcard/users/"):
|
def __init__(self, id, base_url, profile_path, hcard_path="/hcard/users/", atom_path=None, search_path=None):
|
||||||
self.handle, self.guid = parse_profile_diaspora_id(id)
|
self.handle, self.guid = parse_profile_diaspora_id(id)
|
||||||
self.base_url = base_url
|
self.base_url = base_url
|
||||||
self.hcard_path = hcard_path
|
self.hcard_path = hcard_path
|
||||||
|
self.profile_path = profile_path
|
||||||
|
self.atom_path = atom_path
|
||||||
|
self.search_path = search_path
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
return {
|
webfinger = {
|
||||||
"subject": "acct:%s" % self.handle,
|
"subject": "acct:%s" % self.handle,
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
|
@ -309,5 +314,30 @@ class RFC3033Webfinger:
|
||||||
"type": "text/html",
|
"type": "text/html",
|
||||||
"href": self.base_url,
|
"href": self.base_url,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://webfinger.net/rel/profile-page",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "%s%s" % (self.base_url, self.profile_path),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "salmon",
|
||||||
|
"href": "%s/receive/users/%s" % (self.base_url, self.guid),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
if self.atom_path:
|
||||||
|
webfinger['links'].append(
|
||||||
|
{
|
||||||
|
"rel": "http://schemas.google.com/g/2010#updates-from",
|
||||||
|
"type": "application/atom+xml",
|
||||||
|
"href": "%s%s" % (self.base_url, self.atom_path),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if self.search_path:
|
||||||
|
webfinger['links'].append(
|
||||||
|
{
|
||||||
|
"rel": "http://ostatus.org/schema/1.0/subscribe",
|
||||||
|
"template": "%s%s{uri}" % (self.base_url, self.search_path),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return webfinger
|
||||||
|
|
|
@ -4,5 +4,6 @@ INSTALLED_APPS = tuple()
|
||||||
|
|
||||||
FEDERATION = {
|
FEDERATION = {
|
||||||
"base_url": "https://example.com",
|
"base_url": "https://example.com",
|
||||||
"profile_id_function": "federation.tests.hostmeta.django.utils.get_profile_id_by_handle",
|
"get_profile_function": "federation.tests.hostmeta.django.utils.get_profile_by_handle",
|
||||||
|
"search_path": "/search?q=",
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ from unittest.mock import patch, Mock
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
|
|
||||||
from federation.hostmeta.django import rfc3033_webfinger_view
|
from federation.hostmeta.django import rfc3033_webfinger_view
|
||||||
from federation.hostmeta.django.generators import get_profile_id_func
|
from federation.hostmeta.django.generators import get_profile_func
|
||||||
|
|
||||||
|
|
||||||
def test_get_profile_id_func():
|
def test_get_profile_func():
|
||||||
func = get_profile_id_func()
|
func = get_profile_func()
|
||||||
assert callable(func)
|
assert callable(func)
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class TestRFC3033WebfingerView:
|
||||||
response = rfc3033_webfinger_view(request)
|
response = rfc3033_webfinger_view(request)
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
@patch("federation.hostmeta.django.generators.get_profile_id_func")
|
@patch("federation.hostmeta.django.generators.get_profile_func")
|
||||||
def test_unknown_handle_returns_not_found(self, mock_get_func):
|
def test_unknown_handle_returns_not_found(self, mock_get_func):
|
||||||
mock_get_func.return_value = Mock(side_effect=Exception)
|
mock_get_func.return_value = Mock(side_effect=Exception)
|
||||||
request = RequestFactory().get("/.well-known/webfinger?resource=acct:foobar@domain.tld")
|
request = RequestFactory().get("/.well-known/webfinger?resource=acct:foobar@domain.tld")
|
||||||
|
@ -48,5 +48,23 @@ class TestRFC3033WebfingerView:
|
||||||
"type": "text/html",
|
"type": "text/html",
|
||||||
"href": "https://example.com",
|
"href": "https://example.com",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://webfinger.net/rel/profile-page",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "https://example.com/profile/1234/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "salmon",
|
||||||
|
"href": "https://example.com/receive/users/1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://schemas.google.com/g/2010#updates-from",
|
||||||
|
"type": "application/atom+xml",
|
||||||
|
"href": "https://example.com/profile/1234/atom.xml",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://ostatus.org/schema/1.0/subscribe",
|
||||||
|
"template": "https://example.com/search?q={uri}",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
from federation.utils.diaspora import generate_diaspora_profile_id
|
from federation.utils.diaspora import generate_diaspora_profile_id
|
||||||
|
|
||||||
|
|
||||||
def get_profile_id_by_handle(handle):
|
def get_profile_by_handle(handle):
|
||||||
return generate_diaspora_profile_id(handle, "1234")
|
return {
|
||||||
|
"id": generate_diaspora_profile_id(handle, "1234"),
|
||||||
|
"profile_path": "/profile/1234/",
|
||||||
|
"atom_path": "/profile/1234/atom.xml",
|
||||||
|
}
|
||||||
|
|
|
@ -178,10 +178,55 @@ class TestNodeInfoGenerator:
|
||||||
assert wellknown["links"][0]["href"] == "https://example.com/nodeinfo/1.0"
|
assert wellknown["links"][0]["href"] == "https://example.com/nodeinfo/1.0"
|
||||||
|
|
||||||
|
|
||||||
def test_rfc3033_webfinger():
|
class TestRFC3033Webfinger:
|
||||||
|
def test_rfc3033_webfinger__all_properties(self):
|
||||||
webfinger = RFC3033Webfinger(
|
webfinger = RFC3033Webfinger(
|
||||||
"diaspora://foobar@example.com/profile/1234",
|
"diaspora://foobar@example.com/profile/1234",
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
|
profile_path="/profile/1234/",
|
||||||
|
hcard_path="/hcard/path/",
|
||||||
|
atom_path="/profile/1234/atom.xml",
|
||||||
|
search_path="/search?q=",
|
||||||
|
).render()
|
||||||
|
assert webfinger == {
|
||||||
|
"subject": "acct:foobar@example.com",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"rel": "http://microformats.org/profile/hcard",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "https://example.com/hcard/path/1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://joindiaspora.com/seed_location",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "https://example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://webfinger.net/rel/profile-page",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "https://example.com/profile/1234/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "salmon",
|
||||||
|
"href": "https://example.com/receive/users/1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://schemas.google.com/g/2010#updates-from",
|
||||||
|
"type": "application/atom+xml",
|
||||||
|
"href": "https://example.com/profile/1234/atom.xml",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://ostatus.org/schema/1.0/subscribe",
|
||||||
|
"template": "https://example.com/search?q={uri}",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_rfc3033_webfinger__minimal(self):
|
||||||
|
webfinger = RFC3033Webfinger(
|
||||||
|
"diaspora://foobar@example.com/profile/1234",
|
||||||
|
"https://example.com",
|
||||||
|
profile_path="/profile/1234/",
|
||||||
).render()
|
).render()
|
||||||
assert webfinger == {
|
assert webfinger == {
|
||||||
"subject": "acct:foobar@example.com",
|
"subject": "acct:foobar@example.com",
|
||||||
|
@ -196,5 +241,14 @@ def test_rfc3033_webfinger():
|
||||||
"type": "text/html",
|
"type": "text/html",
|
||||||
"href": "https://example.com",
|
"href": "https://example.com",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://webfinger.net/rel/profile-page",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "https://example.com/profile/1234/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "salmon",
|
||||||
|
"href": "https://example.com/receive/users/1234",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue