diff --git a/Dockerfile b/Dockerfile index 0c80b83da..8d6afe8ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM elixir:alpine -RUN apk add --no-cache inotify-tools postgresql-client yarn file make gcc libc-dev argon2 imagemagick cmake build-base libwebp-tools bash ncurses git +RUN apk add --no-cache inotify-tools postgresql-client yarn file make gcc libc-dev argon2 imagemagick cmake build-base libwebp-tools bash ncurses git python3 RUN mix local.hex --force && mix local.rebar --force diff --git a/Makefile b/Makefile index f0eb6eff6..1542c6179 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ init: - @bash docker/message.sh "start" + @bash docker/message.sh "Start" make start setup: stop @@ -10,16 +10,18 @@ migrate: logs: docker-compose logs -f start: stop - @bash docker/message.sh "starting Mobilizon with docker" + @bash docker/message.sh "Starting Mobilizon with Docker" docker-compose up -d api - @bash docker/message.sh "Docker server started." + @bash docker/message.sh "Docker server started" stop: - @bash docker/message.sh "stopping Mobilizon" + @bash docker/message.sh "Stopping Mobilizon" docker-compose down - @bash docker/message.sh "stopped" + @bash docker/message.sh "Mobilizon is stopped" test: stop @bash docker/message.sh "Running tests" - docker-compose -f docker-compose.yml -f docker-compose.test.yml run api mix test - @bash docker/message.sh "Tests runned" - + docker-compose -f docker-compose.yml -f docker-compose.test.yml run api mix test $(only) + @bash docker/message.sh "Done running tests" +format: + docker-compose run --rm api bash -c "mix format && mix credo --strict" + @bash docker/message.sh "Code is now ready to commit :)" target: init diff --git a/lib/federation/activity_pub/transmogrifier.ex b/lib/federation/activity_pub/transmogrifier.ex index ca14b42d0..e0c28c5d2 100644 --- a/lib/federation/activity_pub/transmogrifier.ex +++ b/lib/federation/activity_pub/transmogrifier.ex @@ -67,29 +67,30 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do def handle_incoming(%{"type" => "Create", "object" => %{"type" => "Note"} = object}) do Logger.info("Handle incoming to create notes") - with object_data when is_map(object_data) <- - object |> Converter.Comment.as_to_model_data(), - {:existing_comment, {:error, :comment_not_found}} <- - {:existing_comment, Discussions.get_comment_from_url_with_preload(object_data.url)}, - object_data <- transform_object_data_for_discussion(object_data), - # Check should be better - - {:ok, %Activity{} = activity, entity} <- - (if is_data_for_comment_or_discussion?(object_data) do - Logger.debug("Chosing to create a regular comment") - Actions.Create.create(:comment, object_data, false) - else - Logger.debug("Chosing to initialize or add a comment to a conversation") - Actions.Create.create(:discussion, object_data, false) - end) do - {:ok, activity, entity} - else - {:existing_comment, {:ok, %Comment{} = comment}} -> - {:ok, nil, comment} - - {:error, :event_not_allow_commenting} -> - Logger.debug("Tried to reply to an event for which comments are closed") + case Converter.Comment.as_to_model_data(object) do + %{visibility: visibility, event_id: event_id} + when visibility != :public and event_id != nil -> + Logger.info("Tried to reply to an event with a private comment - ignore") :error + + object_data when is_map(object_data) -> + case Discussions.get_comment_from_url_with_preload(object_data.url) do + {:error, :comment_not_found} -> + object_data = transform_object_data_for_discussion(object_data) + + case create_comment_or_discussion(object_data) do + {:ok, %Activity{} = activity, entity} -> + {:ok, activity, entity} + + {:error, :event_not_allow_commenting} -> + Logger.debug("Tried to reply to an event for which comments are closed") + :error + end + + {:ok, %Comment{} = comment} -> + # Object already exists + {:ok, nil, comment} + end end end @@ -1177,4 +1178,16 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do defp can_manage_event?(%Actor{} = _actor, %Event{} = _event) do false end + + @spec create_comment_or_discussion(map()) :: + {:ok, Activity.t(), struct()} | {:error, atom() | Ecto.Changeset.t()} + defp create_comment_or_discussion(object_data) do + if is_data_for_comment_or_discussion?(object_data) do + Logger.debug("Chosing to create a regular comment") + Actions.Create.create(:comment, object_data, false) + else + Logger.debug("Chosing to initialize or add a comment to a conversation") + Actions.Create.create(:discussion, object_data, false) + end + end end diff --git a/lib/federation/activity_stream/converter/event.ex b/lib/federation/activity_stream/converter/event.ex index 9521a7fc7..78d6ccb55 100644 --- a/lib/federation/activity_stream/converter/event.ex +++ b/lib/federation/activity_stream/converter/event.ex @@ -230,8 +230,6 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do end end - @ap_public "https://www.w3.org/ns/activitystreams#Public" - defp get_visibility(object), do: if(@ap_public in object["to"], do: :public, else: :unlisted) @spec date_to_string(DateTime.t() | nil) :: String.t() diff --git a/mix.exs b/mix.exs index fbdf2cecf..ab4276597 100644 --- a/mix.exs +++ b/mix.exs @@ -247,6 +247,7 @@ defmodule Mobilizon.Mixfile do test: [ "ecto.create", "ecto.migrate", + "tz_world.update", &run_test/1 ], "phx.deps_migrate_serve": [ diff --git a/test/federation/activity_pub/transmogrifier/comments_test.exs b/test/federation/activity_pub/transmogrifier/comments_test.exs index 1f0e95160..19528a95d 100644 --- a/test/federation/activity_pub/transmogrifier/comments_test.exs +++ b/test/federation/activity_pub/transmogrifier/comments_test.exs @@ -117,6 +117,16 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do end) =~ "[warn] Parent object is something we don't handle" end + test "it ignores incoming private notes" do + data = File.read!("test/fixtures/mastodon-post-activity-private.json") |> Jason.decode!() + event = insert(:event) + object = data["object"] + object = Map.put(object, "inReplyTo", event.url) + data = Map.put(data, "object", object) + + :error = Transmogrifier.handle_incoming(data) + end + test "it works for incoming notices" do data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!() diff --git a/test/fixtures/mastodon-post-activity-private.json b/test/fixtures/mastodon-post-activity-private.json new file mode 100644 index 000000000..3f4c8647c --- /dev/null +++ b/test/fixtures/mastodon-post-activity-private.json @@ -0,0 +1,57 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Emoji": "toot:Emoji", + "Hashtag": "as:Hashtag", + "atomUri": "ostatus:atomUri", + "conversation": "ostatus:conversation", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "movedTo": "as:movedTo", + "ostatus": "http://ostatus.org#", + "sensitive": "as:sensitive", + "toot": "http://joinmastodon.org/ns#" + } + ], + "actor": "https://framapiaf.org/users/admin", + "id": "https://framapiaf.org/users/admin/statuses/19512778738411823/activity", + "nickname": "lain", + "object": { + "atomUri": "https://framapiaf.org/users/admin/statuses/19512778738411823", + "attachment": [], + "attributedTo": "https://framapiaf.org/users/admin", + "content": "
@tcit here is a private message
", + "conversation": "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation", + "id": "https://framapiaf.org/users/admin/statuses/19512778738411823", + "inReplyTo": null, + "inReplyToAtomUri": null, + "published": "2018-02-12T14:08:20Z", + "sensitive": true, + "summary": "cw", + "tag": [ + { + "href": "https://framapiaf.org/users/tcit", + "name": "@tcit@framapiaf.org", + "type": "Mention" + } + ], + "to": [ + "https://framapiaf.org/users/tcit" + ], + "type": "Note", + "url": "https://framapiaf.org/@admin/19512778738411823" + }, + "published": "2018-02-12T14:08:20Z", + "signature": { + "created": "2018-02-12T14:08:20Z", + "creator": "https://framapiaf.org/users/admin#main-key", + "signatureValue": "rnNfcopkc6+Ju73P806popcfwrK9wGYHaJVG1/ZvrlEbWVDzaHjkXqj9Q3/xju5l8CSn9tvSgCCtPFqZsFQwn/pFIFUcw7ZWB2xi4bDm3NZ3S4XQ8JRaaX7og5hFxAhWkGhJhAkfxVnOg2hG+w2d/7d7vRVSC1vo5ip4erUaA/PkWusZvPIpxnRWoXaxJsFmVx0gJgjpJkYDyjaXUlp+jmaoseeZ4EPQUWqHLKJ59PRG0mg8j2xAjYH9nQaN14qMRmTGPxY8gfv/CUFcatA+8VJU9KEsJkDAwLVvglydNTLGrxpAJU78a2eaht0foV43XUIZGe3DKiJPgE+UOKGCJw==", + "type": "RsaSignature2017" + }, + "to": [ + "https://framapiaf.org/users/tcit" + ], + "type": "Create" +}