Web.owns_id: check TLD against brevity's allowlist

fixes #1115
pull/1153/head
Ryan Barrett 2024-06-20 23:16:43 -07:00
rodzic bf657d3409
commit 84949f265b
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
7 zmienionych plików z 90 dodań i 99 usunięć

Wyświetl plik

@ -34,7 +34,7 @@ from . import test_activitypub
DID_DOC = {
'id': 'did:plc:user',
'alsoKnownAs': ['at://han.dull'],
'alsoKnownAs': ['at://ha.nl'],
'verificationMethod': [{
'id': 'did:plc:user#atproto',
'type': 'Multikey',
@ -108,12 +108,12 @@ class ATProtoTest(TestCase):
def test_handle(self):
self.store_object(id='did:plc:user', raw=DID_DOC)
self.assertEqual('han.dull', ATProto(id='did:plc:user').handle)
self.assertEqual('ha.nl', ATProto(id='did:plc:user').handle)
@patch('requests.get', return_value=requests_response(DID_DOC))
def test_get_or_create(self, _):
user = self.make_user('did:plc:user', cls=ATProto)
self.assertEqual('han.dull', user.key.get().handle)
self.assertEqual('ha.nl', user.key.get().handle)
def test_owns_id(self):
self.assertFalse(ATProto.owns_id('http://foo'))
@ -148,13 +148,13 @@ class ATProtoTest(TestCase):
def test_handle_to_id(self):
self.store_object(id='did:plc:user', raw=DID_DOC)
self.make_user('did:plc:user', cls=ATProto)
self.assertEqual('did:plc:user', ATProto.handle_to_id('han.dull'))
self.assertEqual('did:plc:user', ATProto.handle_to_id('ha.nl'))
@patch('dns.resolver.resolve', side_effect=NXDOMAIN())
# resolving handle, HTTPS method, not found
@patch('requests.get', return_value=requests_response('', status=404))
def test_handle_to_id_not_found(self, *_):
self.assertIsNone(ATProto.handle_to_id('han.dull'))
self.assertIsNone(ATProto.handle_to_id('ha.nl'))
def test_bridged_web_url_for(self):
self.assertIsNone(ATProto.bridged_web_url_for(ATProto(id='did:plc:foo')))
@ -164,7 +164,7 @@ class ATProtoTest(TestCase):
fake.copies = [Target(uri='did:plc:user', protocol='atproto')]
self.store_object(id='did:plc:user', raw=DID_DOC)
self.assertEqual('https://bsky.app/profile/han.dull',
self.assertEqual('https://bsky.app/profile/ha.nl',
ATProto.bridged_web_url_for(fake))
def test_pds_for_did_no_doc(self):
@ -316,8 +316,8 @@ class ATProtoTest(TestCase):
json=None, data=None, headers=ANY)
def test_fetch_bsky_app_url_fails(self):
for uri in ('https://bsky.app/profile/han.dull',
'https://bsky.app/profile/han.dull/post/789'):
for uri in ('https://bsky.app/profile/ha.nl',
'https://bsky.app/profile/ha.nl/post/789'):
with self.assertRaises(AssertionError):
ATProto.fetch(Object(id=uri))
@ -350,7 +350,7 @@ class ATProtoTest(TestCase):
requests_response(DID_DOC),
])
def test_load_bsky_app_post_url(self, mock_get, _):
obj = ATProto.load('https://bsky.app/profile/han.dull/post/789')
obj = ATProto.load('https://bsky.app/profile/ha.nl/post/789')
self.assertEqual('at://did:plc:user/app.bsky.feed.post/789', obj.key.id())
self.assertEqual({
'$type': 'app.bsky.actor.profile',
@ -374,7 +374,7 @@ class ATProtoTest(TestCase):
self.store_object(id='did:plc:user', raw=DID_DOC)
self.make_user('did:plc:user', cls=ATProto)
obj = ATProto.load('https://bsky.app/profile/han.dull')
obj = ATProto.load('https://bsky.app/profile/ha.nl')
self.assertEqual('at://did:plc:user/app.bsky.actor.profile/self', obj.key.id())
self.assertEqual({
'$type': 'app.bsky.actor.profile',
@ -522,7 +522,7 @@ class ATProtoTest(TestCase):
'objectType': 'activity',
'verb': 'like',
# handle here should be replaced with DID in returned record's URI
'object': 'at://han.dull/app.bsky.feed.post/tid',
'object': 'at://ha.nl/app.bsky.feed.post/tid',
})))
mock_get.assert_called_with(
'https://appview.local/xrpc/com.atproto.repo.getRecord?repo=did%3Aplc%3Auser&collection=app.bsky.feed.post&rkey=tid',
@ -633,11 +633,11 @@ class ATProtoTest(TestCase):
def test_convert_resolve_mention_handle(self, mock_get):
self.store_object(id='did:plc:user', raw=DID_DOC)
content = 'hi <a href="https://bsky.app/profile/han.dull">@han.dull</a> hows it going'
content = 'hi <a href="https://bsky.app/profile/ha.nl">@ha.nl</a> hows it going'
self.assertEqual({
'$type': 'app.bsky.feed.post',
'createdAt': '2022-01-02T03:04:05.000Z',
'text': 'hi @han.dull hows it going',
'text': 'hi @ha.nl hows it going',
'bridgyOriginalText': content,
'facets': [{
'$type': 'app.bsky.richtext.facet',
@ -646,7 +646,7 @@ class ATProtoTest(TestCase):
'did': 'did:plc:user',
}],
'index': {
'byteEnd': 12,
'byteEnd': 9,
'byteStart': 3,
},
}],
@ -659,7 +659,7 @@ class ATProtoTest(TestCase):
'tags': [{
'objectType': 'mention',
'url': 'did:plc:user',
'displayName': '@han.dull'
'displayName': '@ha.nl'
}],
})))
@ -668,11 +668,11 @@ class ATProtoTest(TestCase):
def test_convert_resolve_mention_handle_drop_server(self, mock_get):
self.store_object(id='did:plc:user', raw=DID_DOC)
content = 'hi <a href="https://bsky.brid.gy/ap/did:plc:user">@<span>han.dull</span></a> hows it going'
content = 'hi <a href="https://bsky.brid.gy/ap/did:plc:user">@<span>ha.nl</span></a> hows it going'
self.assertEqual({
'$type': 'app.bsky.feed.post',
'createdAt': '2022-01-02T03:04:05.000Z',
'text': 'hi @han.dull hows it going',
'text': 'hi @ha.nl hows it going',
'bridgyOriginalText': content,
'facets': [{
'$type': 'app.bsky.richtext.facet',
@ -681,7 +681,7 @@ class ATProtoTest(TestCase):
'did': 'did:plc:user',
}],
'index': {
'byteEnd': 12,
'byteEnd': 9,
'byteStart': 3,
},
}],
@ -694,7 +694,7 @@ class ATProtoTest(TestCase):
# we should find the mentioned handle in the content text even
# if it doesn't have @ser.ver
# https://github.com/snarfed/bridgy-fed/issues/957
'displayName': '@han.dull@ser.ver'
'displayName': '@ha.nl@ser.ver'
}],
})))
@ -803,7 +803,7 @@ Sed tortor neque, aliquet quis posuere aliquam […]
self.assertEqual('https://bsky.app/profile/did:plc:user', user.web_url())
self.store_object(id='did:plc:user', raw=DID_DOC)
self.assertEqual('https://bsky.app/profile/han.dull', user.web_url())
self.assertEqual('https://bsky.app/profile/ha.nl', user.web_url())
@patch('requests.get', return_value=requests_response('', status=404))
def test_handle_or_id(self, mock_get):
@ -812,8 +812,8 @@ Sed tortor neque, aliquet quis posuere aliquam […]
self.assertEqual('did:plc:user', user.handle_or_id())
self.store_object(id='did:plc:user', raw=DID_DOC)
self.assertEqual('han.dull', user.handle)
self.assertEqual('han.dull', user.handle_or_id())
self.assertEqual('ha.nl', user.handle)
self.assertEqual('ha.nl', user.handle_or_id())
@patch('requests.get', return_value=requests_response('', status=404))
def test_handle_as(self, mock_get):
@ -824,7 +824,7 @@ Sed tortor neque, aliquet quis posuere aliquam […]
# user.handle_as('activitypub'))
self.store_object(id='did:plc:user', raw=DID_DOC)
self.assertEqual('@han.dull@bsky.brid.gy', user.handle_as('activitypub'))
self.assertEqual('@ha.nl@bsky.brid.gy', user.handle_as('activitypub'))
@patch('requests.get', return_value=requests_response(DID_DOC))
def test_profile_id(self, mock_get):
@ -1603,7 +1603,7 @@ Sed tortor neque, aliquet quis posuere aliquam […]
client = DatastoreClient('https://appview.local')
self.assertEqual({'did': 'did:plc:user'},
client.com.atproto.identity.resolveHandle(handle='han.dull'))
client.com.atproto.identity.resolveHandle(handle='ha.nl'))
def test_datastore_client_resolve_handle_datastore_repo(self):
self.make_user_and_repo()

Wyświetl plik

@ -40,15 +40,15 @@ class UserTest(TestCase):
def setUp(self):
super().setUp()
self.user = self.make_user('y.z', cls=Web)
self.user = self.make_user('y.za', cls=Web)
def test_get_by_id_opted_out(self):
self.assert_entities_equal(self.user, Web.get_by_id('y.z'))
self.assert_entities_equal(self.user, Web.get_by_id('y.za'))
self.user.obj.our_as1 = {'summary': '#nobridge'}
self.user.obj.put()
self.user.put()
self.assertIsNone(Web.get_by_id('y.z'))
self.assertIsNone(Web.get_by_id('y.za'))
def test_get_or_create(self):
user = Fake.get_or_create('fake:user')
@ -140,7 +140,7 @@ class UserTest(TestCase):
user.put()
got = Fake.get_or_create('fake:a')
self.assertEqual('y.z', got.key.id())
self.assertEqual('y.za', got.key.id())
assert got.existing
def test_get_or_create_by_copies(self):
@ -164,8 +164,8 @@ class UserTest(TestCase):
self.assertTrue(pem.decode().endswith('-----END RSA PRIVATE KEY-----'), pem)
def test_user_page_path(self):
self.assertEqual('/web/y.z', self.user.user_page_path())
self.assertEqual('/web/y.z/followers', self.user.user_page_path('followers'))
self.assertEqual('/web/y.za', self.user.user_page_path())
self.assertEqual('/web/y.za/followers', self.user.user_page_path('followers'))
fake_foo = self.make_user('fake:foo', cls=Fake)
self.assertEqual('/fa/fake:handle:foo', fake_foo.user_page_path())
@ -173,37 +173,37 @@ class UserTest(TestCase):
def test_user_link(self):
self.assert_multiline_equals("""\
<span class="logo" title="Web">🌐</span>
<a class="h-card u-author" href="/web/y.z" title="y.z ">
y.z
<a class="h-card u-author" href="/web/y.za" title="y.za ">
y.za
</a>""", self.user.user_link(), ignore_blanks=True)
self.user.obj = Object(id='a', as2=ACTOR)
self.assert_multiline_equals("""\
<span class="logo" title="Web">🌐</span>
<a class="h-card u-author" href="/web/y.z" title="Mrs. ☕ Foo ">
<a class="h-card u-author" href="/web/y.za" title="Mrs. ☕ Foo ">
<img src="https://user.com/me.jpg" class="profile">
Mrs. Foo
</a>""", self.user.user_link(), ignore_blanks=True)
def test_is_web_url(self):
for url in 'y.z', '//y.z', 'http://y.z', 'https://y.z':
for url in 'y.za', '//y.za', 'http://y.za', 'https://y.za':
self.assertTrue(self.user.is_web_url(url), url)
for url in (None, '', 'user', 'com', 'com.user', 'ftp://y.z',
'https://user', '://y.z'):
for url in (None, '', 'user', 'com', 'com.user', 'ftp://y.za',
'https://user', '://y.za'):
self.assertFalse(self.user.is_web_url(url), url)
def test_name(self):
self.assertEqual('y.z', self.user.name())
self.assertEqual('y.za', self.user.name())
self.user.obj = Object(id='a', as2={'id': 'abc'})
self.assertEqual('y.z', self.user.name())
self.assertEqual('y.za', self.user.name())
self.user.obj = Object(id='a', as2={'name': 'alice'})
self.assertEqual('alice', self.user.name())
def test_handle(self):
self.assertEqual('y.z', self.user.handle)
self.assertEqual('y.za', self.user.handle)
def test_id_as(self):
user = self.make_user('fake:user', cls=Fake)
@ -220,10 +220,10 @@ class UserTest(TestCase):
def test_handle_as_web_custom_username(self, *_):
self.user.obj.our_as1 = {
'objectType': 'person',
'url': 'acct:alice@y.z',
'url': 'acct:alice@y.za',
}
self.assertEqual('alice', self.user.username())
self.assertEqual('@y.z@web.brid.gy', self.user.handle_as('ap'))
self.assertEqual('@y.za@web.brid.gy', self.user.handle_as('ap'))
def test_handle_as_None(self):
class NoHandle(Fake):
@ -355,7 +355,7 @@ class UserTest(TestCase):
Follower(from_=Fake(id='c').key, to=self.user.key).put()
# still cached
user = Web.get_by_id('y.z')
user = Web.get_by_id('y.za')
self.assertEqual((0, 0), user.count_followers())
User.count_followers.cache.clear()
@ -537,11 +537,11 @@ class ObjectTest(TestCase):
self.assertEqual(3, Object.query().count())
# if no data property is set, don't clear existing data properties
obj7 = Object.get_or_create('http://b.i/ff', as2={'a': 'b'}, mf2={'c': 'd'},
obj7 = Object.get_or_create('http://b.ee/ff', as2={'a': 'b'}, mf2={'c': 'd'},
source_protocol='web')
Object.get_or_create('http://b.i/ff', authed_as='http://b.i/ff',
Object.get_or_create('http://b.ee/ff', authed_as='http://b.ee/ff',
users=[ndb.Key(Web, 'me')])
self.assert_object('http://b.i/ff', as2={'a': 'b'}, mf2={'c': 'd'},
self.assert_object('http://b.ee/ff', as2={'a': 'b'}, mf2={'c': 'd'},
users=[ndb.Key(Web, 'me')],
source_protocol='web')
@ -1021,7 +1021,7 @@ class ObjectTest(TestCase):
'objectType': 'activity',
'verb': 'follow',
'actor': 'https://bsky.app/profile/did:plc:123',
'object': 'https://bsky.app/profile/han.dull',
'object': 'https://bsky.app/profile/ha.nl',
})
obj.normalize_ids()
self.assert_equals({
@ -1040,10 +1040,10 @@ class ObjectTest(TestCase):
'objectType': 'activity',
'verb': 'post',
'object': {
'id': 'https://bsky.app/profile/han.dull/post/456',
'id': 'https://bsky.app/profile/ha.nl/post/456',
'objectType': 'note',
'inReplyTo': 'https://bsky.app/profile/did:plc:123/post/789',
'author': 'https://bsky.app/profile/han.dull',
'author': 'https://bsky.app/profile/ha.nl',
'tags': [{
'objectType': 'mention',
'url': 'https://bsky.app/profile/did:plc:123',

Wyświetl plik

@ -116,25 +116,25 @@ class ProtocolTest(TestCase):
self.assertEqual(Greedy, Protocol.for_id('https://bar/baz'))
def test_for_id_object(self):
self.store_object(id='http://u.i/obj', source_protocol='ui')
self.assertEqual(UIProtocol, Protocol.for_id('http://u.i/obj'))
self.store_object(id='http://ui.org/obj', source_protocol='ui')
self.assertEqual(UIProtocol, Protocol.for_id('http://ui.org/obj'))
@patch('requests.get', return_value=requests_response())
def test_for_id_object_missing_source_protocol(self, _):
self.store_object(id='http://ba.d/obj')
self.assertIsNone(Protocol.for_id('http://ba.d/obj'))
self.store_object(id='http://b.ad/obj')
self.assertIsNone(Protocol.for_id('http://b.ad/obj'))
@patch('requests.get')
def test_for_id_activitypub_fetch(self, mock_get):
mock_get.return_value = self.as2_resp(ACTOR)
self.assertEqual(ActivityPub, Protocol.for_id('http://a.p/actor'))
self.assertIn(self.as2_req('http://a.p/actor'), mock_get.mock_calls)
self.assertEqual(ActivityPub, Protocol.for_id('http://ap.org/actor'))
self.assertIn(self.as2_req('http://ap.org/actor'), mock_get.mock_calls)
@patch('requests.get')
def test_for_id_activitypub_fetch_fails(self, mock_get):
mock_get.return_value = requests_response('', status=403)
self.assertIsNone(Protocol.for_id('http://a.p/actor'))
self.assertIn(self.as2_req('http://a.p/actor'), mock_get.mock_calls)
self.assertIsNone(Protocol.for_id('http://ap.org/actor'))
self.assertIn(self.as2_req('http://ap.org/actor'), mock_get.mock_calls)
mock_get.assert_called_once()
@patch('requests.get')
@ -176,9 +176,9 @@ class ProtocolTest(TestCase):
self.assertEqual((None, None), Protocol.for_handle('user.com'))
@patch('dns.resolver.resolve', return_value = dns_answer(
'_atproto.han.dull.', '"did=did:plc:123abc"'))
'_atproto.ha.nl.', '"did=did:plc:123abc"'))
def test_for_handle_atproto_resolve(self, _):
self.assertEqual((ATProto, 'did:plc:123abc'), Protocol.for_handle('han.dull'))
self.assertEqual((ATProto, 'did:plc:123abc'), Protocol.for_handle('ha.nl'))
def test_load(self):
Fake.fetchable['foo'] = {'x': 'y'}
@ -275,7 +275,7 @@ class ProtocolTest(TestCase):
@patch('requests.get', return_value=ACTOR_HTML_RESP)
def test_load_remote_true_clear_our_as1(self, _):
self.store_object(id='https://fo.o', our_as1={'should': 'disappear'},
self.store_object(id='https://f.ooo', our_as1={'should': 'disappear'},
source_protocol='web')
expected_mf2 = {
@ -283,7 +283,7 @@ class ProtocolTest(TestCase):
'url': 'https://user.com/',
}
loaded = Web.load('https://fo.o', remote=True)
loaded = Web.load('https://f.ooo', remote=True)
self.assertEqual(expected_mf2, loaded.mf2)
self.assertIsNone(loaded.our_as1)
self.assertEqual(ACTOR_AS1_UNWRAPPED_URLS, loaded.as1)

Wyświetl plik

@ -193,7 +193,7 @@ REPLY_HTML = """\
<body>
<div class="h-entry">
<p class="e-content p-name">
<a class="u-in-reply-to" href="http://no.t/fediverse"></a>
<a class="u-in-reply-to" href="http://no.tt/fediverse"></a>
<a class="u-in-reply-to" href="https://mas.to/toot">foo bar</a>
<a href="http://localhost/"></a>
</p>
@ -248,12 +248,12 @@ AS2_CREATE = {
'id': 'http://localhost/r/https://user.com/reply',
'name': 'foo ☕ bar',
'content': """\
<p><a class="u-in-reply-to" href="http://no.t/fediverse"></a>
<p><a class="u-in-reply-to" href="http://no.tt/fediverse"></a>
<a class="u-in-reply-to" href="https://mas.to/toot">foo bar</a>
<a href="http://localhost/"></a></p>""",
'contentMap': {
'en': """\
<p><a class="u-in-reply-to" href="http://no.t/fediverse"></a>
<p><a class="u-in-reply-to" href="http://no.tt/fediverse"></a>
<a class="u-in-reply-to" href="https://mas.to/toot">foo bar</a>
<a href="http://localhost/"></a></p>""",
},
@ -386,7 +386,7 @@ NOT_FEDIVERSE = requests_response("""\
<div class="e-content">foo</div>
</body>
</html>
""", url='http://no.t/fediverse')
""", url='http://no.tt/fediverse')
ACTIVITYPUB_GETS = [
REPLY,
NOT_FEDIVERSE, # AP
@ -646,7 +646,7 @@ class WebTest(TestCase):
mock_get.side_effect = (
requests_response(
REPLY_HTML.replace('https://mas.to/toot', 'bad:nope')\
.replace('http://no.t/fediverse', ''),
.replace('http://no.tt/fediverse', ''),
content_type=CONTENT_TYPE_HTML, url='https://user.com/reply'),
ValueError('foo bar'), # AS2 fetch
ValueError('foo bar'), # HTML fetch
@ -677,9 +677,9 @@ class WebTest(TestCase):
requests_response(
REPLY_HTML.replace('https://mas.to/toot', 'bad:nope'),
url='https://user.com/post'),
# http://no.t/fediverse AP protocol discovery
# http://no.tt/fediverse AP protocol discovery
requests.Timeout('foo bar'),
# http://no.t/fediverse web protocol discovery
# http://no.tt/fediverse web protocol discovery
requests.Timeout('foo bar'),
]
@ -688,7 +688,7 @@ class WebTest(TestCase):
self.assertEqual(204, got.status_code)
def test_target_fetch_has_no_content_type(self, mock_get, mock_post):
Object(id='http://no.t/fediverse', mf2=NOTE_MF2, source_protocol='web').put()
Object(id='http://no.tt/fediverse', mf2=NOTE_MF2, source_protocol='web').put()
no_content_type = requests_response(REPLY_HTML, content_type='')
@ -698,7 +698,7 @@ class WebTest(TestCase):
no_content_type, # https://mas.to/toot AP protocol discovery
no_content_type, # https://mas.to/toot Web protocol discovery
no_content_type, # https://user.com/ webmention discovery
no_content_type, # http://no.t/fediverse webmention discovery
no_content_type, # http://no.tt/fediverse webmention discovery
)
got = self.post('/queue/webmention', data={'source': 'https://user.com/reply'})
self.assertEqual(204, got.status_code)
@ -744,8 +744,8 @@ class WebTest(TestCase):
mock_get.assert_has_calls((
self.req('https://user.com/reply'),
self.as2_req('http://no.t/fediverse'),
self.req('http://no.t/fediverse'),
self.as2_req('http://no.tt/fediverse'),
self.req('http://no.tt/fediverse'),
self.as2_req('https://mas.to/toot'),
self.as2_req('https://mas.to/author'),
))
@ -868,8 +868,8 @@ class WebTest(TestCase):
mock_get.assert_has_calls((
self.req('https://user.com/reply'),
self.as2_req('http://no.t/fediverse'),
self.req('http://no.t/fediverse'),
self.as2_req('http://no.tt/fediverse'),
self.req('http://no.tt/fediverse'),
self.as2_req('https://mas.to/toot'),
self.as2_req('https://mas.to/author'),
))
@ -957,8 +957,8 @@ class WebTest(TestCase):
mock_get.assert_has_calls((
self.req('https://user.com/reply'),
self.as2_req('http://no.t/fediverse'),
self.req('http://no.t/fediverse'),
self.as2_req('http://no.tt/fediverse'),
self.req('http://no.tt/fediverse'),
self.as2_req('https://mas.to/toot'),
self.as2_req('https://mas.to/toot/id', headers=as2.CONNEG_HEADERS),
self.as2_req('https://mas.to/author'),
@ -2372,7 +2372,7 @@ http://this/404s
]
self._test_verify(True, True, {})
# preferredUsername stays y.z despite user's username. since Mastodon
# preferredUsername stays y.za despite user's username. since Mastodon
# queries Webfinger for preferredUsername@fed.brid.gy
# https://github.com/snarfed/bridgy-fed/issues/77#issuecomment-949955109
postprocessed = ActivityPub.convert(self.user.obj, from_user=self.user)
@ -2480,7 +2480,7 @@ http://this/404s
self.assertEqual(1, Web.query().count())
def test_check_web_site_url_with_path(self, _, __):
got = self.post('/web-site', data={'url': 'https://si.te/foo/bar'})
got = self.post('/web-site', data={'url': 'https://a.site/foo/bar'})
self.assert_equals(400, got.status_code)
self.assertEqual(['Only top-level web sites and domains are supported.'],
get_flashed_messages())
@ -2565,6 +2565,8 @@ class WebUtilTest(TestCase):
self.assertIsNone(Web.owns_id('https://bar.com/baz'))
self.assertEqual(False, Web.owns_id('at://did:plc:foo/bar/123'))
self.assertEqual(False, Web.owns_id('e45fab982'))
self.assertEqual(False, Web.owns_id('foo.bad'))
self.assertEqual(False, Web.owns_id('foo.json'))
self.assertIsNone(Web.owns_id('user.com'))
self.user.has_redirects = True
@ -2789,7 +2791,7 @@ class WebUtilTest(TestCase):
def test_fetch_user_homepage_non_representative_hcard(self, mock_get, __):
mock_get.return_value = requests_response(
'<html><body><a class="h-card u-url" href="https://a.b/">acct:me@y.z</a></body></html>',
'<html><body><a class="h-card u-url" href="https://a.b/">acct:me@y.za</a></body></html>',
content_type=CONTENT_TYPE_HTML)
obj = Object(id='https://user.com/')

Wyświetl plik

@ -342,10 +342,13 @@ class WebfingerTest(TestCase):
self.assertEqual(400, got.status_code, got.get_data(as_text=True))
def test_bad_tld(self):
got = self.client.get(
f'/.well-known/webfinger?resource=acct:user.json@user.json',
base_url='https://web.brid.gy/')
self.assertEqual(400, got.status_code, got.get_data(as_text=True))
for tld in 'json', 'bad':
for host in f'user.{tld}', 'web.brid.gy', 'fed.brid.gy':
with self.subTest(tld=tld, host=host):
got = self.client.get(
f'/.well-known/webfinger?resource=acct:user.{tld}@{host}',
base_url='https://web.brid.gy/')
self.assertEqual(400, got.status_code, got.get_data(as_text=True))
def test_no_handle(self):
class NoHandle(Fake):

18
web.py
Wyświetl plik

@ -8,6 +8,7 @@ import urllib.parse
from urllib.parse import quote, urlencode, urljoin, urlparse
from xml.etree import ElementTree
import brevity
from flask import redirect, render_template, request
from google.cloud import ndb
from google.cloud.ndb import ComputedProperty
@ -42,21 +43,6 @@ logger = logging.getLogger(__name__)
WWW_DOMAINS = frozenset((
'www.jvt.me',
))
NON_TLDS = frozenset((
'gz',
'html',
'ini',
'jpg',
'json',
'php',
'png',
'sql',
'tgz',
'txt',
'xml',
'yaml',
'yml',
))
FEED_TYPES = {
atom.CONTENT_TYPE.split(';')[0]: 'atom',
@ -88,7 +74,7 @@ def is_valid_domain(domain, allow_internal=True):
return False
tld = domain.split('.')[-1]
if tld in NON_TLDS:
if tld not in brevity.TLDS:
logger.info(f"{domain} looks like a domain but {tld} isn't a TLD")
return False

Wyświetl plik

@ -85,7 +85,7 @@ class Webfinger(flask_util.XrdOrJrd):
id = cls.handle_to_id(handle)
if not id:
error(f'{id} is not a valid {cls.LABEL} id')
error(f'{resource} is not a valid handle for a {cls.LABEL} user')
logger.info(f'Protocol {cls.LABEL}, user id {id}')