2017-08-13 07:12:16 +00:00
|
|
|
# coding=utf-8
|
|
|
|
"""Unit tests for activitypub.py.
|
2017-08-13 21:49:35 +00:00
|
|
|
|
|
|
|
TODO: test error handling
|
2017-08-13 07:12:16 +00:00
|
|
|
"""
|
2017-08-23 15:14:51 +00:00
|
|
|
import copy
|
2022-02-09 14:52:41 +00:00
|
|
|
from unittest.mock import ANY, call, patch
|
2017-08-13 07:12:16 +00:00
|
|
|
|
2022-08-24 00:37:50 +00:00
|
|
|
from granary import as2
|
2017-08-23 15:14:51 +00:00
|
|
|
from oauth_dropins.webutil import util
|
2017-08-24 14:41:46 +00:00
|
|
|
from oauth_dropins.webutil.testutil import requests_response
|
2019-12-25 07:26:58 +00:00
|
|
|
from oauth_dropins.webutil.util import json_dumps, json_loads
|
2017-08-13 07:12:16 +00:00
|
|
|
import requests
|
2021-09-01 15:19:38 +00:00
|
|
|
from urllib3.exceptions import ReadTimeoutError
|
2017-08-13 07:12:16 +00:00
|
|
|
|
|
|
|
import activitypub
|
2017-08-15 06:07:24 +00:00
|
|
|
import common
|
2022-11-16 06:00:28 +00:00
|
|
|
from models import Follower, User, Activity
|
2019-12-26 06:20:57 +00:00
|
|
|
from . import testutil
|
2017-08-13 07:12:16 +00:00
|
|
|
|
2018-10-15 15:09:36 +00:00
|
|
|
REPLY_OBJECT = {
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'type': 'Note',
|
|
|
|
'content': 'A ☕ reply',
|
2022-12-10 17:01:04 +00:00
|
|
|
'id': 'http://th.is/reply/id',
|
|
|
|
'url': 'http://th.is/reply',
|
|
|
|
'inReplyTo': 'http://or.ig/post',
|
2022-08-24 00:37:50 +00:00
|
|
|
'to': [as2.PUBLIC_AUDIENCE],
|
2018-10-15 15:09:36 +00:00
|
|
|
}
|
2018-10-17 14:00:31 +00:00
|
|
|
REPLY_OBJECT_WRAPPED = copy.deepcopy(REPLY_OBJECT)
|
2022-12-10 17:01:04 +00:00
|
|
|
REPLY_OBJECT_WRAPPED['inReplyTo'] = 'http://localhost/r/http://or.ig/post'
|
2018-10-21 22:28:42 +00:00
|
|
|
REPLY = {
|
2018-10-15 15:09:36 +00:00
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'type': 'Create',
|
2022-12-10 17:01:04 +00:00
|
|
|
'id': 'http://th.is/reply/as2',
|
2018-10-15 15:09:36 +00:00
|
|
|
'object': REPLY_OBJECT,
|
|
|
|
}
|
2022-11-14 05:46:26 +00:00
|
|
|
NOTE_OBJECT = {
|
2019-04-16 14:59:29 +00:00
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'type': 'Note',
|
2022-11-14 05:46:26 +00:00
|
|
|
'content': '☕ just a normal post',
|
2022-12-10 17:01:04 +00:00
|
|
|
'id': 'http://th.is/note/id',
|
|
|
|
'url': 'http://th.is/note',
|
2022-08-24 00:37:50 +00:00
|
|
|
'to': [as2.PUBLIC_AUDIENCE],
|
2019-04-16 14:59:29 +00:00
|
|
|
'cc': [
|
2022-12-10 17:01:04 +00:00
|
|
|
'https://th.is/author/followers',
|
2019-04-16 14:59:29 +00:00
|
|
|
'https://masto.foo/@other',
|
|
|
|
'http://localhost/target', # redirect-wrapped
|
|
|
|
],
|
|
|
|
}
|
2022-11-14 05:46:26 +00:00
|
|
|
NOTE = {
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'type': 'Create',
|
2022-12-10 17:01:04 +00:00
|
|
|
'id': 'http://th.is/note/as2',
|
2022-11-17 02:53:49 +00:00
|
|
|
'actor': 'https://masto.foo/@author',
|
2022-11-14 05:46:26 +00:00
|
|
|
'object': NOTE_OBJECT,
|
|
|
|
}
|
|
|
|
MENTION_OBJECT = copy.deepcopy(NOTE_OBJECT)
|
2022-11-17 02:53:49 +00:00
|
|
|
MENTION_OBJECT.update({
|
2022-12-10 17:01:04 +00:00
|
|
|
'id': 'http://th.is/mention/id',
|
|
|
|
'url': 'http://th.is/mention',
|
2022-11-17 02:53:49 +00:00
|
|
|
'tag': [{
|
|
|
|
'type': 'Mention',
|
|
|
|
'href': 'https://masto.foo/@other',
|
|
|
|
'name': '@other@masto.foo',
|
|
|
|
}, {
|
|
|
|
'type': 'Mention',
|
2022-12-10 17:01:04 +00:00
|
|
|
'href': 'http://localhost/tar.get', # redirect-wrapped
|
|
|
|
'name': '@tar.get@tar.get',
|
2022-11-17 02:53:49 +00:00
|
|
|
}],
|
|
|
|
})
|
2019-04-16 14:59:29 +00:00
|
|
|
MENTION = {
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'type': 'Create',
|
2022-12-10 17:01:04 +00:00
|
|
|
'id': 'http://th.is/mention/as2',
|
2019-04-16 14:59:29 +00:00
|
|
|
'object': MENTION_OBJECT,
|
|
|
|
}
|
2018-10-17 14:49:04 +00:00
|
|
|
# based on example Mastodon like:
|
|
|
|
# https://github.com/snarfed/bridgy-fed/issues/4#issuecomment-334212362
|
|
|
|
# (reposts are very similar)
|
2018-10-21 22:28:42 +00:00
|
|
|
LIKE = {
|
2018-10-17 14:49:04 +00:00
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
2022-12-10 17:01:04 +00:00
|
|
|
'id': 'http://th.is/like#ok',
|
2018-10-17 14:49:04 +00:00
|
|
|
'type': 'Like',
|
2022-12-10 17:01:04 +00:00
|
|
|
'object': 'http://or.ig/post',
|
|
|
|
'actor': 'http://or.ig/actor',
|
2018-10-17 14:49:04 +00:00
|
|
|
}
|
2018-10-21 22:28:42 +00:00
|
|
|
LIKE_WRAPPED = copy.deepcopy(LIKE)
|
2022-12-10 17:01:04 +00:00
|
|
|
LIKE_WRAPPED['object'] = 'http://localhost/r/http://or.ig/post'
|
2018-10-23 14:52:30 +00:00
|
|
|
LIKE_WITH_ACTOR = copy.deepcopy(LIKE)
|
|
|
|
LIKE_WITH_ACTOR['actor'] = {
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
2022-12-10 17:01:04 +00:00
|
|
|
'id': 'http://or.ig/actor',
|
2018-10-23 14:52:30 +00:00
|
|
|
'type': 'Person',
|
|
|
|
'name': 'Ms. Actor',
|
|
|
|
'preferredUsername': 'msactor',
|
2022-12-10 17:01:04 +00:00
|
|
|
'image': {'type': 'Image', 'url': 'http://or.ig/pic.jpg'},
|
2018-10-23 14:52:30 +00:00
|
|
|
}
|
2018-10-21 22:28:42 +00:00
|
|
|
|
2022-11-17 02:53:49 +00:00
|
|
|
ACTOR = {
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'id': 'https://mastodon.social/users/swentel',
|
|
|
|
'type': 'Person',
|
|
|
|
'inbox': 'http://follower/inbox',
|
|
|
|
}
|
2018-10-23 14:52:30 +00:00
|
|
|
FOLLOW = {
|
2018-10-21 22:28:42 +00:00
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
2018-10-23 14:11:44 +00:00
|
|
|
'id': 'https://mastodon.social/6d1a',
|
2018-10-21 22:28:42 +00:00
|
|
|
'type': 'Follow',
|
2022-11-17 02:53:49 +00:00
|
|
|
'actor': ACTOR['id'],
|
2022-11-08 00:26:33 +00:00
|
|
|
'object': 'https://www.realize.be/',
|
2018-10-21 22:28:42 +00:00
|
|
|
}
|
2018-10-23 14:52:30 +00:00
|
|
|
FOLLOW_WRAPPED = copy.deepcopy(FOLLOW)
|
2022-11-08 00:26:33 +00:00
|
|
|
FOLLOW_WRAPPED['object'] = 'http://localhost/www.realize.be'
|
2018-10-23 14:52:30 +00:00
|
|
|
FOLLOW_WITH_ACTOR = copy.deepcopy(FOLLOW)
|
2022-11-17 02:53:49 +00:00
|
|
|
FOLLOW_WITH_ACTOR['actor'] = ACTOR
|
2018-10-23 14:52:30 +00:00
|
|
|
FOLLOW_WRAPPED_WITH_ACTOR = copy.deepcopy(FOLLOW_WRAPPED)
|
2022-11-17 02:53:49 +00:00
|
|
|
FOLLOW_WRAPPED_WITH_ACTOR['actor'] = ACTOR
|
2018-10-23 14:52:30 +00:00
|
|
|
|
2018-10-21 22:28:42 +00:00
|
|
|
ACCEPT = {
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'type': 'Accept',
|
2023-01-05 23:03:21 +00:00
|
|
|
'id': 'tag:fed.brid.gy:accept/www.realize.be/https://mastodon.social/6d1a',
|
2022-11-08 00:26:33 +00:00
|
|
|
'actor': 'http://localhost/www.realize.be',
|
2018-10-21 22:28:42 +00:00
|
|
|
'object': {
|
|
|
|
'type': 'Follow',
|
|
|
|
'actor': 'https://mastodon.social/users/swentel',
|
2022-11-08 00:26:33 +00:00
|
|
|
'object': 'http://localhost/www.realize.be',
|
2018-10-21 22:28:42 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-15 15:09:36 +00:00
|
|
|
|
2019-08-01 14:32:45 +00:00
|
|
|
UNDO_FOLLOW_WRAPPED = {
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'id': 'https://mastodon.social/6d1b',
|
|
|
|
'type': 'Undo',
|
|
|
|
'actor': 'https://mastodon.social/users/swentel',
|
|
|
|
'object': FOLLOW_WRAPPED,
|
|
|
|
}
|
|
|
|
|
2020-03-01 04:28:53 +00:00
|
|
|
DELETE = {
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'id': 'https://mastodon.social/users/swentel#delete',
|
|
|
|
'type': 'Delete',
|
|
|
|
'actor': 'https://mastodon.social/users/swentel',
|
|
|
|
'object': 'https://mastodon.social/users/swentel',
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-13 06:14:46 +00:00
|
|
|
@patch('requests.post')
|
|
|
|
@patch('requests.get')
|
2018-10-23 14:11:44 +00:00
|
|
|
@patch('requests.head')
|
2017-10-01 14:09:22 +00:00
|
|
|
class ActivityPubTest(testutil.TestCase):
|
2017-08-13 07:12:16 +00:00
|
|
|
|
2021-07-10 15:07:40 +00:00
|
|
|
def test_actor(self, _, mock_get, __):
|
2017-08-24 14:41:46 +00:00
|
|
|
mock_get.return_value = requests_response("""
|
2017-08-13 07:12:16 +00:00
|
|
|
<body>
|
2017-10-24 04:49:43 +00:00
|
|
|
<a class="h-card u-url" rel="me" href="/about-me">Mrs. ☕ Foo</a>
|
2017-08-13 07:12:16 +00:00
|
|
|
</body>
|
2019-10-04 04:08:26 +00:00
|
|
|
""", url='https://foo.com/', content_type=common.CONTENT_TYPE_HTML)
|
2017-08-13 07:12:16 +00:00
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.get('/foo.com')
|
2022-11-16 18:43:34 +00:00
|
|
|
self.assert_req(mock_get, 'https://foo.com/')
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
2019-12-26 06:20:57 +00:00
|
|
|
type = got.headers['Content-Type']
|
2023-01-07 05:01:33 +00:00
|
|
|
self.assertTrue(type.startswith(as2.CONTENT_TYPE), type)
|
2019-12-26 06:20:57 +00:00
|
|
|
self.assertEqual({
|
2021-03-23 06:55:14 +00:00
|
|
|
'@context': [
|
|
|
|
'https://www.w3.org/ns/activitystreams',
|
|
|
|
'https://w3id.org/security/v1',
|
|
|
|
],
|
2017-09-28 14:25:21 +00:00
|
|
|
'type' : 'Person',
|
2017-10-13 06:16:32 +00:00
|
|
|
'name': 'Mrs. ☕ Foo',
|
2019-01-04 15:04:45 +00:00
|
|
|
'summary': '',
|
2017-10-26 15:07:29 +00:00
|
|
|
'preferredUsername': 'foo.com',
|
2017-10-24 04:49:43 +00:00
|
|
|
'id': 'http://localhost/foo.com',
|
2018-10-14 14:58:17 +00:00
|
|
|
'url': 'http://localhost/r/https://foo.com/about-me',
|
2022-11-30 21:19:26 +00:00
|
|
|
'attachment': [{
|
|
|
|
'type': 'PropertyValue',
|
2022-11-30 22:18:38 +00:00
|
|
|
'name': 'Link',
|
2022-12-01 01:40:22 +00:00
|
|
|
'value': '<a rel=\"me\" href="https://foo.com/about-me">foo.com/about-me</a>',
|
2022-11-30 21:19:26 +00:00
|
|
|
}],
|
2017-08-13 07:12:16 +00:00
|
|
|
'inbox': 'http://localhost/foo.com/inbox',
|
2019-01-04 15:04:45 +00:00
|
|
|
'outbox': 'http://localhost/foo.com/outbox',
|
2019-01-14 15:08:04 +00:00
|
|
|
'following': 'http://localhost/foo.com/following',
|
|
|
|
'followers': 'http://localhost/foo.com/followers',
|
2022-11-17 15:42:41 +00:00
|
|
|
'endpoints': {
|
|
|
|
'sharedInbox': 'http://localhost/inbox',
|
|
|
|
},
|
2017-10-01 14:09:22 +00:00
|
|
|
'publicKey': {
|
2022-11-05 22:39:05 +00:00
|
|
|
'id': 'http://localhost/foo.com',
|
|
|
|
'owner': 'http://localhost/foo.com',
|
2022-11-16 06:00:28 +00:00
|
|
|
'publicKeyPem': User.get_by_id('foo.com').public_pem().decode(),
|
2017-10-01 14:09:22 +00:00
|
|
|
},
|
2021-07-10 15:07:40 +00:00
|
|
|
}, got.json)
|
2017-08-13 21:49:35 +00:00
|
|
|
|
2021-07-10 15:07:40 +00:00
|
|
|
def test_actor_no_hcard(self, _, mock_get, __):
|
2017-08-24 14:41:46 +00:00
|
|
|
mock_get.return_value = requests_response("""
|
2017-08-19 20:31:06 +00:00
|
|
|
<body>
|
|
|
|
<div class="h-entry">
|
|
|
|
<p class="e-content">foo bar</p>
|
|
|
|
</div>
|
|
|
|
</body>
|
2017-08-24 14:41:46 +00:00
|
|
|
""")
|
2017-08-19 20:31:06 +00:00
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.get('/foo.com')
|
2022-11-16 18:43:34 +00:00
|
|
|
self.assert_req(mock_get, 'https://foo.com/')
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(400, got.status_code)
|
|
|
|
self.assertIn('representative h-card', got.get_data(as_text=True))
|
2017-08-19 20:31:06 +00:00
|
|
|
|
2021-10-23 04:17:45 +00:00
|
|
|
def test_actor_override_preferredUsername(self, _, mock_get, __):
|
|
|
|
mock_get.return_value = requests_response("""
|
|
|
|
<body>
|
|
|
|
<a class="h-card u-url" rel="me" href="/about-me">
|
|
|
|
<span class="p-nickname">Nick</span>
|
|
|
|
</a>
|
|
|
|
</body>
|
|
|
|
""", url='https://foo.com/', content_type=common.CONTENT_TYPE_HTML)
|
|
|
|
|
|
|
|
got = self.client.get('/foo.com')
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual('foo.com', got.json['preferredUsername'])
|
|
|
|
|
2020-03-02 15:50:37 +00:00
|
|
|
def test_actor_blocked_tld(self, _, __, ___):
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.get('/foo.json')
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(404, got.status_code)
|
2020-03-02 15:50:37 +00:00
|
|
|
|
2022-11-29 01:25:39 +00:00
|
|
|
def test_actor_bad_domain(self, _, mock_get, ___):
|
|
|
|
# https://console.cloud.google.com/errors/detail/CKGv-b6impW3Jg;time=P30D?project=bridgy-federated
|
|
|
|
mock_get.side_effect = [
|
|
|
|
ValueError('Invalid IPv6 URL'),
|
|
|
|
]
|
|
|
|
got = self.client.get('/snarfed.org]')
|
|
|
|
self.assertEqual(400, got.status_code)
|
|
|
|
|
2018-10-23 14:11:44 +00:00
|
|
|
def test_inbox_reply_object(self, *mocks):
|
|
|
|
self._test_inbox_reply(REPLY_OBJECT, REPLY_OBJECT, *mocks)
|
2018-10-15 15:09:36 +00:00
|
|
|
|
2018-10-23 14:11:44 +00:00
|
|
|
def test_inbox_reply_object_wrapped(self, *mocks):
|
|
|
|
self._test_inbox_reply(REPLY_OBJECT_WRAPPED, REPLY_OBJECT, *mocks)
|
2018-10-17 14:00:31 +00:00
|
|
|
|
2018-10-23 14:11:44 +00:00
|
|
|
def test_inbox_reply_create_activity(self, *mocks):
|
|
|
|
self._test_inbox_reply(REPLY, REPLY, *mocks)
|
2018-10-15 15:09:36 +00:00
|
|
|
|
2018-10-23 14:11:44 +00:00
|
|
|
def _test_inbox_reply(self, as2, expected_as2, mock_head, mock_get, mock_post):
|
2022-12-10 17:01:04 +00:00
|
|
|
mock_head.return_value = requests_response(url='http://or.ig/post')
|
2017-08-24 14:41:46 +00:00
|
|
|
mock_get.return_value = requests_response(
|
|
|
|
'<html><head><link rel="webmention" href="/webmention"></html>')
|
|
|
|
mock_post.return_value = requests_response()
|
2017-08-13 21:49:35 +00:00
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json=as2)
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
2022-12-10 17:01:04 +00:00
|
|
|
self.assert_req(mock_get, 'http://or.ig/post')
|
2022-03-17 04:11:09 +00:00
|
|
|
self.assert_req(
|
|
|
|
mock_post,
|
2022-12-10 17:01:04 +00:00
|
|
|
'http://or.ig/webmention',
|
2022-03-17 04:11:09 +00:00
|
|
|
headers={'Accept': '*/*'},
|
|
|
|
allow_redirects=False,
|
2017-08-13 21:49:35 +00:00
|
|
|
data={
|
2022-12-10 17:01:04 +00:00
|
|
|
'source': 'http://localhost/render?source=http%3A%2F%2Fth.is%2Freply&target=http%3A%2F%2For.ig%2Fpost',
|
|
|
|
'target': 'http://or.ig/post',
|
2017-08-13 21:49:35 +00:00
|
|
|
},
|
2022-03-17 04:11:09 +00:00
|
|
|
)
|
2017-10-04 14:07:22 +00:00
|
|
|
|
2022-12-10 17:01:04 +00:00
|
|
|
activity = Activity.get_by_id('http://th.is/reply http://or.ig/post')
|
|
|
|
self.assertEqual(['or.ig'], activity.domain)
|
2022-11-13 17:33:40 +00:00
|
|
|
self.assertEqual('in', activity.direction)
|
|
|
|
self.assertEqual('activitypub', activity.protocol)
|
|
|
|
self.assertEqual('complete', activity.status)
|
|
|
|
self.assertEqual(expected_as2, json_loads(activity.source_as2))
|
2017-10-10 00:29:50 +00:00
|
|
|
|
2022-11-14 15:07:33 +00:00
|
|
|
def test_inbox_reply_to_self_domain(self, mock_head, mock_get, mock_post):
|
2022-12-10 17:01:04 +00:00
|
|
|
self._test_inbox_ignore_reply_to('http://localhost/th.is',
|
2022-11-14 15:07:33 +00:00
|
|
|
mock_head, mock_get, mock_post)
|
2022-12-10 17:01:04 +00:00
|
|
|
self.assert_req(mock_head, 'http://th.is', allow_redirects=True)
|
2022-11-14 15:07:33 +00:00
|
|
|
|
|
|
|
def test_inbox_reply_to_in_blocklist(self, *mocks):
|
2022-11-17 02:53:49 +00:00
|
|
|
self._test_inbox_ignore_reply_to('https://twitter.com/foo', *mocks)
|
2022-11-14 15:07:33 +00:00
|
|
|
|
2022-11-17 02:53:49 +00:00
|
|
|
def _test_inbox_ignore_reply_to(self, reply_to, mock_head, mock_get, mock_post):
|
2019-04-16 14:42:10 +00:00
|
|
|
reply = copy.deepcopy(REPLY_OBJECT)
|
2022-11-14 15:07:33 +00:00
|
|
|
reply['inReplyTo'] = reply_to
|
2019-04-16 14:42:10 +00:00
|
|
|
|
2022-12-10 17:01:04 +00:00
|
|
|
mock_head.return_value = requests_response(url='http://th.is/')
|
2019-04-16 14:42:10 +00:00
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json=reply)
|
2022-11-17 02:53:49 +00:00
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
2019-04-16 14:42:10 +00:00
|
|
|
|
|
|
|
mock_get.assert_not_called()
|
|
|
|
mock_post.assert_not_called()
|
2022-11-12 23:27:59 +00:00
|
|
|
self.assertEqual(0, Activity.query().count())
|
2019-04-16 14:42:10 +00:00
|
|
|
|
2022-11-17 02:53:49 +00:00
|
|
|
def test_inbox_create_activity(self, mock_head, mock_get, mock_post):
|
|
|
|
Follower.get_or_create(ACTOR['id'], 'foo.com')
|
|
|
|
Follower.get_or_create('http://other/actor', 'bar.com')
|
|
|
|
Follower.get_or_create(ACTOR['id'], 'baz.com')
|
|
|
|
|
|
|
|
mock_head.return_value = requests_response(url='http://target')
|
2023-01-07 17:18:11 +00:00
|
|
|
mock_get.return_value = self.as2_resp(ACTOR) # source actor
|
2022-11-17 02:53:49 +00:00
|
|
|
mock_post.return_value = requests_response()
|
|
|
|
|
|
|
|
with self.client:
|
|
|
|
got = self.client.post('/foo.com/inbox', json=NOTE)
|
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
|
|
|
|
2022-12-10 17:01:04 +00:00
|
|
|
activity = Activity.get_by_id('http://th.is/note/as2 Public')
|
2022-11-17 02:53:49 +00:00
|
|
|
self.assertEqual('in', activity.direction)
|
|
|
|
self.assertEqual('activitypub', activity.protocol)
|
|
|
|
self.assertEqual('complete', activity.status)
|
|
|
|
expected_as2 = copy.deepcopy(NOTE)
|
|
|
|
expected_as2['actor'] = ACTOR
|
|
|
|
self.assertEqual(common.redirect_unwrap(expected_as2),
|
|
|
|
json_loads(activity.source_as2))
|
|
|
|
self.assert_equals(['foo.com', 'baz.com'], activity.domain)
|
|
|
|
|
2022-08-24 00:37:50 +00:00
|
|
|
def test_inbox_not_public(self, mock_head, mock_get, mock_post):
|
|
|
|
Follower.get_or_create(ACTOR['id'], 'foo.com')
|
|
|
|
|
|
|
|
mock_head.return_value = requests_response(url='http://target')
|
2023-01-07 17:18:11 +00:00
|
|
|
mock_get.return_value = self.as2_resp(ACTOR) # source actor
|
2022-08-24 00:37:50 +00:00
|
|
|
|
|
|
|
not_public = copy.deepcopy(NOTE)
|
|
|
|
del not_public['object']['to']
|
|
|
|
|
|
|
|
with self.client:
|
|
|
|
got = self.client.post('/foo.com/inbox', json=not_public)
|
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
|
|
|
self.assertEqual(0, Activity.query().count())
|
|
|
|
|
2019-04-16 14:59:29 +00:00
|
|
|
def test_inbox_mention_object(self, *mocks):
|
|
|
|
self._test_inbox_mention(MENTION_OBJECT, *mocks)
|
|
|
|
|
|
|
|
def test_inbox_mention_create_activity(self, *mocks):
|
|
|
|
self._test_inbox_mention(MENTION, *mocks)
|
|
|
|
|
|
|
|
def _test_inbox_mention(self, as2, mock_head, mock_get, mock_post):
|
2022-12-10 17:01:04 +00:00
|
|
|
mock_head.return_value = requests_response(url='http://tar.get')
|
2019-04-16 14:59:29 +00:00
|
|
|
mock_get.return_value = requests_response(
|
|
|
|
'<html><head><link rel="webmention" href="/webmention"></html>')
|
|
|
|
mock_post.return_value = requests_response()
|
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
with self.client:
|
|
|
|
got = self.client.post('/foo.com/inbox', json=as2)
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
2022-12-10 17:01:04 +00:00
|
|
|
self.assert_req(mock_get, 'http://tar.get/')
|
2022-03-17 04:11:09 +00:00
|
|
|
self.assert_req(
|
|
|
|
mock_post,
|
2022-12-10 17:01:04 +00:00
|
|
|
'http://tar.get/webmention',
|
2022-03-17 04:11:09 +00:00
|
|
|
headers={'Accept': '*/*'},
|
|
|
|
allow_redirects=False,
|
2021-07-10 15:07:40 +00:00
|
|
|
data={
|
2022-12-10 17:01:04 +00:00
|
|
|
'source': 'http://localhost/render?source=http%3A%2F%2Fth.is%2Fmention&target=http%3A%2F%2Ftar.get%2F',
|
|
|
|
'target': 'http://tar.get/',
|
2021-07-10 15:07:40 +00:00
|
|
|
},
|
2022-03-17 04:11:09 +00:00
|
|
|
)
|
2021-07-10 15:07:40 +00:00
|
|
|
|
2022-12-10 17:01:04 +00:00
|
|
|
activity = Activity.get_by_id('http://th.is/mention http://tar.get/')
|
|
|
|
self.assertEqual(['tar.get'], activity.domain)
|
2022-11-13 17:33:40 +00:00
|
|
|
self.assertEqual('in', activity.direction)
|
|
|
|
self.assertEqual('activitypub', activity.protocol)
|
|
|
|
self.assertEqual('complete', activity.status)
|
|
|
|
self.assertEqual(common.redirect_unwrap(as2), json_loads(activity.source_as2))
|
2019-04-16 14:59:29 +00:00
|
|
|
|
2018-10-23 14:11:44 +00:00
|
|
|
def test_inbox_like(self, mock_head, mock_get, mock_post):
|
2022-12-10 17:01:04 +00:00
|
|
|
mock_head.return_value = requests_response(url='http://or.ig/post')
|
2017-10-13 06:14:46 +00:00
|
|
|
mock_get.side_effect = [
|
|
|
|
# source actor
|
2023-01-07 17:18:11 +00:00
|
|
|
self.as2_resp(LIKE_WITH_ACTOR['actor']),
|
2017-10-13 06:14:46 +00:00
|
|
|
# target post webmention discovery
|
|
|
|
requests_response(
|
|
|
|
'<html><head><link rel="webmention" href="/webmention"></html>'),
|
|
|
|
]
|
2017-10-11 05:42:19 +00:00
|
|
|
mock_post.return_value = requests_response()
|
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json=LIKE)
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
2017-10-13 06:14:46 +00:00
|
|
|
|
2022-11-24 16:20:04 +00:00
|
|
|
mock_get.assert_has_calls((
|
2022-12-10 17:01:04 +00:00
|
|
|
self.as2_req('http://or.ig/actor'),
|
|
|
|
self.req('http://or.ig/post'),
|
2022-11-24 16:20:04 +00:00
|
|
|
)),
|
2017-10-10 00:29:50 +00:00
|
|
|
|
2017-10-11 05:42:19 +00:00
|
|
|
args, kwargs = mock_post.call_args
|
2022-12-10 17:01:04 +00:00
|
|
|
self.assertEqual(('http://or.ig/webmention',), args)
|
2019-12-26 06:20:57 +00:00
|
|
|
self.assertEqual({
|
2017-10-11 05:42:19 +00:00
|
|
|
# TODO
|
2022-12-10 17:01:04 +00:00
|
|
|
'source': 'http://localhost/render?source=http%3A%2F%2Fth.is%2Flike__ok&target=http%3A%2F%2For.ig%2Fpost',
|
|
|
|
'target': 'http://or.ig/post',
|
2017-10-11 05:42:19 +00:00
|
|
|
}, kwargs['data'])
|
|
|
|
|
2022-12-10 17:01:04 +00:00
|
|
|
activity = Activity.get_by_id('http://th.is/like__ok http://or.ig/post')
|
|
|
|
self.assertEqual(['or.ig'], activity.domain)
|
2022-11-13 17:33:40 +00:00
|
|
|
self.assertEqual('in', activity.direction)
|
|
|
|
self.assertEqual('activitypub', activity.protocol)
|
|
|
|
self.assertEqual('complete', activity.status)
|
|
|
|
self.assertEqual(LIKE_WITH_ACTOR, json_loads(activity.source_as2))
|
2017-10-17 05:21:13 +00:00
|
|
|
|
2023-01-09 01:28:12 +00:00
|
|
|
def test_inbox_follow_accept_with_id(self, mock_head, mock_get, mock_post):
|
|
|
|
self._test_inbox_follow_accept(FOLLOW_WRAPPED, ACCEPT,
|
|
|
|
mock_head, mock_get, mock_post)
|
|
|
|
|
|
|
|
activity = Activity.query().get()
|
2023-01-12 20:28:34 +00:00
|
|
|
follow = copy.deepcopy(FOLLOW_WITH_ACTOR)
|
|
|
|
follow['url'] = 'https://mastodon.social/users/swentel#followed-https://www.realize.be/'
|
|
|
|
|
|
|
|
self.assertEqual(follow, json_loads(activity.source_as2))
|
2023-01-09 01:28:12 +00:00
|
|
|
|
|
|
|
follower = Follower.query().get()
|
|
|
|
self.assertEqual(FOLLOW_WRAPPED_WITH_ACTOR, json_loads(follower.last_follow))
|
|
|
|
|
|
|
|
def test_inbox_follow_accept_with_object(self, mock_head, mock_get, mock_post):
|
|
|
|
wrapped_user = {
|
|
|
|
'id': FOLLOW_WRAPPED['object'],
|
|
|
|
'url': FOLLOW_WRAPPED['object'],
|
|
|
|
}
|
|
|
|
unwrapped_user = {
|
|
|
|
'id': FOLLOW['object'],
|
|
|
|
'url': FOLLOW['object'],
|
|
|
|
}
|
|
|
|
|
|
|
|
follow = copy.deepcopy(FOLLOW_WRAPPED)
|
|
|
|
follow['object'] = wrapped_user
|
|
|
|
|
|
|
|
accept = copy.deepcopy(ACCEPT)
|
|
|
|
accept['actor'] = accept['object']['object'] = wrapped_user
|
|
|
|
|
|
|
|
self._test_inbox_follow_accept(follow, accept, mock_head, mock_get, mock_post)
|
|
|
|
|
|
|
|
follower = Follower.query().get()
|
|
|
|
follow.update({
|
|
|
|
'actor': ACTOR,
|
|
|
|
'object': wrapped_user,
|
|
|
|
})
|
|
|
|
self.assertEqual(follow, json_loads(follower.last_follow))
|
|
|
|
|
2023-01-12 20:28:34 +00:00
|
|
|
activity = Activity.query().get()
|
|
|
|
follow.update({
|
|
|
|
'actor': FOLLOW_WITH_ACTOR['actor'],
|
|
|
|
'object': unwrapped_user,
|
|
|
|
'url': 'https://mastodon.social/users/swentel#followed-https://www.realize.be/',
|
|
|
|
})
|
|
|
|
self.assertEqual(follow, json_loads(activity.source_as2))
|
|
|
|
|
2023-01-09 01:28:12 +00:00
|
|
|
def _test_inbox_follow_accept(self, follow_as2, accept_as2,
|
|
|
|
mock_head, mock_get, mock_post):
|
2022-11-08 00:26:33 +00:00
|
|
|
mock_head.return_value = requests_response(url='https://www.realize.be/')
|
2018-10-21 22:28:42 +00:00
|
|
|
mock_get.side_effect = [
|
|
|
|
# source actor
|
2023-01-07 17:18:11 +00:00
|
|
|
self.as2_resp(FOLLOW_WITH_ACTOR['actor']),
|
2018-10-23 14:11:44 +00:00
|
|
|
# target post webmention discovery
|
|
|
|
requests_response(
|
|
|
|
'<html><head><link rel="webmention" href="/webmention"></html>'),
|
2018-10-21 22:28:42 +00:00
|
|
|
]
|
|
|
|
mock_post.return_value = requests_response()
|
|
|
|
|
2023-01-09 01:28:12 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json=follow_as2)
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
2018-10-21 22:28:42 +00:00
|
|
|
|
2022-11-24 16:20:04 +00:00
|
|
|
mock_get.assert_has_calls((
|
|
|
|
self.as2_req(FOLLOW['actor']),
|
|
|
|
))
|
2018-10-21 22:28:42 +00:00
|
|
|
|
2018-10-23 14:11:44 +00:00
|
|
|
# check AP Accept
|
|
|
|
self.assertEqual(2, len(mock_post.call_args_list))
|
|
|
|
args, kwargs = mock_post.call_args_list[0]
|
2019-12-26 06:20:57 +00:00
|
|
|
self.assertEqual(('http://follower/inbox',), args)
|
2023-01-09 01:28:12 +00:00
|
|
|
self.assertEqual(accept_as2, json_loads(kwargs['data']))
|
2018-10-21 22:28:42 +00:00
|
|
|
|
2018-10-23 14:11:44 +00:00
|
|
|
# check webmention
|
|
|
|
args, kwargs = mock_post.call_args_list[1]
|
2022-11-08 00:26:33 +00:00
|
|
|
self.assertEqual(('https://www.realize.be/webmention',), args)
|
2019-12-26 06:20:57 +00:00
|
|
|
self.assertEqual({
|
2022-11-08 00:26:33 +00:00
|
|
|
'source': 'http://localhost/render?source=https%3A%2F%2Fmastodon.social%2F6d1a&target=https%3A%2F%2Fwww.realize.be%2F',
|
|
|
|
'target': 'https://www.realize.be/',
|
2018-10-23 14:11:44 +00:00
|
|
|
}, kwargs['data'])
|
|
|
|
|
2022-11-13 17:33:40 +00:00
|
|
|
activity = Activity.get_by_id('https://mastodon.social/6d1a https://www.realize.be/')
|
2022-11-17 02:53:49 +00:00
|
|
|
self.assertEqual(['www.realize.be'], activity.domain)
|
2022-11-13 17:33:40 +00:00
|
|
|
self.assertEqual('in', activity.direction)
|
|
|
|
self.assertEqual('activitypub', activity.protocol)
|
|
|
|
self.assertEqual('complete', activity.status)
|
2018-10-23 14:11:44 +00:00
|
|
|
|
2018-10-22 00:37:33 +00:00
|
|
|
# check that we stored a Follower object
|
2022-11-11 23:44:35 +00:00
|
|
|
follower = Follower.get_by_id(f'www.realize.be {FOLLOW["actor"]}')
|
2019-08-01 14:32:45 +00:00
|
|
|
self.assertEqual('active', follower.status)
|
2018-10-22 00:37:33 +00:00
|
|
|
|
2022-12-06 22:09:44 +00:00
|
|
|
def test_inbox_follow_use_instead_strip_www(self, mock_head, mock_get, mock_post):
|
|
|
|
root = User.get_or_create('realize.be')
|
|
|
|
User.get_or_create('www.realize.be', use_instead=root.key)
|
|
|
|
|
|
|
|
mock_head.return_value = requests_response(url='https://www.realize.be/')
|
|
|
|
mock_get.side_effect = [
|
|
|
|
# source actor
|
2023-01-07 17:18:11 +00:00
|
|
|
self.as2_resp(ACTOR),
|
2022-12-06 22:09:44 +00:00
|
|
|
# target post webmention discovery
|
|
|
|
requests_response('<html></html>'),
|
|
|
|
]
|
|
|
|
mock_post.return_value = requests_response()
|
|
|
|
|
|
|
|
follow = copy.deepcopy(FOLLOW_WRAPPED)
|
|
|
|
follow['object'] = 'http://localhost/realize.be'
|
|
|
|
got = self.client.post('/foo.com/inbox', json=follow)
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
|
|
|
|
# check that the Follower doesn't have www
|
|
|
|
follower = Follower.get_by_id(f'realize.be {ACTOR["id"]}')
|
|
|
|
self.assertEqual('active', follower.status)
|
|
|
|
|
|
|
|
follow['actor'] = ACTOR
|
|
|
|
self.assertEqual(follow, json_loads(follower.last_follow))
|
|
|
|
|
2019-08-01 14:32:45 +00:00
|
|
|
def test_inbox_undo_follow(self, mock_head, mock_get, mock_post):
|
2022-11-08 00:26:33 +00:00
|
|
|
mock_head.return_value = requests_response(url='https://www.realize.be/')
|
2019-08-01 14:32:45 +00:00
|
|
|
|
2022-11-17 02:53:49 +00:00
|
|
|
Follower.get_or_create('www.realize.be', ACTOR['id'])
|
2019-08-01 14:32:45 +00:00
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json=UNDO_FOLLOW_WRAPPED)
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
2019-08-01 14:32:45 +00:00
|
|
|
|
2022-11-11 23:44:35 +00:00
|
|
|
follower = Follower.get_by_id(f'www.realize.be {FOLLOW["actor"]}')
|
2019-08-01 14:32:45 +00:00
|
|
|
self.assertEqual('inactive', follower.status)
|
|
|
|
|
2022-11-30 06:43:04 +00:00
|
|
|
def test_inbox_follow_inactive(self, mock_head, mock_get, mock_post):
|
|
|
|
Follower.get_or_create('www.realize.be', ACTOR['id'], status='inactive')
|
|
|
|
|
|
|
|
mock_head.return_value = requests_response(url='https://www.realize.be/')
|
|
|
|
mock_get.side_effect = [
|
|
|
|
# source actor
|
2023-01-07 17:18:11 +00:00
|
|
|
self.as2_resp(FOLLOW_WITH_ACTOR['actor']),
|
2022-11-30 06:43:04 +00:00
|
|
|
# target post webmention discovery
|
|
|
|
requests_response(
|
|
|
|
'<html><head><link rel="webmention" href="/webmention"></html>'),
|
|
|
|
]
|
|
|
|
mock_post.return_value = requests_response()
|
|
|
|
|
|
|
|
got = self.client.post('/foo.com/inbox', json=FOLLOW_WRAPPED)
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
|
|
|
|
# check that the Follower is now active
|
|
|
|
follower = Follower.get_by_id(f'www.realize.be {FOLLOW["actor"]}')
|
|
|
|
self.assertEqual('active', follower.status)
|
|
|
|
|
2019-08-01 14:32:45 +00:00
|
|
|
def test_inbox_undo_follow_doesnt_exist(self, mock_head, mock_get, mock_post):
|
|
|
|
mock_head.return_value = requests_response(url='https://realize.be/')
|
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json=UNDO_FOLLOW_WRAPPED)
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
2019-08-01 14:32:45 +00:00
|
|
|
|
|
|
|
def test_inbox_undo_follow_inactive(self, mock_head, mock_get, mock_post):
|
|
|
|
mock_head.return_value = requests_response(url='https://realize.be/')
|
2022-11-17 02:53:49 +00:00
|
|
|
Follower.get_or_create('realize.be', ACTOR['id'], status='inactive')
|
2019-08-01 14:32:45 +00:00
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json=UNDO_FOLLOW_WRAPPED)
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
2019-08-01 14:32:45 +00:00
|
|
|
|
2023-01-10 06:58:30 +00:00
|
|
|
def test_inbox_undo_follow_composite_object(self, mock_head, mock_get, mock_post):
|
|
|
|
mock_head.return_value = requests_response(url='https://realize.be/')
|
|
|
|
Follower.get_or_create('realize.be', ACTOR['id'], status='inactive')
|
|
|
|
|
|
|
|
undo_follow = copy.deepcopy(UNDO_FOLLOW_WRAPPED)
|
|
|
|
undo_follow['object']['object'] = {'id': undo_follow['object']['object']}
|
|
|
|
got = self.client.post('/foo.com/inbox', json=undo_follow)
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
|
2018-10-23 14:11:44 +00:00
|
|
|
def test_inbox_unsupported_type(self, *_):
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json={
|
2017-10-17 05:21:13 +00:00
|
|
|
'@context': ['https://www.w3.org/ns/activitystreams'],
|
|
|
|
'id': 'https://xoxo.zone/users/aaronpk#follows/40',
|
2018-10-21 22:28:42 +00:00
|
|
|
'type': 'Block',
|
2017-10-17 05:21:13 +00:00
|
|
|
'actor': 'https://xoxo.zone/users/aaronpk',
|
|
|
|
'object': 'http://snarfed.org/',
|
2021-07-10 15:07:40 +00:00
|
|
|
})
|
|
|
|
self.assertEqual(501, got.status_code)
|
2020-03-01 04:28:53 +00:00
|
|
|
|
2022-12-10 17:01:04 +00:00
|
|
|
def test_inbox_bad_object_url(self, mock_head, mock_get, mock_post):
|
|
|
|
# https://console.cloud.google.com/errors/detail/CMKn7tqbq-GIRA;time=P30D?project=bridgy-federated
|
2023-01-07 17:18:11 +00:00
|
|
|
mock_get.return_value = self.as2_resp(ACTOR) # source actor
|
2022-12-10 17:01:04 +00:00
|
|
|
got = self.client.post('/foo.com/inbox', json={
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'id': 'https://mastodon.social/users/tmichellemoore#likes/56486252',
|
|
|
|
'type': 'Like',
|
|
|
|
'actor': ACTOR['id'],
|
|
|
|
'object': 'http://localhost/r/Testing \u2013 Brid.gy \u2013 Post to Mastodon 3',
|
|
|
|
})
|
|
|
|
|
|
|
|
# bad object, should ignore activity
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
mock_post.assert_not_called()
|
|
|
|
self.assertEqual(0, Activity.query().count())
|
|
|
|
|
2022-11-21 20:14:37 +00:00
|
|
|
def test_individual_inbox_delete_actor_noop(self, mock_head, mock_get, mock_post):
|
|
|
|
"""Deletes sent to individual users' inboxes do nothing."""
|
2020-03-01 04:28:53 +00:00
|
|
|
follower = Follower.get_or_create('realize.be', DELETE['actor'])
|
2022-11-21 20:14:37 +00:00
|
|
|
followee = Follower.get_or_create(DELETE['actor'], 'snarfed.org')
|
2020-03-01 04:28:53 +00:00
|
|
|
# other unrelated follower
|
|
|
|
other = Follower.get_or_create('realize.be', 'https://mas.to/users/other')
|
|
|
|
self.assertEqual(3, Follower.query().count())
|
|
|
|
|
2021-08-18 14:59:52 +00:00
|
|
|
got = self.client.post('/realize.be/inbox', json=DELETE)
|
2021-07-10 15:07:40 +00:00
|
|
|
self.assertEqual(200, got.status_code)
|
2022-11-21 20:14:37 +00:00
|
|
|
self.assertEqual('active', follower.key.get().status)
|
|
|
|
self.assertEqual('active', followee.key.get().status)
|
|
|
|
self.assertEqual('active', other.key.get().status)
|
|
|
|
|
|
|
|
def test_shared_inbox_delete_actor(self, mock_head, mock_get, mock_post):
|
|
|
|
"""Deletes sent to the shared inbox actually deactivate followers."""
|
|
|
|
follower = Follower.get_or_create('realize.be', DELETE['actor'])
|
|
|
|
followee = Follower.get_or_create(DELETE['actor'], 'snarfed.org')
|
|
|
|
# other unrelated follower
|
|
|
|
other = Follower.get_or_create('realize.be', 'https://mas.to/users/other')
|
|
|
|
self.assertEqual(3, Follower.query().count())
|
|
|
|
|
|
|
|
got = self.client.post('/inbox', json=DELETE)
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
self.assertEqual('inactive', follower.key.get().status)
|
|
|
|
self.assertEqual('inactive', followee.key.get().status)
|
|
|
|
self.assertEqual('active', other.key.get().status)
|
2020-03-01 04:28:53 +00:00
|
|
|
|
2021-09-01 15:19:38 +00:00
|
|
|
def test_inbox_webmention_discovery_connection_fails(self, mock_head,
|
|
|
|
mock_get, mock_post):
|
|
|
|
mock_get.side_effect = [
|
|
|
|
# source actor
|
2023-01-07 17:18:11 +00:00
|
|
|
self.as2_resp(LIKE_WITH_ACTOR['actor']),
|
2021-09-01 15:19:38 +00:00
|
|
|
# target post webmention discovery
|
|
|
|
ReadTimeoutError(None, None, None),
|
|
|
|
]
|
|
|
|
|
|
|
|
got = self.client.post('/foo.com/inbox', json=LIKE)
|
|
|
|
self.assertEqual(504, got.status_code)
|
|
|
|
|
2022-01-12 06:40:24 +00:00
|
|
|
def test_inbox_no_webmention_endpoint(self, mock_head, mock_get, mock_post):
|
|
|
|
mock_get.side_effect = [
|
|
|
|
# source actor
|
2023-01-07 17:18:11 +00:00
|
|
|
self.as2_resp(LIKE_WITH_ACTOR['actor']),
|
2022-01-12 06:40:24 +00:00
|
|
|
# target post webmention discovery
|
|
|
|
requests_response('<html><body>foo</body></html>'),
|
|
|
|
]
|
|
|
|
|
|
|
|
got = self.client.post('/foo.com/inbox', json=LIKE)
|
|
|
|
self.assertEqual(200, got.status_code)
|
|
|
|
|
2022-12-10 17:01:04 +00:00
|
|
|
activity = Activity.get_by_id('http://th.is/like__ok http://or.ig/post')
|
|
|
|
self.assertEqual(['or.ig'], activity.domain)
|
2022-11-13 17:33:40 +00:00
|
|
|
self.assertEqual('in', activity.direction)
|
|
|
|
self.assertEqual('activitypub', activity.protocol)
|
|
|
|
self.assertEqual('ignored', activity.status)
|
2022-11-22 02:46:10 +00:00
|
|
|
|
|
|
|
def test_followers_collection_unknown_user(self, *args):
|
|
|
|
resp = self.client.get('/foo.com/followers')
|
|
|
|
self.assertEqual(404, resp.status_code)
|
|
|
|
|
|
|
|
def test_followers_collection(self, *args):
|
|
|
|
User.get_or_create('foo.com')
|
|
|
|
|
|
|
|
resp = self.client.get('/foo.com/followers')
|
|
|
|
self.assertEqual(200, resp.status_code)
|
|
|
|
self.assertEqual({
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'summary': "foo.com's followers",
|
|
|
|
'type': 'Collection',
|
|
|
|
'totalItems': 0,
|
|
|
|
'items': [],
|
|
|
|
}, resp.json)
|
|
|
|
|
|
|
|
Follower.get_or_create('foo.com', 'bar.com')
|
|
|
|
Follower.get_or_create('http://other/actor', 'foo.com')
|
|
|
|
Follower.get_or_create('foo.com', 'baz.com')
|
|
|
|
Follower.get_or_create('foo.com', 'baj.com', status='inactive')
|
|
|
|
|
|
|
|
resp = self.client.get('/foo.com/followers')
|
|
|
|
self.assertEqual(200, resp.status_code)
|
|
|
|
self.assertEqual({
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'summary': "foo.com's followers",
|
|
|
|
'type': 'Collection',
|
|
|
|
'totalItems': 2,
|
|
|
|
'items': [],
|
|
|
|
# TODO
|
|
|
|
# {
|
|
|
|
# 'type': 'Create',
|
|
|
|
# 'actor': 'http://www.test.example/sally',
|
|
|
|
# 'object': 'http://example.org/foo',
|
|
|
|
# },
|
|
|
|
# {
|
|
|
|
# 'type': 'Like',
|
|
|
|
# 'actor': 'http://www.test.example/joe',
|
|
|
|
# 'object': 'http://example.org/foo',
|
|
|
|
# }],
|
|
|
|
}, resp.json)
|
|
|
|
|
|
|
|
def test_following_collection_unknown_user(self, *args):
|
|
|
|
resp = self.client.get('/foo.com/following')
|
|
|
|
self.assertEqual(404, resp.status_code)
|
|
|
|
|
|
|
|
def test_following_collection(self, *args):
|
|
|
|
User.get_or_create('foo.com')
|
|
|
|
|
|
|
|
resp = self.client.get('/foo.com/following')
|
|
|
|
self.assertEqual(200, resp.status_code)
|
|
|
|
self.assertEqual({
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'summary': "foo.com's following",
|
|
|
|
'type': 'Collection',
|
|
|
|
'totalItems': 0,
|
|
|
|
'items': [],
|
|
|
|
}, resp.json)
|
|
|
|
|
|
|
|
Follower.get_or_create('bar.com', 'foo.com')
|
|
|
|
Follower.get_or_create('foo.com', 'http://other/actor')
|
|
|
|
Follower.get_or_create('baz.com', 'foo.com')
|
|
|
|
Follower.get_or_create('baj.com', 'foo.com', status='inactive')
|
|
|
|
|
|
|
|
resp = self.client.get('/foo.com/following')
|
|
|
|
self.assertEqual(200, resp.status_code)
|
|
|
|
self.assertEqual({
|
|
|
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
|
|
'summary': "foo.com's following",
|
|
|
|
'type': 'Collection',
|
|
|
|
'totalItems': 2,
|
|
|
|
'items': [],
|
|
|
|
}, resp.json)
|