opt in/out prompt: accept yes/no DMs to bot users to enable/disable protocols

for #880
pull/968/head
Ryan Barrett 2024-04-21 08:08:05 -07:00
rodzic 0c37d94191
commit 1686a2ba91
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
4 zmienionych plików z 70 dodań i 1 usunięć

Wyświetl plik

@ -30,6 +30,7 @@ from common import (
host_url,
LOCAL_DOMAINS,
PRIMARY_DOMAIN,
PROTOCOL_DOMAINS,
redirect_wrap,
subdomain_wrap,
unwrap,
@ -56,6 +57,8 @@ WEB_OPT_OUT_DOMAINS = None
FEDI_URL_RE = re.compile(r'https://[^/]+/(@|users/)([^/@]+)(@[^/@]+)?(/(?:statuses/)?[0-9]+)?')
_BOT_ACTOR_IDS = None
def instance_actor():
global _INSTANCE_ACTOR
@ -65,6 +68,15 @@ def instance_actor():
return _INSTANCE_ACTOR
def bot_actor_ids():
global _BOT_ACTOR_IDS
if _BOT_ACTOR_IDS is None:
from activitypub import ActivityPub
_BOT_ACTOR_IDS = [translate_user_id(id=domain, from_=Web, to=ActivityPub)
for domain in PROTOCOL_DOMAINS]
return _BOT_ACTOR_IDS
class ActivityPub(User, Protocol):
"""ActivityPub protocol class.
@ -926,6 +938,7 @@ def inbox(protocol=None, id=None):
# follows, or other activity types, since Mastodon doesn't currently mark
# those as explicitly public. Use as2's is_public instead of as1's because
# as1's interprets unlisted as true.
# TODO: move this to Protocol
if type == 'Create' and not as2.is_public(activity, unlisted=False):
logger.info('Dropping non-public activity')
return 'OK'

Wyświetl plik

@ -804,6 +804,20 @@ class Protocol:
from_user.disable_protocol(proto)
return 'OK', 200
elif obj.type == 'post':
to_cc = (util.get_list(inner_obj_as1, 'to')
+ util.get_list(inner_obj_as1, 'cc'))
if len(to_cc) == 1 and to_cc[0] in PROTOCOL_DOMAINS:
content = inner_obj_as1.get('content').strip().lower()
logger.info(f'DM to bot user {to_cc}: {content}')
proto = Protocol.for_bridgy_subdomain(to_cc[0])
assert proto
if content in ('yes', 'ok'):
from_user.enable_protocol(proto)
elif content == 'no':
from_user.disable_protocol(proto)
return 'OK', 200
# fetch actor if necessary
if actor and actor.keys() == set(['id']):
logger.info('Fetching actor so we have name, profile photo, etc')

Wyświetl plik

@ -829,6 +829,9 @@ class ActivityPubTest(TestCase):
def test_inbox_unlisted(self, *mocks):
self._test_inbox_with_to_ignored(['@unlisted'], *mocks)
def test_inbox_dm(self, *mocks):
self._test_inbox_with_to_ignored(['http://localhost/web/user.com'], *mocks)
def _test_inbox_with_to_ignored(self, to, mock_head, mock_get, mock_post):
Follower.get_or_create(to=self.make_user(ACTOR['id'], cls=ActivityPub),
from_=self.user)

Wyświetl plik

@ -1796,7 +1796,7 @@ class ProtocolReceiveTest(TestCase):
user = self.make_user('eefake:user', cls=ExplicitEnableFake)
self.assertFalse(ExplicitEnableFake.is_enabled_to(Fake, user))
# protocol isn't enabled yet, block should be a noop
# fake protocol isn't enabled yet, block should be a noop
self.assertEqual(('OK', 200), ExplicitEnableFake.receive_as1(block))
user = user.key.get()
self.assertEqual([], user.enabled_protocols)
@ -1826,6 +1826,45 @@ class ProtocolReceiveTest(TestCase):
self.assertEqual([], user.enabled_protocols)
self.assertFalse(ExplicitEnableFake.is_enabled_to(Fake, user))
def test_dm_no_yes_sets_enabled_protocols(self):
dm = {
'objectType': 'note',
'id': 'eefake:dm',
'actor': 'eefake:user',
'to': ['fa.brid.gy'],
'content': 'no',
}
user = self.make_user('eefake:user', cls=ExplicitEnableFake)
self.assertFalse(ExplicitEnableFake.is_enabled_to(Fake, user))
# fake protocol isn't enabled yet, no DM should be a noop
self.assertEqual(('OK', 200), ExplicitEnableFake.receive_as1(dm))
user = user.key.get()
self.assertEqual([], user.enabled_protocols)
# yes DM should add to enabled_protocols
dm['id'] += '2'
dm['content'] = 'yes'
self.assertEqual(('OK', 200), ExplicitEnableFake.receive_as1(dm))
user = user.key.get()
self.assertEqual(['fake'], user.enabled_protocols)
self.assertTrue(ExplicitEnableFake.is_enabled_to(Fake, user))
# another yes DM should be a noop
dm['id'] += '3'
self.assertEqual(('OK', 200), ExplicitEnableFake.receive_as1(dm))
user = user.key.get()
self.assertEqual(['fake'], user.enabled_protocols)
# block should remove from enabled_protocols
dm['id'] += '4'
dm['content'] = ' \n NO '
self.assertEqual(('OK', 200), ExplicitEnableFake.receive_as1(dm))
user = user.key.get()
self.assertEqual([], user.enabled_protocols)
self.assertFalse(ExplicitEnableFake.is_enabled_to(Fake, user))
def test_receive_task_handler(self):
note = {
'id': 'fake:post',