kopia lustrzana https://github.com/snarfed/bridgy-fed
opt in/out prompt: accept yes/no DMs to bot users to enable/disable protocols
for #880pull/968/head
rodzic
0c37d94191
commit
1686a2ba91
|
@ -30,6 +30,7 @@ from common import (
|
||||||
host_url,
|
host_url,
|
||||||
LOCAL_DOMAINS,
|
LOCAL_DOMAINS,
|
||||||
PRIMARY_DOMAIN,
|
PRIMARY_DOMAIN,
|
||||||
|
PROTOCOL_DOMAINS,
|
||||||
redirect_wrap,
|
redirect_wrap,
|
||||||
subdomain_wrap,
|
subdomain_wrap,
|
||||||
unwrap,
|
unwrap,
|
||||||
|
@ -56,6 +57,8 @@ WEB_OPT_OUT_DOMAINS = None
|
||||||
|
|
||||||
FEDI_URL_RE = re.compile(r'https://[^/]+/(@|users/)([^/@]+)(@[^/@]+)?(/(?:statuses/)?[0-9]+)?')
|
FEDI_URL_RE = re.compile(r'https://[^/]+/(@|users/)([^/@]+)(@[^/@]+)?(/(?:statuses/)?[0-9]+)?')
|
||||||
|
|
||||||
|
_BOT_ACTOR_IDS = None
|
||||||
|
|
||||||
|
|
||||||
def instance_actor():
|
def instance_actor():
|
||||||
global _INSTANCE_ACTOR
|
global _INSTANCE_ACTOR
|
||||||
|
@ -65,6 +68,15 @@ def instance_actor():
|
||||||
return _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):
|
class ActivityPub(User, Protocol):
|
||||||
"""ActivityPub protocol class.
|
"""ActivityPub protocol class.
|
||||||
|
|
||||||
|
@ -926,6 +938,7 @@ def inbox(protocol=None, id=None):
|
||||||
# follows, or other activity types, since Mastodon doesn't currently mark
|
# 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
|
# those as explicitly public. Use as2's is_public instead of as1's because
|
||||||
# as1's interprets unlisted as true.
|
# as1's interprets unlisted as true.
|
||||||
|
# TODO: move this to Protocol
|
||||||
if type == 'Create' and not as2.is_public(activity, unlisted=False):
|
if type == 'Create' and not as2.is_public(activity, unlisted=False):
|
||||||
logger.info('Dropping non-public activity')
|
logger.info('Dropping non-public activity')
|
||||||
return 'OK'
|
return 'OK'
|
||||||
|
|
14
protocol.py
14
protocol.py
|
@ -804,6 +804,20 @@ class Protocol:
|
||||||
from_user.disable_protocol(proto)
|
from_user.disable_protocol(proto)
|
||||||
return 'OK', 200
|
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
|
# fetch actor if necessary
|
||||||
if actor and actor.keys() == set(['id']):
|
if actor and actor.keys() == set(['id']):
|
||||||
logger.info('Fetching actor so we have name, profile photo, etc')
|
logger.info('Fetching actor so we have name, profile photo, etc')
|
||||||
|
|
|
@ -829,6 +829,9 @@ class ActivityPubTest(TestCase):
|
||||||
def test_inbox_unlisted(self, *mocks):
|
def test_inbox_unlisted(self, *mocks):
|
||||||
self._test_inbox_with_to_ignored(['@unlisted'], *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):
|
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),
|
Follower.get_or_create(to=self.make_user(ACTOR['id'], cls=ActivityPub),
|
||||||
from_=self.user)
|
from_=self.user)
|
||||||
|
|
|
@ -1796,7 +1796,7 @@ class ProtocolReceiveTest(TestCase):
|
||||||
user = self.make_user('eefake:user', cls=ExplicitEnableFake)
|
user = self.make_user('eefake:user', cls=ExplicitEnableFake)
|
||||||
self.assertFalse(ExplicitEnableFake.is_enabled_to(Fake, user))
|
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))
|
self.assertEqual(('OK', 200), ExplicitEnableFake.receive_as1(block))
|
||||||
user = user.key.get()
|
user = user.key.get()
|
||||||
self.assertEqual([], user.enabled_protocols)
|
self.assertEqual([], user.enabled_protocols)
|
||||||
|
@ -1826,6 +1826,45 @@ class ProtocolReceiveTest(TestCase):
|
||||||
self.assertEqual([], user.enabled_protocols)
|
self.assertEqual([], user.enabled_protocols)
|
||||||
self.assertFalse(ExplicitEnableFake.is_enabled_to(Fake, user))
|
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):
|
def test_receive_task_handler(self):
|
||||||
note = {
|
note = {
|
||||||
'id': 'fake:post',
|
'id': 'fake:post',
|
||||||
|
|
Ładowanie…
Reference in New Issue