2023-02-10 04:00:58 +00:00
|
|
|
"""Unit tests for webfinger.py."""
|
2023-05-23 18:53:32 +00:00
|
|
|
import copy
|
|
|
|
from unittest.mock import patch
|
2019-12-26 06:20:57 +00:00
|
|
|
import urllib.parse
|
2017-08-19 15:21:05 +00:00
|
|
|
|
2024-05-05 15:39:32 +00:00
|
|
|
from granary.as2 import CONTENT_TYPE, CONTENT_TYPE_LD_PROFILE
|
2024-04-22 20:24:24 +00:00
|
|
|
from oauth_dropins.webutil import util
|
2023-05-23 18:53:32 +00:00
|
|
|
from oauth_dropins.webutil.testutil import requests_response
|
|
|
|
|
2023-05-30 23:36:18 +00:00
|
|
|
# import first so that Fake is defined before URL routes are registered
|
2024-04-23 22:31:24 +00:00
|
|
|
from .testutil import ExplicitEnableFake, Fake, TestCase
|
2023-05-30 23:36:18 +00:00
|
|
|
|
2024-02-11 22:35:10 +00:00
|
|
|
from models import PROTOCOLS
|
2024-01-26 19:37:34 +00:00
|
|
|
import protocol
|
2023-05-30 03:16:15 +00:00
|
|
|
from web import Web
|
2023-09-22 19:48:00 +00:00
|
|
|
from webfinger import fetch, fetch_actor_url
|
2023-05-30 03:16:15 +00:00
|
|
|
|
2023-09-22 22:14:15 +00:00
|
|
|
from . import test_web
|
2023-05-23 18:53:32 +00:00
|
|
|
|
2023-09-29 17:48:59 +00:00
|
|
|
|
2023-05-23 18:53:32 +00:00
|
|
|
WEBFINGER = {
|
|
|
|
'subject': 'acct:user.com@user.com',
|
|
|
|
'aliases': [
|
|
|
|
'https://user.com/about-me',
|
|
|
|
'https://user.com/',
|
|
|
|
],
|
|
|
|
'links': [{
|
|
|
|
'rel': 'http://webfinger.net/rel/profile-page',
|
|
|
|
'type': 'text/html',
|
|
|
|
'href': 'https://user.com/about-me',
|
|
|
|
}, {
|
|
|
|
'rel': 'http://webfinger.net/rel/profile-page',
|
|
|
|
'type': 'text/html',
|
|
|
|
'href': 'https://user.com/',
|
|
|
|
}, {
|
|
|
|
'rel': 'http://webfinger.net/rel/avatar',
|
|
|
|
'href': 'https://user.com/me.jpg',
|
|
|
|
}, {
|
|
|
|
'rel': 'canonical_uri',
|
|
|
|
'type': 'text/html',
|
|
|
|
'href': 'https://user.com/about-me',
|
|
|
|
}, {
|
|
|
|
'rel': 'self',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-05-23 18:53:32 +00:00
|
|
|
'href': 'http://localhost/user.com',
|
2024-05-05 15:39:32 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'self',
|
|
|
|
'type': CONTENT_TYPE,
|
|
|
|
'href': 'http://localhost/user.com',
|
2023-05-23 18:53:32 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'inbox',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-05-23 18:53:32 +00:00
|
|
|
'href': 'http://localhost/user.com/inbox'
|
|
|
|
}, {
|
|
|
|
'rel': 'sharedInbox',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-09-26 23:43:48 +00:00
|
|
|
'href': 'https://web.brid.gy/ap/sharedInbox',
|
2023-05-23 18:53:32 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'http://ostatus.org/schema/1.0/subscribe',
|
2023-11-30 23:43:38 +00:00
|
|
|
# TODO: genericize
|
2023-09-27 20:55:16 +00:00
|
|
|
'template': 'https://fed.brid.gy/web/user.com?url={uri}',
|
2023-05-23 18:53:32 +00:00
|
|
|
}],
|
|
|
|
}
|
|
|
|
WEBFINGER_NO_HCARD = {
|
|
|
|
'subject': 'acct:user.com@user.com',
|
|
|
|
'aliases': ['https://user.com/'],
|
|
|
|
'links': [{
|
|
|
|
'rel': 'http://webfinger.net/rel/profile-page',
|
|
|
|
'type': 'text/html',
|
|
|
|
'href': 'https://user.com/',
|
|
|
|
}, {
|
|
|
|
'rel': 'canonical_uri',
|
|
|
|
'type': 'text/html',
|
|
|
|
'href': 'https://user.com/',
|
|
|
|
}, {
|
|
|
|
'rel': 'self',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-12-01 04:08:41 +00:00
|
|
|
'href': 'https://web.brid.gy/user.com',
|
2024-05-05 15:39:32 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'self',
|
|
|
|
'type': CONTENT_TYPE,
|
|
|
|
'href': 'https://web.brid.gy/user.com',
|
2023-05-23 18:53:32 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'inbox',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-12-01 04:08:41 +00:00
|
|
|
'href': 'https://web.brid.gy/user.com/inbox',
|
2023-05-23 18:53:32 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'sharedInbox',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-09-26 23:43:48 +00:00
|
|
|
'href': 'https://web.brid.gy/ap/sharedInbox',
|
2023-05-23 18:53:32 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'http://ostatus.org/schema/1.0/subscribe',
|
2023-09-27 20:55:16 +00:00
|
|
|
'template': 'https://fed.brid.gy/web/user.com?url={uri}',
|
2023-05-23 18:53:32 +00:00
|
|
|
}],
|
|
|
|
}
|
2023-06-12 22:37:17 +00:00
|
|
|
WEBFINGER_FAKE = {
|
2023-09-25 19:45:47 +00:00
|
|
|
'subject': 'acct:fake:handle:user@fa.brid.gy',
|
2024-05-29 23:46:16 +00:00
|
|
|
'aliases': ['web:fake:user'],
|
2023-06-12 22:37:17 +00:00
|
|
|
'links': [{
|
|
|
|
'rel': 'canonical_uri',
|
|
|
|
'type': 'text/html',
|
2024-05-29 23:46:16 +00:00
|
|
|
'href': 'web:fake:user',
|
2023-06-12 22:37:17 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'self',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-09-25 19:33:24 +00:00
|
|
|
'href': 'http://localhost/ap/fa/fake:user',
|
2024-05-05 15:39:32 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'self',
|
|
|
|
'type': CONTENT_TYPE,
|
|
|
|
'href': 'http://localhost/ap/fa/fake:user',
|
2023-06-12 22:37:17 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'inbox',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-09-25 19:33:24 +00:00
|
|
|
'href': 'http://localhost/ap/fa/fake:user/inbox',
|
2023-06-12 22:37:17 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'sharedInbox',
|
2024-02-27 19:38:00 +00:00
|
|
|
'type': CONTENT_TYPE_LD_PROFILE,
|
2023-09-26 23:43:48 +00:00
|
|
|
'href': 'https://web.brid.gy/ap/sharedInbox',
|
2023-06-12 22:37:17 +00:00
|
|
|
}, {
|
|
|
|
'rel': 'http://ostatus.org/schema/1.0/subscribe',
|
2023-09-27 20:55:16 +00:00
|
|
|
'template': 'https://fed.brid.gy/fa/fake:handle:user?url={uri}',
|
2023-06-12 22:37:17 +00:00
|
|
|
}],
|
|
|
|
}
|
2023-09-26 23:43:48 +00:00
|
|
|
WEBFINGER_FAKE_FA_BRID_GY = copy.deepcopy(WEBFINGER_FAKE)
|
|
|
|
for link in WEBFINGER_FAKE_FA_BRID_GY['links']:
|
2023-09-25 19:33:24 +00:00
|
|
|
if 'href' in link:
|
2023-09-26 23:43:48 +00:00
|
|
|
link['href'] = link['href'].replace('http://localhost/ap/fa', 'https://fa.brid.gy/ap')
|
2024-05-05 15:39:32 +00:00
|
|
|
WEBFINGER_FAKE_FA_BRID_GY['links'][4]['href'] = 'https://fa.brid.gy/ap/sharedInbox'
|
|
|
|
WEBFINGER_FAKE_FA_BRID_GY['links'][5]['template'] = 'https://fed.brid.gy/fa/fake:handle:user?url={uri}'
|
2017-08-19 15:21:05 +00:00
|
|
|
|
|
|
|
|
2023-06-12 22:37:17 +00:00
|
|
|
class HostMetaTest(TestCase):
|
2023-02-10 04:00:58 +00:00
|
|
|
def test_host_meta_xrd(self):
|
|
|
|
got = self.client.get('/.well-known/host-meta')
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual('application/xrd+xml; charset=utf-8',
|
2023-06-20 18:22:54 +00:00
|
|
|
got.headers['Content-Type'])
|
2023-02-10 04:00:58 +00:00
|
|
|
body = got.get_data(as_text=True)
|
|
|
|
self.assertTrue(body.startswith('<?xml'), body)
|
|
|
|
|
|
|
|
def test_host_meta_xrds(self):
|
|
|
|
got = self.client.get('/.well-known/host-meta.xrds')
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual('application/xrds+xml', got.headers['Content-Type'])
|
|
|
|
body = got.get_data(as_text=True)
|
|
|
|
self.assertTrue(body.startswith('<XRDS'), body)
|
|
|
|
|
|
|
|
def test_host_meta_jrd(self):
|
|
|
|
got = self.client.get('/.well-known/host-meta.json')
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
|
|
|
|
body = got.get_data(as_text=True)
|
|
|
|
self.assertTrue(body.startswith('{'), body)
|
|
|
|
|
|
|
|
|
2023-06-12 22:37:17 +00:00
|
|
|
class WebfingerTest(TestCase):
|
2017-08-19 16:24:00 +00:00
|
|
|
|
2017-09-03 22:44:01 +00:00
|
|
|
def setUp(self):
|
2021-08-18 14:59:52 +00:00
|
|
|
super().setUp()
|
2021-07-11 20:39:19 +00:00
|
|
|
|
2023-11-30 05:06:55 +00:00
|
|
|
self.user = self.make_user('user.com', cls=Web, has_hcard=True,
|
|
|
|
has_redirects=True, obj_as2={
|
2023-02-10 04:00:58 +00:00
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'type': 'Person',
|
2023-03-19 22:43:55 +00:00
|
|
|
'url': 'https://user.com/about-me',
|
2023-02-10 04:00:58 +00:00
|
|
|
'name': 'Mrs. ☕ Foo',
|
2023-03-19 22:43:55 +00:00
|
|
|
'icon': {'type': 'Image', 'url': 'https://user.com/me.jpg'},
|
2023-06-16 04:22:20 +00:00
|
|
|
})
|
2017-09-03 22:44:01 +00:00
|
|
|
|
2023-02-10 04:00:58 +00:00
|
|
|
def test_webfinger(self):
|
2024-06-02 00:52:05 +00:00
|
|
|
for resource in ('user.com@user.com', 'acct:user.com@user.com',
|
2023-03-19 22:43:55 +00:00
|
|
|
'user.com', 'http://user.com/', 'https://user.com/',
|
|
|
|
'http://localhost/user.com'):
|
2022-11-26 14:59:27 +00:00
|
|
|
with self.subTest(resource=resource):
|
2023-01-24 20:17:24 +00:00
|
|
|
url = (f'/.well-known/webfinger?' +
|
|
|
|
urllib.parse.urlencode({'resource': resource}))
|
2022-11-26 14:59:27 +00:00
|
|
|
got = self.client.get(url, headers={'Accept': 'application/json'})
|
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
|
|
|
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
|
2023-05-23 18:53:32 +00:00
|
|
|
self.assert_equals(WEBFINGER, got.json)
|
2018-04-12 13:25:39 +00:00
|
|
|
|
2023-11-30 23:43:38 +00:00
|
|
|
def test_webfinger_web_subdomain_redirects(self):
|
|
|
|
path = '/.well-known/webfinger?resource=user.com@user.com'
|
|
|
|
|
2023-12-01 00:31:41 +00:00
|
|
|
self.user.ap_subdomain = 'web'
|
|
|
|
self.user.put()
|
2023-11-30 23:43:38 +00:00
|
|
|
got = self.client.get(path, base_url='https://fed.brid.gy/')
|
|
|
|
self.assertEqual(302, got.status_code)
|
|
|
|
self.assertEqual(f'https://web.brid.gy{path}', got.headers['Location'])
|
|
|
|
|
|
|
|
self.user.ap_subdomain = 'fed'
|
|
|
|
self.user.put()
|
|
|
|
got = self.client.get(path, base_url='https://web.brid.gy/')
|
|
|
|
self.assertEqual(302, got.status_code)
|
|
|
|
self.assertEqual(f'https://fed.brid.gy{path}', got.headers['Location'])
|
|
|
|
|
2023-06-12 22:37:17 +00:00
|
|
|
def test_user_infer_protocol_from_resource_subdomain(self):
|
2023-06-15 17:52:11 +00:00
|
|
|
got = self.client.get(
|
2023-09-25 19:45:47 +00:00
|
|
|
'/.well-known/webfinger?resource=acct:fake:handle:user@fake.brid.gy',
|
2023-09-26 23:43:48 +00:00
|
|
|
base_url='https://fed.brid.gy/',
|
2023-06-15 17:52:11 +00:00
|
|
|
headers={'Accept': 'application/json'})
|
2023-06-12 22:37:17 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
|
2023-09-26 23:43:48 +00:00
|
|
|
self.assert_equals(WEBFINGER_FAKE_FA_BRID_GY, got.json)
|
2023-06-12 22:37:17 +00:00
|
|
|
|
2023-09-29 19:33:55 +00:00
|
|
|
def test_user_unknown_protocol_subdomain(self):
|
|
|
|
got = self.client.get(
|
|
|
|
'/.well-known/webfinger?resource=acct:user@nope.brid.gy',
|
|
|
|
headers={'Accept': 'application/json'})
|
|
|
|
self.assertEqual(404, got.status_code)
|
|
|
|
|
|
|
|
def test_user_unusable_protocol_subdomain(self):
|
2023-10-13 00:55:44 +00:00
|
|
|
from models import PROTOCOLS
|
|
|
|
for base_url in None, 'https://bsky.brid.gy/':
|
|
|
|
got = self.client.get(
|
|
|
|
'/.well-known/webfinger?resource=acct:user.handle@bsky.brid.gy',
|
|
|
|
base_url=base_url, headers={'Accept': 'application/json'})
|
|
|
|
self.assertEqual(400, got.status_code)
|
2023-09-29 19:33:55 +00:00
|
|
|
|
2023-06-12 22:37:17 +00:00
|
|
|
def test_user_infer_protocol_from_request_subdomain(self):
|
2023-06-15 17:52:11 +00:00
|
|
|
self.make_user('fake:user', cls=Fake)
|
|
|
|
got = self.client.get(
|
|
|
|
'/.well-known/webfinger?resource=acct:user@fake:user',
|
|
|
|
base_url='https://fake.brid.gy/',
|
|
|
|
headers={'Accept': 'application/json'})
|
2023-06-12 22:37:17 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
|
2023-09-26 23:43:48 +00:00
|
|
|
self.assert_equals(WEBFINGER_FAKE_FA_BRID_GY, got.json)
|
2023-06-12 22:37:17 +00:00
|
|
|
|
|
|
|
def test_user_infer_protocol_resource_overrides_request(self):
|
2023-06-15 17:52:11 +00:00
|
|
|
got = self.client.get(
|
2023-09-25 19:45:47 +00:00
|
|
|
'/.well-known/webfinger?resource=acct:fake:handle:user@fake.brid.gy',
|
2023-06-15 17:52:11 +00:00
|
|
|
base_url='https://ap.brid.gy/',
|
|
|
|
headers={'Accept': 'application/json'})
|
2023-06-12 22:37:17 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
|
2023-09-26 23:43:48 +00:00
|
|
|
self.assert_equals(WEBFINGER_FAKE_FA_BRID_GY, got.json)
|
2023-06-12 22:37:17 +00:00
|
|
|
|
2023-09-29 17:48:59 +00:00
|
|
|
def test_handle_new_user(self):
|
|
|
|
self.assertIsNone(Fake.get_by_id('fake:user'))
|
|
|
|
|
2023-09-22 22:14:15 +00:00
|
|
|
got = self.client.get(
|
|
|
|
'/.well-known/webfinger?resource=acct:fake:handle:user@fake.brid.gy',
|
2023-09-26 23:43:48 +00:00
|
|
|
base_url='https://fed.brid.gy/',
|
2023-09-22 22:14:15 +00:00
|
|
|
headers={'Accept': 'application/json'})
|
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
2023-09-26 23:43:48 +00:00
|
|
|
self.assert_equals(WEBFINGER_FAKE_FA_BRID_GY, got.json)
|
2023-09-22 22:14:15 +00:00
|
|
|
|
2023-06-12 20:32:21 +00:00
|
|
|
def test_urlencoded(self):
|
2023-06-08 18:04:11 +00:00
|
|
|
"""https://github.com/snarfed/bridgy-fed/issues/535"""
|
2023-06-15 17:52:11 +00:00
|
|
|
got = self.client.get(
|
|
|
|
'/.well-known/webfinger?resource=acct%3Auser.com%40user.com',
|
|
|
|
headers={'Accept': 'application/json'})
|
2023-06-08 18:04:11 +00:00
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
|
|
|
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
|
|
|
|
self.assert_equals(WEBFINGER, got.json)
|
|
|
|
|
2023-06-12 20:32:21 +00:00
|
|
|
def test_custom_username(self):
|
2023-06-16 04:22:20 +00:00
|
|
|
self.user.obj.as2['url'] = [
|
|
|
|
'https://user.com/about-me',
|
|
|
|
'acct:notthisuser@boop.org',
|
|
|
|
'acct:customuser@user.com',
|
|
|
|
]
|
2023-06-22 21:27:02 +00:00
|
|
|
self.user.obj.put()
|
2023-02-10 04:00:58 +00:00
|
|
|
self.user.put()
|
|
|
|
|
2020-12-30 18:26:48 +00:00
|
|
|
for resource in (
|
2023-03-19 22:43:55 +00:00
|
|
|
'customuser@user.com',
|
|
|
|
'acct:customuser@user.com',
|
|
|
|
'user.com',
|
2023-05-23 18:53:32 +00:00
|
|
|
'user.com@user.com',
|
2023-03-19 22:43:55 +00:00
|
|
|
'http://user.com/',
|
|
|
|
'https://user.com/',
|
2023-05-23 18:53:32 +00:00
|
|
|
'acct:user.com@user.com',
|
|
|
|
'acct:@user.com@user.com',
|
2020-12-30 18:26:48 +00:00
|
|
|
# Mastodon requires this as of 3.3.0
|
|
|
|
# https://github.com/snarfed/bridgy-fed/issues/73
|
2023-03-19 22:43:55 +00:00
|
|
|
'acct:user.com@fed.brid.gy',
|
|
|
|
'acct:user.com@localhost',
|
2020-12-30 18:26:48 +00:00
|
|
|
):
|
2022-11-27 00:05:02 +00:00
|
|
|
with self.subTest(resource=resource):
|
2023-01-24 20:17:24 +00:00
|
|
|
url = (f'/.well-known/webfinger?' +
|
|
|
|
urllib.parse.urlencode({'resource': resource}))
|
2022-11-27 00:05:02 +00:00
|
|
|
got = self.client.get(url, headers={'Accept': 'application/json'})
|
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
|
|
|
self.assertEqual('application/jrd+json', got.headers['Content-Type'])
|
2023-05-23 18:53:32 +00:00
|
|
|
self.assert_equals({
|
|
|
|
**WEBFINGER,
|
|
|
|
'subject': 'acct:customuser@user.com',
|
|
|
|
'aliases': [
|
|
|
|
'https://user.com/about-me',
|
|
|
|
'acct:notthisuser@boop.org',
|
|
|
|
'acct:customuser@user.com',
|
|
|
|
'https://user.com/',
|
|
|
|
],
|
|
|
|
}, got.json)
|
|
|
|
|
2023-06-12 20:32:21 +00:00
|
|
|
def test_missing_user(self):
|
2023-06-15 17:52:11 +00:00
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource=acct:nope.com@nope.com')
|
|
|
|
self.assertEqual(404, got.status_code)
|
|
|
|
|
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource=acct:nope.com')
|
|
|
|
self.assertEqual(400, got.status_code)
|
|
|
|
|
|
|
|
def test_indirect_user_not_on_bridgy_fed_subdomain(self):
|
|
|
|
self.user.direct = False
|
|
|
|
self.user.put()
|
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource=acct:user.com@user.com')
|
|
|
|
self.assertEqual(404, got.status_code)
|
|
|
|
|
2024-06-02 00:52:05 +00:00
|
|
|
def test_user_not_custom_username(self):
|
|
|
|
for base_url in (None, 'https://web.brid.gy/', 'https://fed.brid.gy/'):
|
|
|
|
with self.subTest(base_url=base_url):
|
|
|
|
got = self.client.get(
|
|
|
|
f'/.well-known/webfinger?resource=acct:foo@user.com',
|
|
|
|
base_url=base_url)
|
|
|
|
self.assertEqual(404, got.status_code)
|
|
|
|
|
|
|
|
def test_missing_user_web_subdomain(self):
|
|
|
|
self.user.direct = False
|
|
|
|
self.user.put()
|
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource=acct:foo@bar.com')
|
|
|
|
self.assertEqual(404, got.status_code)
|
|
|
|
|
2024-04-23 22:31:24 +00:00
|
|
|
def test_protocol_not_enabled(self):
|
|
|
|
self.make_user('eefake:user', cls=ExplicitEnableFake)
|
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource=acct:eefake:user@eefake.brid.gy')
|
|
|
|
self.assertEqual(404, got.status_code)
|
|
|
|
|
|
|
|
def test_protocol_enabled(self):
|
|
|
|
self.make_user('eefake:user', cls=ExplicitEnableFake,
|
|
|
|
enabled_protocols=['activitypub'])
|
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource=acct:eefake:user@eefake.brid.gy')
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
|
2023-06-15 17:52:11 +00:00
|
|
|
def test_bad_id(self):
|
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource=acct:nope@fa.brid.gy')
|
|
|
|
self.assertEqual(400, got.status_code, got.get_data(as_text=True))
|
|
|
|
|
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource=acct:nope@nope',
|
|
|
|
base_url='https://fa.brid.gy/')
|
|
|
|
self.assertEqual(400, got.status_code, got.get_data(as_text=True))
|
2023-06-12 20:32:21 +00:00
|
|
|
|
|
|
|
def test_bad_tld(self):
|
2023-09-22 22:14:15 +00:00
|
|
|
got = self.client.get(
|
|
|
|
f'/.well-known/webfinger?resource=acct:user.json@user.json',
|
|
|
|
base_url='https://web.brid.gy/')
|
2023-06-15 17:52:11 +00:00
|
|
|
self.assertEqual(400, got.status_code, got.get_data(as_text=True))
|
2023-05-23 18:53:32 +00:00
|
|
|
|
2023-12-01 23:46:37 +00:00
|
|
|
def test_no_handle(self):
|
|
|
|
class NoHandle(Fake):
|
2024-02-11 22:35:10 +00:00
|
|
|
ABBREV = 'nohandle'
|
2023-12-01 23:46:37 +00:00
|
|
|
handle = None
|
|
|
|
|
2024-02-11 22:35:10 +00:00
|
|
|
try:
|
|
|
|
got = self.client.get(
|
|
|
|
'/.well-known/webfinger?resource=acct:nohandle:user@nohandle.brid.gy')
|
|
|
|
self.assertEqual(404, got.status_code)
|
|
|
|
finally:
|
|
|
|
PROTOCOLS.pop('nohandle')
|
2023-12-01 23:46:37 +00:00
|
|
|
|
Revert "cache outbound HTTP request responses, locally to each inbound request"
This reverts commit 30debfc8faf730190bd51a3aef49df6c6bfbd50a.
seemed promising, but broke in production. Saw a lot of `IncompleteRead`s on both GETs and POSTs. Rolled back for now.
```
('Connection broken: IncompleteRead(9172 bytes read, -4586 more expected)', IncompleteRead(9172 bytes read, -4586 more expected))
...
File "oauth_dropins/webutil/util.py", line 1673, in call
resp = getattr((session or requests), fn)(url, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 102, in get
return self.request('GET', url, params=params, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 158, in request
return super().request(method, url, *args, headers=headers, **kwargs) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests/sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 205, in send
response = self._send_and_cache(request, actions, cached_response, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 233, in _send_and_cache
self.cache.save_response(response, actions.cache_key, actions.expires)
File "requests_cache/backends/base.py", line 89, in save_response
cached_response = CachedResponse.from_response(response, expires=expires)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/models/response.py", line 102, in from_response
obj.raw = CachedHTTPResponse.from_response(response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/models/raw_response.py", line 69, in from_response
_ = response.content # This property reads, decodes, and stores response content
^^^^^^^^^^^^^^^^
File "requests/models.py", line 899, in content
self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests/models.py", line 818, in generate
raise ChunkedEncodingError(e)
```
2024-03-08 21:24:28 +00:00
|
|
|
@patch('requests.get')
|
2023-09-22 22:14:15 +00:00
|
|
|
def test_create_user(self, mock_get):
|
2023-05-23 18:53:32 +00:00
|
|
|
self.user.key.delete()
|
2024-01-26 19:37:34 +00:00
|
|
|
self.user.obj_key.delete()
|
2023-05-23 18:53:32 +00:00
|
|
|
|
2024-06-03 23:00:49 +00:00
|
|
|
mock_get.return_value = requests_response(test_web.ACTOR_HTML,
|
|
|
|
url='https://user.com/')
|
2023-05-23 18:53:32 +00:00
|
|
|
expected = copy.deepcopy(WEBFINGER_NO_HCARD)
|
2023-12-01 04:08:41 +00:00
|
|
|
expected['subject'] = 'acct:user.com@web.brid.gy'
|
2023-05-23 18:53:32 +00:00
|
|
|
|
2023-11-30 23:43:38 +00:00
|
|
|
got = self.client.get(
|
2023-12-01 04:08:41 +00:00
|
|
|
'/.well-known/webfinger?resource=acct:user.com@web.brid.gy',
|
2023-11-30 23:43:38 +00:00
|
|
|
headers={'Accept': 'application/json'},
|
2023-12-01 04:08:41 +00:00
|
|
|
base_url='https://web.brid.gy/')
|
2023-05-23 18:53:32 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual(expected, got.json)
|
2022-11-25 16:00:14 +00:00
|
|
|
|
2023-05-30 03:16:15 +00:00
|
|
|
user = Web.get_by_id('user.com')
|
|
|
|
assert not user.direct
|
|
|
|
|
2024-04-22 20:24:24 +00:00
|
|
|
# skip _pre_put_hook since it doesn't allow internal domains
|
|
|
|
@patch.object(Web, '_pre_put_hook', new=lambda self: None)
|
|
|
|
def test_protocol_bot_user(self):
|
|
|
|
self.make_user('bsky.brid.gy', cls=Web, obj_id='https://bsky.brid.gy/',
|
|
|
|
ap_subdomain='bsky')
|
|
|
|
|
|
|
|
for id in ('acct:bsky.brid.gy@bsky.brid.gy',
|
|
|
|
'https://bsky.brid.gy/bsky.brid.gy'):
|
|
|
|
got = self.client.get(f'/.well-known/webfinger?resource={id}')
|
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
|
|
|
self.assertEqual('acct:bsky.brid.gy@bsky.brid.gy', got.json['subject'])
|
|
|
|
self.assertEqual(['https://bsky.brid.gy/'], got.json['aliases'])
|
|
|
|
self.assertIn({
|
2024-04-25 21:29:48 +00:00
|
|
|
'href': 'https://bsky.brid.gy/bsky.brid.gy',
|
2024-04-22 20:24:24 +00:00
|
|
|
'rel': 'self',
|
|
|
|
'type': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
|
|
|
}, got.json['links'])
|
|
|
|
|
|
|
|
def test_internal_domain_error(self):
|
2022-11-25 16:00:14 +00:00
|
|
|
got = self.client.get('/.well-known/webfinger?resource=http://localhost/')
|
|
|
|
self.assertEqual(400, got.status_code, got.get_data(as_text=True))
|
|
|
|
|
2024-04-22 20:24:24 +00:00
|
|
|
got = self.client.get('/.well-known/webfinger?resource=acct:@localhost')
|
2022-11-26 14:59:27 +00:00
|
|
|
self.assertEqual(400, got.status_code, got.get_data(as_text=True))
|
2023-09-22 19:48:00 +00:00
|
|
|
|
Revert "cache outbound HTTP request responses, locally to each inbound request"
This reverts commit 30debfc8faf730190bd51a3aef49df6c6bfbd50a.
seemed promising, but broke in production. Saw a lot of `IncompleteRead`s on both GETs and POSTs. Rolled back for now.
```
('Connection broken: IncompleteRead(9172 bytes read, -4586 more expected)', IncompleteRead(9172 bytes read, -4586 more expected))
...
File "oauth_dropins/webutil/util.py", line 1673, in call
resp = getattr((session or requests), fn)(url, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 102, in get
return self.request('GET', url, params=params, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 158, in request
return super().request(method, url, *args, headers=headers, **kwargs) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests/sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 205, in send
response = self._send_and_cache(request, actions, cached_response, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 233, in _send_and_cache
self.cache.save_response(response, actions.cache_key, actions.expires)
File "requests_cache/backends/base.py", line 89, in save_response
cached_response = CachedResponse.from_response(response, expires=expires)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/models/response.py", line 102, in from_response
obj.raw = CachedHTTPResponse.from_response(response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/models/raw_response.py", line 69, in from_response
_ = response.content # This property reads, decodes, and stores response content
^^^^^^^^^^^^^^^^
File "requests/models.py", line 899, in content
self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests/models.py", line 818, in generate
raise ChunkedEncodingError(e)
```
2024-03-08 21:24:28 +00:00
|
|
|
@patch('requests.get', return_value=requests_response(
|
2023-09-22 19:48:00 +00:00
|
|
|
WEBFINGER, content_type='application/jrd+json'))
|
|
|
|
def test_fetch(self, mock_get):
|
|
|
|
self.assertEqual(WEBFINGER, fetch('@foo@bar'))
|
|
|
|
self.assert_req(mock_get,
|
|
|
|
'https://bar/.well-known/webfinger?resource=acct:foo@bar')
|
|
|
|
|
Revert "cache outbound HTTP request responses, locally to each inbound request"
This reverts commit 30debfc8faf730190bd51a3aef49df6c6bfbd50a.
seemed promising, but broke in production. Saw a lot of `IncompleteRead`s on both GETs and POSTs. Rolled back for now.
```
('Connection broken: IncompleteRead(9172 bytes read, -4586 more expected)', IncompleteRead(9172 bytes read, -4586 more expected))
...
File "oauth_dropins/webutil/util.py", line 1673, in call
resp = getattr((session or requests), fn)(url, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 102, in get
return self.request('GET', url, params=params, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 158, in request
return super().request(method, url, *args, headers=headers, **kwargs) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests/sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 205, in send
response = self._send_and_cache(request, actions, cached_response, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 233, in _send_and_cache
self.cache.save_response(response, actions.cache_key, actions.expires)
File "requests_cache/backends/base.py", line 89, in save_response
cached_response = CachedResponse.from_response(response, expires=expires)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/models/response.py", line 102, in from_response
obj.raw = CachedHTTPResponse.from_response(response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/models/raw_response.py", line 69, in from_response
_ = response.content # This property reads, decodes, and stores response content
^^^^^^^^^^^^^^^^
File "requests/models.py", line 899, in content
self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests/models.py", line 818, in generate
raise ChunkedEncodingError(e)
```
2024-03-08 21:24:28 +00:00
|
|
|
@patch('requests.get', return_value=requests_response(WEBFINGER))
|
2023-09-22 19:48:00 +00:00
|
|
|
def test_fetch_actor_url(self, mock_get):
|
|
|
|
self.assertEqual('http://localhost/user.com', fetch_actor_url('@foo@bar'))
|
|
|
|
self.assert_req(mock_get,
|
|
|
|
'https://bar/.well-known/webfinger?resource=acct:foo@bar')
|
|
|
|
|
Revert "cache outbound HTTP request responses, locally to each inbound request"
This reverts commit 30debfc8faf730190bd51a3aef49df6c6bfbd50a.
seemed promising, but broke in production. Saw a lot of `IncompleteRead`s on both GETs and POSTs. Rolled back for now.
```
('Connection broken: IncompleteRead(9172 bytes read, -4586 more expected)', IncompleteRead(9172 bytes read, -4586 more expected))
...
File "oauth_dropins/webutil/util.py", line 1673, in call
resp = getattr((session or requests), fn)(url, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 102, in get
return self.request('GET', url, params=params, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 158, in request
return super().request(method, url, *args, headers=headers, **kwargs) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests/sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 205, in send
response = self._send_and_cache(request, actions, cached_response, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/session.py", line 233, in _send_and_cache
self.cache.save_response(response, actions.cache_key, actions.expires)
File "requests_cache/backends/base.py", line 89, in save_response
cached_response = CachedResponse.from_response(response, expires=expires)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/models/response.py", line 102, in from_response
obj.raw = CachedHTTPResponse.from_response(response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests_cache/models/raw_response.py", line 69, in from_response
_ = response.content # This property reads, decodes, and stores response content
^^^^^^^^^^^^^^^^
File "requests/models.py", line 899, in content
self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "requests/models.py", line 818, in generate
raise ChunkedEncodingError(e)
```
2024-03-08 21:24:28 +00:00
|
|
|
@patch('requests.get', return_value=requests_response({'links': []}))
|
2023-09-22 19:48:00 +00:00
|
|
|
def test_fetch_actor_url_not_found(self, mock_get):
|
|
|
|
self.assertIsNone(fetch_actor_url('@foo@bar'))
|
|
|
|
self.assert_req(mock_get,
|
|
|
|
'https://bar/.well-known/webfinger?resource=acct:foo@bar')
|