From 8d06be35e0f1cb5caa2b638330c8bb03ad08a127 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 17 Nov 2018 15:51:02 +0000 Subject: [PATCH 01/20] activitypub: utils: add determine_explicit_mentions() and tests --- lib/pleroma/web/activity_pub/utils.ex | 14 +++++++ test/web/activity_pub/utils_test.exs | 57 +++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 test/web/activity_pub/utils_test.exs diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index d2e457a68..d516818d9 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -25,6 +25,20 @@ def normalize_params(params) do Map.put(params, "actor", get_ap_id(params["actor"])) end + def determine_explicit_mentions(%{"tag" => tag} = _object) when is_list(tag) do + tag + |> Enum.filter(fn x -> is_map(x) end) + |> Enum.filter(fn x -> x["type"] == "Mention" end) + |> Enum.map(fn x -> x["href"] end) + end + + def determine_explicit_mentions(%{"tag" => tag} = object) when is_map(tag) do + Map.put(object, "tag", [tag]) + |> determine_explicit_mentions() + end + + def determine_explicit_mentions(_), do: [] + defp recipient_in_collection(ap_id, coll) when is_binary(coll), do: ap_id == coll defp recipient_in_collection(ap_id, coll) when is_list(coll), do: ap_id in coll defp recipient_in_collection(_, _), do: false diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs new file mode 100644 index 000000000..aeed0564c --- /dev/null +++ b/test/web/activity_pub/utils_test.exs @@ -0,0 +1,57 @@ +defmodule Pleroma.Web.ActivityPub.UtilsTest do + use Pleroma.DataCase + alias Pleroma.Web.ActivityPub.Utils + + describe "determine_explicit_mentions()" do + test "works with an object that has mentions" do + object = %{ + "tag" => [ + %{ + "type" => "Mention", + "href" => "https://example.com/~alyssa", + "name" => "Alyssa P. Hacker" + } + ] + } + + assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"] + end + + test "works with an object that does not have mentions" do + object = %{ + "tag" => [ + %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"} + ] + } + + assert Utils.determine_explicit_mentions(object) == [] + end + + test "works with an object that has mentions and other tags" do + object = %{ + "tag" => [ + %{ + "type" => "Mention", + "href" => "https://example.com/~alyssa", + "name" => "Alyssa P. Hacker" + }, + %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"} + ] + } + + assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"] + end + + test "works with an object that has no tags" do + object = %{} + + assert Utils.determine_explicit_mentions(object) == [] + end + + test "works with an object that has only IR tags" do + object = %{"tag" => ["2hu"]} + + assert Utils.determine_explicit_mentions(object) == [] + end + end +end From 681f40ee5c4de644c79f71bb6671c4c63b18e68a Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 17 Nov 2018 16:05:41 +0000 Subject: [PATCH 02/20] activitypub: transmogrifier: fix up to/cc addressing brain damage caused by mastodon-style explicit DMs --- .../web/activity_pub/transmogrifier.ex | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index fa3abe3d8..e9a801cf5 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -93,12 +93,42 @@ def fix_addressing_list(map, field) do end end - def fix_addressing(map) do - map - |> fix_addressing_list("to") - |> fix_addressing_list("cc") - |> fix_addressing_list("bto") - |> fix_addressing_list("bcc") + def fix_explicit_addressing(%{"to" => to, "cc" => cc} = object, explicit_mentions) do + explicit_to = + to + |> Enum.filter(fn x -> x in explicit_mentions end) + + explicit_cc = + to + |> Enum.filter(fn x -> x not in explicit_mentions end) + + final_cc = + (cc ++ explicit_cc) + |> Enum.uniq() + + object + |> Map.put("to", explicit_to) + |> Map.put("cc", final_cc) + end + + def fix_explicit_addressing(object, _explicit_mentions), do: object + + def fix_addressing(object) do + object = + object + |> fix_addressing_list("to") + |> fix_addressing_list("cc") + |> fix_addressing_list("bto") + |> fix_addressing_list("bcc") + + explicit_mentions = + object + |> Utils.determine_explicit_mentions() + + explicit_mentions = explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public"] + + object + |> fix_explicit_addressing(explicit_mentions) end def fix_actor(%{"attributedTo" => actor} = object) do From 21ac35fcc0a531914cc3f84ace89f6cf029cfa6c Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 17 Nov 2018 16:18:40 +0000 Subject: [PATCH 03/20] tests: add tests for DM sanitizer --- test/web/activity_pub/transmogrifier_test.exs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 6107ac4f7..5aa136e65 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -162,6 +162,36 @@ test "it works for incoming notices with url not being a string (prismo)" do assert data["object"]["url"] == "https://prismo.news/posts/83" end + test "it cleans up incoming notices which are not really DMs" do + user = insert(:user) + other_user = insert(:user) + + to = [user.ap_id, other_user.ap_id] + + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("to", to) + |> Map.put("cc", []) + + object = + data["object"] + |> Map.put("to", to) + |> Map.put("cc", []) + + data = Map.put(data, "object", object) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert data["to"] == [] + assert data["cc"] == to + + object = data["object"] + + assert object["to"] == [] + assert object["cc"] == to + end + test "it works for incoming follow requests" do user = insert(:user) From 75dfa1f0b07806908b11735afab3ba0dd3149659 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 17 Nov 2018 16:30:44 +0000 Subject: [PATCH 04/20] mastodon api: get_visibility(): DMs never have a cc list. --- lib/pleroma/web/mastodon_api/views/status_view.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 7f5a52ea3..feabf54c6 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -231,6 +231,9 @@ def get_visibility(object) do Enum.any?(to, &String.contains?(&1, "/followers")) -> "private" + length(cc) > 0 -> + "private" + true -> "direct" end From 75bb6637495ab02233815c04948b3d8b50c31674 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 23 Dec 2018 15:13:06 +0000 Subject: [PATCH 05/20] litepub schema: add litepub:directMessage flag --- priv/static/schemas/litepub-0.1.jsonld | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/priv/static/schemas/litepub-0.1.jsonld b/priv/static/schemas/litepub-0.1.jsonld index 819d25c38..15645646a 100644 --- a/priv/static/schemas/litepub-0.1.jsonld +++ b/priv/static/schemas/litepub-0.1.jsonld @@ -17,7 +17,9 @@ "toot": "http://joinmastodon.org/ns#", "totalItems": "as:totalItems", "value": "schema:value", - "sensitive": "as:sensitive" + "sensitive": "as:sensitive", + "litepub": "http://litepub.social/ns#", + "directMessage": "litepub:directMessage" } ] } From 9adc80afff5ea42e1773c6ada5e078ec6c1cadc8 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 23 Dec 2018 15:26:07 +0000 Subject: [PATCH 06/20] common api: set directMessage flag on our own posts --- lib/pleroma/web/common_api/common_api.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 504670439..7084da6de 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -143,7 +143,7 @@ def post(user, %{"status" => status} = data) do actor: user, context: context, object: object, - additional: %{"cc" => cc} + additional: %{"cc" => cc, "directMessage" => visibility == "direct"} }) res From ddae43eb43c5c63eeb0e93e60917b99b3ffb41d0 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 23 Dec 2018 15:27:08 +0000 Subject: [PATCH 07/20] activitypub: add is_private?/is_direct? helpers --- lib/pleroma/web/activity_pub/activity_pub.ex | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 130c06028..1fedfa854 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -805,6 +805,14 @@ def is_public?(data) do "https://www.w3.org/ns/activitystreams#Public" in (data["to"] ++ (data["cc"] || [])) end + def is_private?(activity) do + !is_public?(activity) && Enum.any?(activity.data["to"], &String.contains?(&1, "/followers")) + end + + def is_direct?(activity) do + !is_public?(activity) && !is_private?(activity) + end + def visible_for_user?(activity, nil) do is_public?(activity) end From 420651157becb8fac62e651d14376b6334316121 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 23 Dec 2018 15:35:49 +0000 Subject: [PATCH 08/20] transmogrifier: don't apply heuristics against messages which have `directMessage` set true --- .../web/activity_pub/transmogrifier.ex | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index e9a801cf5..5400aa657 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -113,14 +113,10 @@ def fix_explicit_addressing(%{"to" => to, "cc" => cc} = object, explicit_mention def fix_explicit_addressing(object, _explicit_mentions), do: object - def fix_addressing(object) do - object = - object - |> fix_addressing_list("to") - |> fix_addressing_list("cc") - |> fix_addressing_list("bto") - |> fix_addressing_list("bcc") + # if directMessage flag is set to true, leave the addressing alone + def fix_explicit_addressing(%{"directMessage" => true} = object), do: object + def fix_explicit_addressing(object) do explicit_mentions = object |> Utils.determine_explicit_mentions() @@ -131,6 +127,14 @@ def fix_addressing(object) do |> fix_explicit_addressing(explicit_mentions) end + def fix_addressing(object) do + object + |> fix_addressing_list("to") + |> fix_addressing_list("cc") + |> fix_addressing_list("bto") + |> fix_addressing_list("bcc") + end + def fix_actor(%{"attributedTo" => actor} = object) do object |> Map.put("actor", get_actor(%{"actor" => actor})) @@ -363,6 +367,7 @@ def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = obj data = Map.put(data, "actor", actor) |> fix_addressing + |> fix_explicit_addressing with nil <- Activity.get_create_activity_by_object_ap_id(object["id"]), %User{} = user <- User.get_or_fetch_by_ap_id(data["actor"]) do @@ -378,6 +383,7 @@ def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = obj additional: Map.take(data, [ "cc", + "directMessage", "id" ]) } From 7c9749f793aa0970a36742bf4177c1a9899b1ff4 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 23 Dec 2018 15:44:26 +0000 Subject: [PATCH 09/20] transmogrifier: slightly clean up fix_explicit_addressing pipeline --- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 5400aa657..5d3feccfe 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -133,6 +133,7 @@ def fix_addressing(object) do |> fix_addressing_list("cc") |> fix_addressing_list("bto") |> fix_addressing_list("bcc") + |> fix_explicit_addressing end def fix_actor(%{"attributedTo" => actor} = object) do @@ -367,7 +368,6 @@ def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = obj data = Map.put(data, "actor", actor) |> fix_addressing - |> fix_explicit_addressing with nil <- Activity.get_create_activity_by_object_ap_id(object["id"]), %User{} = user <- User.get_or_fetch_by_ap_id(data["actor"]) do From cf3099231db2f51a4e804a4e5630cd6774e60c77 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 23 Dec 2018 15:55:07 +0000 Subject: [PATCH 10/20] test: transmogrifier: verify directMessage flag is sent outbound based on declared visibility --- test/web/activity_pub/transmogrifier_test.exs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 5aa136e65..c1d542245 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -902,6 +902,34 @@ test "it adds like collection to object" do assert modified["object"]["likes"]["type"] == "OrderedCollection" assert modified["object"]["likes"]["totalItems"] == 0 end + + test "the directMessage flag is present" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu :moominmamma:"}) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["directMessage"] == false + + {:ok, activity} = + CommonAPI.post(user, %{"status" => "@{other_user.nickname} :moominmamma:"}) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["directMessage"] == false + + {:ok, activity} = + CommonAPI.post(user, %{ + "status" => "@{other_user.nickname} :moominmamma:", + "visibility" => "direct" + }) + + {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) + + assert modified["directMessage"] == true + end end describe "user upgrade" do From aa37313416c155a37b40e09617eb2fe524edbf0b Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 20 Jan 2019 02:30:29 +0000 Subject: [PATCH 11/20] activitypub: short-circuit is_public?() with directMessage flag check --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1fedfa854..68b684c4b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -800,6 +800,7 @@ def fetch_and_contain_remote_object_from_id(id) do def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false def is_public?(%Object{data: data}), do: is_public?(data) def is_public?(%Activity{data: data}), do: is_public?(data) + def is_public?(%{"directMessage" => true}), do: false def is_public?(data) do "https://www.w3.org/ns/activitystreams#Public" in (data["to"] ++ (data["cc"] || [])) @@ -809,6 +810,9 @@ def is_private?(activity) do !is_public?(activity) && Enum.any?(activity.data["to"], &String.contains?(&1, "/followers")) end + def is_direct?(%Activity{data: %{"directMessage" => true}}), do: true + def is_direct?(%Object{data: %{"directMessage" => true}}), do: true + def is_direct?(activity) do !is_public?(activity) && !is_private?(activity) end From aa480f4a8b46f24a07491228462b4318ca25eda7 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 21 Jan 2019 14:16:51 +0300 Subject: [PATCH 12/20] [#530] Prevents user `info` from being overwritten because of race conditions and non-partial update of embed (in WebFinger.ensure_keys_present and other places). --- lib/pleroma/web/activity_pub/activity_pub.ex | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 0431d62af..32c08c9d2 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -140,8 +140,9 @@ def create(%{to: to, actor: actor, context: context, object: object} = params) d additional ), {:ok, activity} <- insert(create_data, local), - :ok <- maybe_federate(activity), - {:ok, _actor} <- User.increase_note_count(actor) do + # Changing note count prior to federation in order not to reload `actor` (potentially updated by federator) + {:ok, _actor} <- User.increase_note_count(actor), + :ok <- maybe_federate(activity) do {:ok, activity} end end @@ -288,8 +289,9 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru with {:ok, _} <- Object.delete(object), {:ok, activity} <- insert(data, local), - :ok <- maybe_federate(activity), - {:ok, _actor} <- User.decrease_note_count(user) do + # Changing note count prior to federation in order not to reload `actor` (potentially updated by federator) + {:ok, _actor} <- User.decrease_note_count(user), + :ok <- maybe_federate(activity) do {:ok, activity} end end From 789a9843da0eef1e5426ab6558f1adf24231ce02 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 21 Jan 2019 14:30:01 +0300 Subject: [PATCH 13/20] [#530] Fixed test. --- test/integration/mastodon_websocket_test.exs | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index 03aabf12c..2e385f5ad 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -66,13 +66,10 @@ test "receives well formatted events" do assert json["payload"] assert {:ok, json} = Jason.decode(json["payload"]) - # Note: we remove the "statuses_count" from this result as it changes in the meantime - view_json = Pleroma.Web.MastodonAPI.StatusView.render("status.json", activity: activity, for: nil) |> Jason.encode!() |> Jason.decode!() - |> put_in(["account", "statuses_count"], 0) assert json == view_json end From a4d3fec8a71241d5c40fa76e33f15fa217154600 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Mon, 21 Jan 2019 14:52:41 +0300 Subject: [PATCH 14/20] [#502] Code comments update. --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 32c08c9d2..fd026a047 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -140,7 +140,7 @@ def create(%{to: to, actor: actor, context: context, object: object} = params) d additional ), {:ok, activity} <- insert(create_data, local), - # Changing note count prior to federation in order not to reload `actor` (potentially updated by federator) + # Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info {:ok, _actor} <- User.increase_note_count(actor), :ok <- maybe_federate(activity) do {:ok, activity} @@ -289,7 +289,7 @@ def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ tru with {:ok, _} <- Object.delete(object), {:ok, activity} <- insert(data, local), - # Changing note count prior to federation in order not to reload `actor` (potentially updated by federator) + # Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info {:ok, _actor} <- User.decrease_note_count(user), :ok <- maybe_federate(activity) do {:ok, activity} From 99763999c19bfb2a5d8a10af98ff3c54d2c929ce Mon Sep 17 00:00:00 2001 From: href Date: Mon, 21 Jan 2019 15:17:24 +0100 Subject: [PATCH 15/20] reverse_proxy - always override plug's cache-control --- lib/pleroma/reverse_proxy.ex | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex index a3846c3bb..a25b5ea4e 100644 --- a/lib/pleroma/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy.ex @@ -275,11 +275,24 @@ defp build_resp_headers(headers, opts) do defp build_resp_cache_headers(headers, _opts) do has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end) + has_cache_control? = List.keymember?(headers, "cache-control", 0) - if has_cache? do - headers - else - List.keystore(headers, "cache-control", 0, {"cache-control", @default_cache_control_header}) + cond do + has_cache? && has_cache_control? -> + headers + + has_cache? -> + # There's caching header present but no cache-control -- we need to explicitely override it to public + # as Plug defaults to "max-age=0, private, must-revalidate" + List.keystore(headers, "cache-control", 0, {"cache-control", "public"}) + + true -> + List.keystore( + headers, + "cache-control", + 0, + {"cache-control", @default_cache_control_header} + ) end end From 762fafe7387648520c8f7e4b5b248bc90e8c0f66 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 21 Jan 2019 17:54:11 +0100 Subject: [PATCH 16/20] Fix buggy test. --- test/web/activity_pub/transmogrifier_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index c1d542245..7db28854a 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -914,7 +914,7 @@ test "the directMessage flag is present" do assert modified["directMessage"] == false {:ok, activity} = - CommonAPI.post(user, %{"status" => "@{other_user.nickname} :moominmamma:"}) + CommonAPI.post(user, %{"status" => "@#{other_user.nickname} :moominmamma:"}) {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) @@ -922,7 +922,7 @@ test "the directMessage flag is present" do {:ok, activity} = CommonAPI.post(user, %{ - "status" => "@{other_user.nickname} :moominmamma:", + "status" => "@#{other_user.nickname} :moominmamma:", "visibility" => "direct" }) From f9a326909979959d6cb43f66177045bb2adccbf4 Mon Sep 17 00:00:00 2001 From: href Date: Mon, 21 Jan 2019 22:44:14 +0100 Subject: [PATCH 17/20] Uploader callback controller --- lib/pleroma/uploaders/uploader.ex | 37 +++++++++++++++++++++++--- lib/pleroma/web/router.ex | 5 ++++ lib/pleroma/web/uploader_controller.ex | 25 +++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 lib/pleroma/web/uploader_controller.ex diff --git a/lib/pleroma/uploaders/uploader.ex b/lib/pleroma/uploaders/uploader.ex index 0959d7a3e..ce83cbbbc 100644 --- a/lib/pleroma/uploaders/uploader.ex +++ b/lib/pleroma/uploaders/uploader.ex @@ -27,18 +27,47 @@ defmodule Pleroma.Uploaders.Uploader do This allows to correctly proxy or redirect requests to the backend, while allowing to migrate backends without breaking any URL. * `{url, url :: String.t}` to bypass `get_file/2` and use the `url` directly in the activity. * `{:error, String.t}` error information if the file failed to be saved to the backend. + * `:wait_callback` will wait for an http post request at `/api/pleroma/upload_callback/:upload_path` and call the uploader's `http_callback/3` method. """ + @type file_spec :: {:file | :url, String.t()} @callback put_file(Pleroma.Upload.t()) :: - :ok | {:ok, {:file | :url, String.t()}} | {:error, String.t()} + :ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback + + @callback http_callback(Plug.Conn.t(), Map.t()) :: + {:ok, Plug.Conn.t()} + | {:ok, Plug.Conn.t(), file_spec()} + | {:error, Plug.Conn.t(), String.t()} + @optional_callbacks http_callback: 2 + + @spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()} - @spec put_file(module(), Pleroma.Upload.t()) :: - {:ok, {:file | :url, String.t()}} | {:error, String.t()} def put_file(uploader, upload) do case uploader.put_file(upload) do :ok -> {:ok, {:file, upload.path}} - other -> other + :wait_callback -> handle_callback(uploader, upload) + {:ok, _} = ok -> ok + {:error, _} = error -> error + end + end + + defp handle_callback(uploader, upload) do + :global.register_name({__MODULE__, upload.path}, self()) + + receive do + {__MODULE__, pid, conn, params} -> + case uploader.http_callback(conn, params) do + {:ok, conn, ok} -> + send(pid, {__MODULE__, conn}) + {:ok, ok} + + {:error, conn, error} -> + send(pid, {__MODULE__, conn}) + {:error, error} + end + after + 30_000 -> {:error, "Uploader callback timeout"} end end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 7a0c9fd25..69ab58c6a 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -107,6 +107,11 @@ defmodule Pleroma.Web.Router do get("/captcha", UtilController, :captcha) end + scope "/api/pleroma", Pleroma.Web do + pipe_through(:pleroma_api) + post("/uploader_callback/:upload_path", UploaderController, :callback) + end + scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) delete("/user", AdminAPIController, :user_delete) diff --git a/lib/pleroma/web/uploader_controller.ex b/lib/pleroma/web/uploader_controller.ex new file mode 100644 index 000000000..6c28d1197 --- /dev/null +++ b/lib/pleroma/web/uploader_controller.ex @@ -0,0 +1,25 @@ +defmodule Pleroma.Web.UploaderController do + use Pleroma.Web, :controller + + alias Pleroma.Uploaders.Uploader + + def callback(conn, params = %{"upload_path" => upload_path}) do + process_callback(conn, :global.whereis_name({Uploader, upload_path}), params) + end + + def callbacks(conn, _) do + send_resp(conn, 400, "bad request") + end + + defp process_callback(conn, pid, params) when is_pid(pid) do + send(pid, {Uploader, self(), conn, params}) + + receive do + {Uploader, conn} -> conn + end + end + + defp process_callback(conn, _, _) do + send_resp(conn, 400, "bad request") + end +end From e460820fcfcdc68c3e2a43ee69d587ca261324f8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 22 Jan 2019 10:54:11 +0300 Subject: [PATCH 18/20] Add get_by_id to activity.ex --- lib/pleroma/activity.ex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 353f9f6cd..8fd0311d2 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -36,6 +36,10 @@ def get_by_ap_id(ap_id) do ) end + def get_by_id(id) do + Repo.get(Activity, id) + end + # TODO: # Go through these and fix them everywhere. # Wrong name, only returns create activities From 34d59e40086ad8adc020bac6d23ab2aa835f267b Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 22 Jan 2019 17:12:53 +0300 Subject: [PATCH 19/20] [#502] Fixed User.active_local_user_query to return users with nil or missing `info.deactivated`. Adjusted test. --- lib/pleroma/user.ex | 2 +- .../web/mastodon_api/mastodon_api_controller_test.exs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 06084b117..18137106e 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -901,7 +901,7 @@ def local_user_query do def active_local_user_query do from( u in local_user_query(), - where: fragment("?->'deactivated' @> 'false'", u.info) + where: fragment("not (?->'deactivated' @> 'true')", u.info) ) end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index dd84052a3..8443dc856 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -10,6 +10,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do alias Pleroma.Web.{OStatus, CommonAPI} alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.MastodonAPI.FilterView + alias Ecto.Changeset import Pleroma.Factory import ExUnit.CaptureLog import Tesla.Mock @@ -1483,6 +1484,16 @@ test "get instance information", %{conn: conn} do {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"}) + # Stats should count users with missing or nil `info.deactivated` value + user = Repo.get(User, user.id) + info_change = Changeset.change(user.info, %{deactivated: nil}) + + {:ok, _user} = + user + |> Changeset.change() + |> Changeset.put_embed(:info, info_change) + |> User.update_and_set_cache() + Pleroma.Stats.update_stats() conn = get(conn, "/api/v1/instance") From 98cbeae49c2144d6e1a4bc6114295e79a23e36c2 Mon Sep 17 00:00:00 2001 From: Michael Loftis Date: Tue, 22 Jan 2019 15:35:21 +0000 Subject: [PATCH 20/20] slightly changes definition so that autovacuum works paralell safe too --- ...90122153157_update_activity_visibility.exs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 priv/repo/migrations/20190122153157_update_activity_visibility.exs diff --git a/priv/repo/migrations/20190122153157_update_activity_visibility.exs b/priv/repo/migrations/20190122153157_update_activity_visibility.exs new file mode 100644 index 000000000..30075137c --- /dev/null +++ b/priv/repo/migrations/20190122153157_update_activity_visibility.exs @@ -0,0 +1,36 @@ +defmodule Pleroma.Repo.Migrations.UpdateActivityVisibility do + use Ecto.Migration + @disable_ddl_transaction true + + def up do + definition = """ + create or replace function activity_visibility(actor varchar, recipients varchar[], data jsonb) returns varchar as $$ + DECLARE + fa varchar; + public varchar := 'https://www.w3.org/ns/activitystreams#Public'; + BEGIN + SELECT COALESCE(users.follower_address, '') into fa from users where users.ap_id = actor; + + IF data->'to' ? public THEN + RETURN 'public'; + ELSIF data->'cc' ? public THEN + RETURN 'unlisted'; + ELSIF ARRAY[fa] && recipients THEN + RETURN 'private'; + ELSIF not(ARRAY[fa, public] && recipients) THEN + RETURN 'direct'; + ELSE + RETURN 'unknown'; + END IF; + END; + $$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE SECURITY DEFINER; + """ + + execute(definition) + + end + + def down do + + end +end