diff --git a/federation/tests/utils/test_diaspora.py b/federation/tests/utils/test_diaspora.py new file mode 100644 index 0000000..f6aaa4e --- /dev/null +++ b/federation/tests/utils/test_diaspora.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +from unittest.mock import patch +from urllib.parse import quote + +from federation.hostmeta.generators import DiasporaWebFinger, DiasporaHostMeta +from federation.utils.diaspora import retrieve_diaspora_hcard, retrieve_diaspora_webfinger, retrieve_diaspora_host_meta + + +class TestRetrieveDiasporaHCard(object): + @patch("federation.utils.diaspora.retrieve_diaspora_webfinger", return_value=None) + def test_retrieve_webfinger_is_called(self, mock_retrieve): + retrieve_diaspora_hcard("bob@localhost") + assert mock_retrieve.called_with("bob@localhost") + + @patch("federation.utils.diaspora.fetch_document") + @patch("federation.utils.diaspora.retrieve_diaspora_webfinger") + def test_fetch_document_is_called(self, mock_retrieve, mock_fetch): + mock_retrieve.return_value = DiasporaWebFinger( + "bob@localhost", "https://localhost", "123", "456" + ).xrd + mock_fetch.return_value = "document", None, None + document = retrieve_diaspora_hcard("bob@localhost") + mock_fetch.assert_called_with("https://localhost/hcard/users/123") + assert document == "document" + + @patch("federation.utils.diaspora.fetch_document") + @patch("federation.utils.diaspora.retrieve_diaspora_webfinger") + def test_returns_none_on_fetch_document_exception(self, mock_retrieve, mock_fetch): + mock_retrieve.return_value = DiasporaWebFinger( + "bob@localhost", "https://localhost", "123", "456" + ).xrd + mock_fetch.return_value = None, None, ValueError() + document = retrieve_diaspora_hcard("bob@localhost") + mock_fetch.assert_called_with("https://localhost/hcard/users/123") + assert document == None + + +class TestRetrieveDiasporaWebfinger(object): + @patch("federation.utils.diaspora.retrieve_diaspora_host_meta", return_value=None) + def test_retrieve_host_meta_is_called(self, mock_retrieve): + retrieve_diaspora_webfinger("bob@localhost") + mock_retrieve.assert_called_with("localhost") + + @patch("federation.utils.diaspora.XRD.parse_xrd") + @patch("federation.utils.diaspora.fetch_document") + @patch("federation.utils.diaspora.retrieve_diaspora_host_meta", return_value=None) + def test_retrieve_fetch_document_is_called(self, mock_retrieve, mock_fetch, mock_xrd): + mock_retrieve.return_value = DiasporaHostMeta( + webfinger_host="https://localhost" + ).xrd + mock_fetch.return_value = "document", None, None + mock_xrd.return_value = "document" + document = retrieve_diaspora_webfinger("bob@localhost") + mock_fetch.assert_called_with("https://localhost/webfinger?q=%s" % quote("bob@localhost")) + assert document == "document" + + @patch("federation.utils.diaspora.fetch_document") + @patch("federation.utils.diaspora.retrieve_diaspora_host_meta", return_value=None) + def test_returns_none_on_fetch_document_exception(self, mock_retrieve, mock_fetch): + mock_retrieve.return_value = DiasporaHostMeta( + webfinger_host="https://localhost" + ).xrd + mock_fetch.return_value = None, None, ValueError() + document = retrieve_diaspora_webfinger("bob@localhost") + mock_fetch.assert_called_with("https://localhost/webfinger?q=%s" % quote("bob@localhost")) + assert document == None + + +class TestRetrieveDiasporaHostMeta(object): + @patch("federation.utils.diaspora.XRD.parse_xrd") + @patch("federation.utils.diaspora.fetch_document") + def test_fetch_document_is_called(self, mock_fetch, mock_xrd): + mock_fetch.return_value = "document", None, None + mock_xrd.return_value = "document" + document = retrieve_diaspora_host_meta("localhost") + mock_fetch.assert_called_with(host="localhost", path="/.well-known/host-meta") + assert document == "document" + + @patch("federation.utils.diaspora.fetch_document") + def test_returns_none_on_fetch_document_exception(self, mock_fetch): + mock_fetch.return_value = None, None, ValueError() + document = retrieve_diaspora_host_meta("localhost") + mock_fetch.assert_called_with(host="localhost", path="/.well-known/host-meta") + assert document == None diff --git a/federation/utils/diaspora.py b/federation/utils/diaspora.py new file mode 100644 index 0000000..2268dd0 --- /dev/null +++ b/federation/utils/diaspora.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +from urllib.parse import quote + +from xrd import XRD + +from federation.utils.network import fetch_document + + +def retrieve_diaspora_hcard(handle): + """Retrieve a remote Diaspora hCard document. + + Args: + handle (str) - Remote handle to retrieve + + Returns: + str (HTML document) + """ + webfinger = retrieve_diaspora_webfinger(handle) + if not webfinger: + return None + url = webfinger.find_link(rels="http://microformats.org/profile/hcard").href + document, code, exception = fetch_document(url) + if exception: + return None + return document + + +def retrieve_diaspora_webfinger(handle): + """Retrieve a remote Diaspora webfinger document. + + Args: + handle (str) - Remote handle to retrieve + + Returns: + XRD + """ + hostmeta = retrieve_diaspora_host_meta(handle.split("@")[1]) + if not hostmeta: + return None + url = hostmeta.find_link(rels="lrdd").template.replace("{uri}", quote(handle)) + document, code, exception = fetch_document(url) + if exception: + return None + xrd = XRD.parse_xrd(document) + return xrd + + +def retrieve_diaspora_host_meta(host): + """Retrieve a remote Diaspora host-meta document. + + Args: + host (str) - Host to retrieve from + + Returns: + XRD + """ + document, code, exception = fetch_document(host=host, path="/.well-known/host-meta") + if exception: + return None + xrd = XRD.parse_xrd(document) + return xrd