Merge pull request #705 from mouse-reeve/federation-errors
Federation errors
This commit is contained in:
commit
1f8e9bc668
|
@ -102,7 +102,7 @@ class ActivityObject:
|
||||||
if allow_create and \
|
if allow_create and \
|
||||||
hasattr(model, 'ignore_activity') and \
|
hasattr(model, 'ignore_activity') and \
|
||||||
model.ignore_activity(self):
|
model.ignore_activity(self):
|
||||||
return None
|
raise ActivitySerializerError()
|
||||||
|
|
||||||
# check for an existing instance
|
# check for an existing instance
|
||||||
instance = instance or model.find_existing(self.serialize())
|
instance = instance or model.find_existing(self.serialize())
|
||||||
|
|
|
@ -449,7 +449,7 @@ def broadcast_task(sender_id, activity, recipients):
|
||||||
for recipient in recipients:
|
for recipient in recipients:
|
||||||
try:
|
try:
|
||||||
sign_and_send(sender, activity, recipient)
|
sign_and_send(sender, activity, recipient)
|
||||||
except (HTTPError, SSLError) as e:
|
except (HTTPError, SSLError, ConnectionError) as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,10 @@ class BookDataModel(ObjectMixin, BookWyrmModel):
|
||||||
self.remote_id = None
|
self.remote_id = None
|
||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def broadcast(self, activity, sender, software='bookwyrm'):
|
||||||
|
''' only send book data updates to other bookwyrm instances '''
|
||||||
|
super().broadcast(activity, sender, software=software)
|
||||||
|
|
||||||
|
|
||||||
class Book(BookDataModel):
|
class Book(BookDataModel):
|
||||||
''' a generic book, which can mean either an edition or a work '''
|
''' a generic book, which can mean either an edition or a work '''
|
||||||
|
|
|
@ -7,6 +7,7 @@ from bookwyrm import activitypub
|
||||||
from .activitypub_mixin import ActivityMixin
|
from .activitypub_mixin import ActivityMixin
|
||||||
from .base_model import BookWyrmModel
|
from .base_model import BookWyrmModel
|
||||||
from . import fields
|
from . import fields
|
||||||
|
from .status import Status
|
||||||
|
|
||||||
class Favorite(ActivityMixin, BookWyrmModel):
|
class Favorite(ActivityMixin, BookWyrmModel):
|
||||||
''' fav'ing a post '''
|
''' fav'ing a post '''
|
||||||
|
@ -17,6 +18,11 @@ class Favorite(ActivityMixin, BookWyrmModel):
|
||||||
|
|
||||||
activity_serializer = activitypub.Like
|
activity_serializer = activitypub.Like
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ignore_activity(cls, activity):
|
||||||
|
''' don't bother with incoming favs of unknown statuses '''
|
||||||
|
return not Status.objects.filter(remote_id=activity.object).exists()
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
''' update user active time '''
|
''' update user active time '''
|
||||||
self.user.last_active_date = timezone.now()
|
self.user.last_active_date = timezone.now()
|
||||||
|
|
|
@ -208,6 +208,9 @@ class BaseActivity(TestCase):
|
||||||
# sets the celery task call to the function call
|
# sets the celery task call to the function call
|
||||||
with patch(
|
with patch(
|
||||||
'bookwyrm.activitypub.base_activity.set_related_field.delay'):
|
'bookwyrm.activitypub.base_activity.set_related_field.delay'):
|
||||||
|
with patch('bookwyrm.models.status.Status.ignore_activity') \
|
||||||
|
as discarder:
|
||||||
|
discarder.return_value = False
|
||||||
update_data.to_model(model=models.Status, instance=status)
|
update_data.to_model(model=models.Status, instance=status)
|
||||||
self.assertIsNone(status.attachments.first())
|
self.assertIsNone(status.attachments.first())
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ class Inbox(TestCase):
|
||||||
mock_valid.return_value = False
|
mock_valid.return_value = False
|
||||||
result = self.client.post(
|
result = self.client.post(
|
||||||
'/user/mouse/inbox',
|
'/user/mouse/inbox',
|
||||||
'{"type": "Test", "object": "exists"}',
|
'{"type": "Announce", "object": "exists"}',
|
||||||
content_type="application/json"
|
content_type="application/json"
|
||||||
)
|
)
|
||||||
self.assertEqual(result.status_code, 401)
|
self.assertEqual(result.status_code, 401)
|
||||||
|
@ -484,7 +484,7 @@ class Inbox(TestCase):
|
||||||
'actor': 'https://example.com/users/rat',
|
'actor': 'https://example.com/users/rat',
|
||||||
'type': 'Like',
|
'type': 'Like',
|
||||||
'published': 'Mon, 25 May 2020 19:31:20 GMT',
|
'published': 'Mon, 25 May 2020 19:31:20 GMT',
|
||||||
'object': 'https://example.com/status/1',
|
'object': self.status.remote_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
views.inbox.activity_task(activity)
|
views.inbox.activity_task(activity)
|
||||||
|
@ -494,6 +494,21 @@ class Inbox(TestCase):
|
||||||
self.assertEqual(fav.remote_id, 'https://example.com/fav/1')
|
self.assertEqual(fav.remote_id, 'https://example.com/fav/1')
|
||||||
self.assertEqual(fav.user, self.remote_user)
|
self.assertEqual(fav.user, self.remote_user)
|
||||||
|
|
||||||
|
def test_ignore_favorite(self):
|
||||||
|
''' don't try to save an unknown status '''
|
||||||
|
activity = {
|
||||||
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
'id': 'https://example.com/fav/1',
|
||||||
|
'actor': 'https://example.com/users/rat',
|
||||||
|
'type': 'Like',
|
||||||
|
'published': 'Mon, 25 May 2020 19:31:20 GMT',
|
||||||
|
'object': 'https://unknown.status/not-found',
|
||||||
|
}
|
||||||
|
|
||||||
|
views.inbox.activity_task(activity)
|
||||||
|
|
||||||
|
self.assertFalse(models.Favorite.objects.exists())
|
||||||
|
|
||||||
def test_handle_unfavorite(self):
|
def test_handle_unfavorite(self):
|
||||||
''' fav a status '''
|
''' fav a status '''
|
||||||
activity = {
|
activity = {
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Inbox(View):
|
||||||
''' requests sent by outside servers'''
|
''' requests sent by outside servers'''
|
||||||
def post(self, request, username=None):
|
def post(self, request, username=None):
|
||||||
''' only works as POST request '''
|
''' only works as POST request '''
|
||||||
# first let's do some basic checks to see if this is legible
|
# make sure the user's inbox even exists
|
||||||
if username:
|
if username:
|
||||||
try:
|
try:
|
||||||
models.User.objects.get(localname=username)
|
models.User.objects.get(localname=username)
|
||||||
|
@ -33,6 +33,11 @@ class Inbox(View):
|
||||||
except json.decoder.JSONDecodeError:
|
except json.decoder.JSONDecodeError:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
if not 'object' in activity_json or \
|
||||||
|
not 'type' in activity_json or \
|
||||||
|
not activity_json['type'] in activitypub.activity_objects:
|
||||||
|
return HttpResponseNotFound()
|
||||||
|
|
||||||
# verify the signature
|
# verify the signature
|
||||||
if not has_valid_signature(request, activity_json):
|
if not has_valid_signature(request, activity_json):
|
||||||
if activity_json['type'] == 'Delete':
|
if activity_json['type'] == 'Delete':
|
||||||
|
@ -42,12 +47,6 @@ class Inbox(View):
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
return HttpResponse(status=401)
|
return HttpResponse(status=401)
|
||||||
|
|
||||||
# just some quick smell tests before we try to parse the json
|
|
||||||
if not 'object' in activity_json or \
|
|
||||||
not 'type' in activity_json or \
|
|
||||||
not activity_json['type'] in activitypub.activity_objects:
|
|
||||||
return HttpResponseNotFound()
|
|
||||||
|
|
||||||
activity_task.delay(activity_json)
|
activity_task.delay(activity_json)
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
|
||||||
|
@ -63,7 +62,11 @@ def activity_task(activity_json):
|
||||||
|
|
||||||
# cool that worked, now we should do the action described by the type
|
# cool that worked, now we should do the action described by the type
|
||||||
# (create, update, delete, etc)
|
# (create, update, delete, etc)
|
||||||
|
try:
|
||||||
activity.action()
|
activity.action()
|
||||||
|
except activitypub.ActivitySerializerError:
|
||||||
|
# this is raised if the activity is discarded
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def has_valid_signature(request, activity):
|
def has_valid_signature(request, activity):
|
||||||
|
|
Loading…
Reference in New Issue