user verification: follow multiple redirects

pull/324/head
Ryan Barrett 2022-11-28 13:10:51 -08:00
rodzic 25b411c2e8
commit d4af114247
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
3 zmienionych plików z 51 dodań i 45 usunięć

Wyświetl plik

@ -40,7 +40,7 @@ def remote_follow():
addr_domain = util.domain_from_link(addr, minimize=False)
resource = addr
else:
flash('Enter your fediverse address in @user@domain.com format')
flash('Enter your fediverse address in @user@domain.social format')
return redirect(f'/user/{domain}')
# look up remote user via webfinger

Wyświetl plik

@ -121,7 +121,6 @@ class User(StringIdModel):
return f'<a href="/user/{domain}"><img src="{img}" class="profile"> {name}</a>'
def verify(self):
"""Fetches site a couple ways to check for redirects and h-card."""
domain = self.key.id()
@ -134,16 +133,15 @@ class User(StringIdModel):
self.redirects_error = None
try:
url = urllib.parse.urljoin(site, path)
resp = util.requests_get(url, allow_redirects=False, gateway=False)
resp = util.requests_get(url, gateway=False)
domain_urls = ([f'https://{domain}/' for domain in common.DOMAINS] +
[request.host_url])
expected = [urllib.parse.urljoin(url, path) for url in domain_urls]
if resp.is_redirect:
got = resp.headers.get('Location')
if got in expected:
if resp.ok:
if resp.url in expected:
self.has_redirects = True
else:
diff = '\n'.join(difflib.Differ().compare([got], [expected[0]]))
elif resp.url:
diff = '\n'.join(difflib.Differ().compare([resp.url], [expected[0]]))
self.redirects_error = f'Current vs expected:<pre>{diff}</pre>'
except requests.RequestException:
pass

Wyświetl plik

@ -52,72 +52,80 @@ class UserTest(testutil.TestCase):
self.user.actor_as2 = '{"urls": ["http://foo", "acct:bar@foo", "acct:baz@y.z"]}'
self.assertEqual('@baz@y.z', self.user.address())
def _test_verify(self, redirects, hcard, actor, redirects_error=None):
with app.test_request_context('/'):
self.user.verify()
with self.subTest(redirects=redirects, hcard=hcard, actor=actor,
redirects_error=redirects_error):
self.assert_equals(redirects, bool(self.user.has_redirects))
self.assert_equals(hcard, bool(self.user.has_hcard))
if actor is None:
self.assertIsNone(self.user.actor_as2)
else:
got = {k: v for k, v in json_loads(self.user.actor_as2).items()
if k in actor}
self.assert_equals(actor, got)
self.assert_equals(redirects_error, self.user.redirects_error)
@mock.patch('requests.get')
def test_verify(self, mock_get):
self.assertFalse(self.user.has_redirects)
self.assertFalse(self.user.has_hcard)
def check(redirects, hcard, actor, redirects_error=None):
with app.test_request_context('/'):
self.user.verify()
with self.subTest(redirects=redirects, hcard=hcard, actor=actor,
redirects_error=redirects_error):
self.assert_equals(redirects, bool(self.user.has_redirects))
self.assert_equals(hcard, bool(self.user.has_hcard))
if actor is None:
self.assertIsNone(self.user.actor_as2)
else:
got = {k: v for k, v in json_loads(self.user.actor_as2).items()
if k in actor}
self.assert_equals(actor, got)
self.assert_equals(redirects_error, self.user.redirects_error)
# both fail
empty = requests_response('', allow_redirects=False)
def test_verify_neither(self, mock_get):
empty = requests_response('')
mock_get.side_effect = [empty, empty]
check(False, False, None)
self._test_verify(False, False, None)
# redirect strips query params, no h-card
@mock.patch('requests.get')
def test_verify_redirect_strips_query_params(self, mock_get):
half_redir = requests_response(
status=302, redirected_url='http://localhost/.well-known/webfinger',
allow_redirects=False)
status=302, redirected_url='http://localhost/.well-known/webfinger')
no_hcard = requests_response('<html><body></body></html>')
mock_get.side_effect = [half_redir, no_hcard]
check(False, False, None, """\
self._test_verify(False, False, None, """\
Current vs expected:<pre>- http://localhost/.well-known/webfinger
+ https://fed.brid.gy/.well-known/webfinger?resource=acct:y.z@y.z</pre>""")
# redirect works, non-representative h-card
@mock.patch('requests.get')
def test_verify_multiple_redirects(self, mock_get):
two_redirs = requests_response(
status=302, redirected_url=[
'https://www.y.z/.well-known/webfinger?resource=acct:y.z@y.z',
'http://localhost/.well-known/webfinger?resource=acct:y.z@y.z',
])
no_hcard = requests_response('<html><body></body></html>')
mock_get.side_effect = [two_redirs, no_hcard]
self._test_verify(True, False, None)
@mock.patch('requests.get')
def test_verify_non_representative_hcard(self, mock_get):
full_redir = requests_response(
status=302, allow_redirects=False,
status=302,
redirected_url='http://localhost/.well-known/webfinger?resource=acct:y.z@y.z')
bad_hcard = requests_response(
'<html><body><a class="h-card u-url" href="https://a.b/">acct:me@y.z</a></body></html>',
url='https://y.z/', allow_redirects=False,
url='https://y.z/',
)
mock_get.side_effect = [full_redir, bad_hcard]
check(True, False, None)
self._test_verify(True, False, None)
# both work
@mock.patch('requests.get')
def test_verify_both_work(self, mock_get):
full_redir = requests_response(
status=302,
redirected_url='http://localhost/.well-known/webfinger?resource=acct:y.z@y.z')
hcard = requests_response("""
<html><body class="h-card">
<a class="u-url p-name" href="/">me</a>
<a class="u-url" href="acct:myself@y.z">Masto</a>
</body></html>""",
url='https://y.z/', allow_redirects=False,
url='https://y.z/',
)
mock_get.side_effect = [full_redir, hcard]
check(True, True, {
self._test_verify(True, True, {
'type': 'Person',
'name': 'me',
'url': 'http://localhost/r/https://y.z/',
'preferredUsername': 'y.z',
})
# reset
mock_get.side_effect = [empty, empty]
check(False, False, None)
class ActivityTest(testutil.TestCase):