Skip to content

Commit

Permalink
User.get_or_create: don't propagate if the user is blocked
Browse files Browse the repository at this point in the history
ie for web sites that don't have RSS or Atom feed or webmentions

for #1458
  • Loading branch information
snarfed committed Nov 27, 2024
1 parent 5371ba6 commit 5380657
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 68 deletions.
5 changes: 0 additions & 5 deletions activitypub.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,11 +1019,6 @@ def actor(handle_or_id):
if request.host != urlparse(id).netloc:
raise MovedPermanently(location=id)

if not user.obj or not user.obj.as1:
user.obj = proto.load(user.profile_id(), gateway=True)
if user.obj:
user.obj.put()

actor = ActivityPub.convert(user.obj, from_user=user) or {
'@context': [as2.CONTEXT],
'type': 'Person',
Expand Down
6 changes: 3 additions & 3 deletions atproto.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,10 @@ def handle_to_id(cls, handle):

return did.resolve_handle(handle, get_fn=util.requests_get)

def reload_profile(self):
def reload_profile(self, **kwargs):
"""Reloads this user's DID doc along with their profile object."""
super().reload_profile()
self.load(self.key.id(), did_doc=True, remote=True)
super().reload_profile(**kwargs)
self.load(self.key.id(), did_doc=True, remote=True, **kwargs)

@classmethod
def bridged_web_url_for(cls, user, fallback=False):
Expand Down
19 changes: 8 additions & 11 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,11 @@ def _run():

user = cls(id=id, **kwargs)
user.existing = False
user.reload_profile(gateway=True, raise_=False)
if user.status and not allow_opt_out:
return None

if propagate:
if propagate and not user.status:
for label in user.enabled_protocols + list(user.DEFAULT_ENABLED_PROTOCOLS):
proto = PROTOCOLS[label]
if proto == cls:
Expand All @@ -336,13 +337,12 @@ def _run():
#
# these can use urandom() and do nontrivial math, so they can take time
# depending on the amount of randomness available and compute needed.
if not user.existing:
if cls.LABEL != 'activitypub':
key = RSA.generate(KEY_BITS,
randfunc=random.randbytes if DEBUG else None)
user.mod = long_to_base64(key.n)
user.public_exponent = long_to_base64(key.e)
user.private_exponent = long_to_base64(key.d)
if not user.existing and cls.LABEL != 'activitypub':
key = RSA.generate(KEY_BITS,
randfunc=random.randbytes if DEBUG else None)
user.mod = long_to_base64(key.n)
user.public_exponent = long_to_base64(key.e)
user.private_exponent = long_to_base64(key.d)

try:
user.put()
Expand All @@ -356,9 +356,6 @@ def _run():
# load and propagate user and profile object
if user:
logger.debug(('Updated ' if user.existing else 'Created new ') + str(user))
if not user.obj_key:
user.obj = cls.load(user.profile_id())
user.put()

return user

Expand Down
27 changes: 20 additions & 7 deletions tests/test_activitypub.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ def test_actor_conneg_html_redirect_to_profile(self, _, __, ___):
def test_actor_new_user_fetch(self, _, mock_get, __):
self.user.obj_key.delete()
self.user.key.delete()
mock_get.side_effect = test_web.WEB_USER_GETS
mock_get.side_effect = test_web.web_user_gets('user.com')

got = self.client.get('/user.com', headers={'Accept': as2.CONTENT_TYPE})
self.assertEqual(200, got.status_code)
Expand Down Expand Up @@ -599,7 +599,10 @@ def reset_instance_actor():
def test_individual_inbox_no_user(self, mock_head, mock_get, mock_post):
self.user.key.delete()

mock_get.side_effect = [self.as2_resp(LIKE_ACTOR)]
mock_get.side_effect = [
self.as2_resp(LIKE_ACTOR),
self.as2_resp(LIKE_ACTOR),
]

reply = {
**REPLY,
Expand Down Expand Up @@ -750,7 +753,7 @@ def _test_inbox_reply(self, reply, mock_head, mock_get, mock_post):
mock_head.return_value = requests_response(url='https://user.com/post')
mock_get.side_effect = (
(list(mock_get.side_effect) if mock_get.side_effect
else [self.as2_resp(ACTOR)])
else [self.as2_resp(ACTOR), self.as2_resp(ACTOR)])
+ [
requests_response(test_web.NOTE_HTML),
requests_response(test_web.NOTE_HTML),
Expand Down Expand Up @@ -973,6 +976,7 @@ def test_inbox_no_user(self, mock_head, mock_get, mock_post):
mock_get.side_effect = [
# source actor
self.as2_resp(LIKE_WITH_ACTOR['actor']),
self.as2_resp(LIKE_WITH_ACTOR['actor']),
# protocol inference
requests_response(test_web.NOTE_HTML),
requests_response(test_web.NOTE_HTML),
Expand Down Expand Up @@ -1090,6 +1094,7 @@ def test_inbox_like(self, mock_head, mock_get, mock_post):
mock_get.side_effect = [
# source actor
self.as2_resp(LIKE_WITH_ACTOR['actor']),
self.as2_resp(LIKE_WITH_ACTOR['actor']),
requests_response(test_web.NOTE_HTML),
requests_response(test_web.NOTE_HTML),
WEBMENTION_DISCOVERY,
Expand Down Expand Up @@ -1265,6 +1270,7 @@ def _test_inbox_follow_accept(self, follow_as2, accept_as2, mock_head,

mock_head.return_value = requests_response(url='https://user.com/')
mock_get.side_effect = [
self.as2_resp(ACTOR), # source actor
self.as2_resp(ACTOR), # source actor
WEBMENTION_DISCOVERY,
]
Expand Down Expand Up @@ -1709,6 +1715,7 @@ def test_delete_note(self, _, mock_get, ___):

mock_get.side_effect = [
self.as2_resp(ACTOR),
self.as2_resp(ACTOR),
]

delete = {
Expand All @@ -1735,6 +1742,7 @@ def test_update_unknown(self, *mocks):
def _test_update(self, _, mock_get, ___):
mock_get.side_effect = [
self.as2_resp(ACTOR),
self.as2_resp(ACTOR),
]

resp = self.post('/ap/sharedInbox', json=UPDATE_NOTE)
Expand Down Expand Up @@ -1766,6 +1774,7 @@ def test_inbox_webmention_discovery_connection_fails(self, mock_head,
mock_get.side_effect = [
# source actor
self.as2_resp(LIKE_WITH_ACTOR['actor']),
self.as2_resp(LIKE_WITH_ACTOR['actor']),
# protocol inference
requests_response(test_web.NOTE_HTML),
requests_response(test_web.NOTE_HTML),
Expand All @@ -1780,6 +1789,7 @@ def test_inbox_no_webmention_endpoint(self, mock_head, mock_get, mock_post):
mock_get.side_effect = [
# source actor
self.as2_resp(LIKE_WITH_ACTOR['actor']),
self.as2_resp(LIKE_WITH_ACTOR['actor']),
# protocol inference
requests_response(test_web.NOTE_HTML),
requests_response(test_web.NOTE_HTML),
Expand Down Expand Up @@ -1821,11 +1831,14 @@ def test_inbox_id_already_seen(self, mock_head, mock_get, mock_post):
@patch('activitypub.PROTOCOLS', new={'fake': Fake, 'other': OtherFake})
def test_inbox_server_actor_create_with_propagate(
self, mock_head, mock_get, mock_post):
actor = self.as2_resp(add_key({
'id': 'https://mas.to/actor',
'type': 'Person',
}))

mock_get.side_effect = [
self.as2_resp(add_key({
'id': 'https://mas.to/actor',
'type': 'Person',
})),
actor,
actor,
self.as2_resp(NOTE),
]

Expand Down
2 changes: 1 addition & 1 deletion tests/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,8 @@ def test_web_to_activitypub_no_user(self, mock_get):
hcard,
hcard,
hcard,
hcard,
requests_response(status=404), # webfinger for protocol inference
hcard, # user for is_enabled protocol check
]

resp = self.client.get(f'/convert/ap/https://nope.com/post',
Expand Down
3 changes: 2 additions & 1 deletion tests/test_follow.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ def test_callback_stored_followee_with_our_as1(self, mock_get, mock_post):
source_protocol='activitypub')

mock_get.side_effect = (
requests_response(''), # indieauth https://alice.com fetch for user json
requests_response(''), # alice.com h-card
requests_response(''), # indieauth alice.com fetch for user json
)
mock_post.side_effect = (
requests_response('me=https://alice.com'),
Expand Down
3 changes: 2 additions & 1 deletion tests/test_integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ def test_activitypub_follow_bsky_bot_user_enables_protocol(self, mock_get, mock_
'image': 'http://pic',
}))
mock_get.side_effect = [
actor,
actor,
actor,
requests_response('blob', headers={'Content-Type': 'image/jpeg'}),
Expand Down Expand Up @@ -503,8 +504,8 @@ def test_activitypub_follow_bsky_bot_bad_username_error(self, mock_get):
}))
@patch('requests.get', side_effect=[
requests_response(PROFILE_GETRECORD), # alice profile
requests_response(PROFILE_GETRECORD), # ...
requests_response(DID_DOC), # alice DID
requests_response(PROFILE_GETRECORD), # alice profile
requests_response({ # getConvoForMembers
'convo': {
'id': 'convo123',
Expand Down
4 changes: 2 additions & 2 deletions tests/test_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
ACTOR_AS1_UNWRAPPED_URLS,
ACTOR_MF2_REL_URLS,
NOTE as NOTE_HTML_RESP,
WEB_USER_GETS,
web_user_gets,
)


Expand Down Expand Up @@ -3349,7 +3349,7 @@ def test_receive_task_handler_authed_as_domain_vs_homepage(self):
'author': 'user.com',
}, Object.get_by_id('https://user.com/c').our_as1)

@patch('requests.get', side_effect=WEB_USER_GETS + [ACTOR_HTML_RESP])
@patch('requests.get', side_effect=web_user_gets('foo.com') + [ACTOR_HTML_RESP])
def test_receive_task_handler_authed_as_www_subdomain(self, _):
note = {
'id': 'http://www.foo.com/post',
Expand Down
4 changes: 2 additions & 2 deletions tests/test_redirect.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ def test_as2_ld(self):
self._test_as2(as2.CONTENT_TYPE_LD_PROFILE)

@patch('requests.get', side_effect=[
requests_response(status=404), # webfinger
ACTOR_HTML_RESP, # h-card fetch
requests_response(status=404), # webfinger
])
def test_as2_creates_user(self, _):
Object(id='https://user.com/repost', source_protocol='web',
Expand Down Expand Up @@ -141,8 +141,8 @@ def test_as2_fetch_post(self, mock_get):
@patch('requests.get', side_effect=[
requests_response(ACTOR_HTML, url='https://user.com/'), # AS2 fetch
requests_response(ACTOR_HTML, url='https://user.com/'), # web fetch
requests_response(status=404), # webfinger
requests_response(ACTOR_HTML, url='https://user.com/'), # h-card fetch
requests_response(status=404), # webfinger
])
def test_as2_no_user_fetch_homepage(self, mock_get):
self.user.key.delete()
Expand Down
Loading

0 comments on commit 5380657

Please sign in to comment.