Repository navigation
Routing Note and activity IDs under their Actor so they dereference #324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| import pytest | ||
| from django.urls import reverse | ||
| from rest_framework import status | ||
| from rest_framework.test import APIClient | ||
|
|
||
| from testbed.core.factories import ( | ||
| CreateActivityFactory, | ||
| FollowActivityFactory, | ||
| IsolatedActorFactory, | ||
| LikeActivityFactory, | ||
| NoteFactory, | ||
| ) | ||
| from testbed.core.json_ld_builders import ( | ||
| build_create_activity_json_ld, | ||
| build_follow_activity_json_ld, | ||
| build_like_activity_json_ld, | ||
| build_note_json_ld, | ||
| ) | ||
| from testbed.core.tests.helpers import lola_client | ||
|
|
||
|
|
||
| def detail_url(route, obj, actor=None): | ||
| return reverse(route, kwargs={"pk": (actor or obj.actor).pk, "object_pk": obj.pk}) | ||
|
|
||
|
|
||
| # ActivityPub §3.1: an object dereferences, and a public one is served to anyone exactly as the collections serve it. | ||
| @pytest.mark.django_db | ||
| @pytest.mark.parametrize("route, object_factory, related, build", [ | ||
| ("note-detail", NoteFactory, {}, build_note_json_ld), | ||
| ("create-activity-detail", CreateActivityFactory, {"note": None}, build_create_activity_json_ld), | ||
| ("like-activity-detail", LikeActivityFactory, {"remote": True}, build_like_activity_json_ld), | ||
| ("follow-activity-detail", FollowActivityFactory, {"remote": True}, build_follow_activity_json_ld), | ||
| ]) | ||
| def test_public_object_is_served_to_anyone(basic_auth_context, route, object_factory, related, build): | ||
| obj = object_factory(actor=IsolatedActorFactory(prefix="object_owner"), visibility="public", **related) | ||
|
|
||
| response = APIClient().get(detail_url(route, obj), HTTP_ACCEPT="application/activity+json") | ||
|
|
||
| assert response.status_code == status.HTTP_200_OK | ||
| assert response["Content-Type"] == "application/activity+json" | ||
| assert response.data == build(obj, basic_auth_context) | ||
| # The id is where the object lives, it names the URL just fetched | ||
| assert response.data["id"] == response.wsgi_request.build_absolute_uri() | ||
|
|
||
|
|
||
| # Anything other than "public" is strict. Only a token bound to the owner gets through | ||
| @pytest.mark.django_db | ||
| @pytest.mark.parametrize("visibility", ["private", "followers-only"]) | ||
| def test_non_public_object_is_seen_only_by_its_owner(visibility): | ||
| owner = IsolatedActorFactory(prefix="hidden_owner") | ||
| other = IsolatedActorFactory(prefix="hidden_other") | ||
| url = detail_url("note-detail", NoteFactory(actor=owner, visibility=visibility)) | ||
|
|
||
| assert APIClient().get(url).status_code == status.HTTP_404_NOT_FOUND | ||
| assert lola_client(other).get(url).status_code == status.HTTP_404_NOT_FOUND | ||
| assert lola_client(owner).get(url).status_code == status.HTTP_200_OK | ||
|
|
||
|
|
||
| # A hidden object, a missing one and one under another actor all give the same 404 | ||
| @pytest.mark.django_db | ||
| def test_hidden_missing_and_misplaced_objects_answer_alike(): | ||
| owner = IsolatedActorFactory(prefix="alike_owner") | ||
| other = IsolatedActorFactory(prefix="alike_other") | ||
| hidden = NoteFactory(actor=owner, visibility="private") | ||
| public = NoteFactory(actor=owner, visibility="public") | ||
|
|
||
| responses = [ | ||
| APIClient().get(detail_url("note-detail", hidden)), | ||
| lola_client(other).get(detail_url("note-detail", hidden)), | ||
| APIClient().get(reverse("note-detail", kwargs={"pk": owner.pk, "object_pk": 999999})), | ||
| APIClient().get(detail_url("note-detail", public, actor=other)), | ||
| ] | ||
|
|
||
| answers = {(r.status_code, r.data["error_code"], r.data["detail"], r.data["hint"]) for r in responses} | ||
| assert len(answers) == 1 | ||
| assert answers.pop()[:2] == (status.HTTP_404_NOT_FOUND, "object_not_found") | ||
|
|
||
|
|
||
| # LOLA §5: a token bound to another actor is refused on a public object, as on every dual-mode endpoint | ||
| @pytest.mark.django_db | ||
| def test_public_object_refuses_another_actors_token(): | ||
| owner = IsolatedActorFactory(prefix="refuse_owner") | ||
| other = IsolatedActorFactory(prefix="refuse_other") | ||
| url = detail_url("note-detail", NoteFactory(actor=owner, visibility="public")) | ||
|
|
||
| response = lola_client(other).get(url) | ||
|
|
||
| assert response.status_code == status.HTTP_403_FORBIDDEN | ||
| assert response.data["error_code"] == "actor_mismatch" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This nested "build_x" approach looks very much like a functional approach for what could be simpler as an object-oriented approach - the method is a very thin wrapper. Error response is already an object concept in python requests, and already an inheritance-based one, so a specific "ObjectNotFound" error could be built on the generic "ResourceNotFound" error
Even cleaner (and requiring less utils) is raising custom exceptions and the custom exceptions get handled in post-view common handling that adds the error code.
Looking at this whole util file as more gets added to it and its purpose gets more clear, I am seeing what it does and guessing that it could be replaced with 10 lines even taking this basic functional approach.
Some of these jobs could be done with simple lookups (if the INSUFFICIENT_SCOPE constant is passed or the InsufficientScopeException is thrown, lookup the correct HTTP status code and explanation to return with the Response. ). Other jobs could be done in the Response object or exception handling. The new ID and timestamp jobs don't seem to be adding value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're absolutely right with it. I'll iterate over it.